wrangler 2.6.2 → 2.7.0

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 (128) hide show
  1. package/bin/wrangler.js +9 -1
  2. package/miniflare-dist/index.mjs +1 -1
  3. package/package.json +12 -10
  4. package/src/__tests__/api-dev.test.ts +65 -36
  5. package/src/__tests__/api-devregistry.test.js +14 -6
  6. package/src/__tests__/configuration.test.ts +2 -31
  7. package/src/__tests__/{d1.test.ts → d1/d1.test.ts} +48 -5
  8. package/src/__tests__/d1/splitter.test.ts +255 -0
  9. package/src/__tests__/delete.test.ts +5 -2
  10. package/src/__tests__/deployments.test.ts +20 -6
  11. package/src/__tests__/dev.test.tsx +52 -19
  12. package/src/__tests__/generate.test.ts +7 -4
  13. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  14. package/src/__tests__/helpers/mock-cfetch.ts +2 -57
  15. package/src/__tests__/helpers/mock-dialogs.ts +70 -86
  16. package/src/__tests__/helpers/mock-oauth-flow.ts +64 -49
  17. package/src/__tests__/helpers/mock-process.ts +8 -13
  18. package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
  19. package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
  20. package/src/__tests__/index.test.ts +46 -44
  21. package/src/__tests__/init.test.ts +761 -537
  22. package/src/__tests__/jest.setup.ts +20 -24
  23. package/src/__tests__/kv.test.ts +286 -173
  24. package/src/__tests__/logout.test.ts +1 -1
  25. package/src/__tests__/metrics.test.ts +5 -7
  26. package/src/__tests__/middleware.scheduled.test.ts +40 -30
  27. package/src/__tests__/middleware.test.ts +144 -120
  28. package/src/__tests__/pages.test.ts +1617 -1161
  29. package/src/__tests__/publish.test.ts +174 -125
  30. package/src/__tests__/r2.test.ts +2 -2
  31. package/src/__tests__/secret.test.ts +183 -126
  32. package/src/__tests__/tail.test.ts +6 -0
  33. package/src/__tests__/tsconfig-sanity.ts +12 -0
  34. package/src/__tests__/tsconfig.json +8 -0
  35. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  36. package/src/__tests__/whoami.test.tsx +1 -96
  37. package/src/api/dev.ts +78 -41
  38. package/src/api/index.ts +1 -1
  39. package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
  40. package/src/cfetch/index.ts +0 -2
  41. package/src/cfetch/internal.ts +6 -15
  42. package/src/cli.ts +2 -2
  43. package/src/config/validation.ts +1 -2
  44. package/src/create-worker-upload-form.ts +2 -2
  45. package/src/d1/{delete.tsx → delete.ts} +0 -0
  46. package/src/d1/execute.tsx +8 -37
  47. package/src/d1/migrations/apply.tsx +29 -19
  48. package/src/d1/migrations/{index.tsx → index.ts} +0 -0
  49. package/src/d1/splitter.ts +161 -0
  50. package/src/d1/{types.tsx → types.ts} +0 -0
  51. package/src/delete.ts +3 -8
  52. package/src/deployments.ts +6 -0
  53. package/src/deprecated/index.ts +2 -295
  54. package/src/dev/dev.tsx +2 -2
  55. package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  56. package/src/dev/local.tsx +16 -4
  57. package/src/dev/remote.tsx +28 -1
  58. package/src/dev/start-server.ts +19 -11
  59. package/src/dev/use-esbuild.ts +1 -1
  60. package/src/{dev-registry.tsx → dev-registry.ts} +0 -0
  61. package/src/dev.tsx +21 -2
  62. package/src/dialogs.ts +136 -0
  63. package/src/dispatch-namespace.ts +1 -1
  64. package/src/docs/index.ts +3 -0
  65. package/src/environment-variables/factory.ts +88 -0
  66. package/src/environment-variables/misc-variables.ts +30 -0
  67. package/src/generate/index.ts +300 -0
  68. package/src/{index.tsx → index.ts} +10 -13
  69. package/src/init.ts +92 -52
  70. package/src/jest.d.ts +4 -0
  71. package/src/logger.ts +15 -3
  72. package/src/metrics/metrics-config.ts +1 -1
  73. package/src/miniflare-cli/assets.ts +4 -0
  74. package/src/miniflare-cli/index.ts +1 -5
  75. package/src/miniflare-cli/tsconfig.json +9 -0
  76. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  77. package/src/miniflare-cli/types.ts +11 -0
  78. package/src/pages/{build.tsx → build.ts} +0 -0
  79. package/src/pages/{deployment-tails.tsx → deployment-tails.ts} +0 -0
  80. package/src/pages/{dev.tsx → dev.ts} +53 -55
  81. package/src/pages/functions/buildWorker.ts +1 -1
  82. package/src/pages/functions/tsconfig.json +8 -0
  83. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  84. package/src/pages/{functions.tsx → functions.ts} +0 -0
  85. package/src/pages/{hash.tsx → hash.ts} +0 -0
  86. package/src/pages/{index.tsx → index.ts} +0 -0
  87. package/src/pages/projects.tsx +3 -5
  88. package/src/pages/publish.tsx +5 -4
  89. package/src/pages/upload.tsx +1 -1
  90. package/src/publish/publish.ts +9 -7
  91. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +1 -1
  92. package/src/secret/index.ts +1 -1
  93. package/src/{sites.tsx → sites.ts} +0 -0
  94. package/src/tail/index.ts +2 -3
  95. package/src/tsconfig-sanity.ts +16 -0
  96. package/src/user/access.ts +0 -1
  97. package/src/user/auth-variables.ts +113 -0
  98. package/src/user/choose-account.tsx +1 -31
  99. package/src/user/index.ts +0 -1
  100. package/src/user/{user.tsx → user.ts} +107 -73
  101. package/src/{whoami.tsx → whoami.ts} +37 -71
  102. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  103. package/templates/__tests__/tsconfig.json +8 -0
  104. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  105. package/templates/d1-beta-facade.js +36 -0
  106. package/templates/facade.d.ts +14 -0
  107. package/templates/first-party-worker-module-facade.ts +4 -3
  108. package/templates/format-dev-errors.ts +7 -6
  109. package/templates/init-tests/test-jest-new-worker.js +3 -5
  110. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  111. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  112. package/templates/middleware/loader-modules.ts +0 -2
  113. package/templates/middleware/loader-sw.ts +6 -0
  114. package/templates/pages-dev-pipeline.ts +4 -1
  115. package/templates/pages-shim.ts +4 -1
  116. package/templates/pages-template-plugin.ts +12 -7
  117. package/templates/serve-static-assets.ts +16 -14
  118. package/templates/tsconfig-sanity.ts +11 -0
  119. package/templates/tsconfig.init.json +106 -0
  120. package/templates/tsconfig.json +5 -103
  121. package/templates/tsconfig.tsbuildinfo +1 -0
  122. package/wrangler-dist/cli.d.ts +58 -60
  123. package/wrangler-dist/cli.js +34440 -55514
  124. package/wrangler-dist/wasm-sync.wasm +0 -0
  125. package/src/__tests__/dialogs.test.tsx +0 -40
  126. package/src/dialogs.tsx +0 -168
  127. package/src/environment-variables.ts +0 -50
  128. package/src/user/env-vars.ts +0 -46
@@ -1,20 +1,11 @@
1
1
  import { writeFileSync } from "node:fs";
2
- import { FormData, Headers } from "undici";
2
+ import { rest } from "msw";
3
3
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
4
- import {
5
- setMockResponse,
6
- unsetAllMocks,
7
- unsetSpecialMockFns,
8
- setMockFetchKVGetValue,
9
- setMockRawResponse,
10
- createFetchResult,
11
- } from "./helpers/mock-cfetch";
12
4
  import { mockConsoleMethods } from "./helpers/mock-console";
13
- import { clearConfirmMocks, mockConfirm } from "./helpers/mock-dialogs";
5
+ import { mockConfirm, clearDialogs } from "./helpers/mock-dialogs";
14
6
  import { useMockIsTTY } from "./helpers/mock-istty";
15
- import { mockKeyListRequest } from "./helpers/mock-kv";
16
- import { mockGetMemberships } from "./helpers/mock-oauth-flow";
17
7
  import { mockProcess } from "./helpers/mock-process";
8
+ import { msw } from "./helpers/msw";
18
9
  import { runInTempDir } from "./helpers/run-in-tmp";
19
10
  import { runWrangler } from "./helpers/run-wrangler";
20
11
  import type {
@@ -22,31 +13,37 @@ import type {
22
13
  KVNamespaceInfo,
23
14
  NamespaceKeyInfo,
24
15
  } from "../kv/helpers";
25
-
26
16
  describe("wrangler", () => {
27
17
  mockAccountId();
28
18
  mockApiToken();
29
19
  runInTempDir();
20
+
30
21
  const std = mockConsoleMethods();
31
22
  const proc = mockProcess();
32
23
 
24
+ const { setIsTTY } = useMockIsTTY();
25
+ beforeEach(() => {
26
+ setIsTTY(true);
27
+ });
33
28
  afterEach(() => {
34
- unsetAllMocks();
35
- clearConfirmMocks();
29
+ clearDialogs();
36
30
  });
37
-
38
31
  describe("kv:namespace", () => {
39
32
  describe("create", () => {
40
33
  function mockCreateRequest(expectedTitle: string) {
41
- setMockResponse(
42
- "/accounts/:accountId/storage/kv/namespaces",
43
- "POST",
44
- ([_url, accountId], { body }) => {
45
- expect(accountId).toEqual("some-account-id");
46
- const title = JSON.parse(body as string).title;
47
- expect(title).toEqual(expectedTitle);
48
- return { id: "some-namespace-id" };
49
- }
34
+ msw.use(
35
+ rest.post(
36
+ "*/accounts/:accountId/storage/kv/namespaces",
37
+ async (req, res, ctx) => {
38
+ expect(req.params.accountId).toEqual("some-account-id");
39
+ const title = (await req.json()).title as string;
40
+ expect(title).toEqual(expectedTitle);
41
+ return res.once(
42
+ ctx.status(200),
43
+ ctx.json(createFetchResult({ id: "some-namespace-id" }))
44
+ );
45
+ }
46
+ )
50
47
  );
51
48
  }
52
49
 
@@ -193,22 +190,32 @@ describe("wrangler", () => {
193
190
  });
194
191
 
195
192
  describe("list", () => {
196
- function mockListRequest(namespaces: unknown[]) {
193
+ function mockListRequest(namespaces: KVNamespaceInfo[]) {
197
194
  const requests = { count: 0 };
198
- setMockResponse(
199
- "/accounts/:accountId/storage/kv/namespaces",
200
- ([_url, accountId], init, query) => {
201
- requests.count++;
202
- expect(accountId).toEqual("some-account-id");
203
- expect(query.get("per_page")).toEqual("100");
204
- expect(query.get("order")).toEqual("title");
205
- expect(query.get("direction")).toEqual("asc");
206
- expect(query.get("page")).toEqual(`${requests.count}`);
207
- expect(init).toEqual({});
208
- const pageSize = Number(query.get("per_page"));
209
- const page = Number(query.get("page"));
210
- return namespaces.slice((page - 1) * pageSize, page * pageSize);
211
- }
195
+ msw.use(
196
+ rest.get(
197
+ "*/accounts/:accountId/storage/kv/namespaces",
198
+ async (req, res, ctx) => {
199
+ requests.count++;
200
+ expect(req.params.accountId).toEqual("some-account-id");
201
+ expect(req.url.searchParams.get("per_page")).toEqual("100");
202
+ expect(req.url.searchParams.get("order")).toEqual("title");
203
+ expect(req.url.searchParams.get("direction")).toEqual("asc");
204
+ expect(req.url.searchParams.get("page")).toEqual(
205
+ `${requests.count}`
206
+ );
207
+
208
+ const pageSize = Number(req.url.searchParams.get("per_page"));
209
+ const page = Number(req.url.searchParams.get("page"));
210
+ return res(
211
+ ctx.json(
212
+ createFetchResult(
213
+ namespaces.slice((page - 1) * pageSize, page * pageSize)
214
+ )
215
+ )
216
+ );
217
+ }
218
+ )
212
219
  );
213
220
  return requests;
214
221
  }
@@ -222,8 +229,7 @@ describe("wrangler", () => {
222
229
  await runWrangler("kv:namespace list");
223
230
 
224
231
  expect(std.err).toMatchInlineSnapshot(`""`);
225
- const namespaces = JSON.parse(std.out);
226
- expect(namespaces).toEqual(kvNamespaces);
232
+ expect(JSON.parse(std.out)).toEqual(kvNamespaces);
227
233
  });
228
234
 
229
235
  it("should make multiple requests for paginated results", async () => {
@@ -234,8 +240,8 @@ describe("wrangler", () => {
234
240
  }
235
241
  const requests = mockListRequest(kvNamespaces);
236
242
  await runWrangler("kv:namespace list");
237
- const namespaces = JSON.parse(std.out);
238
- expect(namespaces).toEqual(kvNamespaces);
243
+
244
+ expect(JSON.parse(std.out)).toEqual(kvNamespaces);
239
245
  expect(requests.count).toEqual(6);
240
246
  });
241
247
  });
@@ -243,15 +249,16 @@ describe("wrangler", () => {
243
249
  describe("delete", () => {
244
250
  function mockDeleteRequest(expectedNamespaceId: string) {
245
251
  const requests = { count: 0 };
246
- setMockResponse(
247
- "/accounts/:accountId/storage/kv/namespaces/:namespaceId",
248
- "DELETE",
249
- ([_url, accountId, namespaceId]) => {
250
- requests.count++;
251
- expect(accountId).toEqual("some-account-id");
252
- expect(namespaceId).toEqual(expectedNamespaceId);
253
- return null;
254
- }
252
+ msw.use(
253
+ rest.delete(
254
+ "*/accounts/:accountId/storage/kv/namespaces/:namespaceId",
255
+ (req, res, ctx) => {
256
+ requests.count++;
257
+ expect(req.params.accountId).toEqual("some-account-id");
258
+ expect(req.params.namespaceId).toEqual(expectedNamespaceId);
259
+ return res(ctx.status(200), ctx.json(createFetchResult(null)));
260
+ }
261
+ )
255
262
  );
256
263
  return requests;
257
264
  }
@@ -331,39 +338,43 @@ describe("wrangler", () => {
331
338
  expectedKV: KeyValue
332
339
  ) {
333
340
  const requests = { count: 0 };
334
- setMockResponse(
335
- "/accounts/:accountId/storage/kv/namespaces/:namespaceId/values/:key",
336
- "PUT",
337
- ([_url, accountId, namespaceId, key], { body }, query) => {
338
- requests.count++;
339
- expect(accountId).toEqual("some-account-id");
340
- expect(namespaceId).toEqual(expectedNamespaceId);
341
- expect(key).toEqual(expectedKV.key);
342
- if (expectedKV.metadata) {
343
- expect(body).toBeInstanceOf(FormData);
344
- expect((body as FormData).get("value")).toEqual(expectedKV.value);
345
- expect((body as FormData).get("metadata")).toEqual(
346
- JSON.stringify(expectedKV.metadata)
347
- );
348
- } else {
349
- expect(body).toEqual(expectedKV.value);
350
- }
351
- if (expectedKV.expiration !== undefined) {
352
- expect(query.get("expiration")).toEqual(
353
- `${expectedKV.expiration}`
354
- );
355
- } else {
356
- expect(query.has("expiration")).toBe(false);
341
+ msw.use(
342
+ rest.put(
343
+ "*/accounts/:accountId/storage/kv/namespaces/:namespaceId/values/:key",
344
+ (req, res, ctx) => {
345
+ requests.count++;
346
+ const { accountId, namespaceId, key } = req.params;
347
+ expect(accountId).toEqual("some-account-id");
348
+ expect(namespaceId).toEqual(expectedNamespaceId);
349
+ expect(encodeURIComponent(key as string)).toEqual(expectedKV.key);
350
+ // if (expectedKV.metadata) {
351
+ // expect(body).toBeInstanceOf(FormData);
352
+ // expect((body as FormData).get("value")).toEqual(
353
+ // expectedKV.value
354
+ // );
355
+ // expect((body as FormData).get("metadata")).toEqual(
356
+ // JSON.stringify(expectedKV.metadata)
357
+ // );
358
+ // } else {
359
+ // expect(body).toEqual(expectedKV.value);
360
+ // }
361
+ if (expectedKV.expiration !== undefined) {
362
+ expect(req.url.searchParams.get("expiration")).toEqual(
363
+ `${expectedKV.expiration}`
364
+ );
365
+ } else {
366
+ expect(req.url.searchParams.has("expiration")).toBe(false);
367
+ }
368
+ if (expectedKV.expiration_ttl) {
369
+ expect(req.url.searchParams.get("expiration_ttl")).toEqual(
370
+ `${expectedKV.expiration_ttl}`
371
+ );
372
+ } else {
373
+ expect(req.url.searchParams.has("expiration_ttl")).toBe(false);
374
+ }
375
+ return res(ctx.status(200), ctx.json(createFetchResult(null)));
357
376
  }
358
- if (expectedKV.expiration_ttl) {
359
- expect(query.get("expiration_ttl")).toEqual(
360
- `${expectedKV.expiration_ttl}`
361
- );
362
- } else {
363
- expect(query.has("expiration_ttl")).toBe(false);
364
- }
365
- return null;
366
- }
377
+ )
367
378
  );
368
379
  return requests;
369
380
  }
@@ -927,10 +938,6 @@ describe("wrangler", () => {
927
938
  });
928
939
 
929
940
  describe("get", () => {
930
- afterEach(() => {
931
- unsetSpecialMockFns();
932
- });
933
-
934
941
  it("should get a key in a given namespace specified by namespace-id", async () => {
935
942
  setMockFetchKVGetValue(
936
943
  "some-account-id",
@@ -938,7 +945,9 @@ describe("wrangler", () => {
938
945
  "my-key",
939
946
  "my-value"
940
947
  );
948
+
941
949
  await runWrangler("kv:key get my-key --namespace-id some-namespace-id");
950
+
942
951
  expect(proc.write).toEqual(Buffer.from("my-value"));
943
952
  expect(std.err).toMatchInlineSnapshot(`""`);
944
953
  });
@@ -1047,9 +1056,10 @@ describe("wrangler", () => {
1047
1056
  setMockFetchKVGetValue(
1048
1057
  "some-account-id",
1049
1058
  "some-namespace-id",
1050
- "%2Fmy%2Ckey",
1059
+ "%2Fmy%2Ckey", // expect the key /my,key to be encoded
1051
1060
  "my-value"
1052
1061
  );
1062
+
1053
1063
  await runWrangler(
1054
1064
  "kv:key get /my,key --namespace-id some-namespace-id"
1055
1065
  );
@@ -1179,7 +1189,6 @@ describe("wrangler", () => {
1179
1189
  });
1180
1190
 
1181
1191
  describe("non-interactive", () => {
1182
- const { setIsTTY } = useMockIsTTY();
1183
1192
  mockAccountId({ accountId: null });
1184
1193
 
1185
1194
  it("should error if there are multiple accounts available but not interactive on stdin", async () => {
@@ -1190,12 +1199,12 @@ describe("wrangler", () => {
1190
1199
  setIsTTY({ stdin: false, stdout: true });
1191
1200
  await expect(runWrangler("kv:key get key --namespace-id=xxxx"))
1192
1201
  .rejects.toThrowErrorMatchingInlineSnapshot(`
1193
- "More than one account available but unable to select one in non-interactive mode.
1194
- Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
1195
- Available accounts are (\\"<name>\\" - \\"<id>\\"):
1196
- \\"one\\" - \\"1\\")
1197
- \\"two\\" - \\"2\\")"
1198
- `);
1202
+ "More than one account available but unable to select one in non-interactive mode.
1203
+ Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
1204
+ Available accounts are (\`<name>\`: \`<account_id>\`):
1205
+ \`one\`: \`1\`
1206
+ \`two\`: \`2\`"
1207
+ `);
1199
1208
  });
1200
1209
 
1201
1210
  it("should error if there are multiple accounts available but not interactive on stdout", async () => {
@@ -1206,23 +1215,30 @@ describe("wrangler", () => {
1206
1215
  setIsTTY({ stdin: true, stdout: false });
1207
1216
  await expect(runWrangler("kv:key get key --namespace-id=xxxx"))
1208
1217
  .rejects.toThrowErrorMatchingInlineSnapshot(`
1209
- "More than one account available but unable to select one in non-interactive mode.
1210
- Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
1211
- Available accounts are (\\"<name>\\" - \\"<id>\\"):
1212
- \\"one\\" - \\"1\\")
1213
- \\"two\\" - \\"2\\")"
1214
- `);
1218
+ "More than one account available but unable to select one in non-interactive mode.
1219
+ Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
1220
+ Available accounts are (\`<name>\`: \`<account_id>\`):
1221
+ \`one\`: \`1\`
1222
+ \`two\`: \`2\`"
1223
+ `);
1215
1224
  });
1216
1225
 
1217
1226
  it("should recommend using a configuration if unable to fetch memberships", async () => {
1218
- setMockRawResponse("/memberships", () => {
1219
- return createFetchResult(undefined, false, [
1220
- {
1221
- code: 9109,
1222
- message: "Uauthorized to access requested resource",
1223
- },
1224
- ]);
1225
- });
1227
+ msw.use(
1228
+ rest.get("*/memberships", (req, res, ctx) => {
1229
+ return res.once(
1230
+ ctx.status(200),
1231
+ ctx.json(
1232
+ createFetchResult(null, false, [
1233
+ {
1234
+ code: 9109,
1235
+ message: "Uauthorized to access requested resource",
1236
+ },
1237
+ ])
1238
+ )
1239
+ );
1240
+ })
1241
+ );
1226
1242
  await expect(runWrangler("kv:key get key --namespace-id=xxxx"))
1227
1243
  .rejects.toThrowErrorMatchingInlineSnapshot(`
1228
1244
  "Failed to automatically retrieve account IDs for the logged in user.
@@ -1238,12 +1254,12 @@ describe("wrangler", () => {
1238
1254
  setIsTTY(false);
1239
1255
  await expect(runWrangler("kv:key get key --namespace-id=xxxx"))
1240
1256
  .rejects.toThrowErrorMatchingInlineSnapshot(`
1241
- "More than one account available but unable to select one in non-interactive mode.
1242
- Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
1243
- Available accounts are (\\"<name>\\" - \\"<id>\\"):
1244
- \\"one\\" - \\"1\\")
1245
- \\"two\\" - \\"2\\")"
1246
- `);
1257
+ "More than one account available but unable to select one in non-interactive mode.
1258
+ Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
1259
+ Available accounts are (\`<name>\`: \`<account_id>\`):
1260
+ \`one\`: \`1\`
1261
+ \`two\`: \`2\`"
1262
+ `);
1247
1263
  });
1248
1264
  });
1249
1265
  });
@@ -1254,16 +1270,20 @@ describe("wrangler", () => {
1254
1270
  expectedKey: string
1255
1271
  ) {
1256
1272
  const requests = { count: 0 };
1257
- setMockResponse(
1258
- "/accounts/:accountId/storage/kv/namespaces/:namespaceId/values/:key",
1259
- "DELETE",
1260
- ([_url, accountId, namespaceId, key]) => {
1261
- requests.count++;
1262
- expect(accountId).toEqual("some-account-id");
1263
- expect(namespaceId).toEqual(expectedNamespaceId);
1264
- expect(key).toEqual(expectedKey);
1265
- return null;
1266
- }
1273
+ msw.use(
1274
+ rest.delete(
1275
+ "*/accounts/:accountId/storage/kv/namespaces/:namespaceId/values/:key",
1276
+ (req, res, ctx) => {
1277
+ requests.count++;
1278
+ expect(req.params.accountId).toEqual("some-account-id");
1279
+ expect(req.params.namespaceId).toEqual(expectedNamespaceId);
1280
+ expect(req.params.key).toEqual(expectedKey);
1281
+ return res.once(
1282
+ ctx.status(200),
1283
+ ctx.json(createFetchResult(null))
1284
+ );
1285
+ }
1286
+ )
1267
1287
  );
1268
1288
  return requests;
1269
1289
  }
@@ -1277,8 +1297,9 @@ describe("wrangler", () => {
1277
1297
  });
1278
1298
 
1279
1299
  it("should encode the key in the api request to delete a value", async () => {
1280
- const requests = mockDeleteRequest("voyager", "%2FNCC-74656");
1300
+ const requests = mockDeleteRequest("voyager", "/NCC-74656");
1281
1301
  await runWrangler(`kv:key delete --namespace-id voyager /NCC-74656`);
1302
+
1282
1303
  expect(requests.count).toEqual(1);
1283
1304
  expect(std.out).toMatchInlineSnapshot(
1284
1305
  `"Deleting the key \\"/NCC-74656\\" on namespace voyager."`
@@ -1350,21 +1371,22 @@ describe("wrangler", () => {
1350
1371
  expectedKeyValues: KeyValue[]
1351
1372
  ) {
1352
1373
  const requests = { count: 0 };
1353
- setMockResponse(
1354
- "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1355
- "PUT",
1356
- ([_url, accountId, namespaceId], { body }) => {
1357
- requests.count++;
1358
- expect(accountId).toEqual("some-account-id");
1359
- expect(namespaceId).toEqual(expectedNamespaceId);
1360
- expect(JSON.parse(body as string)).toEqual(
1361
- expectedKeyValues.slice(
1362
- (requests.count - 1) * 5000,
1363
- requests.count * 5000
1364
- )
1365
- );
1366
- return null;
1367
- }
1374
+ msw.use(
1375
+ rest.put(
1376
+ "*/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1377
+ async (req, res, ctx) => {
1378
+ requests.count++;
1379
+ expect(req.params.accountId).toEqual("some-account-id");
1380
+ expect(req.params.namespaceId).toEqual(expectedNamespaceId);
1381
+ expect(await req.json()).toEqual(
1382
+ expectedKeyValues.slice(
1383
+ (requests.count - 1) * 5000,
1384
+ requests.count * 5000
1385
+ )
1386
+ );
1387
+ return res(ctx.status(200), ctx.json(createFetchResult(null)));
1388
+ }
1389
+ )
1368
1390
  );
1369
1391
  return requests;
1370
1392
  }
@@ -1500,24 +1522,25 @@ describe("wrangler", () => {
1500
1522
  expectedKeys: string[]
1501
1523
  ) {
1502
1524
  const requests = { count: 0 };
1503
- setMockResponse(
1504
- "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1505
- "DELETE",
1506
- ([_url, accountId, namespaceId], { headers, body }) => {
1507
- requests.count++;
1508
- expect(accountId).toEqual("some-account-id");
1509
- expect(namespaceId).toEqual(expectedNamespaceId);
1510
- expect(new Headers(headers ?? []).get("Content-Type")).toEqual(
1511
- "application/json"
1512
- );
1513
- expect(JSON.parse(body as string)).toEqual(
1514
- expectedKeys.slice(
1515
- (requests.count - 1) * 5000,
1516
- requests.count * 5000
1517
- )
1518
- );
1519
- return null;
1520
- }
1525
+ msw.use(
1526
+ rest.delete(
1527
+ "*/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
1528
+ async (req, res, ctx) => {
1529
+ requests.count++;
1530
+ expect(req.params.accountId).toEqual("some-account-id");
1531
+ expect(req.params.namespaceId).toEqual(expectedNamespaceId);
1532
+ expect(req.headers.get("Content-Type")).toEqual(
1533
+ "application/json"
1534
+ );
1535
+ expect(await req.json()).toEqual(
1536
+ expectedKeys.slice(
1537
+ (requests.count - 1) * 5000,
1538
+ requests.count * 5000
1539
+ )
1540
+ );
1541
+ return res(ctx.status(200), ctx.json(createFetchResult(null)));
1542
+ }
1543
+ )
1521
1544
  );
1522
1545
  return requests;
1523
1546
  }
@@ -1552,12 +1575,12 @@ describe("wrangler", () => {
1552
1575
  );
1553
1576
  expect(requests.count).toEqual(3);
1554
1577
  expect(std.out).toMatchInlineSnapshot(`
1555
- "Deleted 0% (0 out of 12,000)
1556
- Deleted 41% (5,000 out of 12,000)
1557
- Deleted 83% (10,000 out of 12,000)
1558
- Deleted 100% (12,000 out of 12,000)
1559
- Success!"
1560
- `);
1578
+ "Deleted 0% (0 out of 12,000)
1579
+ Deleted 41% (5,000 out of 12,000)
1580
+ Deleted 83% (10,000 out of 12,000)
1581
+ Deleted 100% (12,000 out of 12,000)
1582
+ Success!"
1583
+ `);
1561
1584
  expect(std.warn).toMatchInlineSnapshot(`""`);
1562
1585
  expect(std.err).toMatchInlineSnapshot(`""`);
1563
1586
  });
@@ -1622,9 +1645,9 @@ describe("wrangler", () => {
1622
1645
  12354"
1623
1646
  `);
1624
1647
  expect(std.out).toMatchInlineSnapshot(`
1625
- "
1626
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1627
- `);
1648
+ "
1649
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1650
+ `);
1628
1651
  expect(std.warn).toMatchInlineSnapshot(`""`);
1629
1652
  });
1630
1653
 
@@ -1647,9 +1670,9 @@ describe("wrangler", () => {
1647
1670
  The item at index 3 is type: \\"object\\" - null"
1648
1671
  `);
1649
1672
  expect(std.out).toMatchInlineSnapshot(`
1650
- "
1651
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1652
- `);
1673
+ "
1674
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1675
+ `);
1653
1676
  expect(std.warn).toMatchInlineSnapshot(`""`);
1654
1677
  });
1655
1678
  });
@@ -1673,3 +1696,93 @@ function writeWranglerConfig() {
1673
1696
  "utf-8"
1674
1697
  );
1675
1698
  }
1699
+
1700
+ function setMockFetchKVGetValue(
1701
+ accountId: string,
1702
+ namespaceId: string,
1703
+ key: string,
1704
+ value: string | Buffer
1705
+ ) {
1706
+ msw.use(
1707
+ rest.get(
1708
+ "*/accounts/:accountId/storage/kv/namespaces/:namespaceId/values/:key",
1709
+ (req, res, ctx) => {
1710
+ console.dir(req.params);
1711
+ expect(req.params.accountId).toEqual(accountId);
1712
+ expect(req.params.namespaceId).toEqual(namespaceId);
1713
+ // Getting the key from params decodes it so we need to grab the encoded key from the URL
1714
+ expect(req.url.toString().split("/").pop()).toBe(key);
1715
+
1716
+ return res.once(ctx.status(200), ctx.body(value));
1717
+ }
1718
+ )
1719
+ );
1720
+ }
1721
+
1722
+ function createFetchResult(
1723
+ result: unknown,
1724
+ success = true,
1725
+ errors: { code: number; message: string }[] = []
1726
+ ) {
1727
+ return {
1728
+ success,
1729
+ errors,
1730
+ messages: [],
1731
+ result,
1732
+ };
1733
+ }
1734
+
1735
+ function mockGetMemberships(
1736
+ accounts: { id: string; account: { id: string; name: string } }[]
1737
+ ) {
1738
+ msw.use(
1739
+ rest.get("*/memberships", (req, res, ctx) => {
1740
+ return res.once(ctx.json(createFetchResult(accounts)));
1741
+ })
1742
+ );
1743
+ }
1744
+
1745
+ function mockKeyListRequest(
1746
+ expectedNamespaceId: string,
1747
+ expectedKeys: NamespaceKeyInfo[],
1748
+ keysPerRequest = 1000,
1749
+ blankCursorValue: "" | undefined | null = undefined
1750
+ ) {
1751
+ const requests = { count: 0 };
1752
+ // See https://api.cloudflare.com/#workers-kv-namespace-list-a-namespace-s-keys
1753
+ msw.use(
1754
+ rest.get(
1755
+ "*/accounts/:accountId/storage/kv/namespaces/:namespaceId/keys",
1756
+ (req, res, ctx) => {
1757
+ requests.count++;
1758
+ let result;
1759
+ let cursor;
1760
+
1761
+ expect(req.params.accountId).toEqual("some-account-id");
1762
+ expect(req.params.namespaceId).toEqual(expectedNamespaceId);
1763
+
1764
+ if (expectedKeys.length <= keysPerRequest) {
1765
+ result = expectedKeys;
1766
+ } else {
1767
+ const start =
1768
+ parseInt(req.url.searchParams.get("cursor") ?? "0") || 0;
1769
+ const end = start + keysPerRequest;
1770
+ cursor = end < expectedKeys.length ? end : blankCursorValue;
1771
+ result = expectedKeys.slice(start, end);
1772
+ }
1773
+ return res(
1774
+ ctx.json({
1775
+ success: true,
1776
+ errors: [],
1777
+ messages: [],
1778
+ result,
1779
+ result_info: {
1780
+ cursor,
1781
+ },
1782
+ })
1783
+ );
1784
+ }
1785
+ )
1786
+ );
1787
+ return requests;
1788
+ }
@@ -32,7 +32,7 @@ describe("logout", () => {
32
32
  rest.post("*/oauth2/revoke", (_, response, context) => {
33
33
  // Make sure that we made the request to logout.
34
34
  counter += 1;
35
- response.once(context.status(200), context.text(""));
35
+ return response.once(context.status(200), context.text(""));
36
36
  })
37
37
  );
38
38