wrangler 0.0.0-e2a26a0 → 0.0.0-e3278fa

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/Cloudflare_CA.pem +18 -0
  2. package/README.md +27 -14
  3. package/bin/wrangler.js +49 -5
  4. package/miniflare-dist/index.mjs +4886 -0
  5. package/package.json +51 -27
  6. package/pages/functions/buildPlugin.ts +105 -0
  7. package/pages/functions/buildWorker.ts +93 -4
  8. package/pages/functions/filepath-routing.test.ts +223 -36
  9. package/pages/functions/filepath-routing.ts +78 -120
  10. package/pages/functions/routes.ts +13 -17
  11. package/pages/functions/template-plugin.ts +147 -0
  12. package/pages/functions/template-worker.ts +24 -17
  13. package/src/__tests__/config-cache.test.ts +36 -0
  14. package/src/__tests__/configuration.test.ts +3408 -0
  15. package/src/__tests__/dev.test.tsx +977 -65
  16. package/src/__tests__/guess-worker-format.test.ts +85 -0
  17. package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
  18. package/src/__tests__/helpers/mock-account-id.ts +26 -8
  19. package/src/__tests__/helpers/mock-bin.ts +4 -1
  20. package/src/__tests__/helpers/mock-cfetch.ts +10 -6
  21. package/src/__tests__/helpers/mock-console.ts +39 -8
  22. package/src/__tests__/helpers/mock-dialogs.ts +67 -2
  23. package/src/__tests__/helpers/mock-http-server.ts +46 -0
  24. package/src/__tests__/helpers/mock-istty.ts +27 -0
  25. package/src/__tests__/helpers/mock-kv.ts +9 -16
  26. package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
  27. package/src/__tests__/helpers/mock-stdin.ts +103 -0
  28. package/src/__tests__/helpers/mock-web-socket.ts +29 -0
  29. package/src/__tests__/helpers/run-in-tmp.ts +10 -0
  30. package/src/__tests__/helpers/run-wrangler.ts +5 -3
  31. package/src/__tests__/helpers/write-worker-source.ts +31 -0
  32. package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
  33. package/src/__tests__/https-options.test.ts +130 -0
  34. package/src/__tests__/index.test.ts +148 -435
  35. package/src/__tests__/init.test.ts +1637 -0
  36. package/src/__tests__/jest.setup.ts +45 -5
  37. package/src/__tests__/kv.test.ts +590 -248
  38. package/src/__tests__/logger.test.ts +115 -0
  39. package/src/__tests__/package-manager.test.ts +156 -9
  40. package/src/__tests__/pages.test.ts +754 -0
  41. package/src/__tests__/parse.test.ts +330 -0
  42. package/src/__tests__/publish.test.ts +5471 -939
  43. package/src/__tests__/r2.test.ts +233 -0
  44. package/src/__tests__/route.test.ts +45 -0
  45. package/src/__tests__/secret.test.ts +362 -91
  46. package/src/__tests__/tail.test.ts +690 -0
  47. package/src/__tests__/user.test.ts +131 -0
  48. package/src/__tests__/whoami.test.tsx +60 -7
  49. package/src/abort.d.ts +3 -0
  50. package/src/bundle.ts +197 -0
  51. package/src/cfetch/index.ts +27 -8
  52. package/src/cfetch/internal.ts +73 -32
  53. package/src/cli.ts +6 -2
  54. package/src/config/README.md +107 -0
  55. package/src/config/config.ts +234 -0
  56. package/src/config/diagnostics.ts +80 -0
  57. package/src/config/environment.ts +420 -0
  58. package/src/config/index.ts +225 -0
  59. package/src/config/validation-helpers.ts +584 -0
  60. package/src/config/validation.ts +1539 -0
  61. package/src/config-cache.ts +45 -0
  62. package/src/create-worker-preview.ts +185 -0
  63. package/src/create-worker-upload-form.ts +254 -0
  64. package/src/dev/dev-vars.ts +36 -0
  65. package/src/dev/dev.tsx +412 -0
  66. package/src/dev/local.tsx +322 -0
  67. package/src/dev/remote.tsx +237 -0
  68. package/src/dev/use-esbuild.ts +118 -0
  69. package/src/dialogs.tsx +64 -6
  70. package/src/durable.ts +102 -0
  71. package/src/entry.ts +322 -0
  72. package/src/environment-variables.ts +35 -0
  73. package/src/errors.ts +11 -0
  74. package/src/https-options.ts +123 -0
  75. package/src/index.tsx +1747 -1002
  76. package/src/inspect.ts +80 -14
  77. package/src/intl-polyfill.d.ts +139 -0
  78. package/src/{kv.tsx → kv.ts} +192 -68
  79. package/src/logger.ts +66 -0
  80. package/src/miniflare-cli/README.md +30 -0
  81. package/src/miniflare-cli/enum-keys.ts +17 -0
  82. package/src/miniflare-cli/index.ts +41 -0
  83. package/src/miniflare-cli/request-context.ts +40 -0
  84. package/src/module-collection.ts +226 -31
  85. package/src/open-in-browser.ts +19 -0
  86. package/src/package-manager.ts +79 -25
  87. package/src/pages.tsx +1131 -84
  88. package/src/parse.ts +202 -0
  89. package/src/proxy.ts +170 -62
  90. package/src/publish.ts +612 -306
  91. package/src/r2.ts +50 -0
  92. package/src/selfsigned.d.ts +29 -0
  93. package/src/sites.tsx +143 -57
  94. package/src/tail/filters.ts +279 -0
  95. package/src/tail/index.ts +299 -0
  96. package/src/tail/printing.ts +67 -0
  97. package/src/update-check.ts +19 -0
  98. package/src/user.tsx +341 -146
  99. package/src/whoami.tsx +5 -3
  100. package/src/{api/worker.ts → worker.ts} +65 -39
  101. package/src/zones.ts +73 -0
  102. package/templates/gitignore +171 -0
  103. package/templates/new-worker-scheduled.js +17 -0
  104. package/templates/new-worker-scheduled.ts +32 -0
  105. package/templates/new-worker.js +1 -1
  106. package/templates/new-worker.ts +17 -2
  107. package/templates/static-asset-facade.js +1 -5
  108. package/templates/tsconfig.json +105 -0
  109. package/wrangler-dist/cli.js +72295 -71006
  110. package/src/__tests__/helpers/mock-user.ts +0 -27
  111. package/src/__tests__/logout.test.ts +0 -50
  112. package/src/api/form_data.ts +0 -134
  113. package/src/api/preview.ts +0 -128
  114. package/src/config.ts +0 -641
  115. package/src/dev.tsx +0 -834
  116. package/src/tail.tsx +0 -73
  117. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  118. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  119. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  120. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  121. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  122. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  123. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  124. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  125. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  126. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  127. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  128. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  129. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  130. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  131. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  132. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  133. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  134. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  135. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  136. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  137. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  138. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  139. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  140. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  141. package/vendor/wrangler-mime/LICENSE +0 -21
  142. package/vendor/wrangler-mime/Mime.js +0 -97
  143. package/vendor/wrangler-mime/README.md +0 -187
  144. package/vendor/wrangler-mime/cli.js +0 -46
  145. package/vendor/wrangler-mime/index.js +0 -4
  146. package/vendor/wrangler-mime/lite.js +0 -4
  147. package/vendor/wrangler-mime/package.json +0 -52
  148. package/vendor/wrangler-mime/types/other.js +0 -1
  149. package/vendor/wrangler-mime/types/standard.js +0 -1
  150. package/wrangler-dist/cli.js.map +0 -7
@@ -1,4 +1,5 @@
1
1
  import { writeFileSync } from "node:fs";
2
+ import { Headers } from "undici";
2
3
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
3
4
  import {
4
5
  setMockResponse,
@@ -7,10 +8,11 @@ import {
7
8
  setMockFetchKVGetValue,
8
9
  } from "./helpers/mock-cfetch";
9
10
  import { mockConsoleMethods } from "./helpers/mock-console";
11
+ import { clearConfirmMocks, mockConfirm } from "./helpers/mock-dialogs";
10
12
  import { mockKeyListRequest } from "./helpers/mock-kv";
11
13
  import { runInTempDir } from "./helpers/run-in-tmp";
12
14
  import { runWrangler } from "./helpers/run-wrangler";
13
- import type { KVNamespaceInfo } from "../kv";
15
+ import type { KeyValue, KVNamespaceInfo, NamespaceKeyInfo } from "../kv";
14
16
 
15
17
  describe("wrangler", () => {
16
18
  mockAccountId();
@@ -20,6 +22,7 @@ describe("wrangler", () => {
20
22
 
21
23
  afterEach(() => {
22
24
  unsetAllMocks();
25
+ clearConfirmMocks();
23
26
  });
24
27
 
25
28
  describe("kv:namespace", () => {
@@ -43,9 +46,9 @@ describe("wrangler", () => {
43
46
  ).rejects.toThrowErrorMatchingInlineSnapshot(
44
47
  `"Not enough non-option arguments: got 0, need at least 1"`
45
48
  );
46
- expect(std.out).toMatchInlineSnapshot(`""`);
47
- expect(std.err).toMatchInlineSnapshot(`
48
- "wrangler kv:namespace create <namespace>
49
+ expect(std.out).toMatchInlineSnapshot(`
50
+ "
51
+ wrangler kv:namespace create <namespace>
49
52
 
50
53
  Create a new namespace
51
54
 
@@ -58,11 +61,13 @@ describe("wrangler", () => {
58
61
  -v, --version Show version number [boolean]
59
62
 
60
63
  Options:
61
- -l, --local Run on my machine [boolean] [default: false]
62
- --env Perform on a specific environment [string]
63
- --preview Interact with a preview namespace [boolean]
64
+ -e, --env Perform on a specific environment [string]
65
+ --preview Interact with a preview namespace [boolean]"
66
+ `);
67
+ expect(std.err).toMatchInlineSnapshot(`
68
+ "X [ERROR] Not enough non-option arguments: got 0, need at least 1
64
69
 
65
- Not enough non-option arguments: got 0, need at least 1"
70
+ "
66
71
  `);
67
72
  });
68
73
 
@@ -70,11 +75,11 @@ describe("wrangler", () => {
70
75
  await expect(
71
76
  runWrangler("kv:namespace create abc def ghi")
72
77
  ).rejects.toThrowErrorMatchingInlineSnapshot(
73
- `"Unexpected additional positional arguments \\"def ghi\\"."`
78
+ `"Unknown arguments: def, ghi"`
74
79
  );
75
- expect(std.out).toMatchInlineSnapshot(`""`);
76
- expect(std.err).toMatchInlineSnapshot(`
77
- "wrangler kv:namespace create <namespace>
80
+ expect(std.out).toMatchInlineSnapshot(`
81
+ "
82
+ wrangler kv:namespace create <namespace>
78
83
 
79
84
  Create a new namespace
80
85
 
@@ -87,11 +92,13 @@ describe("wrangler", () => {
87
92
  -v, --version Show version number [boolean]
88
93
 
89
94
  Options:
90
- -l, --local Run on my machine [boolean] [default: false]
91
- --env Perform on a specific environment [string]
92
- --preview Interact with a preview namespace [boolean]
95
+ -e, --env Perform on a specific environment [string]
96
+ --preview Interact with a preview namespace [boolean]"
97
+ `);
98
+ expect(std.err).toMatchInlineSnapshot(`
99
+ "X [ERROR] Unknown arguments: def, ghi
93
100
 
94
- Unexpected additional positional arguments \\"def ghi\\"."
101
+ "
95
102
  `);
96
103
  });
97
104
 
@@ -102,9 +109,9 @@ describe("wrangler", () => {
102
109
  `"The namespace binding name \\"abc-def\\" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number."`
103
110
  );
104
111
 
105
- expect(std.out).toMatchInlineSnapshot(`""`);
106
- expect(std.err).toMatchInlineSnapshot(`
107
- "wrangler kv:namespace create <namespace>
112
+ expect(std.out).toMatchInlineSnapshot(`
113
+ "
114
+ wrangler kv:namespace create <namespace>
108
115
 
109
116
  Create a new namespace
110
117
 
@@ -117,11 +124,13 @@ describe("wrangler", () => {
117
124
  -v, --version Show version number [boolean]
118
125
 
119
126
  Options:
120
- -l, --local Run on my machine [boolean] [default: false]
121
- --env Perform on a specific environment [string]
122
- --preview Interact with a preview namespace [boolean]
127
+ -e, --env Perform on a specific environment [string]
128
+ --preview Interact with a preview namespace [boolean]"
129
+ `);
130
+ expect(std.err).toMatchInlineSnapshot(`
131
+ "X [ERROR] The namespace binding name \\"abc-def\\" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number.
123
132
 
124
- The namespace binding name \\"abc-def\\" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number."
133
+ "
125
134
  `);
126
135
  });
127
136
 
@@ -148,11 +157,11 @@ describe("wrangler", () => {
148
157
  });
149
158
 
150
159
  it("should create a namespace using configured worker name", async () => {
151
- writeFileSync("./wrangler.toml", 'name = "otherWorker"', "utf-8");
152
- mockCreateRequest("otherWorker-UnitTestNamespace");
160
+ writeFileSync("./wrangler.toml", 'name = "other-worker"', "utf-8");
161
+ mockCreateRequest("other-worker-UnitTestNamespace");
153
162
  await runWrangler("kv:namespace create UnitTestNamespace");
154
163
  expect(std.out).toMatchInlineSnapshot(`
155
- "🌀 Creating namespace with title \\"otherWorker-UnitTestNamespace\\"
164
+ "🌀 Creating namespace with title \\"other-worker-UnitTestNamespace\\"
156
165
  ✨ Success!
157
166
  Add the following to your configuration file in your kv_namespaces array:
158
167
  { binding = \\"UnitTestNamespace\\", id = \\"some-namespace-id\\" }"
@@ -271,24 +280,11 @@ describe("wrangler", () => {
271
280
  A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."
272
281
  `);
273
282
  expect(std.err).toMatchInlineSnapshot(`
274
- "wrangler kv:namespace delete
283
+ "X [ERROR] Not able to delete namespace.
275
284
 
276
- Deletes a given namespace.
285
+ A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
277
286
 
278
- Flags:
279
- -c, --config Path to .toml configuration file [string]
280
- -h, --help Show help [boolean]
281
- -v, --version Show version number [boolean]
282
-
283
- Options:
284
- -l, --local Run on my machine [boolean] [default: false]
285
- --binding The name of the namespace to delete [string]
286
- --namespace-id The id of the namespace to delete [string]
287
- --env Perform on a specific environment [string]
288
- --preview Interact with a preview namespace [boolean]
289
-
290
- Not able to delete namespace.
291
- A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."
287
+ "
292
288
  `);
293
289
  });
294
290
 
@@ -319,10 +315,7 @@ describe("wrangler", () => {
319
315
  describe("put", () => {
320
316
  function mockKeyPutRequest(
321
317
  expectedNamespaceId: string,
322
- expectedKey: string,
323
- expectedValue: string,
324
- expiration?: number,
325
- expirationTtl?: number
318
+ expectedKV: KeyValue
326
319
  ) {
327
320
  const requests = { count: 0 };
328
321
  setMockResponse(
@@ -332,15 +325,19 @@ describe("wrangler", () => {
332
325
  requests.count++;
333
326
  expect(accountId).toEqual("some-account-id");
334
327
  expect(namespaceId).toEqual(expectedNamespaceId);
335
- expect(key).toEqual(expectedKey);
336
- expect(body).toEqual(expectedValue);
337
- if (expiration !== undefined) {
338
- expect(query.get("expiration")).toEqual(`${expiration}`);
328
+ expect(key).toEqual(expectedKV.key);
329
+ expect(body).toEqual(expectedKV.value);
330
+ if (expectedKV.expiration !== undefined) {
331
+ expect(query.get("expiration")).toEqual(
332
+ `${expectedKV.expiration}`
333
+ );
339
334
  } else {
340
335
  expect(query.has("expiration")).toBe(false);
341
336
  }
342
- if (expirationTtl) {
343
- expect(query.get("expiration_ttl")).toEqual(`${expirationTtl}`);
337
+ if (expectedKV.expiration_ttl) {
338
+ expect(query.get("expiration_ttl")).toEqual(
339
+ `${expectedKV.expiration_ttl}`
340
+ );
344
341
  } else {
345
342
  expect(query.has("expiration_ttl")).toBe(false);
346
343
  }
@@ -351,11 +348,10 @@ describe("wrangler", () => {
351
348
  }
352
349
 
353
350
  it("should put a key in a given namespace specified by namespace-id", async () => {
354
- const requests = mockKeyPutRequest(
355
- "some-namespace-id",
356
- "my-key",
357
- "my-value"
358
- );
351
+ const requests = mockKeyPutRequest("some-namespace-id", {
352
+ key: "my-key",
353
+ value: "my-value",
354
+ });
359
355
 
360
356
  await runWrangler(
361
357
  "kv:key put my-key my-value --namespace-id some-namespace-id"
@@ -363,20 +359,38 @@ describe("wrangler", () => {
363
359
 
364
360
  expect(requests.count).toEqual(1);
365
361
  expect(std.out).toMatchInlineSnapshot(
366
- `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace some-namespace-id"`
362
+ `"Writing the value \\"my-value\\" to key \\"my-key\\" on namespace some-namespace-id."`
363
+ );
364
+ expect(std.err).toMatchInlineSnapshot(`""`);
365
+ });
366
+
367
+ it("should encode the key in the api request to put a value", async () => {
368
+ const requests = mockKeyPutRequest("DS9", {
369
+ key: "%2Fmy-key",
370
+ value: "my-value",
371
+ });
372
+
373
+ await runWrangler("kv:key put /my-key my-value --namespace-id DS9");
374
+
375
+ expect(requests.count).toEqual(1);
376
+ expect(std.out).toMatchInlineSnapshot(
377
+ `"Writing the value \\"my-value\\" to key \\"/my-key\\" on namespace DS9."`
367
378
  );
368
379
  expect(std.err).toMatchInlineSnapshot(`""`);
369
380
  });
370
381
 
371
382
  it("should put a key in a given namespace specified by binding", async () => {
372
383
  writeWranglerConfig();
373
- const requests = mockKeyPutRequest("bound-id", "my-key", "my-value");
384
+ const requests = mockKeyPutRequest("bound-id", {
385
+ key: "my-key",
386
+ value: "my-value",
387
+ });
374
388
  await runWrangler(
375
389
  "kv:key put my-key my-value --binding someBinding --preview false"
376
390
  );
377
391
 
378
392
  expect(std.out).toMatchInlineSnapshot(
379
- `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace bound-id"`
393
+ `"Writing the value \\"my-value\\" to key \\"my-key\\" on namespace bound-id."`
380
394
  );
381
395
  expect(std.err).toMatchInlineSnapshot(`""`);
382
396
  expect(requests.count).toEqual(1);
@@ -384,53 +398,50 @@ describe("wrangler", () => {
384
398
 
385
399
  it("should put a key in a given preview namespace specified by binding", async () => {
386
400
  writeWranglerConfig();
387
- const requests = mockKeyPutRequest(
388
- "preview-bound-id",
389
- "my-key",
390
- "my-value"
391
- );
401
+ const requests = mockKeyPutRequest("preview-bound-id", {
402
+ key: "my-key",
403
+ value: "my-value",
404
+ });
392
405
 
393
406
  await runWrangler(
394
407
  "kv:key put my-key my-value --binding someBinding --preview"
395
408
  );
396
409
 
397
410
  expect(std.out).toMatchInlineSnapshot(
398
- `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace preview-bound-id"`
411
+ `"Writing the value \\"my-value\\" to key \\"my-key\\" on namespace preview-bound-id."`
399
412
  );
400
413
  expect(std.err).toMatchInlineSnapshot(`""`);
401
414
  expect(requests.count).toEqual(1);
402
415
  });
403
416
 
404
417
  it("should add expiration and ttl properties when putting a key", async () => {
405
- const requests = mockKeyPutRequest(
406
- "some-namespace-id",
407
- "my-key",
408
- "my-value",
409
- 10,
410
- 20
411
- );
418
+ const requests = mockKeyPutRequest("some-namespace-id", {
419
+ key: "my-key",
420
+ value: "my-value",
421
+ expiration: 10,
422
+ expiration_ttl: 20,
423
+ });
412
424
  await runWrangler(
413
425
  "kv:key put my-key my-value --namespace-id some-namespace-id --expiration 10 --ttl 20"
414
426
  );
415
427
  expect(requests.count).toEqual(1);
416
428
  expect(std.out).toMatchInlineSnapshot(
417
- `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace some-namespace-id"`
429
+ `"Writing the value \\"my-value\\" to key \\"my-key\\" on namespace some-namespace-id."`
418
430
  );
419
431
  expect(std.err).toMatchInlineSnapshot(`""`);
420
432
  });
421
433
 
422
434
  it("should put a key to the specified environment in a given namespace", async () => {
423
435
  writeWranglerConfig();
424
- const requests = mockKeyPutRequest(
425
- "env-bound-id",
426
- "my-key",
427
- "my-value"
428
- );
436
+ const requests = mockKeyPutRequest("env-bound-id", {
437
+ key: "my-key",
438
+ value: "my-value",
439
+ });
429
440
  await runWrangler(
430
441
  "kv:key put my-key my-value --binding someBinding --env some-environment --preview false"
431
442
  );
432
443
  expect(std.out).toMatchInlineSnapshot(
433
- `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace env-bound-id"`
444
+ `"Writing the value \\"my-value\\" to key \\"my-key\\" on namespace env-bound-id."`
434
445
  );
435
446
  expect(std.err).toMatchInlineSnapshot(`""`);
436
447
  expect(requests.count).toEqual(1);
@@ -438,16 +449,15 @@ describe("wrangler", () => {
438
449
 
439
450
  it("should put a key with a value loaded from a given path", async () => {
440
451
  writeFileSync("foo.txt", "file-contents", "utf-8");
441
- const requests = mockKeyPutRequest(
442
- "some-namespace-id",
443
- "my-key",
444
- "file-contents"
445
- );
452
+ const requests = mockKeyPutRequest("some-namespace-id", {
453
+ key: "my-key",
454
+ value: "file-contents",
455
+ });
446
456
  await runWrangler(
447
457
  "kv:key put my-key --namespace-id some-namespace-id --path foo.txt"
448
458
  );
449
459
  expect(std.out).toMatchInlineSnapshot(
450
- `"writing the contents of foo.txt to the key \\"my-key\\" on namespace some-namespace-id"`
460
+ `"Writing the contents of foo.txt to the key \\"my-key\\" on namespace some-namespace-id."`
451
461
  );
452
462
  expect(std.err).toMatchInlineSnapshot(`""`);
453
463
  expect(requests.count).toEqual(1);
@@ -460,15 +470,15 @@ describe("wrangler", () => {
460
470
  `"Not enough non-option arguments: got 0, need at least 1"`
461
471
  );
462
472
 
463
- expect(std.out).toMatchInlineSnapshot(`""`);
464
- expect(std.err).toMatchInlineSnapshot(`
465
- "wrangler kv:key put <key> [value]
473
+ expect(std.out).toMatchInlineSnapshot(`
474
+ "
475
+ wrangler kv:key put <key> [value]
466
476
 
467
477
  Writes a single key/value pair to the given namespace.
468
478
 
469
479
  Positionals:
470
- key The key to write to. [string] [required]
471
- value The value to write. [string]
480
+ key The key to write to [string] [required]
481
+ value The value to write [string]
472
482
 
473
483
  Flags:
474
484
  -c, --config Path to .toml configuration file [string]
@@ -476,16 +486,18 @@ describe("wrangler", () => {
476
486
  -v, --version Show version number [boolean]
477
487
 
478
488
  Options:
479
- -l, --local Run on my machine [boolean] [default: false]
480
- --binding The binding of the namespace to write to. [string]
481
- --namespace-id The id of the namespace to write to. [string]
482
- --env Perform on a specific environment [string]
489
+ --binding The binding of the namespace to write to [string]
490
+ --namespace-id The id of the namespace to write to [string]
491
+ -e, --env Perform on a specific environment [string]
483
492
  --preview Interact with a preview namespace [boolean]
484
- --ttl Time for which the entries should be visible. [number]
493
+ --ttl Time for which the entries should be visible [number]
485
494
  --expiration Time since the UNIX epoch after which the entry expires [number]
486
- --path Read value from the file at a given path. [string]
495
+ --path Read value from the file at a given path [string]"
496
+ `);
497
+ expect(std.err).toMatchInlineSnapshot(`
498
+ "X [ERROR] Not enough non-option arguments: got 0, need at least 1
487
499
 
488
- Not enough non-option arguments: got 0, need at least 1"
500
+ "
489
501
  `);
490
502
  });
491
503
 
@@ -496,15 +508,15 @@ describe("wrangler", () => {
496
508
  `"Exactly one of the arguments binding and namespace-id is required"`
497
509
  );
498
510
 
499
- expect(std.out).toMatchInlineSnapshot(`""`);
500
- expect(std.err).toMatchInlineSnapshot(`
501
- "wrangler kv:key put <key> [value]
511
+ expect(std.out).toMatchInlineSnapshot(`
512
+ "
513
+ wrangler kv:key put <key> [value]
502
514
 
503
515
  Writes a single key/value pair to the given namespace.
504
516
 
505
517
  Positionals:
506
- key The key to write to. [string] [required]
507
- value The value to write. [string]
518
+ key The key to write to [string] [required]
519
+ value The value to write [string]
508
520
 
509
521
  Flags:
510
522
  -c, --config Path to .toml configuration file [string]
@@ -512,16 +524,18 @@ describe("wrangler", () => {
512
524
  -v, --version Show version number [boolean]
513
525
 
514
526
  Options:
515
- -l, --local Run on my machine [boolean] [default: false]
516
- --binding The binding of the namespace to write to. [string]
517
- --namespace-id The id of the namespace to write to. [string]
518
- --env Perform on a specific environment [string]
527
+ --binding The binding of the namespace to write to [string]
528
+ --namespace-id The id of the namespace to write to [string]
529
+ -e, --env Perform on a specific environment [string]
519
530
  --preview Interact with a preview namespace [boolean]
520
- --ttl Time for which the entries should be visible. [number]
531
+ --ttl Time for which the entries should be visible [number]
521
532
  --expiration Time since the UNIX epoch after which the entry expires [number]
522
- --path Read value from the file at a given path. [string]
533
+ --path Read value from the file at a given path [string]"
534
+ `);
535
+ expect(std.err).toMatchInlineSnapshot(`
536
+ "X [ERROR] Exactly one of the arguments binding and namespace-id is required
523
537
 
524
- Exactly one of the arguments binding and namespace-id is required"
538
+ "
525
539
  `);
526
540
  });
527
541
 
@@ -532,15 +546,15 @@ describe("wrangler", () => {
532
546
  `"Arguments binding and namespace-id are mutually exclusive"`
533
547
  );
534
548
 
535
- expect(std.out).toMatchInlineSnapshot(`""`);
536
- expect(std.err).toMatchInlineSnapshot(`
537
- "wrangler kv:key put <key> [value]
549
+ expect(std.out).toMatchInlineSnapshot(`
550
+ "
551
+ wrangler kv:key put <key> [value]
538
552
 
539
553
  Writes a single key/value pair to the given namespace.
540
554
 
541
555
  Positionals:
542
- key The key to write to. [string] [required]
543
- value The value to write. [string]
556
+ key The key to write to [string] [required]
557
+ value The value to write [string]
544
558
 
545
559
  Flags:
546
560
  -c, --config Path to .toml configuration file [string]
@@ -548,16 +562,18 @@ describe("wrangler", () => {
548
562
  -v, --version Show version number [boolean]
549
563
 
550
564
  Options:
551
- -l, --local Run on my machine [boolean] [default: false]
552
- --binding The binding of the namespace to write to. [string]
553
- --namespace-id The id of the namespace to write to. [string]
554
- --env Perform on a specific environment [string]
565
+ --binding The binding of the namespace to write to [string]
566
+ --namespace-id The id of the namespace to write to [string]
567
+ -e, --env Perform on a specific environment [string]
555
568
  --preview Interact with a preview namespace [boolean]
556
- --ttl Time for which the entries should be visible. [number]
569
+ --ttl Time for which the entries should be visible [number]
557
570
  --expiration Time since the UNIX epoch after which the entry expires [number]
558
- --path Read value from the file at a given path. [string]
571
+ --path Read value from the file at a given path [string]"
572
+ `);
573
+ expect(std.err).toMatchInlineSnapshot(`
574
+ "X [ERROR] Arguments binding and namespace-id are mutually exclusive
559
575
 
560
- Arguments binding and namespace-id are mutually exclusive"
576
+ "
561
577
  `);
562
578
  });
563
579
 
@@ -568,15 +584,15 @@ describe("wrangler", () => {
568
584
  `"Exactly one of the arguments value and path is required"`
569
585
  );
570
586
 
571
- expect(std.out).toMatchInlineSnapshot(`""`);
572
- expect(std.err).toMatchInlineSnapshot(`
573
- "wrangler kv:key put <key> [value]
587
+ expect(std.out).toMatchInlineSnapshot(`
588
+ "
589
+ wrangler kv:key put <key> [value]
574
590
 
575
591
  Writes a single key/value pair to the given namespace.
576
592
 
577
593
  Positionals:
578
- key The key to write to. [string] [required]
579
- value The value to write. [string]
594
+ key The key to write to [string] [required]
595
+ value The value to write [string]
580
596
 
581
597
  Flags:
582
598
  -c, --config Path to .toml configuration file [string]
@@ -584,16 +600,18 @@ describe("wrangler", () => {
584
600
  -v, --version Show version number [boolean]
585
601
 
586
602
  Options:
587
- -l, --local Run on my machine [boolean] [default: false]
588
- --binding The binding of the namespace to write to. [string]
589
- --namespace-id The id of the namespace to write to. [string]
590
- --env Perform on a specific environment [string]
603
+ --binding The binding of the namespace to write to [string]
604
+ --namespace-id The id of the namespace to write to [string]
605
+ -e, --env Perform on a specific environment [string]
591
606
  --preview Interact with a preview namespace [boolean]
592
- --ttl Time for which the entries should be visible. [number]
607
+ --ttl Time for which the entries should be visible [number]
593
608
  --expiration Time since the UNIX epoch after which the entry expires [number]
594
- --path Read value from the file at a given path. [string]
609
+ --path Read value from the file at a given path [string]"
610
+ `);
611
+ expect(std.err).toMatchInlineSnapshot(`
612
+ "X [ERROR] Exactly one of the arguments value and path is required
595
613
 
596
- Exactly one of the arguments value and path is required"
614
+ "
597
615
  `);
598
616
  });
599
617
 
@@ -604,15 +622,15 @@ describe("wrangler", () => {
604
622
  `"Arguments value and path are mutually exclusive"`
605
623
  );
606
624
 
607
- expect(std.out).toMatchInlineSnapshot(`""`);
608
- expect(std.err).toMatchInlineSnapshot(`
609
- "wrangler kv:key put <key> [value]
625
+ expect(std.out).toMatchInlineSnapshot(`
626
+ "
627
+ wrangler kv:key put <key> [value]
610
628
 
611
629
  Writes a single key/value pair to the given namespace.
612
630
 
613
631
  Positionals:
614
- key The key to write to. [string] [required]
615
- value The value to write. [string]
632
+ key The key to write to [string] [required]
633
+ value The value to write [string]
616
634
 
617
635
  Flags:
618
636
  -c, --config Path to .toml configuration file [string]
@@ -620,16 +638,18 @@ describe("wrangler", () => {
620
638
  -v, --version Show version number [boolean]
621
639
 
622
640
  Options:
623
- -l, --local Run on my machine [boolean] [default: false]
624
- --binding The binding of the namespace to write to. [string]
625
- --namespace-id The id of the namespace to write to. [string]
626
- --env Perform on a specific environment [string]
641
+ --binding The binding of the namespace to write to [string]
642
+ --namespace-id The id of the namespace to write to [string]
643
+ -e, --env Perform on a specific environment [string]
627
644
  --preview Interact with a preview namespace [boolean]
628
- --ttl Time for which the entries should be visible. [number]
645
+ --ttl Time for which the entries should be visible [number]
629
646
  --expiration Time since the UNIX epoch after which the entry expires [number]
630
- --path Read value from the file at a given path. [string]
647
+ --path Read value from the file at a given path [string]"
648
+ `);
649
+ expect(std.err).toMatchInlineSnapshot(`
650
+ "X [ERROR] Arguments value and path are mutually exclusive
631
651
 
632
- Arguments value and path are mutually exclusive"
652
+ "
633
653
  `);
634
654
  });
635
655
 
@@ -641,33 +661,36 @@ describe("wrangler", () => {
641
661
  `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
642
662
  );
643
663
 
644
- expect(std.out).toMatchInlineSnapshot(`""`);
664
+ expect(std.out).toMatchInlineSnapshot(`
665
+ "
666
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
667
+ `);
645
668
  expect(std.err).toMatchInlineSnapshot(`
646
- "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
669
+ "X [ERROR] A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
647
670
 
648
- %s
649
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
671
+ "
650
672
  `);
651
673
  });
652
674
 
653
675
  it("should error if a given binding has both preview and non-preview and --preview is not specified", async () => {
654
676
  writeWranglerConfig();
655
- const requests = mockKeyPutRequest(
656
- "preview-bound-id",
657
- "my-key",
658
- "my-value"
659
- );
677
+ const requests = mockKeyPutRequest("preview-bound-id", {
678
+ key: "my-key",
679
+ value: "my-value",
680
+ });
660
681
  await expect(
661
682
  runWrangler("kv:key put my-key my-value --binding someBinding")
662
683
  ).rejects.toThrowErrorMatchingInlineSnapshot(
663
684
  `"someBinding has both a namespace ID and a preview ID. Specify \\"--preview\\" or \\"--preview false\\" to avoid writing data to the wrong namespace."`
664
685
  );
665
- expect(std.out).toMatchInlineSnapshot(`""`);
686
+ expect(std.out).toMatchInlineSnapshot(`
687
+ "
688
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
689
+ `);
666
690
  expect(std.err).toMatchInlineSnapshot(`
667
- "someBinding has both a namespace ID and a preview ID. Specify \\"--preview\\" or \\"--preview false\\" to avoid writing data to the wrong namespace.
691
+ "X [ERROR] someBinding has both a namespace ID and a preview ID. Specify \\"--preview\\" or \\"--preview false\\" to avoid writing data to the wrong namespace.
668
692
 
669
- %s
670
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
693
+ "
671
694
  `);
672
695
  expect(requests.count).toEqual(0);
673
696
  });
@@ -675,26 +698,26 @@ describe("wrangler", () => {
675
698
 
676
699
  describe("list", () => {
677
700
  it("should list the keys of a namespace specified by namespace-id", async () => {
678
- const keys = ["key-1", "key-2", "key-3"];
701
+ const keys = [
702
+ { name: "key-1" },
703
+ { name: "key-2", expiration: 123456789 },
704
+ { name: "key-3", expiration_ttl: 666 },
705
+ ];
679
706
  mockKeyListRequest("some-namespace-id", keys);
680
707
  await runWrangler("kv:key list --namespace-id some-namespace-id");
681
708
  expect(std.err).toMatchInlineSnapshot(`""`);
682
709
  expect(std.out).toMatchInlineSnapshot(`
683
710
  "[
684
711
  {
685
- \\"name\\": \\"key-1\\",
686
- \\"expiration\\": 123456789,
687
- \\"metadata\\": {}
712
+ \\"name\\": \\"key-1\\"
688
713
  },
689
714
  {
690
715
  \\"name\\": \\"key-2\\",
691
- \\"expiration\\": 123456789,
692
- \\"metadata\\": {}
716
+ \\"expiration\\": 123456789
693
717
  },
694
718
  {
695
719
  \\"name\\": \\"key-3\\",
696
- \\"expiration\\": 123456789,
697
- \\"metadata\\": {}
720
+ \\"expiration_ttl\\": 666
698
721
  }
699
722
  ]"
700
723
  `);
@@ -702,7 +725,7 @@ describe("wrangler", () => {
702
725
 
703
726
  it("should list the keys of a namespace specified by binding", async () => {
704
727
  writeWranglerConfig();
705
- const keys = ["key-1", "key-2", "key-3"];
728
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
706
729
  mockKeyListRequest("bound-id", keys);
707
730
 
708
731
  await runWrangler("kv:key list --binding someBinding");
@@ -710,19 +733,13 @@ describe("wrangler", () => {
710
733
  expect(std.out).toMatchInlineSnapshot(`
711
734
  "[
712
735
  {
713
- \\"name\\": \\"key-1\\",
714
- \\"expiration\\": 123456789,
715
- \\"metadata\\": {}
736
+ \\"name\\": \\"key-1\\"
716
737
  },
717
738
  {
718
- \\"name\\": \\"key-2\\",
719
- \\"expiration\\": 123456789,
720
- \\"metadata\\": {}
739
+ \\"name\\": \\"key-2\\"
721
740
  },
722
741
  {
723
- \\"name\\": \\"key-3\\",
724
- \\"expiration\\": 123456789,
725
- \\"metadata\\": {}
742
+ \\"name\\": \\"key-3\\"
726
743
  }
727
744
  ]"
728
745
  `);
@@ -730,26 +747,20 @@ describe("wrangler", () => {
730
747
 
731
748
  it("should list the keys of a preview namespace specified by binding", async () => {
732
749
  writeWranglerConfig();
733
- const keys = ["key-1", "key-2", "key-3"];
750
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
734
751
  mockKeyListRequest("preview-bound-id", keys);
735
752
  await runWrangler("kv:key list --binding someBinding --preview");
736
753
  expect(std.err).toMatchInlineSnapshot(`""`);
737
754
  expect(std.out).toMatchInlineSnapshot(`
738
755
  "[
739
756
  {
740
- \\"name\\": \\"key-1\\",
741
- \\"expiration\\": 123456789,
742
- \\"metadata\\": {}
757
+ \\"name\\": \\"key-1\\"
743
758
  },
744
759
  {
745
- \\"name\\": \\"key-2\\",
746
- \\"expiration\\": 123456789,
747
- \\"metadata\\": {}
760
+ \\"name\\": \\"key-2\\"
748
761
  },
749
762
  {
750
- \\"name\\": \\"key-3\\",
751
- \\"expiration\\": 123456789,
752
- \\"metadata\\": {}
763
+ \\"name\\": \\"key-3\\"
753
764
  }
754
765
  ]"
755
766
  `);
@@ -757,7 +768,7 @@ describe("wrangler", () => {
757
768
 
758
769
  it("should list the keys of a namespace specified by binding, in a given environment", async () => {
759
770
  writeWranglerConfig();
760
- const keys = ["key-1", "key-2", "key-3"];
771
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
761
772
  mockKeyListRequest("env-bound-id", keys);
762
773
  await runWrangler(
763
774
  "kv:key list --binding someBinding --env some-environment"
@@ -766,19 +777,13 @@ describe("wrangler", () => {
766
777
  expect(std.out).toMatchInlineSnapshot(`
767
778
  "[
768
779
  {
769
- \\"name\\": \\"key-1\\",
770
- \\"expiration\\": 123456789,
771
- \\"metadata\\": {}
780
+ \\"name\\": \\"key-1\\"
772
781
  },
773
782
  {
774
- \\"name\\": \\"key-2\\",
775
- \\"expiration\\": 123456789,
776
- \\"metadata\\": {}
783
+ \\"name\\": \\"key-2\\"
777
784
  },
778
785
  {
779
- \\"name\\": \\"key-3\\",
780
- \\"expiration\\": 123456789,
781
- \\"metadata\\": {}
786
+ \\"name\\": \\"key-3\\"
782
787
  }
783
788
  ]"
784
789
  `);
@@ -786,7 +791,7 @@ describe("wrangler", () => {
786
791
 
787
792
  it("should list the keys of a preview namespace specified by binding, in a given environment", async () => {
788
793
  writeWranglerConfig();
789
- const keys = ["key-1", "key-2", "key-3"];
794
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
790
795
  mockKeyListRequest("preview-env-bound-id", keys);
791
796
  await runWrangler(
792
797
  "kv:key list --binding someBinding --preview --env some-environment"
@@ -795,19 +800,13 @@ describe("wrangler", () => {
795
800
  expect(std.out).toMatchInlineSnapshot(`
796
801
  "[
797
802
  {
798
- \\"name\\": \\"key-1\\",
799
- \\"expiration\\": 123456789,
800
- \\"metadata\\": {}
803
+ \\"name\\": \\"key-1\\"
801
804
  },
802
805
  {
803
- \\"name\\": \\"key-2\\",
804
- \\"expiration\\": 123456789,
805
- \\"metadata\\": {}
806
+ \\"name\\": \\"key-2\\"
806
807
  },
807
808
  {
808
- \\"name\\": \\"key-3\\",
809
- \\"expiration\\": 123456789,
810
- \\"metadata\\": {}
809
+ \\"name\\": \\"key-3\\"
811
810
  }
812
811
  ]"
813
812
  `);
@@ -824,9 +823,9 @@ describe("wrangler", () => {
824
823
  describe(`cursor - ${blankCursorValue}`, () => {
825
824
  it("should make multiple requests for paginated results", async () => {
826
825
  // Create a lot of mock keys, so that the fetch requests will be paginated
827
- const keys: string[] = [];
826
+ const keys: NamespaceKeyInfo[] = [];
828
827
  for (let i = 0; i < 550; i++) {
829
- keys.push("key-" + i);
828
+ keys.push({ name: "key-" + i });
830
829
  }
831
830
  // Ask for the keys in pages of size 100.
832
831
  const requests = mockKeyListRequest(
@@ -835,11 +834,9 @@ describe("wrangler", () => {
835
834
  100,
836
835
  blankCursorValue
837
836
  );
838
- await runWrangler(
839
- "kv:key list --namespace-id some-namespace-id --limit 100"
840
- );
837
+ await runWrangler("kv:key list --namespace-id some-namespace-id");
841
838
  expect(std.err).toMatchInlineSnapshot(`""`);
842
- expect(JSON.parse(std.out).map((k) => k.name)).toEqual(keys);
839
+ expect(JSON.parse(std.out)).toEqual(keys);
843
840
  expect(requests.count).toEqual(6);
844
841
  });
845
842
  });
@@ -853,12 +850,14 @@ describe("wrangler", () => {
853
850
  `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
854
851
  );
855
852
  expect(std.err).toMatchInlineSnapshot(`
856
- "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
853
+ "X [ERROR] A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
857
854
 
858
- %s
859
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
855
+ "
856
+ `);
857
+ expect(std.out).toMatchInlineSnapshot(`
858
+ "
859
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
860
860
  `);
861
- expect(std.out).toMatchInlineSnapshot(`""`);
862
861
  });
863
862
  });
864
863
 
@@ -916,7 +915,21 @@ describe("wrangler", () => {
916
915
  "my-value"
917
916
  );
918
917
  await runWrangler(
919
- "kv:key get my-key my-value --binding someBinding --env some-environment --preview false"
918
+ "kv:key get my-key --binding someBinding --env some-environment --preview false"
919
+ );
920
+ expect(std.out).toMatchInlineSnapshot(`"my-value"`);
921
+ expect(std.err).toMatchInlineSnapshot(`""`);
922
+ });
923
+
924
+ it("should encode the key in the api request to get a value", async () => {
925
+ setMockFetchKVGetValue(
926
+ "some-account-id",
927
+ "some-namespace-id",
928
+ "%2Fmy%2Ckey",
929
+ "my-value"
930
+ );
931
+ await runWrangler(
932
+ "kv:key get /my,key --namespace-id some-namespace-id"
920
933
  );
921
934
  expect(std.out).toMatchInlineSnapshot(`"my-value"`);
922
935
  expect(std.err).toMatchInlineSnapshot(`""`);
@@ -928,9 +941,9 @@ describe("wrangler", () => {
928
941
  ).rejects.toThrowErrorMatchingInlineSnapshot(
929
942
  `"Not enough non-option arguments: got 0, need at least 1"`
930
943
  );
931
- expect(std.out).toMatchInlineSnapshot(`""`);
932
- expect(std.err).toMatchInlineSnapshot(`
933
- "wrangler kv:key get <key>
944
+ expect(std.out).toMatchInlineSnapshot(`
945
+ "
946
+ wrangler kv:key get <key>
934
947
 
935
948
  Reads a single value by key from the given namespace.
936
949
 
@@ -943,13 +956,15 @@ describe("wrangler", () => {
943
956
  -v, --version Show version number [boolean]
944
957
 
945
958
  Options:
946
- -l, --local Run on my machine [boolean] [default: false]
947
959
  --binding The name of the namespace to get from [string]
948
960
  --namespace-id The id of the namespace to get from [string]
949
- --env Perform on a specific environment [string]
950
- --preview Interact with a preview namespace [boolean] [default: false]
961
+ -e, --env Perform on a specific environment [string]
962
+ --preview Interact with a preview namespace [boolean] [default: false]"
963
+ `);
964
+ expect(std.err).toMatchInlineSnapshot(`
965
+ "X [ERROR] Not enough non-option arguments: got 0, need at least 1
951
966
 
952
- Not enough non-option arguments: got 0, need at least 1"
967
+ "
953
968
  `);
954
969
  });
955
970
 
@@ -959,9 +974,9 @@ describe("wrangler", () => {
959
974
  ).rejects.toThrowErrorMatchingInlineSnapshot(
960
975
  `"Exactly one of the arguments binding and namespace-id is required"`
961
976
  );
962
- expect(std.out).toMatchInlineSnapshot(`""`);
963
- expect(std.err).toMatchInlineSnapshot(`
964
- "wrangler kv:key get <key>
977
+ expect(std.out).toMatchInlineSnapshot(`
978
+ "
979
+ wrangler kv:key get <key>
965
980
 
966
981
  Reads a single value by key from the given namespace.
967
982
 
@@ -974,13 +989,15 @@ describe("wrangler", () => {
974
989
  -v, --version Show version number [boolean]
975
990
 
976
991
  Options:
977
- -l, --local Run on my machine [boolean] [default: false]
978
992
  --binding The name of the namespace to get from [string]
979
993
  --namespace-id The id of the namespace to get from [string]
980
- --env Perform on a specific environment [string]
981
- --preview Interact with a preview namespace [boolean] [default: false]
994
+ -e, --env Perform on a specific environment [string]
995
+ --preview Interact with a preview namespace [boolean] [default: false]"
996
+ `);
997
+ expect(std.err).toMatchInlineSnapshot(`
998
+ "X [ERROR] Exactly one of the arguments binding and namespace-id is required
982
999
 
983
- Exactly one of the arguments binding and namespace-id is required"
1000
+ "
984
1001
  `);
985
1002
  });
986
1003
 
@@ -991,9 +1008,9 @@ describe("wrangler", () => {
991
1008
  `"Arguments binding and namespace-id are mutually exclusive"`
992
1009
  );
993
1010
 
994
- expect(std.out).toMatchInlineSnapshot(`""`);
995
- expect(std.err).toMatchInlineSnapshot(`
996
- "wrangler kv:key get <key>
1011
+ expect(std.out).toMatchInlineSnapshot(`
1012
+ "
1013
+ wrangler kv:key get <key>
997
1014
 
998
1015
  Reads a single value by key from the given namespace.
999
1016
 
@@ -1006,13 +1023,15 @@ describe("wrangler", () => {
1006
1023
  -v, --version Show version number [boolean]
1007
1024
 
1008
1025
  Options:
1009
- -l, --local Run on my machine [boolean] [default: false]
1010
1026
  --binding The name of the namespace to get from [string]
1011
1027
  --namespace-id The id of the namespace to get from [string]
1012
- --env Perform on a specific environment [string]
1013
- --preview Interact with a preview namespace [boolean] [default: false]
1028
+ -e, --env Perform on a specific environment [string]
1029
+ --preview Interact with a preview namespace [boolean] [default: false]"
1030
+ `);
1031
+ expect(std.err).toMatchInlineSnapshot(`
1032
+ "X [ERROR] Arguments binding and namespace-id are mutually exclusive
1014
1033
 
1015
- Arguments binding and namespace-id are mutually exclusive"
1034
+ "
1016
1035
  `);
1017
1036
  });
1018
1037
 
@@ -1023,12 +1042,14 @@ describe("wrangler", () => {
1023
1042
  ).rejects.toThrowErrorMatchingInlineSnapshot(
1024
1043
  `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
1025
1044
  );
1026
- expect(std.out).toMatchInlineSnapshot(`""`);
1045
+ expect(std.out).toMatchInlineSnapshot(`
1046
+ "
1047
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1048
+ `);
1027
1049
  expect(std.err).toMatchInlineSnapshot(`
1028
- "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
1050
+ "X [ERROR] A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
1029
1051
 
1030
- %s
1031
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1052
+ "
1032
1053
  `);
1033
1054
  });
1034
1055
  });
@@ -1061,6 +1082,16 @@ describe("wrangler", () => {
1061
1082
  expect(requests.count).toEqual(1);
1062
1083
  });
1063
1084
 
1085
+ it("should encode the key in the api request to delete a value", async () => {
1086
+ const requests = mockDeleteRequest("voyager", "%2FNCC-74656");
1087
+ await runWrangler(`kv:key delete --namespace-id voyager /NCC-74656`);
1088
+ expect(requests.count).toEqual(1);
1089
+ expect(std.out).toMatchInlineSnapshot(
1090
+ `"Deleting the key \\"/NCC-74656\\" on namespace voyager."`
1091
+ );
1092
+ expect(std.err).toMatchInlineSnapshot(`""`);
1093
+ });
1094
+
1064
1095
  it("should delete a key in a namespace specified by binding name", async () => {
1065
1096
  writeWranglerConfig();
1066
1097
  const requests = mockDeleteRequest("bound-id", "someKey");
@@ -1088,10 +1119,9 @@ describe("wrangler", () => {
1088
1119
  );
1089
1120
 
1090
1121
  expect(std.err).toMatchInlineSnapshot(`
1091
- "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
1122
+ "X [ERROR] A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
1092
1123
 
1093
- %s
1094
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1124
+ "
1095
1125
  `);
1096
1126
  });
1097
1127
 
@@ -1102,7 +1132,7 @@ describe("wrangler", () => {
1102
1132
  `kv:key delete --binding someBinding --env some-environment --preview false someKey`
1103
1133
  );
1104
1134
  expect(std.out).toMatchInlineSnapshot(
1105
- `"deleting the key \\"someKey\\" on namespace env-bound-id"`
1135
+ `"Deleting the key \\"someKey\\" on namespace env-bound-id."`
1106
1136
  );
1107
1137
  expect(std.err).toMatchInlineSnapshot(`""`);
1108
1138
  expect(requests.count).toEqual(1);
@@ -1118,13 +1148,325 @@ describe("wrangler", () => {
1118
1148
  });
1119
1149
  });
1120
1150
  });
1151
+
1152
+ describe("kv:bulk", () => {
1153
+ describe("put", () => {
1154
+ function mockPutRequest(
1155
+ expectedNamespaceId: string,
1156
+ expectedKeyValues: KeyValue[]
1157
+ ) {
1158
+ const requests = { count: 0 };
1159
+ setMockResponse(
1160
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1161
+ "PUT",
1162
+ ([_url, accountId, namespaceId], { body }) => {
1163
+ requests.count++;
1164
+ expect(accountId).toEqual("some-account-id");
1165
+ expect(namespaceId).toEqual(expectedNamespaceId);
1166
+ expect(JSON.parse(body as string)).toEqual(
1167
+ expectedKeyValues.slice(
1168
+ (requests.count - 1) * 5000,
1169
+ requests.count * 5000
1170
+ )
1171
+ );
1172
+ return null;
1173
+ }
1174
+ );
1175
+ return requests;
1176
+ }
1177
+
1178
+ it("should put the key-values parsed from a file", async () => {
1179
+ const keyValues: KeyValue[] = [
1180
+ { key: "someKey1", value: "someValue1" },
1181
+ { key: "ns:someKey2", value: "123", base64: true },
1182
+ { key: "someKey3", value: "someValue3", expiration: 100 },
1183
+ { key: "someKey4", value: "someValue4", expiration_ttl: 500 },
1184
+ ];
1185
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1186
+ const requests = mockPutRequest("some-namespace-id", keyValues);
1187
+ await runWrangler(
1188
+ `kv:bulk put --namespace-id some-namespace-id keys.json`
1189
+ );
1190
+ expect(requests.count).toEqual(1);
1191
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1192
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1193
+ expect(std.err).toMatchInlineSnapshot(`""`);
1194
+ });
1195
+
1196
+ it("should put the key-values in batches of 5000 parsed from a file", async () => {
1197
+ const keyValues: KeyValue[] = new Array(12000).fill({
1198
+ key: "someKey1",
1199
+ value: "someValue1",
1200
+ });
1201
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1202
+ const requests = mockPutRequest("some-namespace-id", keyValues);
1203
+ await runWrangler(
1204
+ `kv:bulk put --namespace-id some-namespace-id keys.json`
1205
+ );
1206
+ expect(requests.count).toEqual(3);
1207
+ expect(std.out).toMatchInlineSnapshot(`
1208
+ "Uploaded 0% (0 out of 12,000)
1209
+ Uploaded 41% (5,000 out of 12,000)
1210
+ Uploaded 83% (10,000 out of 12,000)
1211
+ Uploaded 100% (12,000 out of 12,000)
1212
+ Success!"
1213
+ `);
1214
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1215
+ expect(std.err).toMatchInlineSnapshot(`""`);
1216
+ });
1217
+
1218
+ it("should error if the file is not a JSON array", async () => {
1219
+ const keyValues = { key: "someKey1", value: "someValue1" };
1220
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1221
+ await expect(
1222
+ runWrangler(`kv:bulk put --namespace-id some-namespace-id keys.json`)
1223
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1224
+ "Unexpected JSON input from \\"keys.json\\".
1225
+ Expected an array of key-value objects but got type \\"object\\"."
1226
+ `);
1227
+ expect(std.out).toMatchInlineSnapshot(`
1228
+ "
1229
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1230
+ `);
1231
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1232
+ });
1233
+
1234
+ it("should error if the array contains items that are not key-value objects", async () => {
1235
+ const keyValues = [
1236
+ 123,
1237
+ "a string",
1238
+ { key: "someKey" },
1239
+ { value: "someValue" },
1240
+ // add a valid object here to make sure it's not included
1241
+ { key: "someKey1", value: "someValue1" },
1242
+ // this one will only add a warning
1243
+ { key: "someKey1", value: "someValue1", invalid: true },
1244
+ // back to the invalid ones
1245
+ { key: 123, value: "somevalue" },
1246
+ { key: "somekey", value: 123 },
1247
+ { key: "someKey1", value: "someValue1", expiration: "string" },
1248
+ { key: "someKey1", value: "someValue1", expiration_ttl: "string" },
1249
+ {
1250
+ key: 123,
1251
+ value: {
1252
+ a: {
1253
+ nested: "object",
1254
+ },
1255
+ },
1256
+ },
1257
+ { key: "someKey1", value: "someValue1", metadata: 123 },
1258
+ { key: "someKey1", value: "someValue1", base64: "string" },
1259
+ ];
1260
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1261
+ await expect(
1262
+ runWrangler(`kv:bulk put --namespace-id some-namespace-id keys.json`)
1263
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1264
+ "Unexpected JSON input from \\"keys.json\\".
1265
+ Each item in the array should be an object that matches:
1266
+
1267
+ interface KeyValue {
1268
+ key: string;
1269
+ value: string;
1270
+ expiration?: number;
1271
+ expiration_ttl?: number;
1272
+ metadata?: object;
1273
+ base64?: boolean;
1274
+ }
1275
+
1276
+ The item at index 0 is 123
1277
+ The item at index 1 is \\"a string\\"
1278
+ The item at index 2 is {\\"key\\":\\"someKey\\"}
1279
+ The item at index 3 is {\\"value\\":\\"someValue\\"}
1280
+ The item at index 6 is {\\"key\\":123,\\"value\\":\\"somevalue\\"}
1281
+ The item at index 7 is {\\"key\\":\\"somekey\\",\\"value\\":123}
1282
+ The item at index 8 is {\\"key\\":\\"someKey1\\",\\"value\\":\\"someValue1\\",\\"expiration\\":\\"string\\"}
1283
+ The item at index 9 is {\\"key\\":\\"someKey1\\",\\"value\\":\\"someValue1\\",\\"expiration_ttl\\":\\"string\\"}
1284
+ The item at index 10 is {\\"key\\":123,\\"value\\":{\\"a\\":{\\"nested\\":\\"object\\"}}}
1285
+ The item at index 11 is {\\"key\\":\\"someKey1\\",\\"value\\":\\"someValue1\\",\\"metadata\\":123}
1286
+ The item at index 12 is {\\"key\\":\\"someKey1\\",\\"value\\":\\"someValue1\\",\\"base64\\":\\"string\\"}"
1287
+ `);
1288
+
1289
+ expect(std.out).toMatchInlineSnapshot(`
1290
+ "
1291
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1292
+ `);
1293
+ expect(std.warn).toMatchInlineSnapshot(`
1294
+ "▲ [WARNING] Unexpected key-value properties in \\"keys.json\\".
1295
+
1296
+ The item at index 5 contains unexpected properties: [\\"invalid\\"].
1297
+
1298
+ "
1299
+ `);
1300
+ });
1301
+ });
1302
+
1303
+ describe("delete", () => {
1304
+ function mockDeleteRequest(
1305
+ expectedNamespaceId: string,
1306
+ expectedKeys: string[]
1307
+ ) {
1308
+ const requests = { count: 0 };
1309
+ setMockResponse(
1310
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1311
+ "DELETE",
1312
+ ([_url, accountId, namespaceId], { headers, body }) => {
1313
+ requests.count++;
1314
+ expect(accountId).toEqual("some-account-id");
1315
+ expect(namespaceId).toEqual(expectedNamespaceId);
1316
+ expect(new Headers(headers ?? []).get("Content-Type")).toEqual(
1317
+ "application/json"
1318
+ );
1319
+ expect(JSON.parse(body as string)).toEqual(
1320
+ expectedKeys.slice(
1321
+ (requests.count - 1) * 5000,
1322
+ requests.count * 5000
1323
+ )
1324
+ );
1325
+ return null;
1326
+ }
1327
+ );
1328
+ return requests;
1329
+ }
1330
+
1331
+ it("should delete the keys parsed from a file", async () => {
1332
+ const keys = ["someKey1", "ns:someKey2"];
1333
+ writeFileSync("./keys.json", JSON.stringify(keys));
1334
+ mockConfirm({
1335
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1336
+ result: true,
1337
+ });
1338
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1339
+ await runWrangler(
1340
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1341
+ );
1342
+ expect(requests.count).toEqual(1);
1343
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1344
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1345
+ expect(std.err).toMatchInlineSnapshot(`""`);
1346
+ });
1347
+
1348
+ it("should delete the keys in batches of 5000 parsed from a file", async () => {
1349
+ const keys = new Array(12000).fill("some-key");
1350
+ writeFileSync("./keys.json", JSON.stringify(keys));
1351
+ mockConfirm({
1352
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1353
+ result: true,
1354
+ });
1355
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1356
+ await runWrangler(
1357
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1358
+ );
1359
+ expect(requests.count).toEqual(3);
1360
+ expect(std.out).toMatchInlineSnapshot(`
1361
+ "Deleted 0% (0 out of 12,000)
1362
+ Deleted 41% (5,000 out of 12,000)
1363
+ Deleted 83% (10,000 out of 12,000)
1364
+ Deleted 100% (12,000 out of 12,000)
1365
+ Success!"
1366
+ `);
1367
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1368
+ expect(std.err).toMatchInlineSnapshot(`""`);
1369
+ });
1370
+
1371
+ it("should not delete the keys if the user confirms no", async () => {
1372
+ const keys = ["someKey1", "ns:someKey2"];
1373
+ writeFileSync("./keys.json", JSON.stringify(keys));
1374
+ mockConfirm({
1375
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1376
+ result: false,
1377
+ });
1378
+ await runWrangler(
1379
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1380
+ );
1381
+ expect(std.out).toMatchInlineSnapshot(
1382
+ `"Not deleting keys read from \\"keys.json\\"."`
1383
+ );
1384
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1385
+ expect(std.err).toMatchInlineSnapshot(`""`);
1386
+ });
1387
+
1388
+ it("should delete the keys without asking if --force is provided", async () => {
1389
+ const keys = ["someKey1", "ns:someKey2"];
1390
+ writeFileSync("./keys.json", JSON.stringify(keys));
1391
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1392
+ await runWrangler(
1393
+ `kv:bulk delete --namespace-id some-namespace-id keys.json --force`
1394
+ );
1395
+ expect(requests.count).toEqual(1);
1396
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1397
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1398
+ expect(std.err).toMatchInlineSnapshot(`""`);
1399
+ });
1400
+
1401
+ it("should delete the keys without asking if -f is provided", async () => {
1402
+ const keys = ["someKey1", "ns:someKey2"];
1403
+ writeFileSync("./keys.json", JSON.stringify(keys));
1404
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1405
+ await runWrangler(
1406
+ `kv:bulk delete --namespace-id some-namespace-id keys.json -f`
1407
+ );
1408
+ expect(requests.count).toEqual(1);
1409
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1410
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1411
+ expect(std.err).toMatchInlineSnapshot(`""`);
1412
+ });
1413
+
1414
+ it("should error if the file is not a JSON array", async () => {
1415
+ const keys = 12354;
1416
+ writeFileSync("./keys.json", JSON.stringify(keys));
1417
+ mockConfirm({
1418
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1419
+ result: true,
1420
+ });
1421
+ await expect(
1422
+ runWrangler(
1423
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1424
+ )
1425
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1426
+ "Unexpected JSON input from \\"keys.json\\".
1427
+ Expected an array of strings but got:
1428
+ 12354"
1429
+ `);
1430
+ expect(std.out).toMatchInlineSnapshot(`
1431
+ "
1432
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1433
+ `);
1434
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1435
+ });
1436
+
1437
+ it("should error if the file contains non-string items", async () => {
1438
+ const keys = ["good", 12354, { key: "someKey" }, null];
1439
+ writeFileSync("./keys.json", JSON.stringify(keys));
1440
+ mockConfirm({
1441
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1442
+ result: true,
1443
+ });
1444
+ await expect(
1445
+ runWrangler(
1446
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1447
+ )
1448
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1449
+ "Unexpected JSON input from \\"keys.json\\".
1450
+ Expected an array of strings.
1451
+ The item at index 1 is type: \\"number\\" - 12354
1452
+ The item at index 2 is type: \\"object\\" - {\\"key\\":\\"someKey\\"}
1453
+ The item at index 3 is type: \\"object\\" - null"
1454
+ `);
1455
+ expect(std.out).toMatchInlineSnapshot(`
1456
+ "
1457
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1458
+ `);
1459
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1460
+ });
1461
+ });
1462
+ });
1121
1463
  });
1122
1464
 
1123
1465
  function writeWranglerConfig() {
1124
1466
  writeFileSync(
1125
1467
  "./wrangler.toml",
1126
1468
  [
1127
- 'name = "otherWorker"',
1469
+ 'name = "other-worker"',
1128
1470
  "kv_namespaces = [",
1129
1471
  ' { binding = "someBinding", id = "bound-id", preview_id = "preview-bound-id" }',
1130
1472
  "]",