wrangler 0.0.0-e3cab74 → 0.0.0-e452a35

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 (102) 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 +42 -28
  6. package/pages/functions/buildPlugin.ts +105 -0
  7. package/pages/functions/buildWorker.ts +93 -4
  8. package/pages/functions/filepath-routing.test.ts +136 -25
  9. package/pages/functions/filepath-routing.ts +14 -3
  10. package/pages/functions/routes.ts +6 -1
  11. package/pages/functions/template-plugin.ts +147 -0
  12. package/pages/functions/template-worker.ts +21 -8
  13. package/src/__tests__/config-cache.test.ts +36 -0
  14. package/src/__tests__/configuration.test.ts +1514 -367
  15. package/src/__tests__/dev.test.tsx +870 -84
  16. package/src/__tests__/guess-worker-format.test.ts +37 -18
  17. package/src/__tests__/helpers/mock-account-id.ts +22 -4
  18. package/src/__tests__/helpers/mock-cfetch.ts +8 -4
  19. package/src/__tests__/helpers/mock-console.ts +35 -10
  20. package/src/__tests__/helpers/mock-dialogs.ts +26 -1
  21. package/src/__tests__/helpers/mock-http-server.ts +46 -0
  22. package/src/__tests__/helpers/mock-istty.ts +27 -0
  23. package/src/__tests__/helpers/mock-kv.ts +9 -16
  24. package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
  25. package/src/__tests__/helpers/mock-stdin.ts +103 -0
  26. package/src/__tests__/helpers/run-in-tmp.ts +10 -0
  27. package/src/__tests__/helpers/write-worker-source.ts +31 -0
  28. package/src/__tests__/https-options.test.ts +130 -0
  29. package/src/__tests__/index.test.ts +137 -747
  30. package/src/__tests__/init.test.ts +1557 -0
  31. package/src/__tests__/jest.setup.ts +28 -8
  32. package/src/__tests__/kv.test.ts +598 -258
  33. package/src/__tests__/logger.test.ts +115 -0
  34. package/src/__tests__/pages.test.ts +657 -0
  35. package/src/__tests__/parse.test.ts +8 -0
  36. package/src/__tests__/publish.test.ts +4003 -941
  37. package/src/__tests__/r2.test.ts +69 -34
  38. package/src/__tests__/route.test.ts +45 -0
  39. package/src/__tests__/secret.test.ts +228 -73
  40. package/src/__tests__/tail.test.ts +146 -20
  41. package/src/__tests__/user.test.ts +131 -0
  42. package/src/__tests__/whoami.test.tsx +26 -7
  43. package/src/abort.d.ts +3 -0
  44. package/src/bundle.ts +74 -7
  45. package/src/cfetch/index.ts +21 -4
  46. package/src/cfetch/internal.ts +20 -14
  47. package/src/cli.ts +5 -11
  48. package/src/config/README.md +7 -7
  49. package/src/config/config.ts +69 -100
  50. package/src/config/environment.ts +119 -4
  51. package/src/config/index.ts +177 -4
  52. package/src/config/validation-helpers.ts +228 -23
  53. package/src/config/validation.ts +687 -174
  54. package/src/config-cache.ts +45 -0
  55. package/src/{api/preview.ts → create-worker-preview.ts} +74 -36
  56. package/src/{api/form_data.ts → create-worker-upload-form.ts} +55 -18
  57. package/src/dev/dev-vars.ts +36 -0
  58. package/src/dev/dev.tsx +422 -0
  59. package/src/dev/local.tsx +318 -0
  60. package/src/dev/remote.tsx +227 -0
  61. package/src/dev/use-esbuild.ts +118 -0
  62. package/src/dialogs.tsx +16 -6
  63. package/src/durable.ts +102 -0
  64. package/src/entry.ts +279 -14
  65. package/src/environment-variables.ts +3 -1
  66. package/src/errors.ts +11 -0
  67. package/src/https-options.ts +123 -0
  68. package/src/index.tsx +1268 -806
  69. package/src/inspect.ts +64 -11
  70. package/src/intl-polyfill.d.ts +139 -0
  71. package/src/{kv.tsx → kv.ts} +195 -62
  72. package/src/logger.ts +66 -0
  73. package/src/miniflare-cli/README.md +30 -0
  74. package/src/miniflare-cli/enum-keys.ts +17 -0
  75. package/src/miniflare-cli/index.ts +41 -0
  76. package/src/miniflare-cli/request-context.ts +40 -0
  77. package/src/module-collection.ts +94 -6
  78. package/src/open-in-browser.ts +9 -3
  79. package/src/package-manager.ts +9 -8
  80. package/src/pages.tsx +1057 -75
  81. package/src/parse.ts +24 -5
  82. package/src/proxy.ts +143 -54
  83. package/src/publish.ts +444 -229
  84. package/src/selfsigned.d.ts +29 -0
  85. package/src/sites.tsx +98 -44
  86. package/src/tail/index.ts +2 -2
  87. package/src/tail/printing.ts +13 -8
  88. package/src/update-check.ts +19 -0
  89. package/src/user.tsx +263 -109
  90. package/src/whoami.tsx +2 -1
  91. package/src/{api/worker.ts → worker.ts} +24 -30
  92. package/templates/gitignore +171 -0
  93. package/templates/new-worker.ts +16 -1
  94. package/templates/static-asset-facade.js +1 -1
  95. package/wrangler-dist/cli.js +55345 -69246
  96. package/src/__tests__/helpers/mock-user.ts +0 -27
  97. package/src/__tests__/logout.test.ts +0 -50
  98. package/src/__tests__/sentry.test.ts +0 -146
  99. package/src/dev.tsx +0 -961
  100. package/src/guess-worker-format.ts +0 -68
  101. package/src/reporting.ts +0 -115
  102. 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, NamespaceKeyInfo } 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
 
@@ -53,16 +56,18 @@ describe("wrangler", () => {
53
56
  namespace The name of the new namespace [string] [required]
54
57
 
55
58
  Flags:
56
- -c, --config Path to .toml configuration file [string]
57
- -h, --help Show help [boolean]
58
- -v, --version Show version number [boolean]
59
- --legacy-env Use legacy environments [boolean]
59
+ -c, --config Path to .toml configuration file [string]
60
+ -h, --help Show help [boolean]
61
+ -v, --version Show version number [boolean]
60
62
 
61
63
  Options:
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
 
@@ -82,16 +87,18 @@ describe("wrangler", () => {
82
87
  namespace The name of the new namespace [string] [required]
83
88
 
84
89
  Flags:
85
- -c, --config Path to .toml configuration file [string]
86
- -h, --help Show help [boolean]
87
- -v, --version Show version number [boolean]
88
- --legacy-env Use legacy environments [boolean]
90
+ -c, --config Path to .toml configuration file [string]
91
+ -h, --help Show help [boolean]
92
+ -v, --version Show version number [boolean]
89
93
 
90
94
  Options:
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
 
@@ -112,16 +119,18 @@ describe("wrangler", () => {
112
119
  namespace The name of the new namespace [string] [required]
113
120
 
114
121
  Flags:
115
- -c, --config Path to .toml configuration file [string]
116
- -h, --help Show help [boolean]
117
- -v, --version Show version number [boolean]
118
- --legacy-env Use legacy environments [boolean]
122
+ -c, --config Path to .toml configuration file [string]
123
+ -h, --help Show help [boolean]
124
+ -v, --version Show version number [boolean]
119
125
 
120
126
  Options:
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.
277
-
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
- --legacy-env Use legacy environments [boolean]
285
+ A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
283
286
 
284
- Options:
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,9 +470,9 @@ 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
 
@@ -471,21 +481,23 @@ describe("wrangler", () => {
471
481
  value The value to write [string]
472
482
 
473
483
  Flags:
474
- -c, --config Path to .toml configuration file [string]
475
- -h, --help Show help [boolean]
476
- -v, --version Show version number [boolean]
477
- --legacy-env Use legacy environments [boolean]
484
+ -c, --config Path to .toml configuration file [string]
485
+ -h, --help Show help [boolean]
486
+ -v, --version Show version number [boolean]
478
487
 
479
488
  Options:
480
489
  --binding The binding of the namespace to write to [string]
481
490
  --namespace-id The id of the namespace to write to [string]
482
- --env Perform on a specific environment [string]
491
+ -e, --env Perform on a specific environment [string]
483
492
  --preview Interact with a preview namespace [boolean]
484
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,9 +508,9 @@ 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
 
@@ -507,21 +519,23 @@ describe("wrangler", () => {
507
519
  value The value to write [string]
508
520
 
509
521
  Flags:
510
- -c, --config Path to .toml configuration file [string]
511
- -h, --help Show help [boolean]
512
- -v, --version Show version number [boolean]
513
- --legacy-env Use legacy environments [boolean]
522
+ -c, --config Path to .toml configuration file [string]
523
+ -h, --help Show help [boolean]
524
+ -v, --version Show version number [boolean]
514
525
 
515
526
  Options:
516
527
  --binding The binding of the namespace to write to [string]
517
528
  --namespace-id The id of the namespace to write to [string]
518
- --env Perform on a specific environment [string]
529
+ -e, --env Perform on a specific environment [string]
519
530
  --preview Interact with a preview namespace [boolean]
520
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,9 +546,9 @@ 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
 
@@ -543,21 +557,23 @@ describe("wrangler", () => {
543
557
  value The value to write [string]
544
558
 
545
559
  Flags:
546
- -c, --config Path to .toml configuration file [string]
547
- -h, --help Show help [boolean]
548
- -v, --version Show version number [boolean]
549
- --legacy-env Use legacy environments [boolean]
560
+ -c, --config Path to .toml configuration file [string]
561
+ -h, --help Show help [boolean]
562
+ -v, --version Show version number [boolean]
550
563
 
551
564
  Options:
552
565
  --binding The binding of the namespace to write to [string]
553
566
  --namespace-id The id of the namespace to write to [string]
554
- --env Perform on a specific environment [string]
567
+ -e, --env Perform on a specific environment [string]
555
568
  --preview Interact with a preview namespace [boolean]
556
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,9 +584,9 @@ 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
 
@@ -579,21 +595,23 @@ describe("wrangler", () => {
579
595
  value The value to write [string]
580
596
 
581
597
  Flags:
582
- -c, --config Path to .toml configuration file [string]
583
- -h, --help Show help [boolean]
584
- -v, --version Show version number [boolean]
585
- --legacy-env Use legacy environments [boolean]
598
+ -c, --config Path to .toml configuration file [string]
599
+ -h, --help Show help [boolean]
600
+ -v, --version Show version number [boolean]
586
601
 
587
602
  Options:
588
603
  --binding The binding of the namespace to write to [string]
589
604
  --namespace-id The id of the namespace to write to [string]
590
- --env Perform on a specific environment [string]
605
+ -e, --env Perform on a specific environment [string]
591
606
  --preview Interact with a preview namespace [boolean]
592
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,9 +622,9 @@ 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
 
@@ -615,21 +633,23 @@ describe("wrangler", () => {
615
633
  value The value to write [string]
616
634
 
617
635
  Flags:
618
- -c, --config Path to .toml configuration file [string]
619
- -h, --help Show help [boolean]
620
- -v, --version Show version number [boolean]
621
- --legacy-env Use legacy environments [boolean]
636
+ -c, --config Path to .toml configuration file [string]
637
+ -h, --help Show help [boolean]
638
+ -v, --version Show version number [boolean]
622
639
 
623
640
  Options:
624
641
  --binding The binding of the namespace to write to [string]
625
642
  --namespace-id The id of the namespace to write to [string]
626
- --env Perform on a specific environment [string]
643
+ -e, --env Perform on a specific environment [string]
627
644
  --preview Interact with a preview namespace [boolean]
628
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."
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."
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,13 +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(
843
- JSON.parse(std.out).map((k: NamespaceKeyInfo) => k.name)
844
- ).toEqual(keys);
839
+ expect(JSON.parse(std.out)).toEqual(keys);
845
840
  expect(requests.count).toEqual(6);
846
841
  });
847
842
  });
@@ -855,12 +850,14 @@ describe("wrangler", () => {
855
850
  `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
856
851
  );
857
852
  expect(std.err).toMatchInlineSnapshot(`
858
- "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\\".
859
854
 
860
- %s
861
- 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."
862
860
  `);
863
- expect(std.out).toMatchInlineSnapshot(`""`);
864
861
  });
865
862
  });
866
863
 
@@ -918,7 +915,21 @@ describe("wrangler", () => {
918
915
  "my-value"
919
916
  );
920
917
  await runWrangler(
921
- "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"
922
933
  );
923
934
  expect(std.out).toMatchInlineSnapshot(`"my-value"`);
924
935
  expect(std.err).toMatchInlineSnapshot(`""`);
@@ -930,9 +941,9 @@ describe("wrangler", () => {
930
941
  ).rejects.toThrowErrorMatchingInlineSnapshot(
931
942
  `"Not enough non-option arguments: got 0, need at least 1"`
932
943
  );
933
- expect(std.out).toMatchInlineSnapshot(`""`);
934
- expect(std.err).toMatchInlineSnapshot(`
935
- "wrangler kv:key get <key>
944
+ expect(std.out).toMatchInlineSnapshot(`
945
+ "
946
+ wrangler kv:key get <key>
936
947
 
937
948
  Reads a single value by key from the given namespace.
938
949
 
@@ -940,18 +951,20 @@ describe("wrangler", () => {
940
951
  key The key value to get. [string] [required]
941
952
 
942
953
  Flags:
943
- -c, --config Path to .toml configuration file [string]
944
- -h, --help Show help [boolean]
945
- -v, --version Show version number [boolean]
946
- --legacy-env Use legacy environments [boolean]
954
+ -c, --config Path to .toml configuration file [string]
955
+ -h, --help Show help [boolean]
956
+ -v, --version Show version number [boolean]
947
957
 
948
958
  Options:
949
959
  --binding The name of the namespace to get from [string]
950
960
  --namespace-id The id of the namespace to get from [string]
951
- --env Perform on a specific environment [string]
952
- --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
953
966
 
954
- Not enough non-option arguments: got 0, need at least 1"
967
+ "
955
968
  `);
956
969
  });
957
970
 
@@ -961,9 +974,9 @@ describe("wrangler", () => {
961
974
  ).rejects.toThrowErrorMatchingInlineSnapshot(
962
975
  `"Exactly one of the arguments binding and namespace-id is required"`
963
976
  );
964
- expect(std.out).toMatchInlineSnapshot(`""`);
965
- expect(std.err).toMatchInlineSnapshot(`
966
- "wrangler kv:key get <key>
977
+ expect(std.out).toMatchInlineSnapshot(`
978
+ "
979
+ wrangler kv:key get <key>
967
980
 
968
981
  Reads a single value by key from the given namespace.
969
982
 
@@ -971,18 +984,20 @@ describe("wrangler", () => {
971
984
  key The key value to get. [string] [required]
972
985
 
973
986
  Flags:
974
- -c, --config Path to .toml configuration file [string]
975
- -h, --help Show help [boolean]
976
- -v, --version Show version number [boolean]
977
- --legacy-env Use legacy environments [boolean]
987
+ -c, --config Path to .toml configuration file [string]
988
+ -h, --help Show help [boolean]
989
+ -v, --version Show version number [boolean]
978
990
 
979
991
  Options:
980
992
  --binding The name of the namespace to get from [string]
981
993
  --namespace-id The id of the namespace to get from [string]
982
- --env Perform on a specific environment [string]
983
- --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
984
999
 
985
- Exactly one of the arguments binding and namespace-id is required"
1000
+ "
986
1001
  `);
987
1002
  });
988
1003
 
@@ -993,9 +1008,9 @@ describe("wrangler", () => {
993
1008
  `"Arguments binding and namespace-id are mutually exclusive"`
994
1009
  );
995
1010
 
996
- expect(std.out).toMatchInlineSnapshot(`""`);
997
- expect(std.err).toMatchInlineSnapshot(`
998
- "wrangler kv:key get <key>
1011
+ expect(std.out).toMatchInlineSnapshot(`
1012
+ "
1013
+ wrangler kv:key get <key>
999
1014
 
1000
1015
  Reads a single value by key from the given namespace.
1001
1016
 
@@ -1003,18 +1018,20 @@ describe("wrangler", () => {
1003
1018
  key The key value to get. [string] [required]
1004
1019
 
1005
1020
  Flags:
1006
- -c, --config Path to .toml configuration file [string]
1007
- -h, --help Show help [boolean]
1008
- -v, --version Show version number [boolean]
1009
- --legacy-env Use legacy environments [boolean]
1021
+ -c, --config Path to .toml configuration file [string]
1022
+ -h, --help Show help [boolean]
1023
+ -v, --version Show version number [boolean]
1010
1024
 
1011
1025
  Options:
1012
1026
  --binding The name of the namespace to get from [string]
1013
1027
  --namespace-id The id of the namespace to get from [string]
1014
- --env Perform on a specific environment [string]
1015
- --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
1016
1033
 
1017
- Arguments binding and namespace-id are mutually exclusive"
1034
+ "
1018
1035
  `);
1019
1036
  });
1020
1037
 
@@ -1025,12 +1042,14 @@ describe("wrangler", () => {
1025
1042
  ).rejects.toThrowErrorMatchingInlineSnapshot(
1026
1043
  `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
1027
1044
  );
1028
- 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."
1048
+ `);
1029
1049
  expect(std.err).toMatchInlineSnapshot(`
1030
- "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\\".
1031
1051
 
1032
- %s
1033
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1052
+ "
1034
1053
  `);
1035
1054
  });
1036
1055
  });
@@ -1063,6 +1082,16 @@ describe("wrangler", () => {
1063
1082
  expect(requests.count).toEqual(1);
1064
1083
  });
1065
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
+
1066
1095
  it("should delete a key in a namespace specified by binding name", async () => {
1067
1096
  writeWranglerConfig();
1068
1097
  const requests = mockDeleteRequest("bound-id", "someKey");
@@ -1090,10 +1119,9 @@ describe("wrangler", () => {
1090
1119
  );
1091
1120
 
1092
1121
  expect(std.err).toMatchInlineSnapshot(`
1093
- "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\\".
1094
1123
 
1095
- %s
1096
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1124
+ "
1097
1125
  `);
1098
1126
  });
1099
1127
 
@@ -1104,7 +1132,7 @@ describe("wrangler", () => {
1104
1132
  `kv:key delete --binding someBinding --env some-environment --preview false someKey`
1105
1133
  );
1106
1134
  expect(std.out).toMatchInlineSnapshot(
1107
- `"deleting the key \\"someKey\\" on namespace env-bound-id"`
1135
+ `"Deleting the key \\"someKey\\" on namespace env-bound-id."`
1108
1136
  );
1109
1137
  expect(std.err).toMatchInlineSnapshot(`""`);
1110
1138
  expect(requests.count).toEqual(1);
@@ -1120,13 +1148,325 @@ describe("wrangler", () => {
1120
1148
  });
1121
1149
  });
1122
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."
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."
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."
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."
1458
+ `);
1459
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1460
+ });
1461
+ });
1462
+ });
1123
1463
  });
1124
1464
 
1125
1465
  function writeWranglerConfig() {
1126
1466
  writeFileSync(
1127
1467
  "./wrangler.toml",
1128
1468
  [
1129
- 'name = "otherWorker"',
1469
+ 'name = "other-worker"',
1130
1470
  "kv_namespaces = [",
1131
1471
  ' { binding = "someBinding", id = "bound-id", preview_id = "preview-bound-id" }',
1132
1472
  "]",