diff --git a/.changeset/kv-namespace-delete-by-name.md b/.changeset/kv-namespace-delete-by-name.md new file mode 100644 index 000000000000..e95e974b3b2f --- /dev/null +++ b/.changeset/kv-namespace-delete-by-name.md @@ -0,0 +1,14 @@ +--- +"wrangler": minor +--- + +Allow deleting KV namespaces by name + +You can now delete a KV namespace by providing its name as a positional argument: + +```bash +wrangler kv namespace delete my-namespace +``` + +This aligns the delete command with the create command, which also accepts a namespace name. +The existing `--namespace-id` and `--binding` flags continue to work as before. diff --git a/packages/wrangler/src/__tests__/index.test.ts b/packages/wrangler/src/__tests__/index.test.ts index 18b4c3f264c8..e5d715125782 100644 --- a/packages/wrangler/src/__tests__/index.test.ts +++ b/packages/wrangler/src/__tests__/index.test.ts @@ -287,7 +287,7 @@ describe("wrangler", () => { COMMANDS wrangler kv namespace create Create a new namespace wrangler kv namespace list Output a list of all KV namespaces associated with your account id - wrangler kv namespace delete Delete a given namespace. + wrangler kv namespace delete [namespace] Delete a given namespace. wrangler kv namespace rename [old-name] Rename a KV namespace GLOBAL FLAGS diff --git a/packages/wrangler/src/__tests__/kv/bulk.test.ts b/packages/wrangler/src/__tests__/kv/bulk.test.ts index 9bbc447fa080..f17d6914085a 100644 --- a/packages/wrangler/src/__tests__/kv/bulk.test.ts +++ b/packages/wrangler/src/__tests__/kv/bulk.test.ts @@ -325,7 +325,7 @@ describe("kv", () => { const keys = ["someKey1", "ns:someKey2"]; writeFileSync("./keys.json", JSON.stringify(keys)); mockConfirm({ - text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`, + text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace id: "some-namespace-id"?`, result: true, }); const requests = mockDeleteRequest("some-namespace-id", keys); @@ -349,7 +349,7 @@ describe("kv", () => { const keys = [{ name: "someKey1" }, { name: "ns:someKey2" }]; writeFileSync("./keys.json", JSON.stringify(keys)); mockConfirm({ - text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`, + text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace id: "some-namespace-id"?`, result: true, }); const requests = mockDeleteRequest( @@ -376,7 +376,7 @@ describe("kv", () => { const keys = new Array(12000).fill("some-key"); writeFileSync("./keys.json", JSON.stringify(keys)); mockConfirm({ - text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`, + text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace id: "some-namespace-id"?`, result: true, }); const requests = mockDeleteRequest("some-namespace-id", keys); @@ -413,7 +413,7 @@ describe("kv", () => { const keys = ["someKey1", "ns:someKey2"]; writeFileSync("./keys.json", JSON.stringify(keys)); mockConfirm({ - text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`, + text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace id: "some-namespace-id"?`, result: false, }); await runWrangler( @@ -477,7 +477,7 @@ describe("kv", () => { const keys = 12354; writeFileSync("./keys.json", JSON.stringify(keys)); mockConfirm({ - text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`, + text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace id: "some-namespace-id"?`, result: true, }); await expect( @@ -485,18 +485,18 @@ describe("kv", () => { `kv bulk delete --remote --namespace-id some-namespace-id keys.json` ) ).rejects.toThrowErrorMatchingInlineSnapshot(` - [Error: Unexpected JSON input from "keys.json". - Expected an array of strings but got: - 12354] + [Error: Unexpected JSON input from "keys.json". + Expected an array of strings but got: + 12354] `); expect(std.out).toMatchInlineSnapshot(` - " - ⛅️ wrangler x.x.x - ────────────────── - Resource location: remote + " + ⛅️ wrangler x.x.x + ────────────────── + Resource location: remote - " - `); + " + `); expect(std.warn).toMatchInlineSnapshot(`""`); }); @@ -504,7 +504,7 @@ describe("kv", () => { const keys = ["good", 12354, { key: "someKey" }, null]; writeFileSync("./keys.json", JSON.stringify(keys)); mockConfirm({ - text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`, + text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace id: "some-namespace-id"?`, result: true, }); await expect( @@ -512,20 +512,20 @@ describe("kv", () => { `kv bulk delete --remote --namespace-id some-namespace-id keys.json` ) ).rejects.toThrowErrorMatchingInlineSnapshot(` - [Error: Unexpected JSON input from "keys.json". - Expected an array of strings or objects with a "name" key. - The item at index 1 is type: "number" - 12354 - The item at index 2 is type: "object" - {"key":"someKey"} - The item at index 3 is type: "object" - null] - `); + [Error: Unexpected JSON input from "keys.json". + Expected an array of strings or objects with a "name" key. + The item at index 1 is type: "number" - 12354 + The item at index 2 is type: "object" - {"key":"someKey"} + The item at index 3 is type: "object" - null] + `); expect(std.out).toMatchInlineSnapshot(` - " - ⛅️ wrangler x.x.x - ────────────────── - Resource location: remote + " + ⛅️ wrangler x.x.x + ────────────────── + Resource location: remote - " - `); + " + `); expect(std.warn).toMatchInlineSnapshot(`""`); }); }); diff --git a/packages/wrangler/src/__tests__/kv/key.test.ts b/packages/wrangler/src/__tests__/kv/key.test.ts index b1669dd7a35f..3d1451e9c116 100644 --- a/packages/wrangler/src/__tests__/kv/key.test.ts +++ b/packages/wrangler/src/__tests__/kv/key.test.ts @@ -101,7 +101,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the value "my-value" to key "my-key" on namespace some-namespace-id." + Writing the value "my-value" to key "my-key" on namespace id: "some-namespace-id"." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -125,7 +125,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the value "my-value" to key "/my-key" on namespace DS9." + Writing the value "my-value" to key "/my-key" on namespace id: "DS9"." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -148,7 +148,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the value "my-value" to key "my-key" on namespace bound-id." + Writing the value "my-value" to key "my-key" on namespace binding: "someBinding" (id: "bound-id")." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -173,7 +173,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the value "my-value" to key "my-key" on namespace preview-bound-id." + Writing the value "my-value" to key "my-key" on namespace binding: "someBinding" (id: "preview-bound-id")." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -198,7 +198,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the value "my-value" to key "my-key" on namespace some-namespace-id." + Writing the value "my-value" to key "my-key" on namespace id: "some-namespace-id"." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -220,7 +220,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the value "my-value" to key "my-key" on namespace env-bound-id." + Writing the value "my-value" to key "my-key" on namespace binding: "someBinding" (id: "env-bound-id")." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -244,7 +244,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the contents of foo.txt to the key "my-key" on namespace some-namespace-id." + Writing the contents of foo.txt to the key "my-key" on namespace id: "some-namespace-id"." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -271,7 +271,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the contents of test.png to the key "my-key" on namespace another-namespace-id." + Writing the contents of test.png to the key "my-key" on namespace id: "another-namespace-id"." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -297,7 +297,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the value "dVal" to key "dKey" on namespace some-namespace-id with metadata "{"mKey":"mValue"}"." + Writing the value "dVal" to key "dKey" on namespace id: "some-namespace-id" with metadata "{"mKey":"mValue"}"." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -327,7 +327,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Writing the contents of test.png to the key "another-my-key" on namespace some-namespace-id with metadata "{"mKey":"mValue"}"." + Writing the contents of test.png to the key "another-my-key" on namespace id: "some-namespace-id" with metadata "{"mKey":"mValue"}"." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -1232,7 +1232,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Deleting the key "/NCC-74656" on namespace voyager." + Deleting the key "/NCC-74656" on namespace id: "voyager"." ` ); expect(std.err).toMatchInlineSnapshot(`""`); @@ -1284,7 +1284,7 @@ describe("kv", () => { ────────────────── Resource location: remote - Deleting the key "someKey" on namespace env-bound-id." + Deleting the key "someKey" on namespace binding: "someBinding" (id: "env-bound-id")." ` ); expect(std.err).toMatchInlineSnapshot(`""`); diff --git a/packages/wrangler/src/__tests__/kv/local.test.ts b/packages/wrangler/src/__tests__/kv/local.test.ts index 2147ac4ee32a..97a07c542252 100644 --- a/packages/wrangler/src/__tests__/kv/local.test.ts +++ b/packages/wrangler/src/__tests__/kv/local.test.ts @@ -28,7 +28,7 @@ describe("kv", () => { Use --remote if you want to access the remote instance. - Writing the value "value" to key "val" on namespace some-namespace-id." + Writing the value "value" to key "val" on namespace id: "some-namespace-id"." `); await runWrangler( @@ -136,7 +136,7 @@ describe("kv", () => { Use --remote if you want to access the remote instance. - Writing the value "value" to key "val" on namespace some-namespace-id. + Writing the value "value" to key "val" on namespace id: "some-namespace-id". value" `); await runWrangler(`kv key delete val --namespace-id some-namespace-id`); @@ -148,7 +148,7 @@ describe("kv", () => { Use --remote if you want to access the remote instance. - Deleting the key "val" on namespace some-namespace-id." + Deleting the key "val" on namespace id: "some-namespace-id"." `); await runWrangler( @@ -401,7 +401,7 @@ describe("kv", () => { Use --remote if you want to access the remote instance. - Writing the value "value" to key "val" on namespace some-namespace-id. + Writing the value "value" to key "val" on namespace id: "some-namespace-id". ⛅️ wrangler x.x.x ────────────────── @@ -409,7 +409,7 @@ describe("kv", () => { Use --remote if you want to access the remote instance. - Writing the value "persistValue" to key "val" on namespace some-namespace-id." + Writing the value "persistValue" to key "val" on namespace id: "some-namespace-id"." `); await runWrangler( diff --git a/packages/wrangler/src/__tests__/kv/namespace.test.ts b/packages/wrangler/src/__tests__/kv/namespace.test.ts index 599441ebcd50..21eeed7e2d48 100644 --- a/packages/wrangler/src/__tests__/kv/namespace.test.ts +++ b/packages/wrangler/src/__tests__/kv/namespace.test.ts @@ -413,11 +413,11 @@ describe("kv", () => { ────────────────── Resource location: remote - About to delete remote KV namespace 'someBinding (env-bound-id)'. + About to delete remote KV namespace binding: "someBinding" (id: "env-bound-id"). This action is irreversible and will permanently delete all data in the KV namespace. - Deleting KV namespace env-bound-id. - Deleted KV namespace env-bound-id." + Deleting KV namespace binding: "someBinding" (id: "env-bound-id"). + Deleted KV namespace binding: "someBinding" (id: "env-bound-id")." `); expect(std.err).toMatchInlineSnapshot(`""`); expect(requests.count).toEqual(1); @@ -435,6 +435,102 @@ describe("kv", () => { ); expect(requests.count).toEqual(1); }); + + function mockListRequestForDelete(namespaces: KVNamespaceInfo[]) { + const requests = { count: 0 }; + msw.use( + http.get( + "*/accounts/:accountId/storage/kv/namespaces", + async ({ request, params }) => { + const url = new URL(request.url); + requests.count++; + expect(params.accountId).toEqual("some-account-id"); + + const pageSize = Number(url.searchParams.get("per_page")); + const page = Number(url.searchParams.get("page") ?? 1); + return HttpResponse.json( + createFetchResult( + namespaces.slice((page - 1) * pageSize, page * pageSize) + ) + ); + } + ) + ); + return requests; + } + + it("should delete a namespace specified by name", async () => { + const listRequests = mockListRequestForDelete([ + { id: "some-namespace-id", title: "my-namespace" }, + { id: "other-namespace-id", title: "other-namespace" }, + ]); + const deleteRequests = mockDeleteRequest("some-namespace-id"); + + mockConfirm({ + text: "Ok to proceed?", + result: true, + }); + + await runWrangler("kv namespace delete my-namespace"); + + expect(listRequests.count).toEqual(1); + expect(deleteRequests.count).toEqual(1); + expect(std.out).toContain( + 'Deleted KV namespace name: "my-namespace" (id: "some-namespace-id")' + ); + }); + + it("should error if namespace name is not found", async () => { + mockListRequestForDelete([ + { id: "other-namespace-id", title: "other-namespace" }, + ]); + + await expect( + runWrangler("kv namespace delete nonexistent-namespace") + ).rejects.toThrowErrorMatchingInlineSnapshot( + ` + [Error: Not able to delete namespace. + No namespace found with the name "nonexistent-namespace". Use --namespace-id or --binding instead, or check available namespaces with "wrangler kv namespace list".] + ` + ); + }); + + it("should error if both namespace name and --namespace-id are provided", async () => { + await expect( + runWrangler("kv namespace delete my-namespace --namespace-id some-id") + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Cannot specify multiple of: namespace name (as positional argument), --binding, or --namespace-id. Use only one.]` + ); + }); + + it("should error if both namespace name and --binding are provided", async () => { + writeWranglerConfig(wranglerKVConfig); + await expect( + runWrangler("kv namespace delete my-namespace --binding someBinding") + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Cannot specify multiple of: namespace name (as positional argument), --binding, or --namespace-id. Use only one.]` + ); + }); + + it("should delete namespace by name with --skip-confirmation flag", async () => { + const listRequests = mockListRequestForDelete([ + { id: "some-namespace-id", title: "my-namespace" }, + ]); + const deleteRequests = mockDeleteRequest("some-namespace-id"); + + await runWrangler("kv namespace delete my-namespace -y"); + + expect(listRequests.count).toEqual(1); + expect(deleteRequests.count).toEqual(1); + }); + + it("should error if no namespace identifier is provided", async () => { + await expect( + runWrangler("kv namespace delete") + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Must specify one of: namespace name (as positional argument), --binding, or --namespace-id]` + ); + }); }); describe("rename", () => { @@ -504,7 +600,7 @@ describe("kv", () => { Rename a KV namespace POSITIONALS - old-name The current name (title) of the namespace to rename [string] + old-name The current name of the namespace to rename [string] GLOBAL FLAGS -c, --config Path to Wrangler configuration file [string] diff --git a/packages/wrangler/src/kv/helpers.ts b/packages/wrangler/src/kv/helpers.ts index 5bee4163815d..be2948472fcf 100644 --- a/packages/wrangler/src/kv/helpers.ts +++ b/packages/wrangler/src/kv/helpers.ts @@ -29,6 +29,7 @@ export const BATCH_KEY_MAX = API_MAX / 10; export const BATCH_MAX_ERRORS_WARNINGS = 12; type KvArgs = { + namespace?: string; binding?: string; "namespace-id"?: string; preview?: boolean; @@ -419,14 +420,39 @@ async function getIdFromSettings( return existingKV.namespace_id as string; } +/** + * Result of resolving a KV namespace ID. + */ +export interface KVNamespaceIdResult { + namespaceId: string; + displayName: string; +} + export async function getKVNamespaceId( - { preview, binding, "namespace-id": namespaceId }: KvArgs, + { namespace, preview, binding, "namespace-id": namespaceId }: KvArgs, config: Config, isLocal: boolean -): Promise { - // nice +): Promise { if (namespaceId) { - return namespaceId; + return { namespaceId, displayName: `id: "${namespaceId}"` }; + } + + // If namespace name is provided, look up the ID from the API + if (namespace) { + const accountId = await requireAuth(config); + const namespaces = await listKVNamespaces(config, accountId); + const found = namespaces.find((ns) => ns.title === namespace); + + if (!found) { + throw new UserError( + `No namespace found with the name "${namespace}". ` + + `Use --namespace-id or --binding instead, or check available namespaces with "wrangler kv namespace list".` + ); + } + return { + namespaceId: found.id, + displayName: `name: "${namespace}" (id: "${found.id}")`, + }; } // begin pre-flight checks @@ -451,10 +477,12 @@ export async function getKVNamespaceId( ); } - const namespace = config.kv_namespaces.find((ns) => ns.binding === binding); + const configNamespace = config.kv_namespaces.find( + (ns) => ns.binding === binding + ); // we couldn't find a namespace with that binding - if (!namespace) { + if (!configNamespace) { throw new UserError( `A namespace with binding name "${binding}" was not found in the configured "kv_namespaces".` ); @@ -462,11 +490,15 @@ export async function getKVNamespaceId( // end pre-flight checks + // Helper to format displayName for binding-based lookups + const formatDisplayName = (nsId: string) => + `binding: "${binding}" (id: "${nsId}")`; + // we're in preview mode, `--preview true` or `--preview` was passed - if (preview && namespace.preview_id) { - namespaceId = namespace.preview_id; + if (preview && configNamespace.preview_id) { + const nsId = configNamespace.preview_id; // We don't want to execute code below if preview is set to true, so we just return. Otherwise we will get errors! - return namespaceId; + return { namespaceId: nsId, displayName: formatDisplayName(nsId) }; } else if (preview) { throw new UserError( `No preview ID found for ${binding}. Add one to your wrangler config file to use a separate namespace for previewing your worker.` @@ -478,14 +510,15 @@ export async function getKVNamespaceId( const previewIsDefined = typeof preview !== "undefined"; // --preview false was passed - if (previewIsDefined && namespace.id) { - namespaceId = namespace.id; + if (previewIsDefined && configNamespace.id) { + const nsId = configNamespace.id; // We don't want to execute code below if preview is set to true, so we just return. Otherwise we can get error! - return namespaceId; + return { namespaceId: nsId, displayName: formatDisplayName(nsId) }; } else if (previewIsDefined) { if (getFlag("RESOURCES_PROVISION")) { assert(binding); - return getIdFromSettings(config, binding, isLocal); + const nsId = await getIdFromSettings(config, binding, isLocal); + return { namespaceId: nsId, displayName: formatDisplayName(nsId) }; } throw new UserError( `No namespace ID found for ${binding}. Add one to your wrangler config file or pass it via \`--namespace-id\`.` @@ -494,33 +527,25 @@ export async function getKVNamespaceId( // `--preview` wasn't passed const bindingHasOnlyOneId = - (namespace.id && !namespace.preview_id) || - (!namespace.id && namespace.preview_id); + (configNamespace.id && !configNamespace.preview_id) || + (!configNamespace.id && configNamespace.preview_id); if (bindingHasOnlyOneId) { - namespaceId = namespace.id || namespace.preview_id; + const nsId = configNamespace.id || configNamespace.preview_id; + assert(nsId); + return { namespaceId: nsId, displayName: formatDisplayName(nsId) }; } else if ( getFlag("RESOURCES_PROVISION") && - !namespace.id && - !namespace.preview_id + !configNamespace.id && + !configNamespace.preview_id ) { assert(binding); - return getIdFromSettings(config, binding, isLocal); + const nsId = await getIdFromSettings(config, binding, isLocal); + return { namespaceId: nsId, displayName: formatDisplayName(nsId) }; } else { throw new UserError( `${binding} has both a namespace ID and a preview ID. Specify "--preview" or "--preview false" to avoid writing data to the wrong namespace.` ); } - - // shouldn't happen. we should be able to prove this with strong typing. - // TODO: when we add strongly typed commands, rewrite these checks so they're exhaustive - if (!namespaceId) { - throw new Error( - "Something went wrong trying to determine which namespace to upload to.\n" + - "Please create a github issue with the command you just ran along with your wrangler configuration." - ); - } - - return namespaceId; } // TODO(soon): once we upgrade to TypeScript 5.2, this should actually use `using`: diff --git a/packages/wrangler/src/kv/index.ts b/packages/wrangler/src/kv/index.ts index c5d02a22e49a..3c72b2a5e4ec 100644 --- a/packages/wrangler/src/kv/index.ts +++ b/packages/wrangler/src/kv/index.ts @@ -191,7 +191,12 @@ export const kvNamespaceDeleteCommand = createCommand({ status: "stable", owner: "Product: KV", }, + positionalArgs: ["namespace"], args: { + namespace: { + type: "string", + describe: "The name of the namespace to delete", + }, binding: { type: "string", requiresArg: true, @@ -215,24 +220,47 @@ export const kvNamespaceDeleteCommand = createCommand({ }, validateArgs(args) { - demandOneOfOption("binding", "namespace-id")(args); + // Check that exactly one of namespace, binding, or namespace-id is provided + const providedOptions = [ + args.namespace, + args.binding, + args.namespaceId, + ].filter(Boolean); + + if (providedOptions.length === 0) { + throw new CommandLineArgsError( + "Must specify one of: namespace name (as positional argument), --binding, or --namespace-id" + ); + } + + if (providedOptions.length > 1) { + throw new CommandLineArgsError( + "Cannot specify multiple of: namespace name (as positional argument), --binding, or --namespace-id. Use only one." + ); + } }, async handler(args) { const config = readConfig(args); printResourceLocation("remote"); - let id; + const accountId = await requireAuth(config); + + let namespaceId: string; + let displayName: string; try { - id = await getKVNamespaceId(args, config, false); + ({ namespaceId, displayName } = await getKVNamespaceId( + args, + config, + false + )); } catch (e) { throw new CommandLineArgsError( "Not able to delete namespace.\n" + ((e as Error).message ?? e) ); } - const accountId = await requireAuth(config); logger.log( - `About to delete ${chalk.bold("remote")} KV namespace '${args.binding ? args.binding + ` (${id})` : args.namespaceId}'.\n` + + `About to delete ${chalk.bold("remote")} KV namespace ${displayName}.\n` + `This action is irreversible and will permanently delete all data in the KV namespace.\n` ); if (!args.skipConfirmation) { @@ -243,9 +271,9 @@ export const kvNamespaceDeleteCommand = createCommand({ } } - logger.log(`Deleting KV namespace ${id}.`); - await deleteKVNamespace(config, accountId, id); - logger.log(`Deleted KV namespace ${id}.`); + logger.log(`Deleting KV namespace ${displayName}.`); + await deleteKVNamespace(config, accountId, namespaceId); + logger.log(`Deleted KV namespace ${displayName}.`); metrics.sendMetricsEvent("delete kv namespace", { sendMetrics: config.send_metrics, }); @@ -259,7 +287,7 @@ export const kvNamespaceDeleteCommand = createCommand({ // ➜ test-mf wrangler kv:namespace delete --namespace-id 2a7d3d8b23fc4159b5afa489d6cfd388 // Are you sure you want to delete namespace 2a7d3d8b23fc4159b5afa489d6cfd388? [y/n] // y - // 🌀 Deleting namespace 2a7d3d8b23fc4159b5afa489d6cfd388 + // 🌀 Deleting namespace name: "my kv store" (id: "2a7d3d8b23fc4159b5afa489d6cfd388") // ✨ Success // ⚠️ Make sure to remove this "kv-namespace" entry from your configuration file! // ➜ test-mf @@ -280,7 +308,7 @@ export const kvNamespaceRenameCommand = createCommand({ args: { "old-name": { type: "string", - describe: "The current name (title) of the namespace to rename", + describe: "The current name of the namespace to rename", }, "namespace-id": { type: "string", @@ -436,7 +464,11 @@ export const kvKeyPutCommand = createCommand({ async handler({ key, ttl, expiration, metadata, ...args }) { const localMode = isLocal(args); const config = readConfig(args); - const namespaceId = await getKVNamespaceId(args, config, localMode); + const { namespaceId, displayName } = await getKVNamespaceId( + args, + config, + localMode + ); // One of `args.path` and `args.value` must be defined const value = args.path ? readFileSyncToBuffer(args.path) @@ -449,11 +481,11 @@ export const kvKeyPutCommand = createCommand({ if (args.path) { logger.log( - `Writing the contents of ${args.path} to the key "${key}" on namespace ${namespaceId}${metadataLog}.` + `Writing the contents of ${args.path} to the key "${key}" on namespace ${displayName}${metadataLog}.` ); } else { logger.log( - `Writing the value "${value}" to key "${key}" on namespace ${namespaceId}${metadataLog}.` + `Writing the value "${value}" to key "${key}" on namespace ${displayName}${metadataLog}.` ); } @@ -548,7 +580,7 @@ export const kvKeyListCommand = createCommand({ const localMode = isLocal(args); // TODO: support for limit+cursor (pagination) const config = readConfig(args); - const namespaceId = await getKVNamespaceId(args, config, localMode); + const { namespaceId } = await getKVNamespaceId(args, config, localMode); let result: NamespaceKeyInfo[]; let metricEvent: EventNames; @@ -646,7 +678,7 @@ export const kvKeyGetCommand = createCommand({ async handler({ key, ...args }) { const localMode = isLocal(args); const config = readConfig(args); - const namespaceId = await getKVNamespaceId(args, config, localMode); + const { namespaceId } = await getKVNamespaceId(args, config, localMode); let bufferKVValue; let metricEvent: EventNames; @@ -745,9 +777,13 @@ export const kvKeyDeleteCommand = createCommand({ async handler({ key, ...args }) { const localMode = isLocal(args); const config = readConfig(args); - const namespaceId = await getKVNamespaceId(args, config, localMode); + const { namespaceId, displayName } = await getKVNamespaceId( + args, + config, + localMode + ); - logger.log(`Deleting the key "${key}" on namespace ${namespaceId}.`); + logger.log(`Deleting the key "${key}" on namespace ${displayName}.`); let metricEvent: EventNames; if (localMode) { @@ -794,7 +830,7 @@ export const kvBulkGetCommand = createCommand({ async handler({ filename, ...args }) { const localMode = isLocal(args); const config = readConfig(args); - const namespaceId = await getKVNamespaceId(args, config, localMode); + const { namespaceId } = await getKVNamespaceId(args, config, localMode); const content = parseJSON(readFileSync(filename), filename) as ( | string @@ -893,7 +929,7 @@ export const kvBulkPutCommand = createCommand({ // but we'll do that in the future if needed. const config = readConfig(args); - const namespaceId = await getKVNamespaceId(args, config, localMode); + const { namespaceId } = await getKVNamespaceId(args, config, localMode); const content = parseJSON(readFileSync(filename), filename); if (!Array.isArray(content)) { @@ -1017,11 +1053,15 @@ export const kvBulkDeleteCommand = createCommand({ async handler({ filename, ...args }) { const localMode = isLocal(args); const config = readConfig(args); - const namespaceId = await getKVNamespaceId(args, config, localMode); + const { namespaceId, displayName } = await getKVNamespaceId( + args, + config, + localMode + ); if (!args.force) { const result = await confirm( - `Are you sure you want to delete all the keys read from "${filename}" from kv-namespace with id "${namespaceId}"?` + `Are you sure you want to delete all the keys read from "${filename}" from kv-namespace ${displayName}?` ); if (!result) { logger.log(`Not deleting keys read from "${filename}".`);