wrangler 0.0.0-e95bea2 → 0.0.0-ea8e701

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 (55) hide show
  1. package/README.md +3 -3
  2. package/bin/wrangler.js +10 -1
  3. package/miniflare-dist/index.mjs +79 -0
  4. package/miniflare-dist/index.mjs.map +7 -0
  5. package/package.json +7 -6
  6. package/pages/functions/filepath-routing.test.ts +125 -25
  7. package/pages/functions/filepath-routing.ts +6 -3
  8. package/src/__tests__/configuration.test.ts +826 -223
  9. package/src/__tests__/dev.test.tsx +145 -9
  10. package/src/__tests__/guess-worker-format.test.ts +26 -1
  11. package/src/__tests__/helpers/mock-account-id.ts +4 -0
  12. package/src/__tests__/helpers/mock-kv.ts +9 -16
  13. package/src/__tests__/helpers/mock-oauth-flow.ts +178 -0
  14. package/src/__tests__/helpers/run-in-tmp.ts +3 -0
  15. package/src/__tests__/index.test.ts +9 -13
  16. package/src/__tests__/jest.setup.ts +5 -0
  17. package/src/__tests__/kv.test.ts +43 -71
  18. package/src/__tests__/pages.test.ts +48 -10
  19. package/src/__tests__/publish.test.ts +1456 -327
  20. package/src/__tests__/r2.test.ts +4 -4
  21. package/src/__tests__/tail.test.ts +78 -4
  22. package/src/__tests__/user.test.ts +83 -0
  23. package/src/__tests__/whoami.test.tsx +16 -7
  24. package/src/bundle.ts +15 -2
  25. package/src/cfetch/internal.ts +9 -5
  26. package/src/config/README.md +6 -6
  27. package/src/config/config.ts +17 -78
  28. package/src/config/environment.ts +67 -1
  29. package/src/config/index.ts +13 -3
  30. package/src/config/validation-helpers.ts +177 -11
  31. package/src/config/validation.ts +305 -100
  32. package/src/dev/dev.tsx +76 -41
  33. package/src/dev/local.tsx +105 -114
  34. package/src/dev/remote.tsx +2 -0
  35. package/src/dev/use-esbuild.ts +4 -0
  36. package/src/entry.ts +103 -6
  37. package/src/index.tsx +251 -189
  38. package/src/intl-polyfill.d.ts +139 -0
  39. package/src/{kv/index.tsx → kv.ts} +8 -28
  40. package/src/miniflare-cli/README.md +30 -0
  41. package/src/miniflare-cli/enum-keys.ts +17 -0
  42. package/src/miniflare-cli/index.ts +37 -0
  43. package/src/module-collection.ts +58 -53
  44. package/src/pages.tsx +26 -10
  45. package/src/proxy.ts +5 -3
  46. package/src/publish.ts +17 -21
  47. package/src/sites.tsx +67 -25
  48. package/src/tail/index.ts +1 -1
  49. package/src/tail/printing.ts +2 -2
  50. package/src/user.tsx +161 -81
  51. package/wrangler-dist/cli.js +3418 -1437
  52. package/wrangler-dist/cli.js.map +3 -3
  53. package/src/__tests__/dev2.test.tsx +0 -152
  54. package/src/__tests__/helpers/mock-user.ts +0 -27
  55. package/src/__tests__/logout.test.ts +0 -50
@@ -1,15 +1,18 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import * as TOML from "@iarna/toml";
4
+ import { writeAuthConfigFile } from "../user";
4
5
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
5
6
  import {
6
7
  createFetchResult,
7
8
  setMockRawResponse,
8
9
  setMockResponse,
9
10
  unsetAllMocks,
11
+ unsetMockFetchKVGetValues,
10
12
  } from "./helpers/mock-cfetch";
11
13
  import { mockConsoleMethods } from "./helpers/mock-console";
12
14
  import { mockKeyListRequest } from "./helpers/mock-kv";
15
+ import { mockOAuthFlow } from "./helpers/mock-oauth-flow";
13
16
  import { runInTempDir } from "./helpers/run-in-tmp";
14
17
  import { runWrangler } from "./helpers/run-wrangler";
15
18
  import writeWranglerToml from "./helpers/write-wrangler-toml";
@@ -18,24 +21,96 @@ import type { KVNamespaceInfo } from "../kv";
18
21
  import type { FormData, File } from "undici";
19
22
 
20
23
  describe("publish", () => {
24
+ mockAccountId();
25
+ mockApiToken();
26
+ runInTempDir({ homedir: "./home" });
27
+ const std = mockConsoleMethods();
28
+ const { mockGrantAccessToken, mockGrantAuthorization } = mockOAuthFlow();
29
+
21
30
  beforeEach(() => {
22
31
  // @ts-expect-error we're using a very simple setTimeout mock here
23
32
  jest.spyOn(global, "setTimeout").mockImplementation((fn, _period) => {
24
- fn();
33
+ setImmediate(fn);
25
34
  });
26
35
  });
27
- mockAccountId();
28
- mockApiToken();
29
- runInTempDir();
30
- const std = mockConsoleMethods();
31
36
 
32
37
  afterEach(() => {
33
38
  unsetAllMocks();
39
+ unsetMockFetchKVGetValues();
40
+ });
41
+
42
+ describe("authentication", () => {
43
+ mockApiToken({ apiToken: null });
44
+ beforeEach(() => {
45
+ // @ts-expect-error disable the mock we'd setup earlier
46
+ // or else our server won't bother listening for oauth requests
47
+ // and will timeout and fail
48
+ global.setTimeout.mockRestore();
49
+ });
50
+
51
+ it("drops a user into the login flow if they're unauthenticated", async () => {
52
+ writeWranglerToml();
53
+ writeWorkerSource();
54
+ mockSubDomainRequest();
55
+ mockUploadWorkerRequest();
56
+
57
+ const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
58
+ mockGrantAuthorization({ respondWith: "success" });
59
+
60
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
61
+
62
+ expect(accessTokenRequest.actual.url).toEqual(
63
+ accessTokenRequest.expected.url
64
+ );
65
+
66
+ expect(std.out).toMatchInlineSnapshot(`
67
+ "Attempting to login via OAuth...
68
+ Successfully logged in.
69
+ Uploaded test-name (TIMINGS)
70
+ Published test-name (TIMINGS)
71
+ test-name.test-sub-domain.workers.dev"
72
+ `);
73
+ expect(std.warn).toMatchInlineSnapshot(`""`);
74
+ expect(std.err).toMatchInlineSnapshot(`""`);
75
+ });
76
+
77
+ it("warns a user when they're authenticated with an API token in wrangler config file", async () => {
78
+ writeWranglerToml();
79
+ writeWorkerSource();
80
+ mockSubDomainRequest();
81
+ mockUploadWorkerRequest();
82
+ writeAuthConfigFile({
83
+ api_token: "some-api-token",
84
+ });
85
+
86
+ const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
87
+ mockGrantAuthorization({ respondWith: "success" });
88
+
89
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
90
+
91
+ expect(accessTokenRequest.actual.url).toEqual(
92
+ accessTokenRequest.expected.url
93
+ );
94
+
95
+ expect(std.out).toMatchInlineSnapshot(`
96
+ "Attempting to login via OAuth...
97
+ Successfully logged in.
98
+ Uploaded test-name (TIMINGS)
99
+ Published test-name (TIMINGS)
100
+ test-name.test-sub-domain.workers.dev"
101
+ `);
102
+ expect(std.warn).toMatchInlineSnapshot(`
103
+ "It looks like you have used Wrangler 1's \`config\` command to login with an API token.
104
+ This is no longer supported in the current version of Wrangler.
105
+ If you wish to authenticate via an API token then please set the \`CLOUDFLARE_API_TOKEN\` environment variable."
106
+ `);
107
+ expect(std.err).toMatchInlineSnapshot(`""`);
108
+ });
34
109
  });
35
110
 
36
111
  describe("environments", () => {
37
112
  it("should use legacy environments by default", async () => {
38
- writeWranglerToml();
113
+ writeWranglerToml({ env: { "some-env": {} } });
39
114
  writeWorkerSource();
40
115
  mockSubDomainRequest();
41
116
  mockUploadWorkerRequest({
@@ -70,8 +145,8 @@ describe("publish", () => {
70
145
  expect(std.warn).toMatchInlineSnapshot(`""`);
71
146
  });
72
147
 
73
- it("appends the environment name when provided", async () => {
74
- writeWranglerToml();
148
+ it("appends the environment name when provided, and there is associated config", async () => {
149
+ writeWranglerToml({ env: { "some-env": {} } });
75
150
  writeWorkerSource();
76
151
  mockSubDomainRequest();
77
152
  mockUploadWorkerRequest({
@@ -87,6 +162,70 @@ describe("publish", () => {
87
162
  expect(std.err).toMatchInlineSnapshot(`""`);
88
163
  expect(std.warn).toMatchInlineSnapshot(`""`);
89
164
  });
165
+
166
+ it("appends the environment name when provided (with a warning), if there are no configured environments", async () => {
167
+ writeWranglerToml({});
168
+ writeWorkerSource();
169
+ mockSubDomainRequest();
170
+ mockUploadWorkerRequest({
171
+ env: "some-env",
172
+ legacyEnv: true,
173
+ });
174
+ await runWrangler("publish index.js --env some-env --legacy-env true");
175
+ expect(std.out).toMatchInlineSnapshot(`
176
+ "Uploaded test-name-some-env (TIMINGS)
177
+ Published test-name-some-env (TIMINGS)
178
+ test-name-some-env.test-sub-domain.workers.dev"
179
+ `);
180
+ expect(std.err).toMatchInlineSnapshot(`""`);
181
+ expect(std.warn).toMatchInlineSnapshot(`
182
+ "Processing wrangler.toml configuration:
183
+ - No environment found in configuration with name \\"some-env\\".
184
+ Before using \`--env=some-env\` there should be an equivalent environment section in the configuration.
185
+
186
+ Consider adding an environment configuration section to the wrangler.toml file:
187
+ \`\`\`
188
+ [env.some-env]
189
+ \`\`\`
190
+ "
191
+ `);
192
+ });
193
+
194
+ it("should throw an error when an environment name when provided, which doesn't match those in the config", async () => {
195
+ writeWranglerToml({ env: { "other-env": {} } });
196
+ writeWorkerSource();
197
+ mockSubDomainRequest();
198
+ await expect(
199
+ runWrangler("publish index.js --env some-env --legacy-env true")
200
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
201
+ "Processing wrangler.toml configuration:
202
+ - No environment found in configuration with name \\"some-env\\".
203
+ Before using \`--env=some-env\` there should be an equivalent environment section in the configuration.
204
+ The available configured environment names are: [\\"other-env\\"]
205
+
206
+ Consider adding an environment configuration section to the wrangler.toml file:
207
+ \`\`\`
208
+ [env.some-env]
209
+ \`\`\`
210
+ "
211
+ `);
212
+ });
213
+
214
+ it("should throw an error w/ helpful message when using --env --name", async () => {
215
+ writeWranglerToml({ env: { "some-env": {} } });
216
+ writeWorkerSource();
217
+ mockSubDomainRequest();
218
+ await runWrangler(
219
+ "publish index.js --name voyager --env some-env --legacy-env true"
220
+ ).catch((err) =>
221
+ expect(err).toMatchInlineSnapshot(`
222
+ [Error: In legacy environment mode you cannot use --name and --env together. If you want to specify a Worker name for a specific environment you can add the following to your wrangler.toml config:
223
+ [env.some-env]
224
+ name = "voyager"
225
+ ]
226
+ `)
227
+ );
228
+ });
90
229
  });
91
230
 
92
231
  describe("services", () => {
@@ -108,7 +247,7 @@ describe("publish", () => {
108
247
  });
109
248
 
110
249
  it("publishes as an environment when provided", async () => {
111
- writeWranglerToml();
250
+ writeWranglerToml({ env: { "some-env": {} } });
112
251
  writeWorkerSource();
113
252
  mockSubDomainRequest();
114
253
  mockUploadWorkerRequest({
@@ -585,6 +724,7 @@ export default{
585
724
  uploading as assets/file-1.2ca234f380.txt...
586
725
  reading assets/file-2.txt...
587
726
  uploading as assets/file-2.5938485188.txt...
727
+ ↗️ Done syncing assets
588
728
  Uploaded test-name (TIMINGS)
589
729
  Published test-name (TIMINGS)
590
730
  test-name.test-sub-domain.workers.dev"
@@ -640,6 +780,7 @@ export default{
640
780
  uploading as assets/file-1.2ca234f380.txt...
641
781
  reading assets/file-2.txt...
642
782
  uploading as assets/file-2.5938485188.txt...
783
+ ↗️ Done syncing assets
643
784
  Uploaded test-name (TIMINGS)
644
785
  Published test-name (TIMINGS)
645
786
  test-name.test-sub-domain.workers.dev"
@@ -689,6 +830,7 @@ export default{
689
830
  uploading as assets/file-1.2ca234f380.txt...
690
831
  reading assets/file-2.txt...
691
832
  uploading as assets/file-2.5938485188.txt...
833
+ ↗️ Done syncing assets
692
834
  Uploaded test-name (TIMINGS)
693
835
  Published test-name (TIMINGS)
694
836
  test-name.test-sub-domain.workers.dev"
@@ -711,6 +853,7 @@ export default{
711
853
  site: {
712
854
  bucket: "assets",
713
855
  },
856
+ env: { "some-env": {} },
714
857
  });
715
858
  writeWorkerSource();
716
859
  writeAssets(assets);
@@ -735,6 +878,7 @@ export default{
735
878
  uploading as assets/file-1.2ca234f380.txt...
736
879
  reading assets/file-2.txt...
737
880
  uploading as assets/file-2.5938485188.txt...
881
+ ↗️ Done syncing assets
738
882
  Uploaded test-name (some-env) (TIMINGS)
739
883
  Published test-name (some-env) (TIMINGS)
740
884
  some-env.test-name.test-sub-domain.workers.dev"
@@ -757,6 +901,7 @@ export default{
757
901
  site: {
758
902
  bucket: "assets",
759
903
  },
904
+ env: { "some-env": {} },
760
905
  });
761
906
  writeWorkerSource();
762
907
  writeAssets(assets);
@@ -782,6 +927,7 @@ export default{
782
927
  uploading as assets/file-1.2ca234f380.txt...
783
928
  reading assets/file-2.txt...
784
929
  uploading as assets/file-2.5938485188.txt...
930
+ ↗️ Done syncing assets
785
931
  Uploaded test-name-some-env (TIMINGS)
786
932
  Published test-name-some-env (TIMINGS)
787
933
  test-name-some-env.test-sub-domain.workers.dev"
@@ -810,7 +956,9 @@ export default{
810
956
  mockSubDomainRequest();
811
957
  mockListKVNamespacesRequest(kvNamespace);
812
958
  // Put file-1 in the KV namespace
813
- mockKeyListRequest(kvNamespace.id, ["assets/file-1.2ca234f380.txt"]);
959
+ mockKeyListRequest(kvNamespace.id, [
960
+ { name: "assets/file-1.2ca234f380.txt" },
961
+ ]);
814
962
  // Check we do not upload file-1
815
963
  mockUploadAssetsToKVRequest(
816
964
  kvNamespace.id,
@@ -823,6 +971,7 @@ export default{
823
971
  skipping - already uploaded
824
972
  reading assets/file-2.txt...
825
973
  uploading as assets/file-2.5938485188.txt...
974
+ ↗️ Done syncing assets
826
975
  Uploaded test-name (TIMINGS)
827
976
  Published test-name (TIMINGS)
828
977
  test-name.test-sub-domain.workers.dev"
@@ -861,6 +1010,7 @@ export default{
861
1010
  expect(std.out).toMatchInlineSnapshot(`
862
1011
  "reading assets/file-1.txt...
863
1012
  uploading as assets/file-1.2ca234f380.txt...
1013
+ ↗️ Done syncing assets
864
1014
  Uploaded test-name (TIMINGS)
865
1015
  Published test-name (TIMINGS)
866
1016
  test-name.test-sub-domain.workers.dev"
@@ -899,6 +1049,7 @@ export default{
899
1049
  expect(std.out).toMatchInlineSnapshot(`
900
1050
  "reading assets/file-1.txt...
901
1051
  uploading as assets/file-1.2ca234f380.txt...
1052
+ ↗️ Done syncing assets
902
1053
  Uploaded test-name (TIMINGS)
903
1054
  Published test-name (TIMINGS)
904
1055
  test-name.test-sub-domain.workers.dev"
@@ -938,6 +1089,7 @@ export default{
938
1089
  expect(std.out).toMatchInlineSnapshot(`
939
1090
  "reading assets/file-1.txt...
940
1091
  uploading as assets/file-1.2ca234f380.txt...
1092
+ ↗️ Done syncing assets
941
1093
  Uploaded test-name (TIMINGS)
942
1094
  Published test-name (TIMINGS)
943
1095
  test-name.test-sub-domain.workers.dev"
@@ -977,6 +1129,7 @@ export default{
977
1129
  expect(std.out).toMatchInlineSnapshot(`
978
1130
  "reading assets/file-1.txt...
979
1131
  uploading as assets/file-1.2ca234f380.txt...
1132
+ ↗️ Done syncing assets
980
1133
  Uploaded test-name (TIMINGS)
981
1134
  Published test-name (TIMINGS)
982
1135
  test-name.test-sub-domain.workers.dev"
@@ -1016,6 +1169,7 @@ export default{
1016
1169
  expect(std.out).toMatchInlineSnapshot(`
1017
1170
  "reading assets/file-1.txt...
1018
1171
  uploading as assets/file-1.2ca234f380.txt...
1172
+ ↗️ Done syncing assets
1019
1173
  Uploaded test-name (TIMINGS)
1020
1174
  Published test-name (TIMINGS)
1021
1175
  test-name.test-sub-domain.workers.dev"
@@ -1055,6 +1209,7 @@ export default{
1055
1209
  expect(std.out).toMatchInlineSnapshot(`
1056
1210
  "reading assets/file-1.txt...
1057
1211
  uploading as assets/file-1.2ca234f380.txt...
1212
+ ↗️ Done syncing assets
1058
1213
  Uploaded test-name (TIMINGS)
1059
1214
  Published test-name (TIMINGS)
1060
1215
  test-name.test-sub-domain.workers.dev"
@@ -1096,6 +1251,7 @@ export default{
1096
1251
  expect(std.out).toMatchInlineSnapshot(`
1097
1252
  "reading assets/directory-1/file-1.txt...
1098
1253
  uploading as assets/directory-1/file-1.2ca234f380.txt...
1254
+ ↗️ Done syncing assets
1099
1255
  Uploaded test-name (TIMINGS)
1100
1256
  Published test-name (TIMINGS)
1101
1257
  test-name.test-sub-domain.workers.dev"
@@ -1141,6 +1297,7 @@ export default{
1141
1297
  expect(std.out).toMatchInlineSnapshot(`
1142
1298
  "reading assets/.well-known/file-2.txt...
1143
1299
  uploading as assets/.well-known/file-2.5938485188.txt...
1300
+ ↗️ Done syncing assets
1144
1301
  Uploaded test-name (TIMINGS)
1145
1302
  Published test-name (TIMINGS)
1146
1303
  test-name.test-sub-domain.workers.dev"
@@ -1232,6 +1389,62 @@ export default{
1232
1389
  %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1233
1390
  `);
1234
1391
  });
1392
+
1393
+ it("should delete uploaded assets that aren't included anymore", async () => {
1394
+ const assets = [
1395
+ { filePath: "assets/file-1.txt", content: "Content of file-1" },
1396
+ { filePath: "assets/file-2.txt", content: "Content of file-2" },
1397
+ ];
1398
+ const kvNamespace = {
1399
+ title: "__test-name-workers_sites_assets",
1400
+ id: "__test-name-workers_sites_assets-id",
1401
+ };
1402
+ writeWranglerToml({
1403
+ main: "./index.js",
1404
+ site: {
1405
+ bucket: "assets",
1406
+ },
1407
+ });
1408
+ writeWorkerSource();
1409
+ writeAssets(assets);
1410
+ mockUploadWorkerRequest();
1411
+ mockSubDomainRequest();
1412
+ mockListKVNamespacesRequest(kvNamespace);
1413
+ mockKeyListRequest(kvNamespace.id, [
1414
+ // Put file-1 in the KV namespace
1415
+ { name: "assets/file-1.2ca234f380.txt" },
1416
+ // As well as a couple from a previous upload
1417
+ { name: "assets/file-3.somehash.txt" },
1418
+ { name: "assets/file-4.anotherhash.txt" },
1419
+ ]);
1420
+
1421
+ // we upload only file-1.txt
1422
+ mockUploadAssetsToKVRequest(kvNamespace.id, [
1423
+ ...assets.filter((a) => a.filePath !== "assets/file-1.txt"),
1424
+ ]);
1425
+
1426
+ // and mark file-3 and file-4 for deletion
1427
+ mockDeleteUnusedAssetsRequest(kvNamespace.id, [
1428
+ "assets/file-3.somehash.txt",
1429
+ "assets/file-4.anotherhash.txt",
1430
+ ]);
1431
+
1432
+ await runWrangler("publish");
1433
+
1434
+ expect(std.out).toMatchInlineSnapshot(`
1435
+ "reading assets/file-1.txt...
1436
+ skipping - already uploaded
1437
+ reading assets/file-2.txt...
1438
+ uploading as assets/file-2.5938485188.txt...
1439
+ deleting assets/file-3.somehash.txt from the asset store...
1440
+ deleting assets/file-4.anotherhash.txt from the asset store...
1441
+ ↗️ Done syncing assets
1442
+ Uploaded test-name (TIMINGS)
1443
+ Published test-name (TIMINGS)
1444
+ test-name.test-sub-domain.workers.dev"
1445
+ `);
1446
+ expect(std.err).toMatchInlineSnapshot(`""`);
1447
+ });
1235
1448
  });
1236
1449
 
1237
1450
  describe("workers_dev setting", () => {
@@ -1522,442 +1735,1275 @@ export default{
1522
1735
  https://dash.cloudflare.com/some-account-id/workers/onboarding"
1523
1736
  `);
1524
1737
  });
1525
- });
1526
1738
 
1527
- describe("custom builds", () => {
1528
- beforeEach(() => {
1529
- // @ts-expect-error disable the mock we'd setup earlier
1530
- // or else custom builds will timeout immediately
1531
- global.setTimeout.mockRestore();
1532
- });
1533
- it("should run a custom build before publishing", async () => {
1739
+ it("should not deploy to workers.dev if there are any routes defined", async () => {
1534
1740
  writeWranglerToml({
1535
- build: {
1536
- command: `node -e "console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')"`,
1537
- },
1538
- });
1539
-
1540
- mockUploadWorkerRequest({
1541
- expectedEntry: "return new Response(123)",
1741
+ routes: ["http://example.com/*"],
1542
1742
  });
1743
+ writeWorkerSource();
1543
1744
  mockSubDomainRequest();
1544
-
1745
+ mockUploadWorkerRequest();
1746
+ mockUpdateWorkerRequest({
1747
+ enabled: false,
1748
+ });
1749
+ mockPublishRoutesRequest({ routes: ["http://example.com/*"] });
1545
1750
  await runWrangler("publish index.js");
1751
+
1546
1752
  expect(std.out).toMatchInlineSnapshot(`
1547
- "running: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
1548
- Uploaded test-name (TIMINGS)
1753
+ "Uploaded test-name (TIMINGS)
1549
1754
  Published test-name (TIMINGS)
1550
- test-name.test-sub-domain.workers.dev"
1755
+ http://example.com/*"
1551
1756
  `);
1552
1757
  expect(std.err).toMatchInlineSnapshot(`""`);
1553
1758
  expect(std.warn).toMatchInlineSnapshot(`""`);
1554
1759
  });
1555
1760
 
1556
- if (process.platform !== "win32") {
1557
- it("should run a custom build of multiple steps combined by && before publishing", async () => {
1558
- writeWranglerToml({
1559
- build: {
1560
- command: `echo "custom build" && echo "export default { fetch(){ return new Response(123) } }" > index.js`,
1761
+ it("should not deploy to workers.dev if there are any routes defined (environments)", async () => {
1762
+ writeWranglerToml({
1763
+ routes: ["http://example.com/*"],
1764
+ env: {
1765
+ production: {
1766
+ routes: ["http://production.example.com/*"],
1561
1767
  },
1562
- });
1563
-
1564
- mockUploadWorkerRequest({
1565
- expectedEntry: "return new Response(123)",
1566
- });
1567
- mockSubDomainRequest();
1568
-
1569
- await runWrangler("publish index.js");
1570
- expect(std.out).toMatchInlineSnapshot(`
1571
- "running: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
1572
- Uploaded test-name (TIMINGS)
1573
- Published test-name (TIMINGS)
1574
- test-name.test-sub-domain.workers.dev"
1575
- `);
1576
- expect(std.err).toMatchInlineSnapshot(`""`);
1577
- expect(std.warn).toMatchInlineSnapshot(`""`);
1768
+ },
1578
1769
  });
1579
- }
1770
+ writeWorkerSource();
1771
+ mockSubDomainRequest();
1772
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1773
+ mockUpdateWorkerRequest({
1774
+ enabled: false,
1775
+ env: "production",
1776
+ legacyEnv: true,
1777
+ });
1778
+ mockPublishRoutesRequest({
1779
+ routes: ["http://production.example.com/*"],
1780
+ env: "production",
1781
+ legacyEnv: true,
1782
+ });
1783
+ await runWrangler("publish index.js --env production");
1580
1784
 
1581
- it("should throw an error if the entry doesn't exist after the build finishes", async () => {
1785
+ expect(std.out).toMatchInlineSnapshot(`
1786
+ "Uploaded test-name-production (TIMINGS)
1787
+ Published test-name-production (TIMINGS)
1788
+ http://production.example.com/*"
1789
+ `);
1790
+ expect(std.err).toMatchInlineSnapshot(`""`);
1791
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1792
+ });
1793
+
1794
+ it("should not deploy to workers.dev if there are any routes defined (only in environments)", async () => {
1582
1795
  writeWranglerToml({
1583
- main: "index.js",
1584
- build: {
1585
- command: `node -e "console.log('custom build');"`,
1796
+ env: {
1797
+ production: {
1798
+ routes: ["http://production.example.com/*"],
1799
+ },
1586
1800
  },
1587
1801
  });
1802
+ writeWorkerSource();
1803
+ mockSubDomainRequest();
1804
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1805
+ mockUpdateWorkerRequest({
1806
+ enabled: false,
1807
+ env: "production",
1808
+ legacyEnv: true,
1809
+ });
1810
+ mockPublishRoutesRequest({
1811
+ routes: ["http://production.example.com/*"],
1812
+ env: "production",
1813
+ legacyEnv: true,
1814
+ });
1815
+ await runWrangler("publish index.js --env production");
1588
1816
 
1589
- await expect(
1590
- runWrangler("publish index.js")
1591
- ).rejects.toThrowErrorMatchingInlineSnapshot(
1592
- `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
1593
- );
1594
- expect(std.out).toMatchInlineSnapshot(
1595
- `"running: node -e \\"console.log('custom build');\\""`
1596
- );
1597
- expect(std.err).toMatchInlineSnapshot(`
1598
- "Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
1599
-
1600
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1817
+ expect(std.out).toMatchInlineSnapshot(`
1818
+ "Uploaded test-name-production (TIMINGS)
1819
+ Published test-name-production (TIMINGS)
1820
+ http://production.example.com/*"
1601
1821
  `);
1822
+ expect(std.err).toMatchInlineSnapshot(`""`);
1602
1823
  expect(std.warn).toMatchInlineSnapshot(`""`);
1603
1824
  });
1604
- });
1605
1825
 
1606
- describe("[wasm_modules]", () => {
1607
- it("should be able to define wasm modules for service-worker format workers", async () => {
1826
+ it("can deploy to both workers.dev and routes if both defined ", async () => {
1608
1827
  writeWranglerToml({
1609
- wasm_modules: {
1610
- TESTWASMNAME: "./path/to/test.wasm",
1611
- },
1612
- });
1613
- writeWorkerSource({ type: "sw" });
1614
- fs.mkdirSync("./path/to", { recursive: true });
1615
- fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
1616
- mockUploadWorkerRequest({
1617
- expectedType: "sw",
1618
- expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
1619
- expectedBindings: [
1620
- { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
1621
- ],
1828
+ workers_dev: true,
1829
+ routes: ["http://example.com/*"],
1622
1830
  });
1831
+ writeWorkerSource();
1623
1832
  mockSubDomainRequest();
1833
+ mockUploadWorkerRequest();
1834
+ mockUpdateWorkerRequest({
1835
+ enabled: false,
1836
+ });
1837
+ mockPublishRoutesRequest({
1838
+ routes: ["http://example.com/*"],
1839
+ });
1624
1840
  await runWrangler("publish index.js");
1841
+
1625
1842
  expect(std.out).toMatchInlineSnapshot(`
1626
1843
  "Uploaded test-name (TIMINGS)
1627
1844
  Published test-name (TIMINGS)
1628
- test-name.test-sub-domain.workers.dev"
1845
+ test-name.test-sub-domain.workers.dev
1846
+ http://example.com/*"
1629
1847
  `);
1630
1848
  expect(std.err).toMatchInlineSnapshot(`""`);
1631
1849
  expect(std.warn).toMatchInlineSnapshot(`""`);
1632
1850
  });
1633
1851
 
1634
- it("should error when defining wasm modules for modules format workers", async () => {
1852
+ it("can deploy to both workers.dev and routes if both defined (environments: 1)", async () => {
1635
1853
  writeWranglerToml({
1636
- wasm_modules: {
1637
- TESTWASMNAME: "./path/to/test.wasm",
1854
+ workers_dev: true,
1855
+ env: {
1856
+ production: {
1857
+ routes: ["http://production.example.com/*"],
1858
+ },
1638
1859
  },
1639
1860
  });
1640
- writeWorkerSource({ type: "esm" });
1641
- fs.mkdirSync("./path/to", { recursive: true });
1642
- fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
1643
-
1644
- await expect(
1645
- runWrangler("publish index.js")
1646
- ).rejects.toThrowErrorMatchingInlineSnapshot(
1647
- `"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"`
1648
- );
1649
- expect(std.out).toMatchInlineSnapshot(`""`);
1650
- expect(std.err).toMatchInlineSnapshot(`
1651
- "You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
1861
+ writeWorkerSource();
1862
+ mockSubDomainRequest();
1863
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1864
+ mockUpdateWorkerRequest({
1865
+ enabled: false,
1866
+ env: "production",
1867
+ legacyEnv: true,
1868
+ });
1869
+ mockPublishRoutesRequest({
1870
+ routes: ["http://production.example.com/*"],
1871
+ env: "production",
1872
+ legacyEnv: true,
1873
+ });
1874
+ await runWrangler("publish index.js --env production");
1652
1875
 
1653
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1876
+ expect(std.out).toMatchInlineSnapshot(`
1877
+ "Uploaded test-name-production (TIMINGS)
1878
+ Published test-name-production (TIMINGS)
1879
+ test-name-production.test-sub-domain.workers.dev
1880
+ http://production.example.com/*"
1654
1881
  `);
1882
+ expect(std.err).toMatchInlineSnapshot(`""`);
1655
1883
  expect(std.warn).toMatchInlineSnapshot(`""`);
1656
1884
  });
1657
1885
 
1658
- it("should resolve wasm modules relative to the wrangler.toml file", async () => {
1659
- fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
1660
- fs.writeFileSync(
1661
- "./path/to/wrangler.toml",
1662
- TOML.stringify({
1663
- compatibility_date: "2022-01-12",
1664
- name: "test-name",
1665
- wasm_modules: {
1666
- TESTWASMNAME: "./and/the/path/to/test.wasm",
1886
+ it("can deploy to both workers.dev and routes if both defined (environments: 2)", async () => {
1887
+ writeWranglerToml({
1888
+ env: {
1889
+ production: {
1890
+ workers_dev: true,
1891
+ routes: ["http://production.example.com/*"],
1667
1892
  },
1668
- }),
1669
-
1670
- "utf-8"
1671
- );
1672
-
1673
- writeWorkerSource({ type: "sw" });
1674
- fs.writeFileSync(
1675
- "./path/to/and/the/path/to/test.wasm",
1676
- "SOME WASM CONTENT"
1677
- );
1678
- mockUploadWorkerRequest({
1679
- expectedType: "sw",
1680
- expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
1681
- expectedBindings: [
1682
- { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
1683
- ],
1684
- expectedCompatibilityDate: "2022-01-12",
1893
+ },
1685
1894
  });
1895
+ writeWorkerSource();
1686
1896
  mockSubDomainRequest();
1687
- await runWrangler("publish index.js --config ./path/to/wrangler.toml");
1897
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1898
+ mockUpdateWorkerRequest({
1899
+ enabled: false,
1900
+ env: "production",
1901
+ legacyEnv: true,
1902
+ });
1903
+ mockPublishRoutesRequest({
1904
+ routes: ["http://production.example.com/*"],
1905
+ env: "production",
1906
+ legacyEnv: true,
1907
+ });
1908
+ await runWrangler("publish index.js --env production");
1909
+
1688
1910
  expect(std.out).toMatchInlineSnapshot(`
1689
- "Uploaded test-name (TIMINGS)
1690
- Published test-name (TIMINGS)
1691
- test-name.test-sub-domain.workers.dev"
1911
+ "Uploaded test-name-production (TIMINGS)
1912
+ Published test-name-production (TIMINGS)
1913
+ test-name-production.test-sub-domain.workers.dev
1914
+ http://production.example.com/*"
1692
1915
  `);
1693
1916
  expect(std.err).toMatchInlineSnapshot(`""`);
1694
1917
  expect(std.warn).toMatchInlineSnapshot(`""`);
1695
1918
  });
1696
1919
 
1697
- it("should be able to import .wasm modules from service-worker format workers", async () => {
1698
- writeWranglerToml();
1699
- fs.writeFileSync("./index.js", "import TESTWASMNAME from './test.wasm';");
1700
- fs.writeFileSync("./test.wasm", "SOME WASM CONTENT");
1701
- mockUploadWorkerRequest({
1702
- expectedType: "sw",
1703
- expectedModules: {
1704
- __94b240d0d692281e6467aa42043986e5c7eea034_test_wasm:
1705
- "SOME WASM CONTENT",
1920
+ it("will deploy only to routes when workers_dev is false (environments 1) ", async () => {
1921
+ writeWranglerToml({
1922
+ workers_dev: false,
1923
+ env: {
1924
+ production: {
1925
+ routes: ["http://production.example.com/*"],
1926
+ },
1706
1927
  },
1707
- expectedBindings: [
1708
- {
1709
- name: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
1710
- part: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
1711
- type: "wasm_module",
1928
+ });
1929
+ writeWorkerSource();
1930
+ mockSubDomainRequest();
1931
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1932
+ mockUpdateWorkerRequest({
1933
+ enabled: false,
1934
+ env: "production",
1935
+ legacyEnv: true,
1936
+ });
1937
+ mockPublishRoutesRequest({
1938
+ routes: ["http://production.example.com/*"],
1939
+ env: "production",
1940
+ legacyEnv: true,
1941
+ });
1942
+ await runWrangler("publish index.js --env production");
1943
+
1944
+ expect(std.out).toMatchInlineSnapshot(`
1945
+ "Uploaded test-name-production (TIMINGS)
1946
+ Published test-name-production (TIMINGS)
1947
+ http://production.example.com/*"
1948
+ `);
1949
+ expect(std.err).toMatchInlineSnapshot(`""`);
1950
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1951
+ });
1952
+
1953
+ it("will deploy only to routes when workers_dev is false (environments 2) ", async () => {
1954
+ writeWranglerToml({
1955
+ env: {
1956
+ production: {
1957
+ workers_dev: false,
1958
+ routes: ["http://production.example.com/*"],
1712
1959
  },
1713
- ],
1960
+ },
1961
+ });
1962
+ writeWorkerSource();
1963
+ mockSubDomainRequest();
1964
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
1965
+ mockUpdateWorkerRequest({
1966
+ enabled: false,
1967
+ env: "production",
1968
+ legacyEnv: true,
1969
+ });
1970
+ mockPublishRoutesRequest({
1971
+ routes: ["http://production.example.com/*"],
1972
+ env: "production",
1973
+ legacyEnv: true,
1974
+ });
1975
+ await runWrangler("publish index.js --env production");
1976
+
1977
+ expect(std.out).toMatchInlineSnapshot(`
1978
+ "Uploaded test-name-production (TIMINGS)
1979
+ Published test-name-production (TIMINGS)
1980
+ http://production.example.com/*"
1981
+ `);
1982
+ expect(std.err).toMatchInlineSnapshot(`""`);
1983
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1984
+ });
1985
+ });
1986
+
1987
+ describe("custom builds", () => {
1988
+ beforeEach(() => {
1989
+ // @ts-expect-error disable the mock we'd setup earlier
1990
+ // or else custom builds will timeout immediately
1991
+ global.setTimeout.mockRestore();
1992
+ });
1993
+ it("should run a custom build before publishing", async () => {
1994
+ writeWranglerToml({
1995
+ build: {
1996
+ command: `node -e "console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')"`,
1997
+ },
1998
+ });
1999
+
2000
+ mockUploadWorkerRequest({
2001
+ expectedEntry: "return new Response(123)",
1714
2002
  });
1715
2003
  mockSubDomainRequest();
2004
+
1716
2005
  await runWrangler("publish index.js");
1717
2006
  expect(std.out).toMatchInlineSnapshot(`
1718
- "Uploaded test-name (TIMINGS)
2007
+ "running: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
2008
+ Uploaded test-name (TIMINGS)
1719
2009
  Published test-name (TIMINGS)
1720
2010
  test-name.test-sub-domain.workers.dev"
1721
2011
  `);
1722
2012
  expect(std.err).toMatchInlineSnapshot(`""`);
1723
2013
  expect(std.warn).toMatchInlineSnapshot(`""`);
1724
2014
  });
2015
+
2016
+ if (process.platform !== "win32") {
2017
+ it("should run a custom build of multiple steps combined by && before publishing", async () => {
2018
+ writeWranglerToml({
2019
+ build: {
2020
+ command: `echo "custom build" && echo "export default { fetch(){ return new Response(123) } }" > index.js`,
2021
+ },
2022
+ });
2023
+
2024
+ mockUploadWorkerRequest({
2025
+ expectedEntry: "return new Response(123)",
2026
+ });
2027
+ mockSubDomainRequest();
2028
+
2029
+ await runWrangler("publish index.js");
2030
+ expect(std.out).toMatchInlineSnapshot(`
2031
+ "running: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
2032
+ Uploaded test-name (TIMINGS)
2033
+ Published test-name (TIMINGS)
2034
+ test-name.test-sub-domain.workers.dev"
2035
+ `);
2036
+ expect(std.err).toMatchInlineSnapshot(`""`);
2037
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2038
+ });
2039
+ }
2040
+
2041
+ it("should throw an error if the entry doesn't exist after the build finishes", async () => {
2042
+ writeWranglerToml({
2043
+ main: "index.js",
2044
+ build: {
2045
+ command: `node -e "console.log('custom build');"`,
2046
+ },
2047
+ });
2048
+
2049
+ await expect(
2050
+ runWrangler("publish index.js")
2051
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
2052
+ `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
2053
+ );
2054
+ expect(std.out).toMatchInlineSnapshot(
2055
+ `"running: node -e \\"console.log('custom build');\\""`
2056
+ );
2057
+ expect(std.err).toMatchInlineSnapshot(`
2058
+ "Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
2059
+
2060
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2061
+ `);
2062
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2063
+ });
1725
2064
  });
1726
2065
 
1727
- describe("[text_blobs]", () => {
1728
- it("should be able to define text blobs for service-worker format workers", async () => {
2066
+ describe("bindings", () => {
2067
+ it("should allow bindings with different names", async () => {
1729
2068
  writeWranglerToml({
2069
+ durable_objects: {
2070
+ bindings: [
2071
+ {
2072
+ name: "DURABLE_OBJECT_ONE",
2073
+ class_name: "SomeDurableObject",
2074
+ script_name: "some-durable-object-worker",
2075
+ },
2076
+ {
2077
+ name: "DURABLE_OBJECT_TWO",
2078
+ class_name: "AnotherDurableObject",
2079
+ script_name: "another-durable-object-worker",
2080
+ },
2081
+ ],
2082
+ },
2083
+ kv_namespaces: [
2084
+ { binding: "KV_NAMESPACE_ONE", id: "kv-ns-one-id" },
2085
+ { binding: "KV_NAMESPACE_TWO", id: "kv-ns-two-id" },
2086
+ ],
2087
+ r2_buckets: [
2088
+ { binding: "R2_BUCKET_ONE", bucket_name: "r2-bucket-one-name" },
2089
+ { binding: "R2_BUCKET_TWO", bucket_name: "r2-bucket-two-name" },
2090
+ ],
1730
2091
  text_blobs: {
1731
- TESTTEXTBLOBNAME: "./path/to/text.file",
2092
+ TEXT_BLOB_ONE: "./my-entire-app-depends-on-this.cfg",
2093
+ TEXT_BLOB_TWO: "./the-entirety-of-human-knowledge.txt",
2094
+ },
2095
+ unsafe: {
2096
+ bindings: [
2097
+ {
2098
+ name: "UNSAFE_BINDING_ONE",
2099
+ type: "some unsafe thing",
2100
+ data: { some: { unsafe: "thing" } },
2101
+ },
2102
+ {
2103
+ name: "UNSAFE_BINDING_TWO",
2104
+ type: "another unsafe thing",
2105
+ data: 1337,
2106
+ },
2107
+ ],
2108
+ },
2109
+ vars: {
2110
+ ENV_VAR_ONE: 123,
2111
+ ENV_VAR_TWO: "Hello, I'm an environment variable",
2112
+ },
2113
+ wasm_modules: {
2114
+ WASM_MODULE_ONE: "./some_wasm.wasm",
2115
+ WASM_MODULE_TWO: "./more_wasm.wasm",
1732
2116
  },
1733
2117
  });
2118
+
1734
2119
  writeWorkerSource({ type: "sw" });
1735
- fs.mkdirSync("./path/to", { recursive: true });
1736
- fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
2120
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
2121
+ fs.writeFileSync(
2122
+ "./the-entirety-of-human-knowledge.txt",
2123
+ "Everything's bigger in Texas"
2124
+ );
2125
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
2126
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
2127
+
1737
2128
  mockUploadWorkerRequest({
1738
2129
  expectedType: "sw",
1739
- expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
1740
2130
  expectedBindings: [
1741
2131
  {
1742
- name: "TESTTEXTBLOBNAME",
1743
- part: "TESTTEXTBLOBNAME",
1744
- type: "text_blob",
2132
+ name: "KV_NAMESPACE_ONE",
2133
+ namespace_id: "kv-ns-one-id",
2134
+ type: "kv_namespace",
2135
+ },
2136
+ {
2137
+ name: "KV_NAMESPACE_TWO",
2138
+ namespace_id: "kv-ns-two-id",
2139
+ type: "kv_namespace",
2140
+ },
2141
+ {
2142
+ class_name: "SomeDurableObject",
2143
+ name: "DURABLE_OBJECT_ONE",
2144
+ script_name: "some-durable-object-worker",
2145
+ type: "durable_object_namespace",
2146
+ },
2147
+ {
2148
+ class_name: "AnotherDurableObject",
2149
+ name: "DURABLE_OBJECT_TWO",
2150
+ script_name: "another-durable-object-worker",
2151
+ type: "durable_object_namespace",
2152
+ },
2153
+ {
2154
+ bucket_name: "r2-bucket-one-name",
2155
+ name: "R2_BUCKET_ONE",
2156
+ type: "r2_bucket",
2157
+ },
2158
+ {
2159
+ bucket_name: "r2-bucket-two-name",
2160
+ name: "R2_BUCKET_TWO",
2161
+ type: "r2_bucket",
2162
+ },
2163
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
2164
+ {
2165
+ name: "ENV_VAR_TWO",
2166
+ text: "Hello, I'm an environment variable",
2167
+ type: "plain_text",
2168
+ },
2169
+ {
2170
+ name: "WASM_MODULE_ONE",
2171
+ part: "WASM_MODULE_ONE",
2172
+ type: "wasm_module",
2173
+ },
2174
+ {
2175
+ name: "WASM_MODULE_TWO",
2176
+ part: "WASM_MODULE_TWO",
2177
+ type: "wasm_module",
2178
+ },
2179
+ { name: "TEXT_BLOB_ONE", part: "TEXT_BLOB_ONE", type: "text_blob" },
2180
+ { name: "TEXT_BLOB_TWO", part: "TEXT_BLOB_TWO", type: "text_blob" },
2181
+ {
2182
+ data: { some: { unsafe: "thing" } },
2183
+ name: "UNSAFE_BINDING_ONE",
2184
+ type: "some unsafe thing",
2185
+ },
2186
+ {
2187
+ data: 1337,
2188
+ name: "UNSAFE_BINDING_TWO",
2189
+ type: "another unsafe thing",
1745
2190
  },
1746
2191
  ],
1747
2192
  });
1748
2193
  mockSubDomainRequest();
1749
- await runWrangler("publish index.js");
2194
+
2195
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
1750
2196
  expect(std.out).toMatchInlineSnapshot(`
1751
2197
  "Uploaded test-name (TIMINGS)
1752
2198
  Published test-name (TIMINGS)
1753
2199
  test-name.test-sub-domain.workers.dev"
1754
2200
  `);
1755
2201
  expect(std.err).toMatchInlineSnapshot(`""`);
1756
- expect(std.warn).toMatchInlineSnapshot(`""`);
2202
+ expect(std.warn).toMatchInlineSnapshot(`
2203
+ "Processing wrangler.toml configuration:
2204
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2205
+ `);
1757
2206
  });
1758
2207
 
1759
- it("should error when defining text blobs for modules format workers", async () => {
1760
- writeWranglerToml({
1761
- text_blobs: {
1762
- TESTTEXTBLOBNAME: "./path/to/text.file",
1763
- },
2208
+ it("should error when bindings of different types have the same name", async () => {
2209
+ writeWranglerToml({
2210
+ durable_objects: {
2211
+ bindings: [
2212
+ {
2213
+ name: "CONFLICTING_NAME_ONE",
2214
+ class_name: "SomeDurableObject",
2215
+ script_name: "some-durable-object-worker",
2216
+ },
2217
+ {
2218
+ name: "CONFLICTING_NAME_TWO",
2219
+ class_name: "AnotherDurableObject",
2220
+ script_name: "another-durable-object-worker",
2221
+ },
2222
+ ],
2223
+ },
2224
+ kv_namespaces: [
2225
+ { binding: "CONFLICTING_NAME_ONE", id: "kv-ns-one-id" },
2226
+ { binding: "CONFLICTING_NAME_TWO", id: "kv-ns-two-id" },
2227
+ ],
2228
+ r2_buckets: [
2229
+ {
2230
+ binding: "CONFLICTING_NAME_ONE",
2231
+ bucket_name: "r2-bucket-one-name",
2232
+ },
2233
+ {
2234
+ binding: "CONFLICTING_NAME_THREE",
2235
+ bucket_name: "r2-bucket-two-name",
2236
+ },
2237
+ ],
2238
+ text_blobs: {
2239
+ CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
2240
+ CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
2241
+ },
2242
+ unsafe: {
2243
+ bindings: [
2244
+ {
2245
+ name: "CONFLICTING_NAME_THREE",
2246
+ type: "some unsafe thing",
2247
+ data: { some: { unsafe: "thing" } },
2248
+ },
2249
+ {
2250
+ name: "CONFLICTING_NAME_FOUR",
2251
+ type: "another unsafe thing",
2252
+ data: 1337,
2253
+ },
2254
+ ],
2255
+ },
2256
+ vars: {
2257
+ ENV_VAR_ONE: 123,
2258
+ CONFLICTING_NAME_THREE: "Hello, I'm an environment variable",
2259
+ },
2260
+ wasm_modules: {
2261
+ WASM_MODULE_ONE: "./some_wasm.wasm",
2262
+ CONFLICTING_NAME_THREE: "./more_wasm.wasm",
2263
+ },
2264
+ });
2265
+
2266
+ writeWorkerSource({ type: "sw" });
2267
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
2268
+ fs.writeFileSync(
2269
+ "./the-entirety-of-human-knowledge.txt",
2270
+ "Everything's bigger in Texas"
2271
+ );
2272
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
2273
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
2274
+
2275
+ await expect(runWrangler("publish index.js")).rejects
2276
+ .toMatchInlineSnapshot(`
2277
+ [Error: Processing wrangler.toml configuration:
2278
+ - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
2279
+ - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
2280
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, and WASM Module bindings.
2281
+ - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
2282
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2283
+ Please change your bindings to have unique names.]
2284
+ `);
2285
+ expect(std.out).toMatchInlineSnapshot(`""`);
2286
+ expect(std.err).toMatchInlineSnapshot(`
2287
+ "Processing wrangler.toml configuration:
2288
+ - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
2289
+ - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
2290
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, and WASM Module bindings.
2291
+ - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
2292
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2293
+ Please change your bindings to have unique names.
2294
+
2295
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2296
+ `);
2297
+ expect(std.warn).toMatchInlineSnapshot(`
2298
+ "Processing wrangler.toml configuration:
2299
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2300
+ `);
2301
+ });
2302
+
2303
+ it("should error when bindings of the same type have the same name", async () => {
2304
+ writeWranglerToml({
2305
+ durable_objects: {
2306
+ bindings: [
2307
+ {
2308
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
2309
+ class_name: "SomeDurableObject",
2310
+ script_name: "some-durable-object-worker",
2311
+ },
2312
+ {
2313
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
2314
+ class_name: "AnotherDurableObject",
2315
+ script_name: "another-durable-object-worker",
2316
+ },
2317
+ ],
2318
+ },
2319
+ kv_namespaces: [
2320
+ { binding: "CONFLICTING_KV_NAMESPACE_NAME", id: "kv-ns-one-id" },
2321
+ { binding: "CONFLICTING_KV_NAMESPACE_NAME", id: "kv-ns-two-id" },
2322
+ ],
2323
+ r2_buckets: [
2324
+ {
2325
+ binding: "CONFLICTING_R2_BUCKET_NAME",
2326
+ bucket_name: "r2-bucket-one-name",
2327
+ },
2328
+ {
2329
+ binding: "CONFLICTING_R2_BUCKET_NAME",
2330
+ bucket_name: "r2-bucket-two-name",
2331
+ },
2332
+ ],
2333
+ unsafe: {
2334
+ bindings: [
2335
+ {
2336
+ name: "CONFLICTING_UNSAFE_NAME",
2337
+ type: "some unsafe thing",
2338
+ data: { some: { unsafe: "thing" } },
2339
+ },
2340
+ {
2341
+ name: "CONFLICTING_UNSAFE_NAME",
2342
+ type: "another unsafe thing",
2343
+ data: 1337,
2344
+ },
2345
+ ],
2346
+ },
2347
+ // text_blobs, vars, and wasm_modules are fine because they're object literals,
2348
+ // and by definition cannot have two keys of the same name
2349
+ //
2350
+ // text_blobs: {
2351
+ // CONFLICTING_TEXT_BLOB_NAME: "./my-entire-app-depends-on-this.cfg",
2352
+ // CONFLICTING_TEXT_BLOB_NAME: "./the-entirety-of-human-knowledge.txt",
2353
+ // },
2354
+ // vars: {
2355
+ // CONFLICTING_VARS_NAME: 123,
2356
+ // CONFLICTING_VARS_NAME: "Hello, I'm an environment variable",
2357
+ // },
2358
+ // wasm_modules: {
2359
+ // CONFLICTING_WASM_MODULE_NAME: "./some_wasm.wasm",
2360
+ // CONFLICTING_WASM_MODULE_NAME: "./more_wasm.wasm",
2361
+ // },
2362
+ });
2363
+
2364
+ writeWorkerSource({ type: "sw" });
2365
+
2366
+ await expect(runWrangler("publish index.js")).rejects
2367
+ .toMatchInlineSnapshot(`
2368
+ [Error: Processing wrangler.toml configuration:
2369
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
2370
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
2371
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
2372
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
2373
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2374
+ Please change your bindings to have unique names.]
2375
+ `);
2376
+ expect(std.out).toMatchInlineSnapshot(`""`);
2377
+ expect(std.err).toMatchInlineSnapshot(`
2378
+ "Processing wrangler.toml configuration:
2379
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
2380
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
2381
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
2382
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
2383
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2384
+ Please change your bindings to have unique names.
2385
+
2386
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2387
+ `);
2388
+ expect(std.warn).toMatchInlineSnapshot(`
2389
+ "Processing wrangler.toml configuration:
2390
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2391
+ `);
2392
+ });
2393
+
2394
+ it("should error correctly when bindings of the same and different types use the same name", async () => {
2395
+ writeWranglerToml({
2396
+ durable_objects: {
2397
+ bindings: [
2398
+ {
2399
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
2400
+ class_name: "SomeDurableObject",
2401
+ script_name: "some-durable-object-worker",
2402
+ },
2403
+ {
2404
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
2405
+ class_name: "AnotherDurableObject",
2406
+ script_name: "another-durable-object-worker",
2407
+ },
2408
+ ],
2409
+ },
2410
+ kv_namespaces: [
2411
+ {
2412
+ binding: "CONFLICTING_KV_NAMESPACE_NAME",
2413
+ id: "kv-ns-one-id",
2414
+ },
2415
+ {
2416
+ binding: "CONFLICTING_KV_NAMESPACE_NAME",
2417
+ id: "kv-ns-two-id",
2418
+ },
2419
+ { binding: "CONFLICTING_NAME_ONE", id: "kv-ns-three-id" },
2420
+ { binding: "CONFLICTING_NAME_TWO", id: "kv-ns-four-id" },
2421
+ ],
2422
+ r2_buckets: [
2423
+ {
2424
+ binding: "CONFLICTING_R2_BUCKET_NAME",
2425
+ bucket_name: "r2-bucket-one-name",
2426
+ },
2427
+ {
2428
+ binding: "CONFLICTING_R2_BUCKET_NAME",
2429
+ bucket_name: "r2-bucket-two-name",
2430
+ },
2431
+ {
2432
+ binding: "CONFLICTING_NAME_THREE",
2433
+ bucket_name: "r2-bucket-three-name",
2434
+ },
2435
+ {
2436
+ binding: "CONFLICTING_NAME_FOUR",
2437
+ bucket_name: "r2-bucket-four-name",
2438
+ },
2439
+ ],
2440
+ text_blobs: {
2441
+ CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
2442
+ CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
2443
+ },
2444
+ unsafe: {
2445
+ bindings: [
2446
+ {
2447
+ name: "CONFLICTING_UNSAFE_NAME",
2448
+ type: "some unsafe thing",
2449
+ data: { some: { unsafe: "thing" } },
2450
+ },
2451
+ {
2452
+ name: "CONFLICTING_UNSAFE_NAME",
2453
+ type: "another unsafe thing",
2454
+ data: 1337,
2455
+ },
2456
+ {
2457
+ name: "CONFLICTING_NAME_THREE",
2458
+ type: "yet another unsafe thing",
2459
+ data: "how is a string unsafe?",
2460
+ },
2461
+ {
2462
+ name: "CONFLICTING_NAME_FOUR",
2463
+ type: "a fourth unsafe thing",
2464
+ data: null,
2465
+ },
2466
+ ],
2467
+ },
2468
+ vars: {
2469
+ ENV_VAR_ONE: 123,
2470
+ CONFLICTING_NAME_THREE: "Hello, I'm an environment variable",
2471
+ },
2472
+ wasm_modules: {
2473
+ WASM_MODULE_ONE: "./some_wasm.wasm",
2474
+ CONFLICTING_NAME_THREE: "./more_wasm.wasm",
2475
+ },
2476
+ });
2477
+
2478
+ writeWorkerSource({ type: "sw" });
2479
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
2480
+ fs.writeFileSync(
2481
+ "./the-entirety-of-human-knowledge.txt",
2482
+ "Everything's bigger in Texas"
2483
+ );
2484
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
2485
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
2486
+
2487
+ await expect(runWrangler("publish index.js")).rejects
2488
+ .toMatchInlineSnapshot(`
2489
+ [Error: Processing wrangler.toml configuration:
2490
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
2491
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
2492
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
2493
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, and WASM Module bindings.
2494
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
2495
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
2496
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2497
+ Please change your bindings to have unique names.]
2498
+ `);
2499
+ expect(std.out).toMatchInlineSnapshot(`""`);
2500
+ expect(std.err).toMatchInlineSnapshot(`
2501
+ "Processing wrangler.toml configuration:
2502
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
2503
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
2504
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
2505
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, and WASM Module bindings.
2506
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
2507
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
2508
+ - Bindings must have unique names, so that they can all be referenced in the worker.
2509
+ Please change your bindings to have unique names.
2510
+
2511
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2512
+ `);
2513
+ expect(std.warn).toMatchInlineSnapshot(`
2514
+ "Processing wrangler.toml configuration:
2515
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2516
+ `);
2517
+ });
2518
+
2519
+ describe("[wasm_modules]", () => {
2520
+ it("should be able to define wasm modules for service-worker format workers", async () => {
2521
+ writeWranglerToml({
2522
+ wasm_modules: {
2523
+ TESTWASMNAME: "./path/to/test.wasm",
2524
+ },
2525
+ });
2526
+ writeWorkerSource({ type: "sw" });
2527
+ fs.mkdirSync("./path/to", { recursive: true });
2528
+ fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
2529
+ mockUploadWorkerRequest({
2530
+ expectedType: "sw",
2531
+ expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
2532
+ expectedBindings: [
2533
+ { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
2534
+ ],
2535
+ });
2536
+ mockSubDomainRequest();
2537
+ await runWrangler("publish index.js");
2538
+ expect(std.out).toMatchInlineSnapshot(`
2539
+ "Uploaded test-name (TIMINGS)
2540
+ Published test-name (TIMINGS)
2541
+ test-name.test-sub-domain.workers.dev"
2542
+ `);
2543
+ expect(std.err).toMatchInlineSnapshot(`""`);
2544
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2545
+ });
2546
+
2547
+ it("should error when defining wasm modules for modules format workers", async () => {
2548
+ writeWranglerToml({
2549
+ wasm_modules: {
2550
+ TESTWASMNAME: "./path/to/test.wasm",
2551
+ },
2552
+ });
2553
+ writeWorkerSource({ type: "esm" });
2554
+ fs.mkdirSync("./path/to", { recursive: true });
2555
+ fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
2556
+
2557
+ await expect(
2558
+ runWrangler("publish index.js")
2559
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
2560
+ `"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"`
2561
+ );
2562
+ expect(std.out).toMatchInlineSnapshot(`""`);
2563
+ expect(std.err).toMatchInlineSnapshot(`
2564
+ "You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
2565
+
2566
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2567
+ `);
2568
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2569
+ });
2570
+
2571
+ it("should resolve wasm modules relative to the wrangler.toml file", async () => {
2572
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
2573
+ fs.writeFileSync(
2574
+ "./path/to/wrangler.toml",
2575
+ TOML.stringify({
2576
+ compatibility_date: "2022-01-12",
2577
+ name: "test-name",
2578
+ wasm_modules: {
2579
+ TESTWASMNAME: "./and/the/path/to/test.wasm",
2580
+ },
2581
+ }),
2582
+
2583
+ "utf-8"
2584
+ );
2585
+
2586
+ writeWorkerSource({ type: "sw" });
2587
+ fs.writeFileSync(
2588
+ "./path/to/and/the/path/to/test.wasm",
2589
+ "SOME WASM CONTENT"
2590
+ );
2591
+ mockUploadWorkerRequest({
2592
+ expectedType: "sw",
2593
+ expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
2594
+ expectedBindings: [
2595
+ { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
2596
+ ],
2597
+ expectedCompatibilityDate: "2022-01-12",
2598
+ });
2599
+ mockSubDomainRequest();
2600
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
2601
+ expect(std.out).toMatchInlineSnapshot(`
2602
+ "Uploaded test-name (TIMINGS)
2603
+ Published test-name (TIMINGS)
2604
+ test-name.test-sub-domain.workers.dev"
2605
+ `);
2606
+ expect(std.err).toMatchInlineSnapshot(`""`);
2607
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2608
+ });
2609
+
2610
+ it("should be able to import .wasm modules from service-worker format workers", async () => {
2611
+ writeWranglerToml();
2612
+ fs.writeFileSync(
2613
+ "./index.js",
2614
+ "import TESTWASMNAME from './test.wasm';"
2615
+ );
2616
+ fs.writeFileSync("./test.wasm", "SOME WASM CONTENT");
2617
+ mockUploadWorkerRequest({
2618
+ expectedType: "sw",
2619
+ expectedModules: {
2620
+ __94b240d0d692281e6467aa42043986e5c7eea034_test_wasm:
2621
+ "SOME WASM CONTENT",
2622
+ },
2623
+ expectedBindings: [
2624
+ {
2625
+ name: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
2626
+ part: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
2627
+ type: "wasm_module",
2628
+ },
2629
+ ],
2630
+ });
2631
+ mockSubDomainRequest();
2632
+ await runWrangler("publish index.js");
2633
+ expect(std.out).toMatchInlineSnapshot(`
2634
+ "Uploaded test-name (TIMINGS)
2635
+ Published test-name (TIMINGS)
2636
+ test-name.test-sub-domain.workers.dev"
2637
+ `);
2638
+ expect(std.err).toMatchInlineSnapshot(`""`);
2639
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2640
+ });
2641
+ });
2642
+
2643
+ describe("[text_blobs]", () => {
2644
+ it("should be able to define text blobs for service-worker format workers", async () => {
2645
+ writeWranglerToml({
2646
+ text_blobs: {
2647
+ TESTTEXTBLOBNAME: "./path/to/text.file",
2648
+ },
2649
+ });
2650
+ writeWorkerSource({ type: "sw" });
2651
+ fs.mkdirSync("./path/to", { recursive: true });
2652
+ fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
2653
+ mockUploadWorkerRequest({
2654
+ expectedType: "sw",
2655
+ expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
2656
+ expectedBindings: [
2657
+ {
2658
+ name: "TESTTEXTBLOBNAME",
2659
+ part: "TESTTEXTBLOBNAME",
2660
+ type: "text_blob",
2661
+ },
2662
+ ],
2663
+ });
2664
+ mockSubDomainRequest();
2665
+ await runWrangler("publish index.js");
2666
+ expect(std.out).toMatchInlineSnapshot(`
2667
+ "Uploaded test-name (TIMINGS)
2668
+ Published test-name (TIMINGS)
2669
+ test-name.test-sub-domain.workers.dev"
2670
+ `);
2671
+ expect(std.err).toMatchInlineSnapshot(`""`);
2672
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2673
+ });
2674
+
2675
+ it("should error when defining text blobs for modules format workers", async () => {
2676
+ writeWranglerToml({
2677
+ text_blobs: {
2678
+ TESTTEXTBLOBNAME: "./path/to/text.file",
2679
+ },
2680
+ });
2681
+ writeWorkerSource({ type: "esm" });
2682
+ fs.mkdirSync("./path/to", { recursive: true });
2683
+ fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
2684
+
2685
+ await expect(
2686
+ runWrangler("publish index.js")
2687
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
2688
+ `"You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[build.upload.rules]\` in your wrangler.toml"`
2689
+ );
2690
+ expect(std.out).toMatchInlineSnapshot(`""`);
2691
+ expect(std.err).toMatchInlineSnapshot(`
2692
+ "You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[build.upload.rules]\` in your wrangler.toml
2693
+
2694
+ %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2695
+ `);
2696
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2697
+ });
2698
+
2699
+ it("should resolve text blobs relative to the wrangler.toml file", async () => {
2700
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
2701
+ fs.writeFileSync(
2702
+ "./path/to/wrangler.toml",
2703
+ TOML.stringify({
2704
+ compatibility_date: "2022-01-12",
2705
+ name: "test-name",
2706
+ text_blobs: {
2707
+ TESTTEXTBLOBNAME: "./and/the/path/to/text.file",
2708
+ },
2709
+ }),
2710
+
2711
+ "utf-8"
2712
+ );
2713
+
2714
+ writeWorkerSource({ type: "sw" });
2715
+ fs.writeFileSync(
2716
+ "./path/to/and/the/path/to/text.file",
2717
+ "SOME TEXT CONTENT"
2718
+ );
2719
+ mockUploadWorkerRequest({
2720
+ expectedType: "sw",
2721
+ expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
2722
+ expectedBindings: [
2723
+ {
2724
+ name: "TESTTEXTBLOBNAME",
2725
+ part: "TESTTEXTBLOBNAME",
2726
+ type: "text_blob",
2727
+ },
2728
+ ],
2729
+ expectedCompatibilityDate: "2022-01-12",
2730
+ });
2731
+ mockSubDomainRequest();
2732
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
2733
+ expect(std.out).toMatchInlineSnapshot(`
2734
+ "Uploaded test-name (TIMINGS)
2735
+ Published test-name (TIMINGS)
2736
+ test-name.test-sub-domain.workers.dev"
2737
+ `);
2738
+ expect(std.err).toMatchInlineSnapshot(`""`);
2739
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2740
+ });
2741
+ });
2742
+
2743
+ describe("[vars]", () => {
2744
+ it("should support json bindings", async () => {
2745
+ writeWranglerToml({
2746
+ vars: {
2747
+ text: "plain ol' string",
2748
+ count: 1,
2749
+ complex: { enabled: true, id: 123 },
2750
+ },
2751
+ });
2752
+ writeWorkerSource();
2753
+ mockSubDomainRequest();
2754
+ mockUploadWorkerRequest({
2755
+ expectedBindings: [
2756
+ { name: "text", type: "plain_text", text: "plain ol' string" },
2757
+ { name: "count", type: "json", json: 1 },
2758
+ {
2759
+ name: "complex",
2760
+ type: "json",
2761
+ json: { enabled: true, id: 123 },
2762
+ },
2763
+ ],
2764
+ });
2765
+
2766
+ await runWrangler("publish index.js");
2767
+ expect(std.out).toMatchInlineSnapshot(`
2768
+ "Uploaded test-name (TIMINGS)
2769
+ Published test-name (TIMINGS)
2770
+ test-name.test-sub-domain.workers.dev"
2771
+ `);
2772
+ expect(std.err).toMatchInlineSnapshot(`""`);
2773
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1764
2774
  });
1765
- writeWorkerSource({ type: "esm" });
1766
- fs.mkdirSync("./path/to", { recursive: true });
1767
- fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
2775
+ });
1768
2776
 
1769
- await expect(
1770
- runWrangler("publish index.js")
1771
- ).rejects.toThrowErrorMatchingInlineSnapshot(
1772
- `"You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[build.upload.rules]\` in your wrangler.toml"`
1773
- );
1774
- expect(std.out).toMatchInlineSnapshot(`""`);
1775
- expect(std.err).toMatchInlineSnapshot(`
1776
- "You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[build.upload.rules]\` in your wrangler.toml
2777
+ describe("[r2_buckets]", () => {
2778
+ it("should support r2 bucket bindings", async () => {
2779
+ writeWranglerToml({
2780
+ r2_buckets: [{ binding: "FOO", bucket_name: "foo-bucket" }],
2781
+ });
2782
+ writeWorkerSource();
2783
+ mockSubDomainRequest();
2784
+ mockUploadWorkerRequest({
2785
+ expectedBindings: [
2786
+ { bucket_name: "foo-bucket", name: "FOO", type: "r2_bucket" },
2787
+ ],
2788
+ });
1777
2789
 
1778
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1779
- `);
1780
- expect(std.warn).toMatchInlineSnapshot(`""`);
2790
+ await runWrangler("publish index.js");
2791
+ expect(std.out).toMatchInlineSnapshot(`
2792
+ "Uploaded test-name (TIMINGS)
2793
+ Published test-name (TIMINGS)
2794
+ test-name.test-sub-domain.workers.dev"
2795
+ `);
2796
+ expect(std.err).toMatchInlineSnapshot(`""`);
2797
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2798
+ });
1781
2799
  });
1782
2800
 
1783
- it("should resolve text blobs relative to the wrangler.toml file", async () => {
1784
- fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
1785
- fs.writeFileSync(
1786
- "./path/to/wrangler.toml",
1787
- TOML.stringify({
1788
- compatibility_date: "2022-01-12",
1789
- name: "test-name",
1790
- text_blobs: {
1791
- TESTTEXTBLOBNAME: "./and/the/path/to/text.file",
2801
+ describe("[durable_objects]", () => {
2802
+ it("should support durable object bindings", async () => {
2803
+ writeWranglerToml({
2804
+ durable_objects: {
2805
+ bindings: [
2806
+ {
2807
+ name: "EXAMPLE_DO_BINDING",
2808
+ class_name: "ExampleDurableObject",
2809
+ },
2810
+ ],
1792
2811
  },
1793
- }),
2812
+ });
2813
+ writeWorkerSource({ type: "esm" });
2814
+ mockSubDomainRequest();
2815
+ mockUploadWorkerRequest({
2816
+ expectedBindings: [
2817
+ {
2818
+ class_name: "ExampleDurableObject",
2819
+ name: "EXAMPLE_DO_BINDING",
2820
+ type: "durable_object_namespace",
2821
+ },
2822
+ ],
2823
+ });
1794
2824
 
1795
- "utf-8"
1796
- );
2825
+ await runWrangler("publish index.js");
2826
+ expect(std.out).toMatchInlineSnapshot(`
2827
+ "Uploaded test-name (TIMINGS)
2828
+ Published test-name (TIMINGS)
2829
+ test-name.test-sub-domain.workers.dev"
2830
+ `);
2831
+ expect(std.err).toMatchInlineSnapshot(`""`);
2832
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2833
+ });
1797
2834
 
1798
- writeWorkerSource({ type: "sw" });
1799
- fs.writeFileSync(
1800
- "./path/to/and/the/path/to/text.file",
1801
- "SOME TEXT CONTENT"
1802
- );
1803
- mockUploadWorkerRequest({
1804
- expectedType: "sw",
1805
- expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
1806
- expectedBindings: [
1807
- {
1808
- name: "TESTTEXTBLOBNAME",
1809
- part: "TESTTEXTBLOBNAME",
1810
- type: "text_blob",
2835
+ it("should support service-workers binding to external durable objects", async () => {
2836
+ writeWranglerToml({
2837
+ durable_objects: {
2838
+ bindings: [
2839
+ {
2840
+ name: "EXAMPLE_DO_BINDING",
2841
+ class_name: "ExampleDurableObject",
2842
+ script_name: "example-do-binding-worker",
2843
+ },
2844
+ ],
1811
2845
  },
1812
- ],
1813
- expectedCompatibilityDate: "2022-01-12",
1814
- });
1815
- mockSubDomainRequest();
1816
- await runWrangler("publish index.js --config ./path/to/wrangler.toml");
1817
- expect(std.out).toMatchInlineSnapshot(`
1818
- "Uploaded test-name (TIMINGS)
1819
- Published test-name (TIMINGS)
1820
- test-name.test-sub-domain.workers.dev"
1821
- `);
1822
- expect(std.err).toMatchInlineSnapshot(`""`);
1823
- expect(std.warn).toMatchInlineSnapshot(`""`);
1824
- });
1825
- });
2846
+ });
2847
+ writeWorkerSource({ type: "sw" });
2848
+ mockSubDomainRequest();
2849
+ mockUploadWorkerRequest({
2850
+ expectedType: "sw",
2851
+ expectedBindings: [
2852
+ {
2853
+ name: "EXAMPLE_DO_BINDING",
2854
+ class_name: "ExampleDurableObject",
2855
+ script_name: "example-do-binding-worker",
2856
+ type: "durable_object_namespace",
2857
+ },
2858
+ ],
2859
+ });
1826
2860
 
1827
- describe("vars bindings", () => {
1828
- it("should support json bindings", async () => {
1829
- writeWranglerToml({
1830
- vars: {
1831
- text: "plain ol' string",
1832
- count: 1,
1833
- complex: { enabled: true, id: 123 },
1834
- },
2861
+ await runWrangler("publish index.js");
2862
+ expect(std.out).toMatchInlineSnapshot(`
2863
+ "Uploaded test-name (TIMINGS)
2864
+ Published test-name (TIMINGS)
2865
+ test-name.test-sub-domain.workers.dev"
2866
+ `);
2867
+ expect(std.err).toMatchInlineSnapshot(`""`);
2868
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1835
2869
  });
1836
- writeWorkerSource();
1837
- mockSubDomainRequest();
1838
- mockUploadWorkerRequest({
1839
- expectedBindings: [
1840
- { name: "text", type: "plain_text", text: "plain ol' string" },
1841
- { name: "count", type: "json", json: 1 },
1842
- {
1843
- name: "complex",
1844
- type: "json",
1845
- json: { enabled: true, id: 123 },
2870
+
2871
+ it("should support module workers implementing durable objects", async () => {
2872
+ writeWranglerToml({
2873
+ durable_objects: {
2874
+ bindings: [
2875
+ {
2876
+ name: "EXAMPLE_DO_BINDING",
2877
+ class_name: "ExampleDurableObject",
2878
+ },
2879
+ ],
1846
2880
  },
1847
- ],
2881
+ });
2882
+ writeWorkerSource({ type: "esm" });
2883
+ mockSubDomainRequest();
2884
+ mockUploadWorkerRequest({
2885
+ expectedType: "esm",
2886
+ expectedBindings: [
2887
+ {
2888
+ name: "EXAMPLE_DO_BINDING",
2889
+ class_name: "ExampleDurableObject",
2890
+ type: "durable_object_namespace",
2891
+ },
2892
+ ],
2893
+ });
2894
+
2895
+ await runWrangler("publish index.js");
2896
+ expect(std.out).toMatchInlineSnapshot(`
2897
+ "Uploaded test-name (TIMINGS)
2898
+ Published test-name (TIMINGS)
2899
+ test-name.test-sub-domain.workers.dev"
2900
+ `);
2901
+ expect(std.err).toMatchInlineSnapshot(`""`);
2902
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1848
2903
  });
1849
2904
 
1850
- await runWrangler("publish index.js");
1851
- expect(std.out).toMatchInlineSnapshot(`
1852
- "Uploaded test-name (TIMINGS)
1853
- Published test-name (TIMINGS)
1854
- test-name.test-sub-domain.workers.dev"
1855
- `);
1856
- expect(std.err).toMatchInlineSnapshot(`""`);
1857
- expect(std.warn).toMatchInlineSnapshot(`""`);
1858
- });
1859
- });
2905
+ it("should error when detecting service workers implementing durable objects", async () => {
2906
+ writeWranglerToml({
2907
+ durable_objects: {
2908
+ bindings: [
2909
+ {
2910
+ name: "EXAMPLE_DO_BINDING",
2911
+ class_name: "ExampleDurableObject",
2912
+ },
2913
+ ],
2914
+ },
2915
+ });
2916
+ writeWorkerSource({ type: "sw" });
2917
+ mockSubDomainRequest();
1860
2918
 
1861
- describe("r2 bucket bindings", () => {
1862
- it("should support r2 bucket bindings", async () => {
1863
- writeWranglerToml({
1864
- r2_buckets: [{ binding: "FOO", bucket_name: "foo-bucket" }],
1865
- });
1866
- writeWorkerSource();
1867
- mockSubDomainRequest();
1868
- mockUploadWorkerRequest({
1869
- expectedBindings: [
1870
- { bucket_name: "foo-bucket", name: "FOO", type: "r2_bucket" },
1871
- ],
2919
+ await expect(runWrangler("publish index.js")).rejects
2920
+ .toThrowErrorMatchingInlineSnapshot(`
2921
+ "You seem to be trying to use Durable Objects in a Worker written with Service Worker syntax.
2922
+ You can use Durable Objects defined in other Workers by specifying a \`script_name\` in your wrangler.toml, where \`script_name\` is the name of the Worker that implements that Durable Object. For example:
2923
+ { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject } ==> { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject, script_name = example-do-binding-worker }
2924
+ Alternatively, migrate your worker to ES Module syntax to implement a Durable Object in this Worker:
2925
+ https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
2926
+ `);
1872
2927
  });
1873
-
1874
- await runWrangler("publish index.js");
1875
- expect(std.out).toMatchInlineSnapshot(`
1876
- "Uploaded test-name (TIMINGS)
1877
- Published test-name (TIMINGS)
1878
- test-name.test-sub-domain.workers.dev"
1879
- `);
1880
- expect(std.err).toMatchInlineSnapshot(`""`);
1881
- expect(std.warn).toMatchInlineSnapshot(`""`);
1882
2928
  });
1883
- });
1884
2929
 
1885
- describe("unsafe bindings", () => {
1886
- it("should warn if using unsafe bindings", async () => {
1887
- writeWranglerToml({
1888
- unsafe: {
1889
- bindings: [
2930
+ describe("[unsafe]", () => {
2931
+ it("should warn if using unsafe bindings", async () => {
2932
+ writeWranglerToml({
2933
+ unsafe: {
2934
+ bindings: [
2935
+ {
2936
+ name: "my-binding",
2937
+ type: "binding-type",
2938
+ param: "binding-param",
2939
+ },
2940
+ ],
2941
+ },
2942
+ });
2943
+ writeWorkerSource();
2944
+ mockSubDomainRequest();
2945
+ mockUploadWorkerRequest({
2946
+ expectedBindings: [
1890
2947
  {
1891
2948
  name: "my-binding",
1892
2949
  type: "binding-type",
1893
2950
  param: "binding-param",
1894
2951
  },
1895
2952
  ],
1896
- },
2953
+ });
2954
+
2955
+ await runWrangler("publish index.js");
2956
+ expect(std.out).toMatchInlineSnapshot(`
2957
+ "Uploaded test-name (TIMINGS)
2958
+ Published test-name (TIMINGS)
2959
+ test-name.test-sub-domain.workers.dev"
2960
+ `);
2961
+ expect(std.err).toMatchInlineSnapshot(`""`);
2962
+ expect(std.warn).toMatchInlineSnapshot(`
2963
+ "Processing wrangler.toml configuration:
2964
+ - \\"unsafe\\" fields are experimental and may change or break at any time."
2965
+ `);
1897
2966
  });
1898
- writeWorkerSource();
1899
- mockSubDomainRequest();
1900
- mockUploadWorkerRequest({
1901
- expectedBindings: [
1902
- {
1903
- name: "my-binding",
1904
- type: "binding-type",
1905
- param: "binding-param",
2967
+ it("should warn if using unsafe bindings already handled by wrangler", async () => {
2968
+ writeWranglerToml({
2969
+ unsafe: {
2970
+ bindings: [
2971
+ {
2972
+ name: "my-binding",
2973
+ type: "plain_text",
2974
+ text: "text",
2975
+ },
2976
+ ],
1906
2977
  },
1907
- ],
1908
- });
1909
-
1910
- await runWrangler("publish index.js");
1911
- expect(std.out).toMatchInlineSnapshot(`
1912
- "Uploaded test-name (TIMINGS)
1913
- Published test-name (TIMINGS)
1914
- test-name.test-sub-domain.workers.dev"
1915
- `);
1916
- expect(std.err).toMatchInlineSnapshot(`""`);
1917
- expect(std.warn).toMatchInlineSnapshot(`
1918
- "Processing wrangler.toml configuration:
1919
- - \\"unsafe\\" fields are experimental and may change or break at any time."
1920
- `);
1921
- });
1922
- it("should warn if using unsafe bindings already handled by wrangler", async () => {
1923
- writeWranglerToml({
1924
- unsafe: {
1925
- bindings: [
2978
+ });
2979
+ writeWorkerSource();
2980
+ mockSubDomainRequest();
2981
+ mockUploadWorkerRequest({
2982
+ expectedBindings: [
1926
2983
  {
1927
2984
  name: "my-binding",
1928
2985
  type: "plain_text",
1929
2986
  text: "text",
1930
2987
  },
1931
2988
  ],
1932
- },
1933
- });
1934
- writeWorkerSource();
1935
- mockSubDomainRequest();
1936
- mockUploadWorkerRequest({
1937
- expectedBindings: [
1938
- {
1939
- name: "my-binding",
1940
- type: "plain_text",
1941
- text: "text",
1942
- },
1943
- ],
1944
- });
2989
+ });
1945
2990
 
1946
- await runWrangler("publish index.js");
1947
- expect(std.out).toMatchInlineSnapshot(`
1948
- "Uploaded test-name (TIMINGS)
1949
- Published test-name (TIMINGS)
1950
- test-name.test-sub-domain.workers.dev"
1951
- `);
1952
- expect(std.err).toMatchInlineSnapshot(`""`);
1953
- expect(std.warn).toMatchInlineSnapshot(`
1954
- "Processing wrangler.toml configuration:
1955
- - \\"unsafe\\" fields are experimental and may change or break at any time.
1956
- - \\"unsafe.bindings[0]\\": {\\"name\\":\\"my-binding\\",\\"type\\":\\"plain_text\\",\\"text\\":\\"text\\"}
1957
- - The binding type \\"plain_text\\" is directly supported by wrangler.
1958
- Consider migrating this unsafe binding to a format for 'plain_text' bindings that is supported by wrangler for optimal support.
1959
- For more details, see https://developers.cloudflare.com/workers/cli-wrangler/configuration"
1960
- `);
2991
+ await runWrangler("publish index.js");
2992
+ expect(std.out).toMatchInlineSnapshot(`
2993
+ "Uploaded test-name (TIMINGS)
2994
+ Published test-name (TIMINGS)
2995
+ test-name.test-sub-domain.workers.dev"
2996
+ `);
2997
+ expect(std.err).toMatchInlineSnapshot(`""`);
2998
+ expect(std.warn).toMatchInlineSnapshot(`
2999
+ "Processing wrangler.toml configuration:
3000
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3001
+ - \\"unsafe.bindings[0]\\": {\\"name\\":\\"my-binding\\",\\"type\\":\\"plain_text\\",\\"text\\":\\"text\\"}
3002
+ - The binding type \\"plain_text\\" is directly supported by wrangler.
3003
+ Consider migrating this unsafe binding to a format for 'plain_text' bindings that is supported by wrangler for optimal support.
3004
+ For more details, see https://developers.cloudflare.com/workers/cli-wrangler/configuration"
3005
+ `);
3006
+ });
1961
3007
  });
1962
3008
  });
1963
3009
 
@@ -2154,6 +3200,40 @@ export default{
2154
3200
  The default module rule {\\"type\\":\\"Text\\",\\"globs\\":[\\"**/*.txt\\",\\"**/*.html\\"]} has the same type as a previous rule (at position 0, {\\"type\\":\\"Text\\",\\"globs\\":[\\"**/*.file\\"]}). This rule will be ignored. To the previous rule, add \`fallthrough = true\` to allow the default one to also be used, or \`fallthrough = false\` to silence this warning."
2155
3201
  `);
2156
3202
  });
3203
+
3204
+ describe("inject process.env.NODE_ENV", () => {
3205
+ let actualProcessEnvNodeEnv: string | undefined;
3206
+ beforeEach(() => {
3207
+ actualProcessEnvNodeEnv = process.env.NODE_ENV;
3208
+ process.env.NODE_ENV = "some-node-env";
3209
+ });
3210
+ afterEach(() => {
3211
+ process.env.NODE_ENV = actualProcessEnvNodeEnv;
3212
+ });
3213
+ it("should replace `process.env.NODE_ENV` in scripts", async () => {
3214
+ writeWranglerToml();
3215
+ fs.writeFileSync(
3216
+ "./index.js",
3217
+ `export default {
3218
+ fetch(){
3219
+ return new Response(process.env.NODE_ENV);
3220
+ }
3221
+ }`
3222
+ );
3223
+ mockSubDomainRequest();
3224
+ mockUploadWorkerRequest({
3225
+ expectedEntry: `return new Response("some-node-env");`,
3226
+ });
3227
+ await runWrangler("publish index.js");
3228
+ expect(std.out).toMatchInlineSnapshot(`
3229
+ "Uploaded test-name (TIMINGS)
3230
+ Published test-name (TIMINGS)
3231
+ test-name.test-sub-domain.workers.dev"
3232
+ `);
3233
+ expect(std.err).toMatchInlineSnapshot(`""`);
3234
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3235
+ });
3236
+ });
2157
3237
  });
2158
3238
 
2159
3239
  describe("legacy module specifiers", () => {
@@ -2211,6 +3291,30 @@ export default{
2211
3291
  `"Deprecation warning: detected a legacy module import in \\"./index.js\\". This will stop working in the future. Replace references to \\"index.wasm\\" with \\"./index.wasm\\";"`
2212
3292
  );
2213
3293
  });
3294
+
3295
+ it("should not match regular module specifiers when there aren't any possible legacy module matches", async () => {
3296
+ // see https://github.com/cloudflare/wrangler2/issues/655 for bug details
3297
+
3298
+ fs.writeFileSync(
3299
+ "./index.js",
3300
+ `import inner from './inner/index.js'; export default {};`
3301
+ );
3302
+ fs.mkdirSync("./inner", { recursive: true });
3303
+ fs.writeFileSync("./inner/index.js", `export default 123`);
3304
+ mockSubDomainRequest();
3305
+ mockUploadWorkerRequest();
3306
+
3307
+ await runWrangler(
3308
+ "publish index.js --compatibility-date 2022-03-17 --name test-name"
3309
+ );
3310
+ expect(std.out).toMatchInlineSnapshot(`
3311
+ "Uploaded test-name (TIMINGS)
3312
+ Published test-name (TIMINGS)
3313
+ test-name.test-sub-domain.workers.dev"
3314
+ `);
3315
+ expect(std.err).toMatchInlineSnapshot(`""`);
3316
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3317
+ });
2214
3318
  });
2215
3319
 
2216
3320
  /** Write a mock Worker script to disk. */
@@ -2417,7 +3521,12 @@ function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
2417
3521
  /** Create a mock handler for the request that tries to do a bulk upload of assets to a KV namespace. */
2418
3522
  function mockUploadAssetsToKVRequest(
2419
3523
  expectedNamespaceId: string,
2420
- assets: { filePath: string; content: string }[]
3524
+ assets: {
3525
+ filePath: string;
3526
+ content: string;
3527
+ expiration?: number;
3528
+ expiration_ttl?: number;
3529
+ }[]
2421
3530
  ) {
2422
3531
  setMockResponse(
2423
3532
  "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
@@ -2446,8 +3555,28 @@ function mockUploadAssetsToKVRequest(
2446
3555
  expect(Buffer.from(upload.value, "base64").toString()).toEqual(
2447
3556
  asset.content
2448
3557
  );
3558
+ expect(upload.expiration).toEqual(asset.expiration);
3559
+ expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
2449
3560
  }
2450
3561
  return null;
2451
3562
  }
2452
3563
  );
2453
3564
  }
3565
+
3566
+ /** Create a mock handler for thr request that does a bulk delete of unused assets */
3567
+ function mockDeleteUnusedAssetsRequest(
3568
+ expectedNamespaceId: string,
3569
+ assets: string[]
3570
+ ) {
3571
+ setMockResponse(
3572
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
3573
+ "DELETE",
3574
+ ([_url, accountId, namespaceId], { body }) => {
3575
+ expect(accountId).toEqual("some-account-id");
3576
+ expect(namespaceId).toEqual(expectedNamespaceId);
3577
+ const deletes = JSON.parse(body as string);
3578
+ expect(assets).toEqual(deletes);
3579
+ return null;
3580
+ }
3581
+ );
3582
+ }