From 1a3216e13730f8351b4418d4a1434b8c952d3dcd Mon Sep 17 00:00:00 2001 From: tcerqueira Date: Mon, 29 Jun 2026 13:34:44 +0100 Subject: [PATCH 1/3] feat(database): expose KV connect database id and connect url in list `database list` dropped the per-environment Deno KV connect database UUID (metadata.td_id), so agents could not build the `Deno.openKv("https://api.deno.com/v2/databases//connect")` URL without opening the Console UI. Surface it per KV environment: `--json` now includes `databaseId` and a derived `connectUrl`, and the table gains a DATABASE ID column. Closes #106 --- deploy/database.ts | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/deploy/database.ts b/deploy/database.ts index eb823b2..831a78b 100644 --- a/deploy/database.ts +++ b/deploy/database.ts @@ -15,6 +15,14 @@ export type DatabaseContext = GlobalContext & { org?: string; }; +/** + * Build the Deno KV connect URL for a per-environment database id, suitable for + * `Deno.openKv("https://api.deno.com/v2/databases//connect")`. + */ +function kvConnectUrl(databaseId: string): string { + return `https://api.deno.com/v2/databases/${databaseId}/connect`; +} + const databasesProvisionCommand = new Command() .description("Provision a database") .example("Provision a Deno KV database", "provision my-db --kind denokv") @@ -332,7 +340,12 @@ const databasesListCommand = new Command() { slug: string; created_at: Date; - databases: Array<{ name: string; status: string; created_at: Date }>; + databases: Array<{ + name: string; + status: string; + created_at: Date; + metadata?: { td_id?: string }; + }>; assignments: Array<{ app_slug: string }>; } & ConnectionInfo >; @@ -344,11 +357,17 @@ const databasesListCommand = new Command() createdAt: database.created_at, assignments: database.assignments.map((a) => a.app_slug), connection: database.safeConnectionConfig, - databases: database.databases.map((db) => ({ - name: db.name, - status: db.status, - createdAt: db.created_at, - })), + databases: database.databases.map((db) => { + const databaseId = db.metadata?.td_id; + return { + name: db.name, + status: db.status, + createdAt: db.created_at, + ...(databaseId + ? { databaseId, connectUrl: kvConnectUrl(databaseId) } + : {}), + }; + }), }))); return; } @@ -371,7 +390,7 @@ const databasesListCommand = new Command() }, (database) => { return { - headers: ["NAME", "STATUS", "CREATED"], + headers: ["NAME", "STATUS", "CREATED", "DATABASE ID"], rows: database.databases.map((database) => { return [ database.name, @@ -379,6 +398,7 @@ const databasesListCommand = new Command() renderTemporalTimestamp( database.created_at.toISOString(), ), + database.metadata?.td_id ?? "", ]; }), }; From 81851e62629f383a8be654b7e4fde15990c311c2 Mon Sep 17 00:00:00 2001 From: tcerqueira Date: Mon, 29 Jun 2026 13:34:44 +0100 Subject: [PATCH 2/3] fix(database): emit JSON results and route status to stderr for mutations provision/link/assign/detach/delete printed human text to stdout and never emitted a JSON result, breaking stdout discipline under `--json`. They now write a single JSON result via writeJsonResult on stdout in `--json` mode and route the success/status text to stderr otherwise. --- deploy/database.ts | 58 +++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/deploy/database.ts b/deploy/database.ts index 831a78b..3f83223 100644 --- a/deploy/database.ts +++ b/deploy/database.ts @@ -80,11 +80,15 @@ const databasesProvisionCommand = new Command() }, }); - console.log( - `${ - green("✔") - } Successfully provisioned ${options.kind} database '${name}'.`, - ); + if (options.json) { + writeJsonResult({ name, engine: options.kind, org }); + } else { + console.error( + `${ + green("✔") + } Successfully provisioned ${options.kind} database '${name}'.`, + ); + } })); const databasesLinkCommand = new Command() @@ -172,7 +176,11 @@ const databasesLinkCommand = new Command() engine, connection_config: connectionConfig, }); - console.log(`${green("✔")} Connection test successful.`); + if (options.json) { + writeJsonResult({ name, engine, dryRun: true, ok: true }); + } else { + console.error(`${green("✔")} Connection test successful.`); + } } else { await trpcClient.mutation("databases.createInstance", { org: org, @@ -180,7 +188,11 @@ const databasesLinkCommand = new Command() engine, connectionConfig, }); - console.log(`${green("✔")} Successfully linked database '${name}'.`); + if (options.json) { + writeJsonResult({ name, engine, org }); + } else { + console.error(`${green("✔")} Successfully linked database '${name}'.`); + } } })); @@ -201,9 +213,15 @@ const databasesAssignCommand = new Command() databaseInstance: name, }); - console.log( - `${green("✔")} Successfully assigned database '${name}' to app '${app}'.`, - ); + if (options.json) { + writeJsonResult({ database: name, app, org }); + } else { + console.error( + `${ + green("✔") + } Successfully assigned database '${name}' to app '${app}'.`, + ); + } })); const databasesDetachCommand = new Command() @@ -223,11 +241,15 @@ const databasesDetachCommand = new Command() databaseInstance: name, }); - console.log( - `${ - green("✔") - } Successfully detached database '${name}' from app '${app}'.`, - ); + if (options.json) { + writeJsonResult({ database: name, app, org }); + } else { + console.error( + `${ + green("✔") + } Successfully detached database '${name}' from app '${app}'.`, + ); + } })); const databasesQueryCommand = new Command() @@ -420,7 +442,11 @@ const databasesDeleteCommand = new Command() databaseInstance: name, }); - console.log(`${green("✔")} Successfully deleted database '${name}'.`); + if (options.json) { + writeJsonResult({ name, org }); + } else { + console.error(`${green("✔")} Successfully deleted database '${name}'.`); + } })); export const databasesCommand = new Command() From 78c18fd01811a5f0fa34fa3854158891b20ea2cc Mon Sep 17 00:00:00 2001 From: tcerqueira Date: Mon, 29 Jun 2026 15:43:48 +0100 Subject: [PATCH 3/3] refactor(database): use consistent `database` key in mutation JSON results provision/link/delete emitted the database name under `name` while assign/detach used `database`, forcing consumers to special-case the key per subcommand. Standardize all mutation JSON results on `database`. --- deploy/database.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/database.ts b/deploy/database.ts index 3f83223..5603290 100644 --- a/deploy/database.ts +++ b/deploy/database.ts @@ -81,7 +81,7 @@ const databasesProvisionCommand = new Command() }); if (options.json) { - writeJsonResult({ name, engine: options.kind, org }); + writeJsonResult({ database: name, engine: options.kind, org }); } else { console.error( `${ @@ -177,7 +177,7 @@ const databasesLinkCommand = new Command() connection_config: connectionConfig, }); if (options.json) { - writeJsonResult({ name, engine, dryRun: true, ok: true }); + writeJsonResult({ database: name, engine, dryRun: true, ok: true }); } else { console.error(`${green("✔")} Connection test successful.`); } @@ -189,7 +189,7 @@ const databasesLinkCommand = new Command() connectionConfig, }); if (options.json) { - writeJsonResult({ name, engine, org }); + writeJsonResult({ database: name, engine, org }); } else { console.error(`${green("✔")} Successfully linked database '${name}'.`); } @@ -443,7 +443,7 @@ const databasesDeleteCommand = new Command() }); if (options.json) { - writeJsonResult({ name, org }); + writeJsonResult({ database: name, org }); } else { console.error(`${green("✔")} Successfully deleted database '${name}'.`); }