wrangler 0.0.0-e5d3690 → 0.0.0-e88a54e

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 (98) hide show
  1. package/bin/wrangler.js +2 -2
  2. package/miniflare-dist/index.mjs +79 -0
  3. package/miniflare-dist/index.mjs.map +7 -0
  4. package/package.json +32 -16
  5. package/pages/functions/buildWorker.ts +1 -1
  6. package/pages/functions/filepath-routing.test.ts +212 -28
  7. package/pages/functions/filepath-routing.ts +83 -130
  8. package/pages/functions/routes.ts +11 -18
  9. package/pages/functions/template-worker.ts +3 -9
  10. package/src/__tests__/configuration.test.ts +2796 -0
  11. package/src/__tests__/dev.test.tsx +488 -59
  12. package/src/__tests__/dev2.test.tsx +154 -0
  13. package/src/__tests__/guess-worker-format.test.ts +58 -0
  14. package/src/__tests__/{clipboardy-mock.js → helpers/clipboardy-mock.js} +0 -0
  15. package/src/__tests__/helpers/cmd-shim.d.ts +11 -0
  16. package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
  17. package/src/__tests__/helpers/mock-account-id.ts +48 -0
  18. package/src/__tests__/helpers/mock-bin.ts +36 -0
  19. package/src/__tests__/{mock-cfetch.ts → helpers/mock-cfetch.ts} +48 -14
  20. package/src/__tests__/helpers/mock-console.ts +70 -0
  21. package/src/__tests__/{mock-dialogs.ts → helpers/mock-dialogs.ts} +1 -1
  22. package/src/__tests__/helpers/mock-kv.ts +33 -0
  23. package/src/__tests__/helpers/mock-stdin.ts +103 -0
  24. package/src/__tests__/helpers/mock-web-socket.ts +29 -0
  25. package/src/__tests__/helpers/run-in-tmp.ts +32 -0
  26. package/src/__tests__/helpers/run-wrangler.ts +16 -0
  27. package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
  28. package/src/__tests__/https-options.test.ts +127 -0
  29. package/src/__tests__/index.test.ts +777 -75
  30. package/src/__tests__/jest.setup.ts +53 -6
  31. package/src/__tests__/kv.test.ts +674 -491
  32. package/src/__tests__/logout.test.ts +52 -0
  33. package/src/__tests__/package-manager.test.ts +206 -0
  34. package/src/__tests__/pages.test.ts +44 -0
  35. package/src/__tests__/parse.test.ts +322 -0
  36. package/src/__tests__/publish.test.ts +2327 -295
  37. package/src/__tests__/r2.test.ts +198 -0
  38. package/src/__tests__/route.test.ts +45 -0
  39. package/src/__tests__/secret.test.ts +425 -0
  40. package/src/__tests__/sentry.test.ts +146 -0
  41. package/src/__tests__/tail.test.ts +564 -0
  42. package/src/__tests__/whoami.test.tsx +26 -56
  43. package/src/bundle.ts +142 -0
  44. package/src/cfetch/index.ts +13 -19
  45. package/src/cfetch/internal.ts +91 -23
  46. package/src/cli.ts +10 -0
  47. package/src/config/README.md +107 -0
  48. package/src/config/config.ts +218 -0
  49. package/src/config/diagnostics.ts +80 -0
  50. package/src/config/environment.ts +366 -0
  51. package/src/config/index.ts +62 -0
  52. package/src/config/validation-helpers.ts +486 -0
  53. package/src/config/validation.ts +1090 -0
  54. package/src/{api/preview.ts → create-worker-preview.ts} +61 -23
  55. package/src/create-worker-upload-form.ts +217 -0
  56. package/src/dev/dev.tsx +364 -0
  57. package/src/dev/local.tsx +232 -0
  58. package/src/dev/remote.tsx +203 -0
  59. package/src/dev/use-esbuild.ts +100 -0
  60. package/src/dialogs.tsx +2 -2
  61. package/src/entry.ts +208 -0
  62. package/src/environment-variables.ts +33 -0
  63. package/src/https-options.ts +122 -0
  64. package/src/index.tsx +1175 -777
  65. package/src/inspect.ts +95 -21
  66. package/src/{kv.tsx → kv.ts} +104 -61
  67. package/src/miniflare-cli/README.md +30 -0
  68. package/src/miniflare-cli/enum-keys.ts +17 -0
  69. package/src/miniflare-cli/index.ts +37 -0
  70. package/src/module-collection.ts +229 -35
  71. package/src/open-in-browser.ts +25 -0
  72. package/src/package-manager.ts +126 -0
  73. package/src/pages.tsx +39 -32
  74. package/src/parse.ts +183 -0
  75. package/src/paths.ts +26 -0
  76. package/src/proxy.ts +177 -39
  77. package/src/publish.ts +274 -309
  78. package/src/r2.ts +50 -0
  79. package/src/reporting.ts +131 -0
  80. package/src/selfsigned.d.ts +29 -0
  81. package/src/sites.tsx +95 -58
  82. package/src/tail/filters.ts +279 -0
  83. package/src/tail/index.ts +299 -0
  84. package/src/tail/printing.ts +62 -0
  85. package/src/user.tsx +233 -134
  86. package/src/{api/worker.ts → worker.ts} +45 -37
  87. package/templates/new-worker.js +15 -0
  88. package/templates/new-worker.ts +15 -0
  89. package/{static-asset-facade.js → templates/static-asset-facade.js} +0 -0
  90. package/templates/tsconfig.json +105 -0
  91. package/wrangler-dist/cli.js +130352 -112740
  92. package/wrangler-dist/cli.js.map +3 -3
  93. package/src/__tests__/run-in-tmp.ts +0 -19
  94. package/src/__tests__/run-wrangler.ts +0 -32
  95. package/src/api/form_data.ts +0 -131
  96. package/src/config.ts +0 -646
  97. package/src/dev.tsx +0 -779
  98. package/src/tail.tsx +0 -73
@@ -1,16 +1,24 @@
1
- import { writeFileSync } from "fs";
2
- import type { KVNamespaceInfo } from "../kv";
1
+ import { writeFileSync } from "node:fs";
2
+ import { Headers } from "undici";
3
+ import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
3
4
  import {
4
5
  setMockResponse,
5
- setMockRawResponse,
6
6
  unsetAllMocks,
7
- createFetchResult,
8
- } from "./mock-cfetch";
9
- import { runWrangler } from "./run-wrangler";
10
- import { runInTempDir } from "./run-in-tmp";
7
+ unsetMockFetchKVGetValues,
8
+ setMockFetchKVGetValue,
9
+ } from "./helpers/mock-cfetch";
10
+ import { mockConsoleMethods } from "./helpers/mock-console";
11
+ import { mockConfirm } from "./helpers/mock-dialogs";
12
+ import { mockKeyListRequest } from "./helpers/mock-kv";
13
+ import { runInTempDir } from "./helpers/run-in-tmp";
14
+ import { runWrangler } from "./helpers/run-wrangler";
15
+ import type { KeyValue, KVNamespaceInfo, NamespaceKeyInfo } from "../kv";
11
16
 
12
17
  describe("wrangler", () => {
18
+ mockAccountId();
19
+ mockApiToken();
13
20
  runInTempDir();
21
+ const std = mockConsoleMethods();
14
22
 
15
23
  afterEach(() => {
16
24
  unsetAllMocks();
@@ -32,11 +40,13 @@ describe("wrangler", () => {
32
40
  }
33
41
 
34
42
  it("should error if no namespace is given", async () => {
35
- const { error, stdout, stderr } = await runWrangler(
36
- "kv:namespace create"
43
+ await expect(
44
+ runWrangler("kv:namespace create")
45
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
46
+ `"Not enough non-option arguments: got 0, need at least 1"`
37
47
  );
38
- expect(stdout).toMatchInlineSnapshot(`""`);
39
- expect(stderr).toMatchInlineSnapshot(`
48
+ expect(std.out).toMatchInlineSnapshot(`""`);
49
+ expect(std.err).toMatchInlineSnapshot(`
40
50
  "wrangler kv:namespace create <namespace>
41
51
 
42
52
  Create a new namespace
@@ -45,28 +55,27 @@ describe("wrangler", () => {
45
55
  namespace The name of the new namespace [string] [required]
46
56
 
47
57
  Flags:
48
- -c, --config Path to .toml configuration file [string]
49
- -h, --help Show help [boolean]
50
- -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]
51
62
 
52
63
  Options:
53
- -l, --local Run on my machine [boolean] [default: false]
54
- --env Perform on a specific environment [string]
64
+ -e, --env Perform on a specific environment [string]
55
65
  --preview Interact with a preview namespace [boolean]
56
66
 
57
67
  Not enough non-option arguments: got 0, need at least 1"
58
68
  `);
59
- expect(error).toMatchInlineSnapshot(
60
- `[Error: Not enough non-option arguments: got 0, need at least 1]`
61
- );
62
69
  });
63
70
 
64
71
  it("should error if the namespace to create contains spaces", async () => {
65
- const { error, stdout, stderr } = await runWrangler(
66
- "kv:namespace create abc def ghi"
72
+ await expect(
73
+ runWrangler("kv:namespace create abc def ghi")
74
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
75
+ `"Unexpected additional positional arguments \\"def ghi\\"."`
67
76
  );
68
- expect(stdout).toMatchInlineSnapshot(`""`);
69
- expect(stderr).toMatchInlineSnapshot(`
77
+ expect(std.out).toMatchInlineSnapshot(`""`);
78
+ expect(std.err).toMatchInlineSnapshot(`
70
79
  "wrangler kv:namespace create <namespace>
71
80
 
72
81
  Create a new namespace
@@ -75,28 +84,28 @@ describe("wrangler", () => {
75
84
  namespace The name of the new namespace [string] [required]
76
85
 
77
86
  Flags:
78
- -c, --config Path to .toml configuration file [string]
79
- -h, --help Show help [boolean]
80
- -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]
81
91
 
82
92
  Options:
83
- -l, --local Run on my machine [boolean] [default: false]
84
- --env Perform on a specific environment [string]
93
+ -e, --env Perform on a specific environment [string]
85
94
  --preview Interact with a preview namespace [boolean]
86
95
 
87
96
  Unexpected additional positional arguments \\"def ghi\\"."
88
97
  `);
89
- expect(error).toMatchInlineSnapshot(
90
- `[Error: Unexpected additional positional arguments "def ghi".]`
91
- );
92
98
  });
93
99
 
94
100
  it("should error if the namespace to create is not valid", async () => {
95
- const { error, stdout, stderr } = await runWrangler(
96
- "kv:namespace create abc-def"
101
+ await expect(
102
+ runWrangler("kv:namespace create abc-def")
103
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
104
+ `"The namespace binding name \\"abc-def\\" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number."`
97
105
  );
98
- expect(stdout).toMatchInlineSnapshot(`""`);
99
- expect(stderr).toMatchInlineSnapshot(`
106
+
107
+ expect(std.out).toMatchInlineSnapshot(`""`);
108
+ expect(std.err).toMatchInlineSnapshot(`
100
109
  "wrangler kv:namespace create <namespace>
101
110
 
102
111
  Create a new namespace
@@ -105,28 +114,23 @@ describe("wrangler", () => {
105
114
  namespace The name of the new namespace [string] [required]
106
115
 
107
116
  Flags:
108
- -c, --config Path to .toml configuration file [string]
109
- -h, --help Show help [boolean]
110
- -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]
111
121
 
112
122
  Options:
113
- -l, --local Run on my machine [boolean] [default: false]
114
- --env Perform on a specific environment [string]
123
+ -e, --env Perform on a specific environment [string]
115
124
  --preview Interact with a preview namespace [boolean]
116
125
 
117
126
  The namespace binding name \\"abc-def\\" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number."
118
127
  `);
119
- expect(error).toMatchInlineSnapshot(
120
- `[Error: The namespace binding name "abc-def" is invalid. It can only have alphanumeric and _ characters, and cannot begin with a number.]`
121
- );
122
128
  });
123
129
 
124
130
  it("should create a namespace", async () => {
125
131
  mockCreateRequest("worker-UnitTestNamespace");
126
- const { stdout } = await runWrangler(
127
- "kv:namespace create UnitTestNamespace"
128
- );
129
- expect(stdout).toMatchInlineSnapshot(`
132
+ await runWrangler("kv:namespace create UnitTestNamespace");
133
+ expect(std.out).toMatchInlineSnapshot(`
130
134
  "🌀 Creating namespace with title \\"worker-UnitTestNamespace\\"
131
135
  ✨ Success!
132
136
  Add the following to your configuration file in your kv_namespaces array:
@@ -136,10 +140,8 @@ describe("wrangler", () => {
136
140
 
137
141
  it("should create a preview namespace if configured to do so", async () => {
138
142
  mockCreateRequest("worker-UnitTestNamespace_preview");
139
- const { stdout } = await runWrangler(
140
- "kv:namespace create UnitTestNamespace --preview"
141
- );
142
- expect(stdout).toMatchInlineSnapshot(`
143
+ await runWrangler("kv:namespace create UnitTestNamespace --preview");
144
+ expect(std.out).toMatchInlineSnapshot(`
143
145
  "🌀 Creating namespace with title \\"worker-UnitTestNamespace_preview\\"
144
146
  ✨ Success!
145
147
  Add the following to your configuration file in your kv_namespaces array:
@@ -150,10 +152,8 @@ describe("wrangler", () => {
150
152
  it("should create a namespace using configured worker name", async () => {
151
153
  writeFileSync("./wrangler.toml", 'name = "otherWorker"', "utf-8");
152
154
  mockCreateRequest("otherWorker-UnitTestNamespace");
153
- const { stdout } = await runWrangler(
154
- "kv:namespace create UnitTestNamespace"
155
- );
156
- expect(stdout).toMatchInlineSnapshot(`
155
+ await runWrangler("kv:namespace create UnitTestNamespace");
156
+ expect(std.out).toMatchInlineSnapshot(`
157
157
  "🌀 Creating namespace with title \\"otherWorker-UnitTestNamespace\\"
158
158
  ✨ Success!
159
159
  Add the following to your configuration file in your kv_namespaces array:
@@ -163,10 +163,10 @@ describe("wrangler", () => {
163
163
 
164
164
  it("should create a namespace in an environment if configured to do so", async () => {
165
165
  mockCreateRequest("worker-customEnv-UnitTestNamespace");
166
- const { stdout } = await runWrangler(
166
+ await runWrangler(
167
167
  "kv:namespace create UnitTestNamespace --env customEnv"
168
168
  );
169
- expect(stdout).toMatchInlineSnapshot(`
169
+ expect(std.out).toMatchInlineSnapshot(`
170
170
  "🌀 Creating namespace with title \\"worker-customEnv-UnitTestNamespace\\"
171
171
  ✨ Success!
172
172
  Add the following to your configuration file in your kv_namespaces array under [env.customEnv]:
@@ -202,12 +202,10 @@ describe("wrangler", () => {
202
202
  { title: "title-2", id: "id-2" },
203
203
  ];
204
204
  mockListRequest(kvNamespaces);
205
- const { error, stdout, stderr } = await runWrangler(
206
- "kv:namespace list"
207
- );
208
- expect(error).toMatchInlineSnapshot(`undefined`);
209
- expect(stderr).toMatchInlineSnapshot(`""`);
210
- const namespaces = JSON.parse(stdout);
205
+ await runWrangler("kv:namespace list");
206
+
207
+ expect(std.err).toMatchInlineSnapshot(`""`);
208
+ const namespaces = JSON.parse(std.out);
211
209
  expect(namespaces).toEqual(kvNamespaces);
212
210
  });
213
211
 
@@ -218,8 +216,8 @@ describe("wrangler", () => {
218
216
  kvNamespaces.push({ title: "title-" + i, id: "id-" + i });
219
217
  }
220
218
  const requests = mockListRequest(kvNamespaces);
221
- const { stdout } = await runWrangler("kv:namespace list");
222
- const namespaces = JSON.parse(stdout);
219
+ await runWrangler("kv:namespace list");
220
+ const namespaces = JSON.parse(std.out);
223
221
  expect(namespaces).toEqual(kvNamespaces);
224
222
  expect(requests.count).toEqual(6);
225
223
  });
@@ -269,24 +267,26 @@ describe("wrangler", () => {
269
267
 
270
268
  it("should error if a given binding name is not in the configured kv namespaces", async () => {
271
269
  writeWranglerConfig();
272
- const { stderr } = await runWrangler(
273
- `kv:namespace delete --binding otherBinding`
274
- );
275
- expect(stderr).toMatchInlineSnapshot(`
270
+ await expect(runWrangler("kv:namespace delete --binding otherBinding"))
271
+ .rejects.toThrowErrorMatchingInlineSnapshot(`
272
+ "Not able to delete namespace.
273
+ A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."
274
+ `);
275
+ expect(std.err).toMatchInlineSnapshot(`
276
276
  "wrangler kv:namespace delete
277
277
 
278
278
  Deletes a given namespace.
279
279
 
280
280
  Flags:
281
- -c, --config Path to .toml configuration file [string]
282
- -h, --help Show help [boolean]
283
- -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]
284
285
 
285
286
  Options:
286
- -l, --local Run on my machine [boolean] [default: false]
287
287
  --binding The name of the namespace to delete [string]
288
288
  --namespace-id The id of the namespace to delete [string]
289
- --env Perform on a specific environment [string]
289
+ -e, --env Perform on a specific environment [string]
290
290
  --preview Interact with a preview namespace [boolean]
291
291
 
292
292
  Not able to delete namespace.
@@ -297,12 +297,12 @@ describe("wrangler", () => {
297
297
  it("should delete a namespace specified by binding name in a given environment", async () => {
298
298
  writeWranglerConfig();
299
299
  const requests = mockDeleteRequest("env-bound-id");
300
- const { stdout, stderr, error } = await runWrangler(
301
- `kv:namespace delete --binding someBinding --env some-environment --preview false`
300
+ await runWrangler(
301
+ "kv:namespace delete --binding someBinding --env some-environment --preview false"
302
302
  );
303
- expect(stdout).toMatchInlineSnapshot(`""`);
304
- expect(stderr).toMatchInlineSnapshot(`""`);
305
- expect(error).toMatchInlineSnapshot(`undefined`);
303
+
304
+ expect(std.out).toMatchInlineSnapshot(`""`);
305
+ expect(std.err).toMatchInlineSnapshot(`""`);
306
306
  expect(requests.count).toEqual(1);
307
307
  });
308
308
 
@@ -321,10 +321,7 @@ describe("wrangler", () => {
321
321
  describe("put", () => {
322
322
  function mockKeyPutRequest(
323
323
  expectedNamespaceId: string,
324
- expectedKey: string,
325
- expectedValue: string,
326
- expiration?: number,
327
- expirationTtl?: number
324
+ expectedKV: KeyValue
328
325
  ) {
329
326
  const requests = { count: 0 };
330
327
  setMockResponse(
@@ -334,15 +331,19 @@ describe("wrangler", () => {
334
331
  requests.count++;
335
332
  expect(accountId).toEqual("some-account-id");
336
333
  expect(namespaceId).toEqual(expectedNamespaceId);
337
- expect(key).toEqual(expectedKey);
338
- expect(body).toEqual(expectedValue);
339
- if (expiration !== undefined) {
340
- 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
+ );
341
340
  } else {
342
341
  expect(query.has("expiration")).toBe(false);
343
342
  }
344
- if (expirationTtl) {
345
- expect(query.get("expiration_ttl")).toEqual(`${expirationTtl}`);
343
+ if (expectedKV.expiration_ttl) {
344
+ expect(query.get("expiration_ttl")).toEqual(
345
+ `${expectedKV.expiration_ttl}`
346
+ );
346
347
  } else {
347
348
  expect(query.has("expiration_ttl")).toBe(false);
348
349
  }
@@ -353,358 +354,345 @@ describe("wrangler", () => {
353
354
  }
354
355
 
355
356
  it("should put a key in a given namespace specified by namespace-id", async () => {
356
- const requests = mockKeyPutRequest(
357
- "some-namespace-id",
358
- "my-key",
359
- "my-value"
360
- );
361
- const { error, stderr, stdout } = await runWrangler(
357
+ const requests = mockKeyPutRequest("some-namespace-id", {
358
+ key: "my-key",
359
+ value: "my-value",
360
+ });
361
+
362
+ await runWrangler(
362
363
  "kv:key put my-key my-value --namespace-id some-namespace-id"
363
364
  );
365
+
364
366
  expect(requests.count).toEqual(1);
365
- expect(stdout).toMatchInlineSnapshot(
367
+ expect(std.out).toMatchInlineSnapshot(
366
368
  `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace some-namespace-id"`
367
369
  );
368
- expect(stderr).toMatchInlineSnapshot(`""`);
369
- expect(error).toMatchInlineSnapshot(`undefined`);
370
+ expect(std.err).toMatchInlineSnapshot(`""`);
370
371
  });
371
372
 
372
373
  it("should put a key in a given namespace specified by binding", async () => {
373
374
  writeWranglerConfig();
374
- const requests = mockKeyPutRequest("bound-id", "my-key", "my-value");
375
- const { error, stderr, stdout } = await runWrangler(
375
+ const requests = mockKeyPutRequest("bound-id", {
376
+ key: "my-key",
377
+ value: "my-value",
378
+ });
379
+ await runWrangler(
376
380
  "kv:key put my-key my-value --binding someBinding --preview false"
377
381
  );
378
- expect(stdout).toMatchInlineSnapshot(
382
+
383
+ expect(std.out).toMatchInlineSnapshot(
379
384
  `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace bound-id"`
380
385
  );
381
- expect(stderr).toMatchInlineSnapshot(`""`);
382
- expect(error).toMatchInlineSnapshot(`undefined`);
386
+ expect(std.err).toMatchInlineSnapshot(`""`);
383
387
  expect(requests.count).toEqual(1);
384
388
  });
385
389
 
386
390
  it("should put a key in a given preview namespace specified by binding", async () => {
387
391
  writeWranglerConfig();
388
- const requests = mockKeyPutRequest(
389
- "preview-bound-id",
390
- "my-key",
391
- "my-value"
392
- );
393
- const { error, stderr, stdout } = await runWrangler(
392
+ const requests = mockKeyPutRequest("preview-bound-id", {
393
+ key: "my-key",
394
+ value: "my-value",
395
+ });
396
+
397
+ await runWrangler(
394
398
  "kv:key put my-key my-value --binding someBinding --preview"
395
399
  );
396
- expect(stdout).toMatchInlineSnapshot(
400
+
401
+ expect(std.out).toMatchInlineSnapshot(
397
402
  `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace preview-bound-id"`
398
403
  );
399
- expect(stderr).toMatchInlineSnapshot(`""`);
400
- expect(error).toMatchInlineSnapshot(`undefined`);
404
+ expect(std.err).toMatchInlineSnapshot(`""`);
401
405
  expect(requests.count).toEqual(1);
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
- );
412
- const { error, stderr, stdout } = await runWrangler(
409
+ const requests = mockKeyPutRequest("some-namespace-id", {
410
+ key: "my-key",
411
+ value: "my-value",
412
+ expiration: 10,
413
+ expiration_ttl: 20,
414
+ });
415
+ await runWrangler(
413
416
  "kv:key put my-key my-value --namespace-id some-namespace-id --expiration 10 --ttl 20"
414
417
  );
415
418
  expect(requests.count).toEqual(1);
416
- expect(stdout).toMatchInlineSnapshot(
419
+ expect(std.out).toMatchInlineSnapshot(
417
420
  `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace some-namespace-id"`
418
421
  );
419
- expect(stderr).toMatchInlineSnapshot(`""`);
420
- expect(error).toMatchInlineSnapshot(`undefined`);
422
+ expect(std.err).toMatchInlineSnapshot(`""`);
421
423
  });
422
424
 
423
425
  it("should put a key to the specified environment in a given namespace", async () => {
424
426
  writeWranglerConfig();
425
- const requests = mockKeyPutRequest(
426
- "env-bound-id",
427
- "my-key",
428
- "my-value"
429
- );
430
- const { error, stderr, stdout } = await runWrangler(
427
+ const requests = mockKeyPutRequest("env-bound-id", {
428
+ key: "my-key",
429
+ value: "my-value",
430
+ });
431
+ await runWrangler(
431
432
  "kv:key put my-key my-value --binding someBinding --env some-environment --preview false"
432
433
  );
433
- expect(stdout).toMatchInlineSnapshot(
434
+ expect(std.out).toMatchInlineSnapshot(
434
435
  `"writing the value \\"my-value\\" to key \\"my-key\\" on namespace env-bound-id"`
435
436
  );
436
- expect(stderr).toMatchInlineSnapshot(`""`);
437
- expect(error).toMatchInlineSnapshot(`undefined`);
437
+ expect(std.err).toMatchInlineSnapshot(`""`);
438
438
  expect(requests.count).toEqual(1);
439
439
  });
440
440
 
441
441
  it("should put a key with a value loaded from a given path", async () => {
442
442
  writeFileSync("foo.txt", "file-contents", "utf-8");
443
- const requests = mockKeyPutRequest(
444
- "some-namespace-id",
445
- "my-key",
446
- "file-contents"
447
- );
448
- const { error, stderr, stdout } = await runWrangler(
443
+ const requests = mockKeyPutRequest("some-namespace-id", {
444
+ key: "my-key",
445
+ value: "file-contents",
446
+ });
447
+ await runWrangler(
449
448
  "kv:key put my-key --namespace-id some-namespace-id --path foo.txt"
450
449
  );
451
- expect(stdout).toMatchInlineSnapshot(
450
+ expect(std.out).toMatchInlineSnapshot(
452
451
  `"writing the contents of foo.txt to the key \\"my-key\\" on namespace some-namespace-id"`
453
452
  );
454
- expect(stderr).toMatchInlineSnapshot(`""`);
455
- expect(error).toMatchInlineSnapshot(`undefined`);
453
+ expect(std.err).toMatchInlineSnapshot(`""`);
456
454
  expect(requests.count).toEqual(1);
457
455
  });
458
456
 
459
457
  it("should error if no key is provided", async () => {
460
- const { error, stdout, stderr } = await runWrangler("kv:key put");
458
+ await expect(
459
+ runWrangler("kv:key put")
460
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
461
+ `"Not enough non-option arguments: got 0, need at least 1"`
462
+ );
461
463
 
462
- expect(stdout).toMatchInlineSnapshot(`""`);
463
- expect(stderr).toMatchInlineSnapshot(`
464
+ expect(std.out).toMatchInlineSnapshot(`""`);
465
+ expect(std.err).toMatchInlineSnapshot(`
464
466
  "wrangler kv:key put <key> [value]
465
467
 
466
468
  Writes a single key/value pair to the given namespace.
467
469
 
468
470
  Positionals:
469
- key The key to write to. [string] [required]
470
- value The value to write. [string]
471
+ key The key to write to [string] [required]
472
+ value The value to write [string]
471
473
 
472
474
  Flags:
473
- -c, --config Path to .toml configuration file [string]
474
- -h, --help Show help [boolean]
475
- -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]
476
479
 
477
480
  Options:
478
- -l, --local Run on my machine [boolean] [default: false]
479
- --binding The binding of the namespace to write to. [string]
480
- --namespace-id The id of the namespace to write to. [string]
481
- --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]
482
484
  --preview Interact with a preview namespace [boolean]
483
- --ttl Time for which the entries should be visible. [number]
485
+ --ttl Time for which the entries should be visible [number]
484
486
  --expiration Time since the UNIX epoch after which the entry expires [number]
485
- --path Read value from the file at a given path. [string]
487
+ --path Read value from the file at a given path [string]
486
488
 
487
489
  Not enough non-option arguments: got 0, need at least 1"
488
490
  `);
489
- expect(error).toMatchInlineSnapshot(
490
- `[Error: Not enough non-option arguments: got 0, need at least 1]`
491
- );
492
491
  });
493
492
 
494
493
  it("should error if no binding nor namespace is provided", async () => {
495
- const { error, stdout, stderr } = await runWrangler(
496
- "kv:key put foo bar"
494
+ await expect(
495
+ runWrangler("kv:key put foo bar")
496
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
497
+ `"Exactly one of the arguments binding and namespace-id is required"`
497
498
  );
498
499
 
499
- expect(stdout).toMatchInlineSnapshot(`""`);
500
- expect(stderr).toMatchInlineSnapshot(`
500
+ expect(std.out).toMatchInlineSnapshot(`""`);
501
+ expect(std.err).toMatchInlineSnapshot(`
501
502
  "wrangler kv:key put <key> [value]
502
503
 
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
  `);
526
- expect(error).toMatchInlineSnapshot(
527
- `[Error: Exactly one of the arguments binding and namespace-id is required]`
528
- );
529
527
  });
530
528
 
531
529
  it("should error if both binding and namespace is provided", async () => {
532
- const { error, stdout, stderr } = await runWrangler(
533
- "kv:key put foo bar --binding x --namespace-id y"
530
+ await expect(
531
+ runWrangler("kv:key put foo bar --binding x --namespace-id y")
532
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
533
+ `"Arguments binding and namespace-id are mutually exclusive"`
534
534
  );
535
535
 
536
- expect(stdout).toMatchInlineSnapshot(`""`);
537
- expect(stderr).toMatchInlineSnapshot(`
536
+ expect(std.out).toMatchInlineSnapshot(`""`);
537
+ expect(std.err).toMatchInlineSnapshot(`
538
538
  "wrangler kv:key put <key> [value]
539
539
 
540
540
  Writes a single key/value pair to the given namespace.
541
541
 
542
542
  Positionals:
543
- key The key to write to. [string] [required]
544
- value The value to write. [string]
543
+ key The key to write to [string] [required]
544
+ value The value to write [string]
545
545
 
546
546
  Flags:
547
- -c, --config Path to .toml configuration file [string]
548
- -h, --help Show help [boolean]
549
- -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]
550
551
 
551
552
  Options:
552
- -l, --local Run on my machine [boolean] [default: false]
553
- --binding The binding of the namespace to write to. [string]
554
- --namespace-id The id of the namespace to write to. [string]
555
- --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]
556
556
  --preview Interact with a preview namespace [boolean]
557
- --ttl Time for which the entries should be visible. [number]
557
+ --ttl Time for which the entries should be visible [number]
558
558
  --expiration Time since the UNIX epoch after which the entry expires [number]
559
- --path Read value from the file at a given path. [string]
559
+ --path Read value from the file at a given path [string]
560
560
 
561
561
  Arguments binding and namespace-id are mutually exclusive"
562
562
  `);
563
- expect(error).toMatchInlineSnapshot(
564
- `[Error: Arguments binding and namespace-id are mutually exclusive]`
565
- );
566
563
  });
567
564
 
568
565
  it("should error if no value nor path is provided", async () => {
569
- const { error, stdout, stderr } = await runWrangler(
570
- "kv:key put key --namespace-id 12345"
566
+ await expect(
567
+ runWrangler("kv:key put key --namespace-id 12345")
568
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
569
+ `"Exactly one of the arguments value and path is required"`
571
570
  );
572
571
 
573
- expect(stdout).toMatchInlineSnapshot(`""`);
574
- expect(stderr).toMatchInlineSnapshot(`
572
+ expect(std.out).toMatchInlineSnapshot(`""`);
573
+ expect(std.err).toMatchInlineSnapshot(`
575
574
  "wrangler kv:key put <key> [value]
576
575
 
577
576
  Writes a single key/value pair to the given namespace.
578
577
 
579
578
  Positionals:
580
- key The key to write to. [string] [required]
581
- value The value to write. [string]
579
+ key The key to write to [string] [required]
580
+ value The value to write [string]
582
581
 
583
582
  Flags:
584
- -c, --config Path to .toml configuration file [string]
585
- -h, --help Show help [boolean]
586
- -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]
587
587
 
588
588
  Options:
589
- -l, --local Run on my machine [boolean] [default: false]
590
- --binding The binding of the namespace to write to. [string]
591
- --namespace-id The id of the namespace to write to. [string]
592
- --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]
593
592
  --preview Interact with a preview namespace [boolean]
594
- --ttl Time for which the entries should be visible. [number]
593
+ --ttl Time for which the entries should be visible [number]
595
594
  --expiration Time since the UNIX epoch after which the entry expires [number]
596
- --path Read value from the file at a given path. [string]
595
+ --path Read value from the file at a given path [string]
597
596
 
598
597
  Exactly one of the arguments value and path is required"
599
598
  `);
600
- expect(error).toMatchInlineSnapshot(
601
- `[Error: Exactly one of the arguments value and path is required]`
602
- );
603
599
  });
604
600
 
605
601
  it("should error if both value and path is provided", async () => {
606
- const { error, stdout, stderr } = await runWrangler(
607
- "kv:key put key value --path xyz --namespace-id 12345"
602
+ await expect(
603
+ runWrangler("kv:key put key value --path xyz --namespace-id 12345")
604
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
605
+ `"Arguments value and path are mutually exclusive"`
608
606
  );
609
607
 
610
- expect(stdout).toMatchInlineSnapshot(`""`);
611
- expect(stderr).toMatchInlineSnapshot(`
608
+ expect(std.out).toMatchInlineSnapshot(`""`);
609
+ expect(std.err).toMatchInlineSnapshot(`
612
610
  "wrangler kv:key put <key> [value]
613
611
 
614
612
  Writes a single key/value pair to the given namespace.
615
613
 
616
614
  Positionals:
617
- key The key to write to. [string] [required]
618
- value The value to write. [string]
615
+ key The key to write to [string] [required]
616
+ value The value to write [string]
619
617
 
620
618
  Flags:
621
- -c, --config Path to .toml configuration file [string]
622
- -h, --help Show help [boolean]
623
- -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]
624
623
 
625
624
  Options:
626
- -l, --local Run on my machine [boolean] [default: false]
627
- --binding The binding of the namespace to write to. [string]
628
- --namespace-id The id of the namespace to write to. [string]
629
- --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]
630
628
  --preview Interact with a preview namespace [boolean]
631
- --ttl Time for which the entries should be visible. [number]
629
+ --ttl Time for which the entries should be visible [number]
632
630
  --expiration Time since the UNIX epoch after which the entry expires [number]
633
- --path Read value from the file at a given path. [string]
631
+ --path Read value from the file at a given path [string]
634
632
 
635
633
  Arguments value and path are mutually exclusive"
636
634
  `);
637
- expect(error).toMatchInlineSnapshot(
638
- `[Error: Arguments value and path are mutually exclusive]`
639
- );
640
635
  });
641
636
 
642
637
  it("should error if a given binding name is not in the configured kv namespaces", async () => {
643
638
  writeWranglerConfig();
644
- const { error, stdout, stderr } = await runWrangler(
645
- `kv:key put key value --binding otherBinding`
639
+ await expect(
640
+ runWrangler("kv:key put key value --binding otherBinding")
641
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
642
+ `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
646
643
  );
647
- expect(stdout).toMatchInlineSnapshot(`""`);
648
- expect(stderr).toMatchInlineSnapshot(`
644
+
645
+ expect(std.out).toMatchInlineSnapshot(`""`);
646
+ expect(std.err).toMatchInlineSnapshot(`
649
647
  "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
650
648
 
651
- %s
652
- 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."
653
650
  `);
654
- expect(error).toMatchInlineSnapshot(
655
- `[Error: A namespace with binding name "otherBinding" was not found in the configured "kv_namespaces".]`
656
- );
657
651
  });
658
652
 
659
653
  it("should error if a given binding has both preview and non-preview and --preview is not specified", async () => {
660
654
  writeWranglerConfig();
661
- const requests = mockKeyPutRequest(
662
- "preview-bound-id",
663
- "my-key",
664
- "my-value"
665
- );
666
- const { error, stderr, stdout } = await runWrangler(
667
- "kv:key put my-key my-value --binding someBinding"
668
- );
669
- expect(stdout).toMatchInlineSnapshot(`""`);
670
- expect(stderr).toMatchInlineSnapshot(`
655
+ const requests = mockKeyPutRequest("preview-bound-id", {
656
+ key: "my-key",
657
+ value: "my-value",
658
+ });
659
+ await expect(
660
+ runWrangler("kv:key put my-key my-value --binding someBinding")
661
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
662
+ `"someBinding has both a namespace ID and a preview ID. Specify \\"--preview\\" or \\"--preview false\\" to avoid writing data to the wrong namespace."`
663
+ );
664
+ expect(std.out).toMatchInlineSnapshot(`""`);
665
+ expect(std.err).toMatchInlineSnapshot(`
671
666
  "someBinding has both a namespace ID and a preview ID. Specify \\"--preview\\" or \\"--preview false\\" to avoid writing data to the wrong namespace.
672
667
 
673
- %s
674
- 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."
675
669
  `);
676
- expect(error).toMatchInlineSnapshot(
677
- `[Error: someBinding has both a namespace ID and a preview ID. Specify "--preview" or "--preview false" to avoid writing data to the wrong namespace.]`
678
- );
679
670
  expect(requests.count).toEqual(0);
680
671
  });
681
672
  });
682
673
 
683
674
  describe("list", () => {
684
675
  it("should list the keys of a namespace specified by namespace-id", async () => {
685
- 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
+ ];
686
681
  mockKeyListRequest("some-namespace-id", keys);
687
- const { error, stdout, stderr } = await runWrangler(
688
- "kv:key list --namespace-id some-namespace-id"
689
- );
690
- expect(error).toMatchInlineSnapshot(`undefined`);
691
- expect(stderr).toMatchInlineSnapshot(`""`);
692
- expect(stdout).toMatchInlineSnapshot(`
682
+ await runWrangler("kv:key list --namespace-id some-namespace-id");
683
+ expect(std.err).toMatchInlineSnapshot(`""`);
684
+ expect(std.out).toMatchInlineSnapshot(`
693
685
  "[
694
686
  {
695
- \\"name\\": \\"key-1\\",
696
- \\"expiration\\": 123456789,
697
- \\"metadata\\": {}
687
+ \\"name\\": \\"key-1\\"
698
688
  },
699
689
  {
700
690
  \\"name\\": \\"key-2\\",
701
- \\"expiration\\": 123456789,
702
- \\"metadata\\": {}
691
+ \\"expiration\\": 123456789
703
692
  },
704
693
  {
705
694
  \\"name\\": \\"key-3\\",
706
- \\"expiration\\": 123456789,
707
- \\"metadata\\": {}
695
+ \\"expiration_ttl\\": 666
708
696
  }
709
697
  ]"
710
698
  `);
@@ -712,29 +700,21 @@ describe("wrangler", () => {
712
700
 
713
701
  it("should list the keys of a namespace specified by binding", async () => {
714
702
  writeWranglerConfig();
715
- const keys = ["key-1", "key-2", "key-3"];
703
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
716
704
  mockKeyListRequest("bound-id", keys);
717
- const { error, stdout, stderr } = await runWrangler(
718
- "kv:key list --binding someBinding"
719
- );
720
- expect(error).toMatchInlineSnapshot(`undefined`);
721
- expect(stderr).toMatchInlineSnapshot(`""`);
722
- expect(stdout).toMatchInlineSnapshot(`
705
+
706
+ await runWrangler("kv:key list --binding someBinding");
707
+ expect(std.err).toMatchInlineSnapshot(`""`);
708
+ expect(std.out).toMatchInlineSnapshot(`
723
709
  "[
724
710
  {
725
- \\"name\\": \\"key-1\\",
726
- \\"expiration\\": 123456789,
727
- \\"metadata\\": {}
711
+ \\"name\\": \\"key-1\\"
728
712
  },
729
713
  {
730
- \\"name\\": \\"key-2\\",
731
- \\"expiration\\": 123456789,
732
- \\"metadata\\": {}
714
+ \\"name\\": \\"key-2\\"
733
715
  },
734
716
  {
735
- \\"name\\": \\"key-3\\",
736
- \\"expiration\\": 123456789,
737
- \\"metadata\\": {}
717
+ \\"name\\": \\"key-3\\"
738
718
  }
739
719
  ]"
740
720
  `);
@@ -742,29 +722,20 @@ describe("wrangler", () => {
742
722
 
743
723
  it("should list the keys of a preview namespace specified by binding", async () => {
744
724
  writeWranglerConfig();
745
- const keys = ["key-1", "key-2", "key-3"];
725
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
746
726
  mockKeyListRequest("preview-bound-id", keys);
747
- const { error, stdout, stderr } = await runWrangler(
748
- "kv:key list --binding someBinding --preview"
749
- );
750
- expect(error).toMatchInlineSnapshot(`undefined`);
751
- expect(stderr).toMatchInlineSnapshot(`""`);
752
- expect(stdout).toMatchInlineSnapshot(`
727
+ await runWrangler("kv:key list --binding someBinding --preview");
728
+ expect(std.err).toMatchInlineSnapshot(`""`);
729
+ expect(std.out).toMatchInlineSnapshot(`
753
730
  "[
754
731
  {
755
- \\"name\\": \\"key-1\\",
756
- \\"expiration\\": 123456789,
757
- \\"metadata\\": {}
732
+ \\"name\\": \\"key-1\\"
758
733
  },
759
734
  {
760
- \\"name\\": \\"key-2\\",
761
- \\"expiration\\": 123456789,
762
- \\"metadata\\": {}
735
+ \\"name\\": \\"key-2\\"
763
736
  },
764
737
  {
765
- \\"name\\": \\"key-3\\",
766
- \\"expiration\\": 123456789,
767
- \\"metadata\\": {}
738
+ \\"name\\": \\"key-3\\"
768
739
  }
769
740
  ]"
770
741
  `);
@@ -772,29 +743,22 @@ describe("wrangler", () => {
772
743
 
773
744
  it("should list the keys of a namespace specified by binding, in a given environment", async () => {
774
745
  writeWranglerConfig();
775
- const keys = ["key-1", "key-2", "key-3"];
746
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
776
747
  mockKeyListRequest("env-bound-id", keys);
777
- const { error, stdout, stderr } = await runWrangler(
748
+ await runWrangler(
778
749
  "kv:key list --binding someBinding --env some-environment"
779
750
  );
780
- expect(error).toMatchInlineSnapshot(`undefined`);
781
- expect(stderr).toMatchInlineSnapshot(`""`);
782
- expect(stdout).toMatchInlineSnapshot(`
751
+ expect(std.err).toMatchInlineSnapshot(`""`);
752
+ expect(std.out).toMatchInlineSnapshot(`
783
753
  "[
784
754
  {
785
- \\"name\\": \\"key-1\\",
786
- \\"expiration\\": 123456789,
787
- \\"metadata\\": {}
755
+ \\"name\\": \\"key-1\\"
788
756
  },
789
757
  {
790
- \\"name\\": \\"key-2\\",
791
- \\"expiration\\": 123456789,
792
- \\"metadata\\": {}
758
+ \\"name\\": \\"key-2\\"
793
759
  },
794
760
  {
795
- \\"name\\": \\"key-3\\",
796
- \\"expiration\\": 123456789,
797
- \\"metadata\\": {}
761
+ \\"name\\": \\"key-3\\"
798
762
  }
799
763
  ]"
800
764
  `);
@@ -802,153 +766,143 @@ describe("wrangler", () => {
802
766
 
803
767
  it("should list the keys of a preview namespace specified by binding, in a given environment", async () => {
804
768
  writeWranglerConfig();
805
- const keys = ["key-1", "key-2", "key-3"];
769
+ const keys = [{ name: "key-1" }, { name: "key-2" }, { name: "key-3" }];
806
770
  mockKeyListRequest("preview-env-bound-id", keys);
807
- const { error, stdout, stderr } = await runWrangler(
771
+ await runWrangler(
808
772
  "kv:key list --binding someBinding --preview --env some-environment"
809
773
  );
810
- expect(error).toMatchInlineSnapshot(`undefined`);
811
- expect(stderr).toMatchInlineSnapshot(`""`);
812
- expect(stdout).toMatchInlineSnapshot(`
774
+ expect(std.err).toMatchInlineSnapshot(`""`);
775
+ expect(std.out).toMatchInlineSnapshot(`
813
776
  "[
814
777
  {
815
- \\"name\\": \\"key-1\\",
816
- \\"expiration\\": 123456789,
817
- \\"metadata\\": {}
778
+ \\"name\\": \\"key-1\\"
818
779
  },
819
780
  {
820
- \\"name\\": \\"key-2\\",
821
- \\"expiration\\": 123456789,
822
- \\"metadata\\": {}
781
+ \\"name\\": \\"key-2\\"
823
782
  },
824
783
  {
825
- \\"name\\": \\"key-3\\",
826
- \\"expiration\\": 123456789,
827
- \\"metadata\\": {}
784
+ \\"name\\": \\"key-3\\"
828
785
  }
829
786
  ]"
830
787
  `);
831
788
  });
832
789
 
833
- it("should make multiple requests for paginated results", async () => {
834
- // Create a lot of mock keys, so that the fetch requests will be paginated
835
- const keys: string[] = [];
836
- for (let i = 0; i < 550; i++) {
837
- keys.push("key-" + i);
838
- }
839
- // Ask for the keys in pages of size 100.
840
- const requests = mockKeyListRequest("some-namespace-id", keys, 100);
841
- const { stdout, stderr, error } = await runWrangler(
842
- "kv:key list --namespace-id some-namespace-id --limit 100"
843
- );
844
- expect(error).toMatchInlineSnapshot(`undefined`);
845
- expect(stderr).toMatchInlineSnapshot(`""`);
846
- expect(JSON.parse(stdout).map((k) => k.name)).toEqual(keys);
847
- expect(requests.count).toEqual(6);
848
- });
790
+ // We'll run the next test with variations on the cursor
791
+ // that's returned on cloudflare's API after all results
792
+ // have been drained.
793
+ for (const blankCursorValue of [undefined, null, ""] as [
794
+ undefined,
795
+ null,
796
+ ""
797
+ ]) {
798
+ describe(`cursor - ${blankCursorValue}`, () => {
799
+ it("should make multiple requests for paginated results", async () => {
800
+ // Create a lot of mock keys, so that the fetch requests will be paginated
801
+ const keys: NamespaceKeyInfo[] = [];
802
+ for (let i = 0; i < 550; i++) {
803
+ keys.push({ name: "key-" + i });
804
+ }
805
+ // Ask for the keys in pages of size 100.
806
+ const requests = mockKeyListRequest(
807
+ "some-namespace-id",
808
+ keys,
809
+ 100,
810
+ blankCursorValue
811
+ );
812
+ await runWrangler(
813
+ "kv:key list --namespace-id some-namespace-id --limit 100"
814
+ );
815
+ expect(std.err).toMatchInlineSnapshot(`""`);
816
+ expect(JSON.parse(std.out)).toEqual(keys);
817
+ expect(requests.count).toEqual(6);
818
+ });
819
+ });
820
+ }
849
821
 
850
822
  it("should error if a given binding name is not in the configured kv namespaces", async () => {
851
823
  writeWranglerConfig();
852
- const { error, stdout, stderr } = await runWrangler(
853
- "kv:key list --binding otherBinding"
854
- );
855
- expect(error).toMatchInlineSnapshot(
856
- `[Error: A namespace with binding name "otherBinding" was not found in the configured "kv_namespaces".]`
824
+ await expect(
825
+ runWrangler("kv:key list --binding otherBinding")
826
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
827
+ `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
857
828
  );
858
- expect(stderr).toMatchInlineSnapshot(`
829
+ expect(std.err).toMatchInlineSnapshot(`
859
830
  "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
860
831
 
861
- %s
862
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
832
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
863
833
  `);
864
- expect(stdout).toMatchInlineSnapshot(`""`);
834
+ expect(std.out).toMatchInlineSnapshot(`""`);
865
835
  });
866
836
  });
867
837
 
868
838
  describe("get", () => {
869
- function mockKeyGetRequest(
870
- expectedNamespaceId: string,
871
- expectedKey: string,
872
- expectedValue: string
873
- ) {
874
- const requests = { count: 0 };
875
- setMockRawResponse(
876
- "/accounts/:accountId/storage/kv/namespaces/:namespaceId/values/:key",
877
- ([_url, accountId, namespaceId, key]) => {
878
- requests.count++;
879
- expect(accountId).toEqual("some-account-id");
880
- expect(namespaceId).toEqual(expectedNamespaceId);
881
- expect(key).toEqual(expectedKey);
882
- return expectedValue;
883
- }
884
- );
885
- return requests;
886
- }
839
+ afterEach(() => {
840
+ unsetMockFetchKVGetValues();
841
+ });
887
842
 
888
843
  it("should get a key in a given namespace specified by namespace-id", async () => {
889
- const requests = mockKeyGetRequest(
844
+ setMockFetchKVGetValue(
845
+ "some-account-id",
890
846
  "some-namespace-id",
891
847
  "my-key",
892
848
  "my-value"
893
849
  );
894
- const { error, stderr, stdout } = await runWrangler(
895
- "kv:key get my-key --namespace-id some-namespace-id"
896
- );
897
- expect(stdout).toMatchInlineSnapshot(`"my-value"`);
898
- expect(stderr).toMatchInlineSnapshot(`""`);
899
- expect(error).toMatchInlineSnapshot(`undefined`);
900
- expect(requests.count).toEqual(1);
850
+ await runWrangler("kv:key get my-key --namespace-id some-namespace-id");
851
+ expect(std.out).toMatchInlineSnapshot(`"my-value"`);
852
+ expect(std.err).toMatchInlineSnapshot(`""`);
901
853
  });
902
854
 
903
855
  it("should get a key in a given namespace specified by binding", async () => {
904
856
  writeWranglerConfig();
905
- const requests = mockKeyGetRequest("bound-id", "my-key", "my-value");
906
- const { error, stderr, stdout } = await runWrangler(
857
+ setMockFetchKVGetValue(
858
+ "some-account-id",
859
+ "bound-id",
860
+ "my-key",
861
+ "my-value"
862
+ );
863
+ await runWrangler(
907
864
  "kv:key get my-key --binding someBinding --preview false"
908
865
  );
909
- expect(stdout).toMatchInlineSnapshot(`"my-value"`);
910
- expect(stderr).toMatchInlineSnapshot(`""`);
911
- expect(error).toMatchInlineSnapshot(`undefined`);
912
- expect(requests.count).toEqual(1);
866
+ expect(std.out).toMatchInlineSnapshot(`"my-value"`);
867
+ expect(std.err).toMatchInlineSnapshot(`""`);
913
868
  });
914
869
 
915
870
  it("should get a key in a given preview namespace specified by binding", async () => {
916
871
  writeWranglerConfig();
917
- const requests = mockKeyGetRequest(
872
+ setMockFetchKVGetValue(
873
+ "some-account-id",
918
874
  "preview-bound-id",
919
875
  "my-key",
920
876
  "my-value"
921
877
  );
922
- const { error, stderr, stdout } = await runWrangler(
923
- "kv:key get my-key --binding someBinding --preview"
924
- );
925
- expect(stdout).toMatchInlineSnapshot(`"my-value"`);
926
- expect(stderr).toMatchInlineSnapshot(`""`);
927
- expect(error).toMatchInlineSnapshot(`undefined`);
928
- expect(requests.count).toEqual(1);
878
+ await runWrangler("kv:key get my-key --binding someBinding --preview");
879
+ expect(std.out).toMatchInlineSnapshot(`"my-value"`);
880
+ expect(std.err).toMatchInlineSnapshot(`""`);
929
881
  });
930
882
 
931
883
  it("should get a key for the specified environment in a given namespace", async () => {
932
884
  writeWranglerConfig();
933
- const requests = mockKeyGetRequest(
885
+ setMockFetchKVGetValue(
886
+ "some-account-id",
934
887
  "env-bound-id",
935
888
  "my-key",
936
889
  "my-value"
937
890
  );
938
- const { error, stderr, stdout } = await runWrangler(
891
+ await runWrangler(
939
892
  "kv:key get my-key my-value --binding someBinding --env some-environment --preview false"
940
893
  );
941
- expect(stdout).toMatchInlineSnapshot(`"my-value"`);
942
- expect(stderr).toMatchInlineSnapshot(`""`);
943
- expect(error).toMatchInlineSnapshot(`undefined`);
944
- expect(requests.count).toEqual(1);
894
+ expect(std.out).toMatchInlineSnapshot(`"my-value"`);
895
+ expect(std.err).toMatchInlineSnapshot(`""`);
945
896
  });
946
897
 
947
898
  it("should error if no key is provided", async () => {
948
- const { error, stdout, stderr } = await runWrangler("kv:key get");
949
-
950
- expect(stdout).toMatchInlineSnapshot(`""`);
951
- expect(stderr).toMatchInlineSnapshot(`
899
+ await expect(
900
+ runWrangler("kv:key get")
901
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
902
+ `"Not enough non-option arguments: got 0, need at least 1"`
903
+ );
904
+ expect(std.out).toMatchInlineSnapshot(`""`);
905
+ expect(std.err).toMatchInlineSnapshot(`
952
906
  "wrangler kv:key get <key>
953
907
 
954
908
  Reads a single value by key from the given namespace.
@@ -957,29 +911,29 @@ describe("wrangler", () => {
957
911
  key The key value to get. [string] [required]
958
912
 
959
913
  Flags:
960
- -c, --config Path to .toml configuration file [string]
961
- -h, --help Show help [boolean]
962
- -v, --version Show version number [boolean]
914
+ -c, --config Path to .toml configuration file [string]
915
+ -h, --help Show help [boolean]
916
+ -v, --version Show version number [boolean]
917
+ --legacy-env Use legacy environments [boolean]
963
918
 
964
919
  Options:
965
- -l, --local Run on my machine [boolean] [default: false]
966
920
  --binding The name of the namespace to get from [string]
967
921
  --namespace-id The id of the namespace to get from [string]
968
- --env Perform on a specific environment [string]
922
+ -e, --env Perform on a specific environment [string]
969
923
  --preview Interact with a preview namespace [boolean] [default: false]
970
924
 
971
925
  Not enough non-option arguments: got 0, need at least 1"
972
926
  `);
973
- expect(error).toMatchInlineSnapshot(
974
- `[Error: Not enough non-option arguments: got 0, need at least 1]`
975
- );
976
927
  });
977
928
 
978
929
  it("should error if no binding nor namespace is provided", async () => {
979
- const { error, stdout, stderr } = await runWrangler("kv:key get foo");
980
-
981
- expect(stdout).toMatchInlineSnapshot(`""`);
982
- expect(stderr).toMatchInlineSnapshot(`
930
+ await expect(
931
+ runWrangler("kv:key get foo")
932
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
933
+ `"Exactly one of the arguments binding and namespace-id is required"`
934
+ );
935
+ expect(std.out).toMatchInlineSnapshot(`""`);
936
+ expect(std.err).toMatchInlineSnapshot(`
983
937
  "wrangler kv:key get <key>
984
938
 
985
939
  Reads a single value by key from the given namespace.
@@ -988,31 +942,30 @@ describe("wrangler", () => {
988
942
  key The key value to get. [string] [required]
989
943
 
990
944
  Flags:
991
- -c, --config Path to .toml configuration file [string]
992
- -h, --help Show help [boolean]
993
- -v, --version Show version number [boolean]
945
+ -c, --config Path to .toml configuration file [string]
946
+ -h, --help Show help [boolean]
947
+ -v, --version Show version number [boolean]
948
+ --legacy-env Use legacy environments [boolean]
994
949
 
995
950
  Options:
996
- -l, --local Run on my machine [boolean] [default: false]
997
951
  --binding The name of the namespace to get from [string]
998
952
  --namespace-id The id of the namespace to get from [string]
999
- --env Perform on a specific environment [string]
953
+ -e, --env Perform on a specific environment [string]
1000
954
  --preview Interact with a preview namespace [boolean] [default: false]
1001
955
 
1002
956
  Exactly one of the arguments binding and namespace-id is required"
1003
957
  `);
1004
- expect(error).toMatchInlineSnapshot(
1005
- `[Error: Exactly one of the arguments binding and namespace-id is required]`
1006
- );
1007
958
  });
1008
959
 
1009
960
  it("should error if both binding and namespace is provided", async () => {
1010
- const { error, stdout, stderr } = await runWrangler(
1011
- "kv:key get foo --binding x --namespace-id y"
961
+ await expect(
962
+ runWrangler("kv:key get foo --binding x --namespace-id y")
963
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
964
+ `"Arguments binding and namespace-id are mutually exclusive"`
1012
965
  );
1013
966
 
1014
- expect(stdout).toMatchInlineSnapshot(`""`);
1015
- expect(stderr).toMatchInlineSnapshot(`
967
+ expect(std.out).toMatchInlineSnapshot(`""`);
968
+ expect(std.err).toMatchInlineSnapshot(`
1016
969
  "wrangler kv:key get <key>
1017
970
 
1018
971
  Reads a single value by key from the given namespace.
@@ -1021,39 +974,34 @@ describe("wrangler", () => {
1021
974
  key The key value to get. [string] [required]
1022
975
 
1023
976
  Flags:
1024
- -c, --config Path to .toml configuration file [string]
1025
- -h, --help Show help [boolean]
1026
- -v, --version Show version number [boolean]
977
+ -c, --config Path to .toml configuration file [string]
978
+ -h, --help Show help [boolean]
979
+ -v, --version Show version number [boolean]
980
+ --legacy-env Use legacy environments [boolean]
1027
981
 
1028
982
  Options:
1029
- -l, --local Run on my machine [boolean] [default: false]
1030
983
  --binding The name of the namespace to get from [string]
1031
984
  --namespace-id The id of the namespace to get from [string]
1032
- --env Perform on a specific environment [string]
985
+ -e, --env Perform on a specific environment [string]
1033
986
  --preview Interact with a preview namespace [boolean] [default: false]
1034
987
 
1035
988
  Arguments binding and namespace-id are mutually exclusive"
1036
989
  `);
1037
- expect(error).toMatchInlineSnapshot(
1038
- `[Error: Arguments binding and namespace-id are mutually exclusive]`
1039
- );
1040
990
  });
1041
991
 
1042
992
  it("should error if a given binding name is not in the configured kv namespaces", async () => {
1043
993
  writeWranglerConfig();
1044
- const { error, stdout, stderr } = await runWrangler(
1045
- `kv:key get key --binding otherBinding`
994
+ await expect(
995
+ runWrangler("kv:key get key --binding otherBinding")
996
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
997
+ `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
1046
998
  );
1047
- expect(stdout).toMatchInlineSnapshot(`""`);
1048
- expect(stderr).toMatchInlineSnapshot(`
999
+ expect(std.out).toMatchInlineSnapshot(`""`);
1000
+ expect(std.err).toMatchInlineSnapshot(`
1049
1001
  "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
1050
1002
 
1051
- %s
1052
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1003
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1053
1004
  `);
1054
- expect(error).toMatchInlineSnapshot(
1055
- `[Error: A namespace with binding name "otherBinding" was not found in the configured "kv_namespaces".]`
1056
- );
1057
1005
  });
1058
1006
  });
1059
1007
 
@@ -1105,28 +1053,29 @@ describe("wrangler", () => {
1105
1053
 
1106
1054
  it("should error if a given binding name is not in the configured kv namespaces", async () => {
1107
1055
  writeWranglerConfig();
1108
- const { stderr } = await runWrangler(
1109
- `kv:key delete --binding otherBinding someKey`
1056
+ await expect(
1057
+ runWrangler(`kv:key delete --binding otherBinding someKey`)
1058
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1059
+ `"A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\"."`
1110
1060
  );
1111
- expect(stderr).toMatchInlineSnapshot(`
1061
+
1062
+ expect(std.err).toMatchInlineSnapshot(`
1112
1063
  "A namespace with binding name \\"otherBinding\\" was not found in the configured \\"kv_namespaces\\".
1113
1064
 
1114
- %s
1115
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1065
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1116
1066
  `);
1117
1067
  });
1118
1068
 
1119
1069
  it("should delete a key in a namespace specified by binding name in a given environment", async () => {
1120
1070
  writeWranglerConfig();
1121
1071
  const requests = mockDeleteRequest("env-bound-id", "someKey");
1122
- const { stdout, stderr, error } = await runWrangler(
1072
+ await runWrangler(
1123
1073
  `kv:key delete --binding someBinding --env some-environment --preview false someKey`
1124
1074
  );
1125
- expect(stdout).toMatchInlineSnapshot(
1075
+ expect(std.out).toMatchInlineSnapshot(
1126
1076
  `"deleting the key \\"someKey\\" on namespace env-bound-id"`
1127
1077
  );
1128
- expect(stderr).toMatchInlineSnapshot(`""`);
1129
- expect(error).toMatchInlineSnapshot(`undefined`);
1078
+ expect(std.err).toMatchInlineSnapshot(`""`);
1130
1079
  expect(requests.count).toEqual(1);
1131
1080
  });
1132
1081
 
@@ -1140,6 +1089,278 @@ describe("wrangler", () => {
1140
1089
  });
1141
1090
  });
1142
1091
  });
1092
+
1093
+ describe("kv:bulk", () => {
1094
+ describe("put", () => {
1095
+ function mockPutRequest(
1096
+ expectedNamespaceId: string,
1097
+ expectedKeyValues: KeyValue[]
1098
+ ) {
1099
+ const requests = { count: 0 };
1100
+ setMockResponse(
1101
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1102
+ "PUT",
1103
+ ([_url, accountId, namespaceId], { body }) => {
1104
+ requests.count++;
1105
+ expect(accountId).toEqual("some-account-id");
1106
+ expect(namespaceId).toEqual(expectedNamespaceId);
1107
+ expect(JSON.parse(body as string)).toEqual(
1108
+ expectedKeyValues.slice(
1109
+ (requests.count - 1) * 5000,
1110
+ requests.count * 5000
1111
+ )
1112
+ );
1113
+ return null;
1114
+ }
1115
+ );
1116
+ return requests;
1117
+ }
1118
+
1119
+ it("should put the key-values parsed from a file", async () => {
1120
+ const keyValues: KeyValue[] = [
1121
+ { key: "someKey1", value: "someValue1" },
1122
+ { key: "ns:someKey2", value: "123", base64: true },
1123
+ { key: "someKey3", value: "someValue3", expiration: 100 },
1124
+ { key: "someKey4", value: "someValue4", expiration_ttl: 500 },
1125
+ ];
1126
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1127
+ const requests = mockPutRequest("some-namespace-id", keyValues);
1128
+ await runWrangler(
1129
+ `kv:bulk put --namespace-id some-namespace-id keys.json`
1130
+ );
1131
+ expect(requests.count).toEqual(1);
1132
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1133
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1134
+ expect(std.err).toMatchInlineSnapshot(`""`);
1135
+ });
1136
+
1137
+ it("should put the key-values in batches of 5000 parsed from a file", async () => {
1138
+ const keyValues: KeyValue[] = new Array(12000).fill({
1139
+ key: "someKey1",
1140
+ value: "someValue1",
1141
+ });
1142
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1143
+ const requests = mockPutRequest("some-namespace-id", keyValues);
1144
+ await runWrangler(
1145
+ `kv:bulk put --namespace-id some-namespace-id keys.json`
1146
+ );
1147
+ expect(requests.count).toEqual(3);
1148
+ expect(std.out).toMatchInlineSnapshot(`
1149
+ "Uploaded 0 of 12000.
1150
+ Uploaded 5000 of 12000.
1151
+ Uploaded 10000 of 12000.
1152
+ Uploaded 12000 of 12000.
1153
+ Success!"
1154
+ `);
1155
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1156
+ expect(std.err).toMatchInlineSnapshot(`""`);
1157
+ });
1158
+
1159
+ it("should error if the file is not a JSON array", async () => {
1160
+ const keyValues = { key: "someKey1", value: "someValue1" };
1161
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1162
+ await expect(
1163
+ runWrangler(`kv:bulk put --namespace-id some-namespace-id keys.json`)
1164
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1165
+ "Unexpected JSON input from \\"keys.json\\".
1166
+ Expected an array of key-value objects but got type \\"object\\"."
1167
+ `);
1168
+ expect(std.out).toMatchInlineSnapshot(`""`);
1169
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1170
+ });
1171
+
1172
+ it("should error if the array contains items that are not key-value objects", async () => {
1173
+ const keyValues = [
1174
+ 123,
1175
+ "a string",
1176
+ { key: "someKey" },
1177
+ { value: "someValue" },
1178
+ { key: "someKey1", value: "someValue1", invalid: true },
1179
+ ];
1180
+ writeFileSync("./keys.json", JSON.stringify(keyValues));
1181
+ await expect(
1182
+ runWrangler(`kv:bulk put --namespace-id some-namespace-id keys.json`)
1183
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1184
+ "Unexpected JSON input from \\"keys.json\\".
1185
+ Each item in the array should be an object that matches:
1186
+
1187
+ interface KeyValue {
1188
+ key: string;
1189
+ value: string;
1190
+ expiration?: number;
1191
+ expiration_ttl?: number;
1192
+ metadata?: object;
1193
+ base64?: boolean;
1194
+ }
1195
+
1196
+ The item at index 0 is type: \\"number\\" - 123
1197
+ The item at index 1 is type: \\"string\\" - \\"a string\\"
1198
+ The item at index 2 is {\\"key\\":\\"someKey\\"}
1199
+ The item at index 3 is {\\"value\\":\\"someValue\\"}"
1200
+ `);
1201
+
1202
+ expect(std.out).toMatchInlineSnapshot(`""`);
1203
+ expect(std.warn).toMatchInlineSnapshot(`
1204
+ "Unexpected key-value properties in \\"keys.json\\".
1205
+ The item at index 4 contains unexpected properties: [\\"invalid\\"]."
1206
+ `);
1207
+ });
1208
+ });
1209
+
1210
+ describe("delete", () => {
1211
+ function mockDeleteRequest(
1212
+ expectedNamespaceId: string,
1213
+ expectedKeys: string[]
1214
+ ) {
1215
+ const requests = { count: 0 };
1216
+ setMockResponse(
1217
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1218
+ "DELETE",
1219
+ ([_url, accountId, namespaceId], { headers, body }) => {
1220
+ requests.count++;
1221
+ expect(accountId).toEqual("some-account-id");
1222
+ expect(namespaceId).toEqual(expectedNamespaceId);
1223
+ expect(new Headers(headers ?? []).get("Content-Type")).toEqual(
1224
+ "application/json"
1225
+ );
1226
+ expect(JSON.parse(body as string)).toEqual(
1227
+ expectedKeys.slice(
1228
+ (requests.count - 1) * 5000,
1229
+ requests.count * 5000
1230
+ )
1231
+ );
1232
+ return null;
1233
+ }
1234
+ );
1235
+ return requests;
1236
+ }
1237
+
1238
+ it("should delete the keys parsed from a file", async () => {
1239
+ const keys = ["someKey1", "ns:someKey2"];
1240
+ writeFileSync("./keys.json", JSON.stringify(keys));
1241
+ mockConfirm({
1242
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1243
+ result: true,
1244
+ });
1245
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1246
+ await runWrangler(
1247
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1248
+ );
1249
+ expect(requests.count).toEqual(1);
1250
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1251
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1252
+ expect(std.err).toMatchInlineSnapshot(`""`);
1253
+ });
1254
+
1255
+ it("should delete the keys in batches of 5000 parsed from a file", async () => {
1256
+ const keys = new Array(12000).fill("some-key");
1257
+ writeFileSync("./keys.json", JSON.stringify(keys));
1258
+ mockConfirm({
1259
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1260
+ result: true,
1261
+ });
1262
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1263
+ await runWrangler(
1264
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1265
+ );
1266
+ expect(requests.count).toEqual(3);
1267
+ expect(std.out).toMatchInlineSnapshot(`
1268
+ "Deleted 0 of 12000.
1269
+ Deleted 5000 of 12000.
1270
+ Deleted 10000 of 12000.
1271
+ Deleted 12000 of 12000.
1272
+ Success!"
1273
+ `);
1274
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1275
+ expect(std.err).toMatchInlineSnapshot(`""`);
1276
+ });
1277
+
1278
+ it("should not delete the keys if the user confirms no", async () => {
1279
+ const keys = ["someKey1", "ns:someKey2"];
1280
+ writeFileSync("./keys.json", JSON.stringify(keys));
1281
+ mockConfirm({
1282
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1283
+ result: false,
1284
+ });
1285
+ await runWrangler(
1286
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1287
+ );
1288
+ expect(std.out).toMatchInlineSnapshot(
1289
+ `"Not deleting keys read from \\"keys.json\\"."`
1290
+ );
1291
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1292
+ expect(std.err).toMatchInlineSnapshot(`""`);
1293
+ });
1294
+
1295
+ it("should delete the keys without asking if --force is provided", async () => {
1296
+ const keys = ["someKey1", "ns:someKey2"];
1297
+ writeFileSync("./keys.json", JSON.stringify(keys));
1298
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1299
+ await runWrangler(
1300
+ `kv:bulk delete --namespace-id some-namespace-id keys.json --force`
1301
+ );
1302
+ expect(requests.count).toEqual(1);
1303
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1304
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1305
+ expect(std.err).toMatchInlineSnapshot(`""`);
1306
+ });
1307
+
1308
+ it("should delete the keys without asking if -f is provided", async () => {
1309
+ const keys = ["someKey1", "ns:someKey2"];
1310
+ writeFileSync("./keys.json", JSON.stringify(keys));
1311
+ const requests = mockDeleteRequest("some-namespace-id", keys);
1312
+ await runWrangler(
1313
+ `kv:bulk delete --namespace-id some-namespace-id keys.json -f`
1314
+ );
1315
+ expect(requests.count).toEqual(1);
1316
+ expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1317
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1318
+ expect(std.err).toMatchInlineSnapshot(`""`);
1319
+ });
1320
+
1321
+ it("should error if the file is not a JSON array", async () => {
1322
+ const keys = 12354;
1323
+ writeFileSync("./keys.json", JSON.stringify(keys));
1324
+ mockConfirm({
1325
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1326
+ result: true,
1327
+ });
1328
+ await expect(
1329
+ runWrangler(
1330
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1331
+ )
1332
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1333
+ "Unexpected JSON input from \\"keys.json\\".
1334
+ Expected an array of strings but got:
1335
+ 12354"
1336
+ `);
1337
+ expect(std.out).toMatchInlineSnapshot(`""`);
1338
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1339
+ });
1340
+
1341
+ it("should error if the file contains non-string items", async () => {
1342
+ const keys = ["good", 12354, { key: "someKey" }, null];
1343
+ writeFileSync("./keys.json", JSON.stringify(keys));
1344
+ mockConfirm({
1345
+ text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1346
+ result: true,
1347
+ });
1348
+ await expect(
1349
+ runWrangler(
1350
+ `kv:bulk delete --namespace-id some-namespace-id keys.json`
1351
+ )
1352
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
1353
+ "Unexpected JSON input from \\"keys.json\\".
1354
+ Expected an array of strings.
1355
+ The item at index 1 is type: \\"number\\" - 12354
1356
+ The item at index 2 is type: \\"object\\" - {\\"key\\":\\"someKey\\"}
1357
+ The item at index 3 is type: \\"object\\" - null"
1358
+ `);
1359
+ expect(std.out).toMatchInlineSnapshot(`""`);
1360
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1361
+ });
1362
+ });
1363
+ });
1143
1364
  });
1144
1365
 
1145
1366
  function writeWranglerConfig() {
@@ -1159,41 +1380,3 @@ function writeWranglerConfig() {
1159
1380
  "utf-8"
1160
1381
  );
1161
1382
  }
1162
-
1163
- export function mockKeyListRequest(
1164
- expectedNamespaceId: string,
1165
- expectedKeys: string[],
1166
- keysPerRequest = 1000
1167
- ) {
1168
- const requests = { count: 0 };
1169
- // See https://api.cloudflare.com/#workers-kv-namespace-list-a-namespace-s-keys
1170
- const expectedKeyObjects = expectedKeys.map((name) => ({
1171
- name,
1172
- expiration: 123456789,
1173
- metadata: {},
1174
- }));
1175
- setMockRawResponse(
1176
- "/accounts/:accountId/storage/kv/namespaces/:namespaceId/keys",
1177
- "GET",
1178
- ([_url, accountId, namespaceId], _init, query) => {
1179
- requests.count++;
1180
- expect(accountId).toEqual("some-account-id");
1181
- expect(namespaceId).toEqual(expectedNamespaceId);
1182
- if (expectedKeyObjects.length <= keysPerRequest) {
1183
- return createFetchResult(expectedKeyObjects);
1184
- } else {
1185
- const start = parseInt(query.get("cursor") ?? "0") || 0;
1186
- const end = start + keysPerRequest;
1187
- const cursor = end < expectedKeyObjects.length ? end : undefined;
1188
- return createFetchResult(
1189
- expectedKeyObjects.slice(start, end),
1190
- true,
1191
- [],
1192
- [],
1193
- { cursor }
1194
- );
1195
- }
1196
- }
1197
- );
1198
- return requests;
1199
- }