wrangler 0.0.0-e2a26a0 → 0.0.0-e3e3243

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 (91) hide show
  1. package/README.md +1 -1
  2. package/bin/wrangler.js +10 -1
  3. package/miniflare-dist/index.mjs +79 -0
  4. package/miniflare-dist/index.mjs.map +7 -0
  5. package/package.json +24 -12
  6. package/pages/functions/filepath-routing.test.ts +212 -36
  7. package/pages/functions/filepath-routing.ts +69 -119
  8. package/pages/functions/routes.ts +8 -17
  9. package/pages/functions/template-worker.ts +3 -9
  10. package/src/__tests__/configuration.test.ts +2820 -0
  11. package/src/__tests__/dev.test.tsx +535 -65
  12. package/src/__tests__/guess-worker-format.test.ts +68 -0
  13. package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
  14. package/src/__tests__/helpers/mock-account-id.ts +26 -8
  15. package/src/__tests__/helpers/mock-bin.ts +4 -1
  16. package/src/__tests__/helpers/mock-cfetch.ts +5 -5
  17. package/src/__tests__/helpers/mock-console.ts +21 -7
  18. package/src/__tests__/helpers/mock-kv.ts +9 -16
  19. package/src/__tests__/helpers/mock-stdin.ts +103 -0
  20. package/src/__tests__/helpers/mock-web-socket.ts +29 -0
  21. package/src/__tests__/helpers/run-in-tmp.ts +3 -0
  22. package/src/__tests__/helpers/run-wrangler.ts +5 -3
  23. package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
  24. package/src/__tests__/https-options.test.ts +127 -0
  25. package/src/__tests__/index.test.ts +467 -27
  26. package/src/__tests__/jest.setup.ts +37 -5
  27. package/src/__tests__/kv.test.ts +442 -201
  28. package/src/__tests__/logout.test.ts +15 -13
  29. package/src/__tests__/package-manager.test.ts +2 -2
  30. package/src/__tests__/pages.test.ts +82 -0
  31. package/src/__tests__/parse.test.ts +322 -0
  32. package/src/__tests__/publish.test.ts +2717 -430
  33. package/src/__tests__/r2.test.ts +198 -0
  34. package/src/__tests__/route.test.ts +45 -0
  35. package/src/__tests__/secret.test.ts +301 -86
  36. package/src/__tests__/sentry.test.ts +146 -0
  37. package/src/__tests__/tail.test.ts +562 -0
  38. package/src/__tests__/whoami.test.tsx +21 -7
  39. package/src/bundle.ts +155 -0
  40. package/src/cfetch/index.ts +8 -6
  41. package/src/cfetch/internal.ts +60 -22
  42. package/src/cli.ts +10 -0
  43. package/src/config/README.md +107 -0
  44. package/src/config/config.ts +218 -0
  45. package/src/config/diagnostics.ts +80 -0
  46. package/src/config/environment.ts +371 -0
  47. package/src/config/index.ts +62 -0
  48. package/src/config/validation-helpers.ts +554 -0
  49. package/src/config/validation.ts +1232 -0
  50. package/src/{api/preview.ts → create-worker-preview.ts} +59 -21
  51. package/src/create-worker-upload-form.ts +217 -0
  52. package/src/dev/dev.tsx +392 -0
  53. package/src/dev/local.tsx +232 -0
  54. package/src/dev/remote.tsx +203 -0
  55. package/src/dev/use-esbuild.ts +104 -0
  56. package/src/entry.ts +240 -0
  57. package/src/environment-variables.ts +33 -0
  58. package/src/https-options.ts +122 -0
  59. package/src/index.tsx +1067 -779
  60. package/src/inspect.ts +25 -4
  61. package/src/intl-polyfill.d.ts +139 -0
  62. package/src/{kv.tsx → kv.ts} +95 -60
  63. package/src/miniflare-cli/README.md +30 -0
  64. package/src/miniflare-cli/enum-keys.ts +17 -0
  65. package/src/miniflare-cli/index.ts +37 -0
  66. package/src/module-collection.ts +226 -31
  67. package/src/open-in-browser.ts +25 -0
  68. package/src/package-manager.ts +21 -15
  69. package/src/pages.tsx +35 -20
  70. package/src/parse.ts +183 -0
  71. package/src/proxy.ts +115 -45
  72. package/src/publish.ts +268 -328
  73. package/src/r2.ts +50 -0
  74. package/src/reporting.ts +131 -0
  75. package/src/selfsigned.d.ts +29 -0
  76. package/src/sites.tsx +83 -43
  77. package/src/tail/filters.ts +279 -0
  78. package/src/tail/index.ts +299 -0
  79. package/src/tail/printing.ts +62 -0
  80. package/src/user.tsx +234 -126
  81. package/src/{api/worker.ts → worker.ts} +44 -36
  82. package/templates/new-worker.js +1 -1
  83. package/templates/new-worker.ts +1 -1
  84. package/templates/tsconfig.json +105 -0
  85. package/wrangler-dist/cli.js +131201 -114242
  86. package/wrangler-dist/cli.js.map +3 -3
  87. package/src/__tests__/helpers/mock-user.ts +0 -27
  88. package/src/api/form_data.ts +0 -134
  89. package/src/config.ts +0 -641
  90. package/src/dev.tsx +0 -834
  91. package/src/tail.tsx +0 -73
@@ -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 { 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();
@@ -53,13 +55,13 @@ describe("wrangler", () => {
53
55
  namespace The name of the new namespace [string] [required]
54
56
 
55
57
  Flags:
56
- -c, --config Path to .toml configuration file [string]
57
- -h, --help Show help [boolean]
58
- -v, --version Show version number [boolean]
58
+ -c, --config Path to .toml configuration file [string]
59
+ -h, --help Show help [boolean]
60
+ -v, --version Show version number [boolean]
61
+ --legacy-env Use legacy environments [boolean]
59
62
 
60
63
  Options:
61
- -l, --local Run on my machine [boolean] [default: false]
62
- --env Perform on a specific environment [string]
64
+ -e, --env Perform on a specific environment [string]
63
65
  --preview Interact with a preview namespace [boolean]
64
66
 
65
67
  Not enough non-option arguments: got 0, need at least 1"
@@ -70,7 +72,7 @@ describe("wrangler", () => {
70
72
  await expect(
71
73
  runWrangler("kv:namespace create abc def ghi")
72
74
  ).rejects.toThrowErrorMatchingInlineSnapshot(
73
- `"Unexpected additional positional arguments \\"def ghi\\"."`
75
+ `"Unknown arguments: def, ghi"`
74
76
  );
75
77
  expect(std.out).toMatchInlineSnapshot(`""`);
76
78
  expect(std.err).toMatchInlineSnapshot(`
@@ -82,16 +84,16 @@ describe("wrangler", () => {
82
84
  namespace The name of the new namespace [string] [required]
83
85
 
84
86
  Flags:
85
- -c, --config Path to .toml configuration file [string]
86
- -h, --help Show help [boolean]
87
- -v, --version Show version number [boolean]
87
+ -c, --config Path to .toml configuration file [string]
88
+ -h, --help Show help [boolean]
89
+ -v, --version Show version number [boolean]
90
+ --legacy-env Use legacy environments [boolean]
88
91
 
89
92
  Options:
90
- -l, --local Run on my machine [boolean] [default: false]
91
- --env Perform on a specific environment [string]
93
+ -e, --env Perform on a specific environment [string]
92
94
  --preview Interact with a preview namespace [boolean]
93
95
 
94
- Unexpected additional positional arguments \\"def ghi\\"."
96
+ Unknown arguments: def, ghi"
95
97
  `);
96
98
  });
97
99
 
@@ -112,13 +114,13 @@ describe("wrangler", () => {
112
114
  namespace The name of the new namespace [string] [required]
113
115
 
114
116
  Flags:
115
- -c, --config Path to .toml configuration file [string]
116
- -h, --help Show help [boolean]
117
- -v, --version Show version number [boolean]
117
+ -c, --config Path to .toml configuration file [string]
118
+ -h, --help Show help [boolean]
119
+ -v, --version Show version number [boolean]
120
+ --legacy-env Use legacy environments [boolean]
118
121
 
119
122
  Options:
120
- -l, --local Run on my machine [boolean] [default: false]
121
- --env Perform on a specific environment [string]
123
+ -e, --env Perform on a specific environment [string]
122
124
  --preview Interact with a preview namespace [boolean]
123
125
 
124
126
  The namespace binding name \\"abc-def\\" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number."
@@ -276,15 +278,15 @@ describe("wrangler", () => {
276
278
  Deletes a given namespace.
277
279
 
278
280
  Flags:
279
- -c, --config Path to .toml configuration file [string]
280
- -h, --help Show help [boolean]
281
- -v, --version Show version number [boolean]
281
+ -c, --config Path to .toml configuration file [string]
282
+ -h, --help Show help [boolean]
283
+ -v, --version Show version number [boolean]
284
+ --legacy-env Use legacy environments [boolean]
282
285
 
283
286
  Options:
284
- -l, --local Run on my machine [boolean] [default: false]
285
287
  --binding The name of the namespace to delete [string]
286
288
  --namespace-id The id of the namespace to delete [string]
287
- --env Perform on a specific environment [string]
289
+ -e, --env Perform on a specific environment [string]
288
290
  --preview Interact with a preview namespace [boolean]
289
291
 
290
292
  Not able to delete namespace.
@@ -319,10 +321,7 @@ describe("wrangler", () => {
319
321
  describe("put", () => {
320
322
  function mockKeyPutRequest(
321
323
  expectedNamespaceId: string,
322
- expectedKey: string,
323
- expectedValue: string,
324
- expiration?: number,
325
- expirationTtl?: number
324
+ expectedKV: KeyValue
326
325
  ) {
327
326
  const requests = { count: 0 };
328
327
  setMockResponse(
@@ -332,15 +331,19 @@ describe("wrangler", () => {
332
331
  requests.count++;
333
332
  expect(accountId).toEqual("some-account-id");
334
333
  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}`);
334
+ expect(key).toEqual(expectedKV.key);
335
+ expect(body).toEqual(expectedKV.value);
336
+ if (expectedKV.expiration !== undefined) {
337
+ expect(query.get("expiration")).toEqual(
338
+ `${expectedKV.expiration}`
339
+ );
339
340
  } else {
340
341
  expect(query.has("expiration")).toBe(false);
341
342
  }
342
- if (expirationTtl) {
343
- expect(query.get("expiration_ttl")).toEqual(`${expirationTtl}`);
343
+ if (expectedKV.expiration_ttl) {
344
+ expect(query.get("expiration_ttl")).toEqual(
345
+ `${expectedKV.expiration_ttl}`
346
+ );
344
347
  } else {
345
348
  expect(query.has("expiration_ttl")).toBe(false);
346
349
  }
@@ -351,11 +354,10 @@ describe("wrangler", () => {
351
354
  }
352
355
 
353
356
  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
- );
357
+ const requests = mockKeyPutRequest("some-namespace-id", {
358
+ key: "my-key",
359
+ value: "my-value",
360
+ });
359
361
 
360
362
  await runWrangler(
361
363
  "kv:key put my-key my-value --namespace-id some-namespace-id"
@@ -370,7 +372,10 @@ describe("wrangler", () => {
370
372
 
371
373
  it("should put a key in a given namespace specified by binding", async () => {
372
374
  writeWranglerConfig();
373
- const requests = mockKeyPutRequest("bound-id", "my-key", "my-value");
375
+ const requests = mockKeyPutRequest("bound-id", {
376
+ key: "my-key",
377
+ value: "my-value",
378
+ });
374
379
  await runWrangler(
375
380
  "kv:key put my-key my-value --binding someBinding --preview false"
376
381
  );
@@ -384,11 +389,10 @@ describe("wrangler", () => {
384
389
 
385
390
  it("should put a key in a given preview namespace specified by binding", async () => {
386
391
  writeWranglerConfig();
387
- const requests = mockKeyPutRequest(
388
- "preview-bound-id",
389
- "my-key",
390
- "my-value"
391
- );
392
+ const requests = mockKeyPutRequest("preview-bound-id", {
393
+ key: "my-key",
394
+ value: "my-value",
395
+ });
392
396
 
393
397
  await runWrangler(
394
398
  "kv:key put my-key my-value --binding someBinding --preview"
@@ -402,13 +406,12 @@ describe("wrangler", () => {
402
406
  });
403
407
 
404
408
  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
- );
409
+ const requests = mockKeyPutRequest("some-namespace-id", {
410
+ key: "my-key",
411
+ value: "my-value",
412
+ expiration: 10,
413
+ expiration_ttl: 20,
414
+ });
412
415
  await runWrangler(
413
416
  "kv:key put my-key my-value --namespace-id some-namespace-id --expiration 10 --ttl 20"
414
417
  );
@@ -421,11 +424,10 @@ describe("wrangler", () => {
421
424
 
422
425
  it("should put a key to the specified environment in a given namespace", async () => {
423
426
  writeWranglerConfig();
424
- const requests = mockKeyPutRequest(
425
- "env-bound-id",
426
- "my-key",
427
- "my-value"
428
- );
427
+ const requests = mockKeyPutRequest("env-bound-id", {
428
+ key: "my-key",
429
+ value: "my-value",
430
+ });
429
431
  await runWrangler(
430
432
  "kv:key put my-key my-value --binding someBinding --env some-environment --preview false"
431
433
  );
@@ -438,11 +440,10 @@ describe("wrangler", () => {
438
440
 
439
441
  it("should put a key with a value loaded from a given path", async () => {
440
442
  writeFileSync("foo.txt", "file-contents", "utf-8");
441
- const requests = mockKeyPutRequest(
442
- "some-namespace-id",
443
- "my-key",
444
- "file-contents"
445
- );
443
+ const requests = mockKeyPutRequest("some-namespace-id", {
444
+ key: "my-key",
445
+ value: "file-contents",
446
+ });
446
447
  await runWrangler(
447
448
  "kv:key put my-key --namespace-id some-namespace-id --path foo.txt"
448
449
  );
@@ -467,23 +468,23 @@ describe("wrangler", () => {
467
468
  Writes a single key/value pair to the given namespace.
468
469
 
469
470
  Positionals:
470
- key The key to write to. [string] [required]
471
- value The value to write. [string]
471
+ key The key to write to [string] [required]
472
+ value The value to write [string]
472
473
 
473
474
  Flags:
474
- -c, --config Path to .toml configuration file [string]
475
- -h, --help Show help [boolean]
476
- -v, --version Show version number [boolean]
475
+ -c, --config Path to .toml configuration file [string]
476
+ -h, --help Show help [boolean]
477
+ -v, --version Show version number [boolean]
478
+ --legacy-env Use legacy environments [boolean]
477
479
 
478
480
  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]
481
+ --binding The binding of the namespace to write to [string]
482
+ --namespace-id The id of the namespace to write to [string]
483
+ -e, --env Perform on a specific environment [string]
483
484
  --preview Interact with a preview namespace [boolean]
484
- --ttl Time for which the entries should be visible. [number]
485
+ --ttl Time for which the entries should be visible [number]
485
486
  --expiration Time since the UNIX epoch after which the entry expires [number]
486
- --path Read value from the file at a given path. [string]
487
+ --path Read value from the file at a given path [string]
487
488
 
488
489
  Not enough non-option arguments: got 0, need at least 1"
489
490
  `);
@@ -503,23 +504,23 @@ describe("wrangler", () => {
503
504
  Writes a single key/value pair to the given namespace.
504
505
 
505
506
  Positionals:
506
- key The key to write to. [string] [required]
507
- value The value to write. [string]
507
+ key The key to write to [string] [required]
508
+ value The value to write [string]
508
509
 
509
510
  Flags:
510
- -c, --config Path to .toml configuration file [string]
511
- -h, --help Show help [boolean]
512
- -v, --version Show version number [boolean]
511
+ -c, --config Path to .toml configuration file [string]
512
+ -h, --help Show help [boolean]
513
+ -v, --version Show version number [boolean]
514
+ --legacy-env Use legacy environments [boolean]
513
515
 
514
516
  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]
517
+ --binding The binding of the namespace to write to [string]
518
+ --namespace-id The id of the namespace to write to [string]
519
+ -e, --env Perform on a specific environment [string]
519
520
  --preview Interact with a preview namespace [boolean]
520
- --ttl Time for which the entries should be visible. [number]
521
+ --ttl Time for which the entries should be visible [number]
521
522
  --expiration Time since the UNIX epoch after which the entry expires [number]
522
- --path Read value from the file at a given path. [string]
523
+ --path Read value from the file at a given path [string]
523
524
 
524
525
  Exactly one of the arguments binding and namespace-id is required"
525
526
  `);
@@ -539,23 +540,23 @@ describe("wrangler", () => {
539
540
  Writes a single key/value pair to the given namespace.
540
541
 
541
542
  Positionals:
542
- key The key to write to. [string] [required]
543
- value The value to write. [string]
543
+ key The key to write to [string] [required]
544
+ value The value to write [string]
544
545
 
545
546
  Flags:
546
- -c, --config Path to .toml configuration file [string]
547
- -h, --help Show help [boolean]
548
- -v, --version Show version number [boolean]
547
+ -c, --config Path to .toml configuration file [string]
548
+ -h, --help Show help [boolean]
549
+ -v, --version Show version number [boolean]
550
+ --legacy-env Use legacy environments [boolean]
549
551
 
550
552
  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]
553
+ --binding The binding of the namespace to write to [string]
554
+ --namespace-id The id of the namespace to write to [string]
555
+ -e, --env Perform on a specific environment [string]
555
556
  --preview Interact with a preview namespace [boolean]
556
- --ttl Time for which the entries should be visible. [number]
557
+ --ttl Time for which the entries should be visible [number]
557
558
  --expiration Time since the UNIX epoch after which the entry expires [number]
558
- --path Read value from the file at a given path. [string]
559
+ --path Read value from the file at a given path [string]
559
560
 
560
561
  Arguments binding and namespace-id are mutually exclusive"
561
562
  `);
@@ -575,23 +576,23 @@ describe("wrangler", () => {
575
576
  Writes a single key/value pair to the given namespace.
576
577
 
577
578
  Positionals:
578
- key The key to write to. [string] [required]
579
- value The value to write. [string]
579
+ key The key to write to [string] [required]
580
+ value The value to write [string]
580
581
 
581
582
  Flags:
582
- -c, --config Path to .toml configuration file [string]
583
- -h, --help Show help [boolean]
584
- -v, --version Show version number [boolean]
583
+ -c, --config Path to .toml configuration file [string]
584
+ -h, --help Show help [boolean]
585
+ -v, --version Show version number [boolean]
586
+ --legacy-env Use legacy environments [boolean]
585
587
 
586
588
  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]
589
+ --binding The binding of the namespace to write to [string]
590
+ --namespace-id The id of the namespace to write to [string]
591
+ -e, --env Perform on a specific environment [string]
591
592
  --preview Interact with a preview namespace [boolean]
592
- --ttl Time for which the entries should be visible. [number]
593
+ --ttl Time for which the entries should be visible [number]
593
594
  --expiration Time since the UNIX epoch after which the entry expires [number]
594
- --path Read value from the file at a given path. [string]
595
+ --path Read value from the file at a given path [string]
595
596
 
596
597
  Exactly one of the arguments value and path is required"
597
598
  `);
@@ -611,23 +612,23 @@ describe("wrangler", () => {
611
612
  Writes a single key/value pair to the given namespace.
612
613
 
613
614
  Positionals:
614
- key The key to write to. [string] [required]
615
- value The value to write. [string]
615
+ key The key to write to [string] [required]
616
+ value The value to write [string]
616
617
 
617
618
  Flags:
618
- -c, --config Path to .toml configuration file [string]
619
- -h, --help Show help [boolean]
620
- -v, --version Show version number [boolean]
619
+ -c, --config Path to .toml configuration file [string]
620
+ -h, --help Show help [boolean]
621
+ -v, --version Show version number [boolean]
622
+ --legacy-env Use legacy environments [boolean]
621
623
 
622
624
  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]
625
+ --binding The binding of the namespace to write to [string]
626
+ --namespace-id The id of the namespace to write to [string]
627
+ -e, --env Perform on a specific environment [string]
627
628
  --preview Interact with a preview namespace [boolean]
628
- --ttl Time for which the entries should be visible. [number]
629
+ --ttl Time for which the entries should be visible [number]
629
630
  --expiration Time since the UNIX epoch after which the entry expires [number]
630
- --path Read value from the file at a given path. [string]
631
+ --path Read value from the file at a given path [string]
631
632
 
632
633
  Arguments value and path are mutually exclusive"
633
634
  `);
@@ -645,18 +646,16 @@ describe("wrangler", () => {
645
646
  expect(std.err).toMatchInlineSnapshot(`
646
647
  "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
647
648
 
648
- %s
649
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
649
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
650
650
  `);
651
651
  });
652
652
 
653
653
  it("should error if a given binding has both preview and non-preview and --preview is not specified", async () => {
654
654
  writeWranglerConfig();
655
- const requests = mockKeyPutRequest(
656
- "preview-bound-id",
657
- "my-key",
658
- "my-value"
659
- );
655
+ const requests = mockKeyPutRequest("preview-bound-id", {
656
+ key: "my-key",
657
+ value: "my-value",
658
+ });
660
659
  await expect(
661
660
  runWrangler("kv:key put my-key my-value --binding someBinding")
662
661
  ).rejects.toThrowErrorMatchingInlineSnapshot(
@@ -666,8 +665,7 @@ describe("wrangler", () => {
666
665
  expect(std.err).toMatchInlineSnapshot(`
667
666
  "someBinding has both a namespace ID and a preview ID. Specify \\"--preview\\" or \\"--preview false\\" to avoid writing data to the wrong namespace.
668
667
 
669
- %s
670
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
668
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
671
669
  `);
672
670
  expect(requests.count).toEqual(0);
673
671
  });
@@ -675,26 +673,26 @@ describe("wrangler", () => {
675
673
 
676
674
  describe("list", () => {
677
675
  it("should list the keys of a namespace specified by namespace-id", async () => {
678
- const keys = ["key-1", "key-2", "key-3"];
676
+ const keys = [
677
+ { name: "key-1" },
678
+ { name: "key-2", expiration: 123456789 },
679
+ { name: "key-3", expiration_ttl: 666 },
680
+ ];
679
681
  mockKeyListRequest("some-namespace-id", keys);
680
682
  await runWrangler("kv:key list --namespace-id some-namespace-id");
681
683
  expect(std.err).toMatchInlineSnapshot(`""`);
682
684
  expect(std.out).toMatchInlineSnapshot(`
683
685
  "[
684
686
  {
685
- \\"name\\": \\"key-1\\",
686
- \\"expiration\\": 123456789,
687
- \\"metadata\\": {}
687
+ \\"name\\": \\"key-1\\"
688
688
  },
689
689
  {
690
690
  \\"name\\": \\"key-2\\",
691
- \\"expiration\\": 123456789,
692
- \\"metadata\\": {}
691
+ \\"expiration\\": 123456789
693
692
  },
694
693
  {
695
694
  \\"name\\": \\"key-3\\",
696
- \\"expiration\\": 123456789,
697
- \\"metadata\\": {}
695
+ \\"expiration_ttl\\": 666
698
696
  }
699
697
  ]"
700
698
  `);
@@ -702,7 +700,7 @@ describe("wrangler", () => {
702
700
 
703
701
  it("should list the keys of a namespace specified by binding", async () => {
704
702
  writeWranglerConfig();
705
- const keys = ["key-1", "key-2", "key-3"];
703
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
706
704
  mockKeyListRequest("bound-id", keys);
707
705
 
708
706
  await runWrangler("kv:key list --binding someBinding");
@@ -710,19 +708,13 @@ describe("wrangler", () => {
710
708
  expect(std.out).toMatchInlineSnapshot(`
711
709
  "[
712
710
  {
713
- \\"name\\": \\"key-1\\",
714
- \\"expiration\\": 123456789,
715
- \\"metadata\\": {}
711
+ \\"name\\": \\"key-1\\"
716
712
  },
717
713
  {
718
- \\"name\\": \\"key-2\\",
719
- \\"expiration\\": 123456789,
720
- \\"metadata\\": {}
714
+ \\"name\\": \\"key-2\\"
721
715
  },
722
716
  {
723
- \\"name\\": \\"key-3\\",
724
- \\"expiration\\": 123456789,
725
- \\"metadata\\": {}
717
+ \\"name\\": \\"key-3\\"
726
718
  }
727
719
  ]"
728
720
  `);
@@ -730,26 +722,20 @@ describe("wrangler", () => {
730
722
 
731
723
  it("should list the keys of a preview namespace specified by binding", async () => {
732
724
  writeWranglerConfig();
733
- const keys = ["key-1", "key-2", "key-3"];
725
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
734
726
  mockKeyListRequest("preview-bound-id", keys);
735
727
  await runWrangler("kv:key list --binding someBinding --preview");
736
728
  expect(std.err).toMatchInlineSnapshot(`""`);
737
729
  expect(std.out).toMatchInlineSnapshot(`
738
730
  "[
739
731
  {
740
- \\"name\\": \\"key-1\\",
741
- \\"expiration\\": 123456789,
742
- \\"metadata\\": {}
732
+ \\"name\\": \\"key-1\\"
743
733
  },
744
734
  {
745
- \\"name\\": \\"key-2\\",
746
- \\"expiration\\": 123456789,
747
- \\"metadata\\": {}
735
+ \\"name\\": \\"key-2\\"
748
736
  },
749
737
  {
750
- \\"name\\": \\"key-3\\",
751
- \\"expiration\\": 123456789,
752
- \\"metadata\\": {}
738
+ \\"name\\": \\"key-3\\"
753
739
  }
754
740
  ]"
755
741
  `);
@@ -757,7 +743,7 @@ describe("wrangler", () => {
757
743
 
758
744
  it("should list the keys of a namespace specified by binding, in a given environment", async () => {
759
745
  writeWranglerConfig();
760
- const keys = ["key-1", "key-2", "key-3"];
746
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
761
747
  mockKeyListRequest("env-bound-id", keys);
762
748
  await runWrangler(
763
749
  "kv:key list --binding someBinding --env some-environment"
@@ -766,19 +752,13 @@ describe("wrangler", () => {
766
752
  expect(std.out).toMatchInlineSnapshot(`
767
753
  "[
768
754
  {
769
- \\"name\\": \\"key-1\\",
770
- \\"expiration\\": 123456789,
771
- \\"metadata\\": {}
755
+ \\"name\\": \\"key-1\\"
772
756
  },
773
757
  {
774
- \\"name\\": \\"key-2\\",
775
- \\"expiration\\": 123456789,
776
- \\"metadata\\": {}
758
+ \\"name\\": \\"key-2\\"
777
759
  },
778
760
  {
779
- \\"name\\": \\"key-3\\",
780
- \\"expiration\\": 123456789,
781
- \\"metadata\\": {}
761
+ \\"name\\": \\"key-3\\"
782
762
  }
783
763
  ]"
784
764
  `);
@@ -786,7 +766,7 @@ describe("wrangler", () => {
786
766
 
787
767
  it("should list the keys of a preview namespace specified by binding, in a given environment", async () => {
788
768
  writeWranglerConfig();
789
- const keys = ["key-1", "key-2", "key-3"];
769
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
790
770
  mockKeyListRequest("preview-env-bound-id", keys);
791
771
  await runWrangler(
792
772
  "kv:key list --binding someBinding --preview --env some-environment"
@@ -795,19 +775,13 @@ describe("wrangler", () => {
795
775
  expect(std.out).toMatchInlineSnapshot(`
796
776
  "[
797
777
  {
798
- \\"name\\": \\"key-1\\",
799
- \\"expiration\\": 123456789,
800
- \\"metadata\\": {}
778
+ \\"name\\": \\"key-1\\"
801
779
  },
802
780
  {
803
- \\"name\\": \\"key-2\\",
804
- \\"expiration\\": 123456789,
805
- \\"metadata\\": {}
781
+ \\"name\\": \\"key-2\\"
806
782
  },
807
783
  {
808
- \\"name\\": \\"key-3\\",
809
- \\"expiration\\": 123456789,
810
- \\"metadata\\": {}
784
+ \\"name\\": \\"key-3\\"
811
785
  }
812
786
  ]"
813
787
  `);
@@ -824,9 +798,9 @@ describe("wrangler", () => {
824
798
  describe(`cursor - ${blankCursorValue}`, () => {
825
799
  it("should make multiple requests for paginated results", async () => {
826
800
  // Create a lot of mock keys, so that the fetch requests will be paginated
827
- const keys: string[] = [];
801
+ const keys: NamespaceKeyInfo[] = [];
828
802
  for (let i = 0; i < 550; i++) {
829
- keys.push("key-" + i);
803
+ keys.push({ name: "key-" + i });
830
804
  }
831
805
  // Ask for the keys in pages of size 100.
832
806
  const requests = mockKeyListRequest(
@@ -835,11 +809,9 @@ describe("wrangler", () => {
835
809
  100,
836
810
  blankCursorValue
837
811
  );
838
- await runWrangler(
839
- "kv:key list --namespace-id some-namespace-id --limit 100"
840
- );
812
+ await runWrangler("kv:key list --namespace-id some-namespace-id");
841
813
  expect(std.err).toMatchInlineSnapshot(`""`);
842
- expect(JSON.parse(std.out).map((k) => k.name)).toEqual(keys);
814
+ expect(JSON.parse(std.out)).toEqual(keys);
843
815
  expect(requests.count).toEqual(6);
844
816
  });
845
817
  });
@@ -855,8 +827,7 @@ describe("wrangler", () => {
855
827
  expect(std.err).toMatchInlineSnapshot(`
856
828
  "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
857
829
 
858
- %s
859
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
830
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
860
831
  `);
861
832
  expect(std.out).toMatchInlineSnapshot(`""`);
862
833
  });
@@ -916,7 +887,7 @@ describe("wrangler", () => {
916
887
  "my-value"
917
888
  );
918
889
  await runWrangler(
919
- "kv:key get my-key my-value --binding someBinding --env some-environment --preview false"
890
+ "kv:key get my-key --binding someBinding --env some-environment --preview false"
920
891
  );
921
892
  expect(std.out).toMatchInlineSnapshot(`"my-value"`);
922
893
  expect(std.err).toMatchInlineSnapshot(`""`);
@@ -938,15 +909,15 @@ describe("wrangler", () => {
938
909
  key The key value to get. [string] [required]
939
910
 
940
911
  Flags:
941
- -c, --config Path to .toml configuration file [string]
942
- -h, --help Show help [boolean]
943
- -v, --version Show version number [boolean]
912
+ -c, --config Path to .toml configuration file [string]
913
+ -h, --help Show help [boolean]
914
+ -v, --version Show version number [boolean]
915
+ --legacy-env Use legacy environments [boolean]
944
916
 
945
917
  Options:
946
- -l, --local Run on my machine [boolean] [default: false]
947
918
  --binding The name of the namespace to get from [string]
948
919
  --namespace-id The id of the namespace to get from [string]
949
- --env Perform on a specific environment [string]
920
+ -e, --env Perform on a specific environment [string]
950
921
  --preview Interact with a preview namespace [boolean] [default: false]
951
922
 
952
923
  Not enough non-option arguments: got 0, need at least 1"
@@ -969,15 +940,15 @@ describe("wrangler", () => {
969
940
  key The key value to get. [string] [required]
970
941
 
971
942
  Flags:
972
- -c, --config Path to .toml configuration file [string]
973
- -h, --help Show help [boolean]
974
- -v, --version Show version number [boolean]
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]
975
947
 
976
948
  Options:
977
- -l, --local Run on my machine [boolean] [default: false]
978
949
  --binding The name of the namespace to get from [string]
979
950
  --namespace-id The id of the namespace to get from [string]
980
- --env Perform on a specific environment [string]
951
+ -e, --env Perform on a specific environment [string]
981
952
  --preview Interact with a preview namespace [boolean] [default: false]
982
953
 
983
954
  Exactly one of the arguments binding and namespace-id is required"
@@ -1001,15 +972,15 @@ describe("wrangler", () => {
1001
972
  key The key value to get. [string] [required]
1002
973
 
1003
974
  Flags:
1004
- -c, --config Path to .toml configuration file [string]
1005
- -h, --help Show help [boolean]
1006
- -v, --version Show version number [boolean]
975
+ -c, --config Path to .toml configuration file [string]
976
+ -h, --help Show help [boolean]
977
+ -v, --version Show version number [boolean]
978
+ --legacy-env Use legacy environments [boolean]
1007
979
 
1008
980
  Options:
1009
- -l, --local Run on my machine [boolean] [default: false]
1010
981
  --binding The name of the namespace to get from [string]
1011
982
  --namespace-id The id of the namespace to get from [string]
1012
- --env Perform on a specific environment [string]
983
+ -e, --env Perform on a specific environment [string]
1013
984
  --preview Interact with a preview namespace [boolean] [default: false]
1014
985
 
1015
986
  Arguments binding and namespace-id are mutually exclusive"
@@ -1027,8 +998,7 @@ describe("wrangler", () => {
1027
998
  expect(std.err).toMatchInlineSnapshot(`
1028
999
  "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
1029
1000
 
1030
- %s
1031
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1001
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1032
1002
  `);
1033
1003
  });
1034
1004
  });
@@ -1090,8 +1060,7 @@ describe("wrangler", () => {
1090
1060
  expect(std.err).toMatchInlineSnapshot(`
1091
1061
  "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
1092
1062
 
1093
- %s
1094
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1063
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1095
1064
  `);
1096
1065
  });
1097
1066
 
@@ -1118,6 +1087,278 @@ describe("wrangler", () => {
1118
1087
  });
1119
1088
  });
1120
1089
  });
1090
+
1091
+ describe("kv:bulk", () => {
1092
+ describe("put", () => {
1093
+ function mockPutRequest(
1094
+ expectedNamespaceId: string,
1095
+ expectedKeyValues: KeyValue[]
1096
+ ) {
1097
+ const requests = { count: 0 };
1098
+ setMockResponse(
1099
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1100
+ "PUT",
1101
+ ([_url, accountId, namespaceId], { body }) => {
1102
+ requests.count++;
1103
+ expect(accountId).toEqual("some-account-id");
1104
+ expect(namespaceId).toEqual(expectedNamespaceId);
1105
+ expect(JSON.parse(body as string)).toEqual(
1106
+ expectedKeyValues.slice(
1107
+ (requests.count - 1) * 5000,
1108
+ requests.count * 5000
1109
+ )
1110
+ );
1111
+ return null;
1112
+ }
1113
+ );
1114
+ return requests;
1115
+ }
1116
+
1117
+ it("should put the key-values parsed from a file", async () => {
1118
+ const keyValues: KeyValue[] = [
1119
+ { key: "someKey1", value: "someValue1" },
1120
+ { key: "ns:someKey2", value: "123", base64: true },
1121
+ { key: "someKey3", value: "someValue3", expiration: 100 },
1122
+ { key: "someKey4", value: "someValue4", expiration_ttl: 500 },
1123
+ ];
1124
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1125
+ const requests = mockPutRequest("some-namespace-id", keyValues);
1126
+ await runWrangler(
1127
+ `kv:bulk put --namespace-id some-namespace-id keys.json`
1128
+ );
1129
+ expect(requests.count).toEqual(1);
1130
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1131
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1132
+ expect(std.err).toMatchInlineSnapshot(`""`);
1133
+ });
1134
+
1135
+ it("should put the key-values in batches of 5000 parsed from a file", async () => {
1136
+ const keyValues: KeyValue[] = new Array(12000).fill({
1137
+ key: "someKey1",
1138
+ value: "someValue1",
1139
+ });
1140
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1141
+ const requests = mockPutRequest("some-namespace-id", keyValues);
1142
+ await runWrangler(
1143
+ `kv:bulk put --namespace-id some-namespace-id keys.json`
1144
+ );
1145
+ expect(requests.count).toEqual(3);
1146
+ expect(std.out).toMatchInlineSnapshot(`
1147
+ "Uploaded 0 of 12000.
1148
+ Uploaded 5000 of 12000.
1149
+ Uploaded 10000 of 12000.
1150
+ Uploaded 12000 of 12000.
1151
+ Success!"
1152
+ `);
1153
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1154
+ expect(std.err).toMatchInlineSnapshot(`""`);
1155
+ });
1156
+
1157
+ it("should error if the file is not a JSON array", async () => {
1158
+ const keyValues = { key: "someKey1", value: "someValue1" };
1159
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1160
+ await expect(
1161
+ runWrangler(`kv:bulk put --namespace-id some-namespace-id keys.json`)
1162
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1163
+ "Unexpected JSON input from \\"keys.json\\".
1164
+ Expected an array of key-value objects but got type \\"object\\"."
1165
+ `);
1166
+ expect(std.out).toMatchInlineSnapshot(`""`);
1167
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1168
+ });
1169
+
1170
+ it("should error if the array contains items that are not key-value objects", async () => {
1171
+ const keyValues = [
1172
+ 123,
1173
+ "a string",
1174
+ { key: "someKey" },
1175
+ { value: "someValue" },
1176
+ { key: "someKey1", value: "someValue1", invalid: true },
1177
+ ];
1178
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1179
+ await expect(
1180
+ runWrangler(`kv:bulk put --namespace-id some-namespace-id keys.json`)
1181
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1182
+ "Unexpected JSON input from \\"keys.json\\".
1183
+ Each item in the array should be an object that matches:
1184
+
1185
+ interface KeyValue {
1186
+ key: string;
1187
+ value: string;
1188
+ expiration?: number;
1189
+ expiration_ttl?: number;
1190
+ metadata?: object;
1191
+ base64?: boolean;
1192
+ }
1193
+
1194
+ The item at index 0 is type: \\"number\\" - 123
1195
+ The item at index 1 is type: \\"string\\" - \\"a string\\"
1196
+ The item at index 2 is {\\"key\\":\\"someKey\\"}
1197
+ The item at index 3 is {\\"value\\":\\"someValue\\"}"
1198
+ `);
1199
+
1200
+ expect(std.out).toMatchInlineSnapshot(`""`);
1201
+ expect(std.warn).toMatchInlineSnapshot(`
1202
+ "Unexpected key-value properties in \\"keys.json\\".
1203
+ The item at index 4 contains unexpected properties: [\\"invalid\\"]."
1204
+ `);
1205
+ });
1206
+ });
1207
+
1208
+ describe("delete", () => {
1209
+ function mockDeleteRequest(
1210
+ expectedNamespaceId: string,
1211
+ expectedKeys: string[]
1212
+ ) {
1213
+ const requests = { count: 0 };
1214
+ setMockResponse(
1215
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1216
+ "DELETE",
1217
+ ([_url, accountId, namespaceId], { headers, body }) => {
1218
+ requests.count++;
1219
+ expect(accountId).toEqual("some-account-id");
1220
+ expect(namespaceId).toEqual(expectedNamespaceId);
1221
+ expect(new Headers(headers ?? []).get("Content-Type")).toEqual(
1222
+ "application/json"
1223
+ );
1224
+ expect(JSON.parse(body as string)).toEqual(
1225
+ expectedKeys.slice(
1226
+ (requests.count - 1) * 5000,
1227
+ requests.count * 5000
1228
+ )
1229
+ );
1230
+ return null;
1231
+ }
1232
+ );
1233
+ return requests;
1234
+ }
1235
+
1236
+ it("should delete the keys parsed from a file", async () => {
1237
+ const keys = ["someKey1", "ns:someKey2"];
1238
+ writeFileSync("./keys.json", JSON.stringify(keys));
1239
+ mockConfirm({
1240
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1241
+ result: true,
1242
+ });
1243
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1244
+ await runWrangler(
1245
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1246
+ );
1247
+ expect(requests.count).toEqual(1);
1248
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1249
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1250
+ expect(std.err).toMatchInlineSnapshot(`""`);
1251
+ });
1252
+
1253
+ it("should delete the keys in batches of 5000 parsed from a file", async () => {
1254
+ const keys = new Array(12000).fill("some-key");
1255
+ writeFileSync("./keys.json", JSON.stringify(keys));
1256
+ mockConfirm({
1257
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1258
+ result: true,
1259
+ });
1260
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1261
+ await runWrangler(
1262
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1263
+ );
1264
+ expect(requests.count).toEqual(3);
1265
+ expect(std.out).toMatchInlineSnapshot(`
1266
+ "Deleted 0 of 12000.
1267
+ Deleted 5000 of 12000.
1268
+ Deleted 10000 of 12000.
1269
+ Deleted 12000 of 12000.
1270
+ Success!"
1271
+ `);
1272
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1273
+ expect(std.err).toMatchInlineSnapshot(`""`);
1274
+ });
1275
+
1276
+ it("should not delete the keys if the user confirms no", async () => {
1277
+ const keys = ["someKey1", "ns:someKey2"];
1278
+ writeFileSync("./keys.json", JSON.stringify(keys));
1279
+ mockConfirm({
1280
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1281
+ result: false,
1282
+ });
1283
+ await runWrangler(
1284
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1285
+ );
1286
+ expect(std.out).toMatchInlineSnapshot(
1287
+ `"Not deleting keys read from \\"keys.json\\"."`
1288
+ );
1289
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1290
+ expect(std.err).toMatchInlineSnapshot(`""`);
1291
+ });
1292
+
1293
+ it("should delete the keys without asking if --force is provided", async () => {
1294
+ const keys = ["someKey1", "ns:someKey2"];
1295
+ writeFileSync("./keys.json", JSON.stringify(keys));
1296
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1297
+ await runWrangler(
1298
+ `kv:bulk delete --namespace-id some-namespace-id keys.json --force`
1299
+ );
1300
+ expect(requests.count).toEqual(1);
1301
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1302
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1303
+ expect(std.err).toMatchInlineSnapshot(`""`);
1304
+ });
1305
+
1306
+ it("should delete the keys without asking if -f is provided", async () => {
1307
+ const keys = ["someKey1", "ns:someKey2"];
1308
+ writeFileSync("./keys.json", JSON.stringify(keys));
1309
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1310
+ await runWrangler(
1311
+ `kv:bulk delete --namespace-id some-namespace-id keys.json -f`
1312
+ );
1313
+ expect(requests.count).toEqual(1);
1314
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1315
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1316
+ expect(std.err).toMatchInlineSnapshot(`""`);
1317
+ });
1318
+
1319
+ it("should error if the file is not a JSON array", async () => {
1320
+ const keys = 12354;
1321
+ writeFileSync("./keys.json", JSON.stringify(keys));
1322
+ mockConfirm({
1323
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1324
+ result: true,
1325
+ });
1326
+ await expect(
1327
+ runWrangler(
1328
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1329
+ )
1330
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1331
+ "Unexpected JSON input from \\"keys.json\\".
1332
+ Expected an array of strings but got:
1333
+ 12354"
1334
+ `);
1335
+ expect(std.out).toMatchInlineSnapshot(`""`);
1336
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1337
+ });
1338
+
1339
+ it("should error if the file contains non-string items", async () => {
1340
+ const keys = ["good", 12354, { key: "someKey" }, null];
1341
+ writeFileSync("./keys.json", JSON.stringify(keys));
1342
+ mockConfirm({
1343
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1344
+ result: true,
1345
+ });
1346
+ await expect(
1347
+ runWrangler(
1348
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1349
+ )
1350
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1351
+ "Unexpected JSON input from \\"keys.json\\".
1352
+ Expected an array of strings.
1353
+ The item at index 1 is type: \\"number\\" - 12354
1354
+ The item at index 2 is type: \\"object\\" - {\\"key\\":\\"someKey\\"}
1355
+ The item at index 3 is type: \\"object\\" - null"
1356
+ `);
1357
+ expect(std.out).toMatchInlineSnapshot(`""`);
1358
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1359
+ });
1360
+ });
1361
+ });
1121
1362
  });
1122
1363
 
1123
1364
  function writeWranglerConfig() {