wrangler 0.0.0-e043479 → 0.0.0-e0a0509

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 (96) hide show
  1. package/README.md +27 -14
  2. package/bin/wrangler.js +13 -1
  3. package/miniflare-dist/index.mjs +4886 -0
  4. package/package.json +38 -25
  5. package/pages/functions/buildPlugin.ts +92 -0
  6. package/pages/functions/buildWorker.ts +80 -4
  7. package/pages/functions/filepath-routing.test.ts +136 -25
  8. package/pages/functions/filepath-routing.ts +14 -3
  9. package/pages/functions/routes.ts +6 -1
  10. package/pages/functions/template-plugin.ts +146 -0
  11. package/pages/functions/template-worker.ts +21 -8
  12. package/src/__tests__/config-cache.test.ts +36 -0
  13. package/src/__tests__/configuration.test.ts +1294 -355
  14. package/src/__tests__/dev.test.tsx +592 -12
  15. package/src/__tests__/guess-worker-format.test.ts +37 -18
  16. package/src/__tests__/helpers/mock-account-id.ts +4 -0
  17. package/src/__tests__/helpers/mock-cfetch.ts +8 -4
  18. package/src/__tests__/helpers/mock-console.ts +20 -3
  19. package/src/__tests__/helpers/mock-dialogs.ts +26 -1
  20. package/src/__tests__/helpers/mock-http-server.ts +46 -0
  21. package/src/__tests__/helpers/mock-istty.ts +27 -0
  22. package/src/__tests__/helpers/mock-kv.ts +9 -16
  23. package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
  24. package/src/__tests__/helpers/run-in-tmp.ts +10 -0
  25. package/src/__tests__/helpers/write-worker-source.ts +31 -0
  26. package/src/__tests__/https-options.test.ts +130 -0
  27. package/src/__tests__/index.test.ts +129 -753
  28. package/src/__tests__/init.test.ts +1516 -0
  29. package/src/__tests__/jest.setup.ts +13 -5
  30. package/src/__tests__/kv.test.ts +208 -174
  31. package/src/__tests__/logger.test.ts +115 -0
  32. package/src/__tests__/pages.test.ts +327 -0
  33. package/src/__tests__/parse.test.ts +4 -0
  34. package/src/__tests__/publish.test.ts +3313 -505
  35. package/src/__tests__/r2.test.ts +38 -26
  36. package/src/__tests__/route.test.ts +45 -0
  37. package/src/__tests__/secret.test.ts +55 -34
  38. package/src/__tests__/tail.test.ts +146 -20
  39. package/src/__tests__/user.test.ts +131 -0
  40. package/src/__tests__/whoami.test.tsx +26 -7
  41. package/src/bundle.ts +43 -7
  42. package/src/cfetch/internal.ts +9 -5
  43. package/src/cli.ts +5 -11
  44. package/src/config/README.md +7 -7
  45. package/src/config/config.ts +69 -105
  46. package/src/config/environment.ts +93 -4
  47. package/src/config/index.ts +15 -4
  48. package/src/config/validation-helpers.ts +228 -23
  49. package/src/config/validation.ts +559 -154
  50. package/src/config-cache.ts +45 -0
  51. package/src/{api/preview.ts → create-worker-preview.ts} +41 -13
  52. package/src/{api/form_data.ts → create-worker-upload-form.ts} +33 -10
  53. package/src/dev/dev-vars.ts +36 -0
  54. package/src/dev/dev.tsx +418 -0
  55. package/src/dev/local.tsx +312 -0
  56. package/src/dev/remote.tsx +213 -0
  57. package/src/dev/use-esbuild.ts +118 -0
  58. package/src/dialogs.tsx +16 -6
  59. package/src/entry.ts +222 -12
  60. package/src/environment-variables.ts +3 -1
  61. package/src/errors.ts +11 -0
  62. package/src/https-options.ts +123 -0
  63. package/src/index.tsx +878 -482
  64. package/src/inspect.ts +25 -11
  65. package/src/intl-polyfill.d.ts +139 -0
  66. package/src/{kv.tsx → kv.ts} +7 -27
  67. package/src/logger.ts +66 -0
  68. package/src/miniflare-cli/README.md +30 -0
  69. package/src/miniflare-cli/enum-keys.ts +17 -0
  70. package/src/miniflare-cli/index.ts +41 -0
  71. package/src/miniflare-cli/request-context.ts +40 -0
  72. package/src/module-collection.ts +94 -6
  73. package/src/open-in-browser.ts +18 -5
  74. package/src/package-manager.ts +9 -8
  75. package/src/pages.tsx +892 -62
  76. package/src/parse.ts +4 -2
  77. package/src/proxy.ts +128 -55
  78. package/src/publish.ts +305 -199
  79. package/src/selfsigned.d.ts +29 -0
  80. package/src/sites.tsx +88 -33
  81. package/src/tail/index.ts +2 -2
  82. package/src/tail/printing.ts +13 -8
  83. package/src/update-check.ts +19 -0
  84. package/src/user.tsx +244 -104
  85. package/src/whoami.tsx +2 -1
  86. package/src/{api/worker.ts → worker.ts} +15 -29
  87. package/templates/gitignore +171 -0
  88. package/templates/static-asset-facade.js +1 -1
  89. package/wrangler-dist/cli.js +23568 -50489
  90. package/src/__tests__/helpers/mock-user.ts +0 -27
  91. package/src/__tests__/logout.test.ts +0 -50
  92. package/src/__tests__/sentry.test.ts +0 -146
  93. package/src/dev.tsx +0 -960
  94. package/src/guess-worker-format.ts +0 -68
  95. package/src/reporting.ts +0 -115
  96. package/wrangler-dist/cli.js.map +0 -7
@@ -1,37 +1,277 @@
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 * as esbuild from "esbuild";
5
+ import { writeAuthConfigFile } from "../user";
4
6
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
5
- import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
6
- import { mockConsoleMethods } from "./helpers/mock-console";
7
+ import {
8
+ createFetchResult,
9
+ setMockRawResponse,
10
+ setMockResponse,
11
+ unsetAllMocks,
12
+ unsetMockFetchKVGetValues,
13
+ } from "./helpers/mock-cfetch";
14
+ import { mockConsoleMethods, normalizeSlashes } from "./helpers/mock-console";
15
+ import { useMockIsTTY } from "./helpers/mock-istty";
7
16
  import { mockKeyListRequest } from "./helpers/mock-kv";
17
+ import { mockOAuthFlow } from "./helpers/mock-oauth-flow";
8
18
  import { runInTempDir } from "./helpers/run-in-tmp";
9
19
  import { runWrangler } from "./helpers/run-wrangler";
20
+ import { writeWorkerSource } from "./helpers/write-worker-source";
10
21
  import writeWranglerToml from "./helpers/write-wrangler-toml";
11
- import type { WorkerMetadata } from "../api/form_data";
12
22
  import type { Config } from "../config";
23
+ import type { WorkerMetadata } from "../create-worker-upload-form";
13
24
  import type { KVNamespaceInfo } from "../kv";
25
+ import type { CfWorkerInit } from "../worker";
14
26
  import type { FormData, File } from "undici";
15
27
 
16
28
  describe("publish", () => {
29
+ mockAccountId();
30
+ mockApiToken();
31
+ runInTempDir({ homedir: "./home" });
32
+ const { setIsTTY } = useMockIsTTY();
33
+ const std = mockConsoleMethods();
34
+ const {
35
+ mockOAuthServerCallback,
36
+ mockGrantAccessToken,
37
+ mockGrantAuthorization,
38
+ mockGetMemberships,
39
+ } = mockOAuthFlow();
40
+
17
41
  beforeEach(() => {
18
42
  // @ts-expect-error we're using a very simple setTimeout mock here
19
43
  jest.spyOn(global, "setTimeout").mockImplementation((fn, _period) => {
20
- fn();
44
+ setImmediate(fn);
21
45
  });
46
+ setIsTTY(true);
22
47
  });
23
- mockAccountId();
24
- mockApiToken();
25
- runInTempDir();
26
- const std = mockConsoleMethods();
27
48
 
28
49
  afterEach(() => {
29
50
  unsetAllMocks();
51
+ unsetMockFetchKVGetValues();
52
+ });
53
+
54
+ describe("authentication", () => {
55
+ mockApiToken({ apiToken: null });
56
+ beforeEach(() => {
57
+ // @ts-expect-error disable the mock we'd setup earlier
58
+ // or else our server won't bother listening for oauth requests
59
+ // and will timeout and fail
60
+ global.setTimeout.mockRestore();
61
+ });
62
+
63
+ it("drops a user into the login flow if they're unauthenticated", async () => {
64
+ writeWranglerToml();
65
+ writeWorkerSource();
66
+ mockSubDomainRequest();
67
+ mockUploadWorkerRequest();
68
+
69
+ mockOAuthServerCallback();
70
+ const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
71
+ mockGrantAuthorization({ respondWith: "success" });
72
+
73
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
74
+
75
+ expect(accessTokenRequest.actual.url).toEqual(
76
+ accessTokenRequest.expected.url
77
+ );
78
+
79
+ expect(std.out).toMatchInlineSnapshot(`
80
+ "Attempting to login via OAuth...
81
+ Successfully logged in.
82
+ Uploaded test-name (TIMINGS)
83
+ Published test-name (TIMINGS)
84
+ test-name.test-sub-domain.workers.dev"
85
+ `);
86
+ expect(std.warn).toMatchInlineSnapshot(`""`);
87
+ expect(std.err).toMatchInlineSnapshot(`""`);
88
+ });
89
+
90
+ it("warns a user when they're authenticated with an API token in wrangler config file", async () => {
91
+ writeWranglerToml();
92
+ writeWorkerSource();
93
+ mockSubDomainRequest();
94
+ mockUploadWorkerRequest();
95
+ writeAuthConfigFile({
96
+ api_token: "some-api-token",
97
+ });
98
+
99
+ const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
100
+ mockGrantAuthorization({ respondWith: "success" });
101
+
102
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
103
+
104
+ expect(accessTokenRequest.actual.url).toEqual(
105
+ accessTokenRequest.expected.url
106
+ );
107
+
108
+ expect(std.out).toMatchInlineSnapshot(`
109
+ "Attempting to login via OAuth...
110
+ Successfully logged in.
111
+ Uploaded test-name (TIMINGS)
112
+ Published test-name (TIMINGS)
113
+ test-name.test-sub-domain.workers.dev"
114
+ `);
115
+ expect(std.warn).toMatchInlineSnapshot(`
116
+ "▲ [WARNING] It looks like you have used Wrangler 1's \`config\` command to login with an API token.
117
+
118
+ This is no longer supported in the current version of Wrangler.
119
+ If you wish to authenticate via an API token then please set the \`CLOUDFLARE_API_TOKEN\`
120
+ environment variable.
121
+
122
+ "
123
+ `);
124
+ expect(std.err).toMatchInlineSnapshot(`""`);
125
+ });
126
+
127
+ describe("non-TTY", () => {
128
+ const ENV_COPY = process.env;
129
+
130
+ afterEach(() => {
131
+ process.env = ENV_COPY;
132
+ });
133
+
134
+ it("should not throw an error in non-TTY if 'CLOUDFLARE_API_TOKEN' & 'account_id' are in scope", async () => {
135
+ process.env = {
136
+ CLOUDFLARE_API_TOKEN: "123456789",
137
+ };
138
+ setIsTTY(false);
139
+ writeWranglerToml({
140
+ account_id: "some-account-id",
141
+ });
142
+ writeWorkerSource();
143
+ mockSubDomainRequest();
144
+ mockUploadWorkerRequest();
145
+ mockOAuthServerCallback();
146
+
147
+ await runWrangler("publish index.js");
148
+
149
+ expect(std.out).toMatchInlineSnapshot(`
150
+ "Uploaded test-name (TIMINGS)
151
+ Published test-name (TIMINGS)
152
+ test-name.test-sub-domain.workers.dev"
153
+ `);
154
+ expect(std.err).toMatchInlineSnapshot(`""`);
155
+ });
156
+
157
+ it("should not throw an error if 'CLOUDFLARE_ACCOUNT_ID' & 'CLOUDFLARE_API_TOKEN' are in scope", async () => {
158
+ process.env = {
159
+ CLOUDFLARE_API_TOKEN: "hunter2",
160
+ CLOUDFLARE_ACCOUNT_ID: "some-account-id",
161
+ };
162
+ setIsTTY(false);
163
+ writeWranglerToml();
164
+ writeWorkerSource();
165
+ mockSubDomainRequest();
166
+ mockUploadWorkerRequest();
167
+ mockOAuthServerCallback();
168
+ mockGetMemberships({
169
+ success: true,
170
+ result: [],
171
+ });
172
+
173
+ await runWrangler("publish index.js");
174
+
175
+ expect(std.out).toMatchInlineSnapshot(`
176
+ "Uploaded test-name (TIMINGS)
177
+ Published test-name (TIMINGS)
178
+ test-name.test-sub-domain.workers.dev"
179
+ `);
180
+ expect(std.err).toMatchInlineSnapshot(`""`);
181
+ });
182
+
183
+ it("should throw an error in non-TTY & there is more than one account associated with API token", async () => {
184
+ setIsTTY(false);
185
+ process.env = {
186
+ CLOUDFLARE_API_TOKEN: "hunter2",
187
+ CLOUDFLARE_ACCOUNT_ID: undefined,
188
+ };
189
+ writeWranglerToml({
190
+ account_id: undefined,
191
+ });
192
+ writeWorkerSource();
193
+ mockSubDomainRequest();
194
+ mockUploadWorkerRequest();
195
+ mockOAuthServerCallback();
196
+ mockGetMemberships({
197
+ success: true,
198
+ result: [
199
+ { id: "IG-88", account: { id: "1701", name: "enterprise" } },
200
+ { id: "R2-D2", account: { id: "nx01", name: "enterprise-nx" } },
201
+ ],
202
+ });
203
+
204
+ await expect(runWrangler("publish index.js")).rejects
205
+ .toMatchInlineSnapshot(`
206
+ [Error: More than one account available but unable to select one in non-interactive mode.
207
+ Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
208
+ Available accounts are ("<name>" - "<id>"):
209
+ "enterprise" - "1701")
210
+ "enterprise-nx" - "nx01")]
211
+ `);
212
+ });
213
+
214
+ it("should throw error in non-TTY if 'CLOUDFLARE_API_TOKEN' is missing", async () => {
215
+ setIsTTY(false);
216
+ writeWranglerToml({
217
+ account_id: undefined,
218
+ });
219
+ process.env = {
220
+ CLOUDFLARE_API_TOKEN: undefined,
221
+ CLOUDFLARE_ACCOUNT_ID: "badwolf",
222
+ };
223
+ writeWorkerSource();
224
+ mockSubDomainRequest();
225
+ mockUploadWorkerRequest();
226
+ mockOAuthServerCallback();
227
+ mockGetMemberships({
228
+ success: true,
229
+ result: [
230
+ { id: "IG-88", account: { id: "1701", name: "enterprise" } },
231
+ { id: "R2-D2", account: { id: "nx01", name: "enterprise-nx" } },
232
+ ],
233
+ });
234
+
235
+ await expect(runWrangler("publish index.js")).rejects.toThrowError();
236
+
237
+ expect(std.err).toMatchInlineSnapshot(`
238
+ "X [ERROR] In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/api/tokens/create/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN.
239
+
240
+ "
241
+ `);
242
+ });
243
+ it("should throw error with no account ID provided and no members retrieved", async () => {
244
+ setIsTTY(false);
245
+ writeWranglerToml({
246
+ account_id: undefined,
247
+ });
248
+ process.env = {
249
+ CLOUDFLARE_API_TOKEN: "picard",
250
+ CLOUDFLARE_ACCOUNT_ID: undefined,
251
+ };
252
+ writeWorkerSource();
253
+ mockSubDomainRequest();
254
+ mockUploadWorkerRequest();
255
+ mockOAuthServerCallback();
256
+ mockGetMemberships({
257
+ success: false,
258
+ result: [],
259
+ });
260
+
261
+ await expect(runWrangler("publish index.js")).rejects.toThrowError();
262
+
263
+ expect(std.err).toMatchInlineSnapshot(`
264
+ "X [ERROR] Failed to automatically retrieve account IDs for the logged in user. In a non-interactive environment, it is mandatory to specify an account ID, either by assigning its value to CLOUDFLARE_ACCOUNT_ID, or as \`account_id\` in your \`wrangler.toml\` file.
265
+
266
+ "
267
+ `);
268
+ });
269
+ });
30
270
  });
31
271
 
32
272
  describe("environments", () => {
33
273
  it("should use legacy environments by default", async () => {
34
- writeWranglerToml();
274
+ writeWranglerToml({ env: { "some-env": {} } });
35
275
  writeWorkerSource();
36
276
  mockSubDomainRequest();
37
277
  mockUploadWorkerRequest({
@@ -66,8 +306,8 @@ describe("publish", () => {
66
306
  expect(std.warn).toMatchInlineSnapshot(`""`);
67
307
  });
68
308
 
69
- it("appends the environment name when provided", async () => {
70
- writeWranglerToml();
309
+ it("appends the environment name when provided, and there is associated config", async () => {
310
+ writeWranglerToml({ env: { "some-env": {} } });
71
311
  writeWorkerSource();
72
312
  mockSubDomainRequest();
73
313
  mockUploadWorkerRequest({
@@ -83,6 +323,74 @@ describe("publish", () => {
83
323
  expect(std.err).toMatchInlineSnapshot(`""`);
84
324
  expect(std.warn).toMatchInlineSnapshot(`""`);
85
325
  });
326
+
327
+ it("appends the environment name when provided (with a warning), if there are no configured environments", async () => {
328
+ writeWranglerToml({});
329
+ writeWorkerSource();
330
+ mockSubDomainRequest();
331
+ mockUploadWorkerRequest({
332
+ env: "some-env",
333
+ legacyEnv: true,
334
+ });
335
+ await runWrangler("publish index.js --env some-env --legacy-env true");
336
+ expect(std.out).toMatchInlineSnapshot(`
337
+ "Uploaded test-name-some-env (TIMINGS)
338
+ Published test-name-some-env (TIMINGS)
339
+ test-name-some-env.test-sub-domain.workers.dev"
340
+ `);
341
+ expect(std.err).toMatchInlineSnapshot(`""`);
342
+ expect(std.warn).toMatchInlineSnapshot(`
343
+ "▲ [WARNING] Processing wrangler.toml configuration:
344
+
345
+ - No environment found in configuration with name \\"some-env\\".
346
+ Before using \`--env=some-env\` there should be an equivalent environment section in the
347
+ configuration.
348
+
349
+ Consider adding an environment configuration section to the wrangler.toml file:
350
+ \`\`\`
351
+ [env.some-env]
352
+ \`\`\`
353
+
354
+
355
+ "
356
+ `);
357
+ });
358
+
359
+ it("should throw an error when an environment name when provided, which doesn't match those in the config", async () => {
360
+ writeWranglerToml({ env: { "other-env": {} } });
361
+ writeWorkerSource();
362
+ mockSubDomainRequest();
363
+ await expect(
364
+ runWrangler("publish index.js --env some-env --legacy-env true")
365
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
366
+ "Processing wrangler.toml configuration:
367
+ - No environment found in configuration with name \\"some-env\\".
368
+ Before using \`--env=some-env\` there should be an equivalent environment section in the configuration.
369
+ The available configured environment names are: [\\"other-env\\"]
370
+
371
+ Consider adding an environment configuration section to the wrangler.toml file:
372
+ \`\`\`
373
+ [env.some-env]
374
+ \`\`\`
375
+ "
376
+ `);
377
+ });
378
+
379
+ it("should throw an error w/ helpful message when using --env --name", async () => {
380
+ writeWranglerToml({ env: { "some-env": {} } });
381
+ writeWorkerSource();
382
+ mockSubDomainRequest();
383
+ await runWrangler(
384
+ "publish index.js --name voyager --env some-env --legacy-env true"
385
+ ).catch((err) =>
386
+ expect(err).toMatchInlineSnapshot(`
387
+ [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:
388
+ [env.some-env]
389
+ name = "voyager"
390
+ ]
391
+ `)
392
+ );
393
+ });
86
394
  });
87
395
 
88
396
  describe("services", () => {
@@ -93,18 +401,25 @@ describe("publish", () => {
93
401
  mockUploadWorkerRequest({
94
402
  legacyEnv: false,
95
403
  });
96
- await runWrangler("publish index.js");
404
+ await runWrangler("publish index.js --legacy-env false");
97
405
  expect(std.out).toMatchInlineSnapshot(`
98
406
  "Uploaded test-name (TIMINGS)
99
407
  Published test-name (TIMINGS)
100
408
  test-name.test-sub-domain.workers.dev"
101
409
  `);
102
410
  expect(std.err).toMatchInlineSnapshot(`""`);
103
- expect(std.warn).toMatchInlineSnapshot(`""`);
411
+ expect(std.warn).toMatchInlineSnapshot(`
412
+ "▲ [WARNING] Processing wrangler.toml configuration:
413
+
414
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
415
+ the future. DO NOT USE IN PRODUCTION.
416
+
417
+ "
418
+ `);
104
419
  });
105
420
 
106
421
  it("publishes as an environment when provided", async () => {
107
- writeWranglerToml();
422
+ writeWranglerToml({ env: { "some-env": {} } });
108
423
  writeWorkerSource();
109
424
  mockSubDomainRequest();
110
425
  mockUploadWorkerRequest({
@@ -118,7 +433,14 @@ describe("publish", () => {
118
433
  some-env.test-name.test-sub-domain.workers.dev"
119
434
  `);
120
435
  expect(std.err).toMatchInlineSnapshot(`""`);
121
- expect(std.warn).toMatchInlineSnapshot(`""`);
436
+ expect(std.warn).toMatchInlineSnapshot(`
437
+ "▲ [WARNING] Processing wrangler.toml configuration:
438
+
439
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
440
+ the future. DO NOT USE IN PRODUCTION.
441
+
442
+ "
443
+ `);
122
444
  });
123
445
  });
124
446
  });
@@ -143,6 +465,7 @@ describe("publish", () => {
143
465
  type: "json",
144
466
  },
145
467
  ],
468
+ expectedCompatibilityDate: "2022-01-12",
146
469
  });
147
470
  mockSubDomainRequest();
148
471
  await runWrangler("publish ./some-path/worker/index.js");
@@ -166,6 +489,116 @@ describe("publish", () => {
166
489
  await runWrangler("publish ./index");
167
490
  });
168
491
 
492
+ it("should publish to a route with a pattern/{zone_id|zone_name} combo", async () => {
493
+ writeWranglerToml({
494
+ routes: [
495
+ "some-example.com/some-route/*",
496
+ { pattern: "*a-boring-website.com", zone_id: "54sdf7fsda" },
497
+ {
498
+ pattern: "*another-boring-website.com",
499
+ zone_name: "some-zone.com",
500
+ },
501
+ { pattern: "example.com/some-route/*", zone_id: "JGHFHG654gjcj" },
502
+ "more-examples.com/*",
503
+ ],
504
+ });
505
+ writeWorkerSource();
506
+ mockUpdateWorkerRequest({ enabled: false });
507
+ mockUploadWorkerRequest({ expectedType: "esm" });
508
+ mockPublishRoutesRequest({
509
+ routes: [
510
+ "some-example.com/some-route/*",
511
+ { pattern: "*a-boring-website.com", zone_id: "54sdf7fsda" },
512
+ {
513
+ pattern: "*another-boring-website.com",
514
+ zone_name: "some-zone.com",
515
+ },
516
+ { pattern: "example.com/some-route/*", zone_id: "JGHFHG654gjcj" },
517
+ "more-examples.com/*",
518
+ ],
519
+ });
520
+ await runWrangler("publish ./index");
521
+ expect(std).toMatchInlineSnapshot(`
522
+ Object {
523
+ "debug": "",
524
+ "err": "",
525
+ "out": "Uploaded test-name (TIMINGS)
526
+ Published test-name (TIMINGS)
527
+ some-example.com/some-route/*
528
+ *a-boring-website.com (zone id: 54sdf7fsda)
529
+ *another-boring-website.com (zone name: some-zone.com)
530
+ example.com/some-route/* (zone id: JGHFHG654gjcj)
531
+ more-examples.com/*",
532
+ "warn": "",
533
+ }
534
+ `);
535
+ });
536
+
537
+ it("should publish to a route with a pattern/{zone_id|zone_name} combo (service environments)", async () => {
538
+ writeWranglerToml({
539
+ env: {
540
+ staging: {
541
+ routes: [
542
+ "some-example.com/some-route/*",
543
+ { pattern: "*a-boring-website.com", zone_id: "54sdf7fsda" },
544
+ {
545
+ pattern: "*another-boring-website.com",
546
+ zone_name: "some-zone.com",
547
+ },
548
+ { pattern: "example.com/some-route/*", zone_id: "JGHFHG654gjcj" },
549
+ "more-examples.com/*",
550
+ ],
551
+ },
552
+ },
553
+ });
554
+ mockSubDomainRequest();
555
+ writeWorkerSource();
556
+ mockUpdateWorkerRequest({
557
+ enabled: false,
558
+ env: "staging",
559
+ legacyEnv: false,
560
+ });
561
+ mockUploadWorkerRequest({
562
+ expectedType: "esm",
563
+ env: "staging",
564
+ legacyEnv: false,
565
+ });
566
+ mockPublishRoutesRequest({
567
+ routes: [
568
+ "some-example.com/some-route/*",
569
+ { pattern: "*a-boring-website.com", zone_id: "54sdf7fsda" },
570
+ {
571
+ pattern: "*another-boring-website.com",
572
+ zone_name: "some-zone.com",
573
+ },
574
+ { pattern: "example.com/some-route/*", zone_id: "JGHFHG654gjcj" },
575
+ "more-examples.com/*",
576
+ ],
577
+ env: "staging",
578
+ legacyEnv: false,
579
+ });
580
+ await runWrangler("publish ./index --legacy-env false --env staging");
581
+ expect(std).toMatchInlineSnapshot(`
582
+ Object {
583
+ "debug": "",
584
+ "err": "",
585
+ "out": "Uploaded test-name (staging) (TIMINGS)
586
+ Published test-name (staging) (TIMINGS)
587
+ some-example.com/some-route/*
588
+ *a-boring-website.com (zone id: 54sdf7fsda)
589
+ *another-boring-website.com (zone name: some-zone.com)
590
+ example.com/some-route/* (zone id: JGHFHG654gjcj)
591
+ more-examples.com/*",
592
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
593
+
594
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
595
+ the future. DO NOT USE IN PRODUCTION.
596
+
597
+ ",
598
+ }
599
+ `);
600
+ });
601
+
169
602
  it("should publish to legacy environment specific routes", async () => {
170
603
  writeWranglerToml({
171
604
  routes: ["example.com/some-route/*"],
@@ -297,13 +730,16 @@ describe("publish", () => {
297
730
  `);
298
731
  expect(std.err).toMatchInlineSnapshot(`""`);
299
732
  expect(std.warn).toMatchInlineSnapshot(`
300
- "Processing wrangler.toml configuration:
301
- - DEPRECATION: \\"build.upload.main\\":
302
- Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
303
- Then add the top level \`main\` field to your configuration file:
304
- \`\`\`
305
- main = \\"dist/index.js\\"
306
- \`\`\`"
733
+ "▲ [WARNING] Processing wrangler.toml configuration:
734
+
735
+ - Deprecation: \\"build.upload.main\\":
736
+ Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
737
+ Then add the top level \`main\` field to your configuration file:
738
+ \`\`\`
739
+ main = \\"dist/index.js\\"
740
+ \`\`\`
741
+
742
+ "
307
743
  `);
308
744
  });
309
745
 
@@ -329,15 +765,19 @@ describe("publish", () => {
329
765
  `);
330
766
  expect(std.err).toMatchInlineSnapshot(`""`);
331
767
  expect(std.warn).toMatchInlineSnapshot(`
332
- "Processing ../wrangler.toml configuration:
333
- - DEPRECATION: \\"build.upload.main\\":
334
- Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
335
- Then add the top level \`main\` field to your configuration file:
336
- \`\`\`
337
- main = \\"foo/index.js\\"
338
- \`\`\`
339
- - DEPRECATION: \\"build.upload.dir\\":
340
- Use the top level \\"main\\" field or a command-line argument to specify the entry-point for the Worker."
768
+ "▲ [WARNING] Processing ../wrangler.toml configuration:
769
+
770
+ - Deprecation: \\"build.upload.main\\":
771
+ Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
772
+ Then add the top level \`main\` field to your configuration file:
773
+ \`\`\`
774
+ main = \\"foo/index.js\\"
775
+ \`\`\`
776
+ - Deprecation: \\"build.upload.dir\\":
777
+ Use the top level \\"main\\" field or a command-line argument to specify the entry-point for the
778
+ Worker.
779
+
780
+ "
341
781
  `);
342
782
  });
343
783
 
@@ -439,6 +879,77 @@ export default{
439
879
  expect(std.err).toMatchInlineSnapshot(`""`);
440
880
  });
441
881
 
882
+ it("should preserve exports on a module format worker", async () => {
883
+ writeWranglerToml();
884
+ fs.writeFileSync(
885
+ "index.js",
886
+ `
887
+ export const abc = 123;
888
+ export const def = "show me the money";
889
+ export default {};`
890
+ );
891
+
892
+ await runWrangler("publish index.js --dry-run --outdir out");
893
+
894
+ expect(
895
+ (
896
+ await esbuild.build({
897
+ entryPoints: [path.resolve("./out/index.js")],
898
+ metafile: true,
899
+ write: false,
900
+ })
901
+ ).metafile?.outputs["index.js"].exports
902
+ ).toMatchInlineSnapshot(`
903
+ Array [
904
+ "abc",
905
+ "def",
906
+ "default",
907
+ ]
908
+ `);
909
+ expect(std).toMatchInlineSnapshot(`
910
+ Object {
911
+ "debug": "",
912
+ "err": "",
913
+ "out": "--dry-run: exiting now.",
914
+ "warn": "",
915
+ }
916
+ `);
917
+ });
918
+
919
+ it("should not preserve exports on a service-worker format worker", async () => {
920
+ writeWranglerToml();
921
+ fs.writeFileSync(
922
+ "index.js",
923
+ `
924
+ export const abc = 123;
925
+ export const def = "show me the money";
926
+ addEventListener('fetch', event => {});`
927
+ );
928
+
929
+ await runWrangler("publish index.js --dry-run --outdir out --minify");
930
+
931
+ expect(
932
+ (
933
+ await esbuild.build({
934
+ entryPoints: [path.resolve("./out/index.js")],
935
+ metafile: true,
936
+ write: false,
937
+ })
938
+ ).metafile?.outputs["index.js"].exports
939
+ ).toMatchInlineSnapshot(`Array []`);
940
+
941
+ expect(std).toMatchInlineSnapshot(`
942
+ Object {
943
+ "debug": "",
944
+ "err": "",
945
+ "out": "--dry-run: exiting now.",
946
+ "warn": "▲ [WARNING] The entrypoint index.js has exports like an ES Module, but hasn't defined a default export like a module worker normally would. Building the worker using \\"service-worker\\" format...
947
+
948
+ ",
949
+ }
950
+ `);
951
+ });
952
+
442
953
  it("should be able to transpile entry-points in sub-directories (sw)", async () => {
443
954
  writeWranglerToml();
444
955
  writeWorkerSource({ basePath: "./src", type: "sw" });
@@ -460,9 +971,8 @@ export default{
460
971
 
461
972
  it('should error if a site definition doesn\'t have a "bucket" field', async () => {
462
973
  writeWranglerToml({
463
- site: {
464
- "entry-point": "./index.js",
465
- } as Config["site"],
974
+ // @ts-expect-error we're intentionally setting an invalid config
975
+ site: {},
466
976
  });
467
977
  writeWorkerSource();
468
978
  mockUploadWorkerRequest();
@@ -471,17 +981,32 @@ export default{
471
981
  await expect(runWrangler("publish ./index.js")).rejects
472
982
  .toThrowErrorMatchingInlineSnapshot(`
473
983
  "Processing wrangler.toml configuration:
474
- - ERROR: \\"site.bucket\\" is a required field."
984
+ - \\"site.bucket\\" is a required field."
475
985
  `);
476
986
 
477
- expect(std.out).toMatchInlineSnapshot(`""`);
987
+ expect(std.out).toMatchInlineSnapshot(`
988
+ "
989
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
990
+ `);
478
991
  expect(std.err).toMatchInlineSnapshot(`
479
- "Processing wrangler.toml configuration:
480
- - ERROR: \\"site.bucket\\" is a required field.
992
+ "X [ERROR] Processing wrangler.toml configuration:
993
+
994
+ - \\"site.bucket\\" is a required field.
481
995
 
482
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
996
+ "
997
+ `);
998
+ expect(normalizeSlashes(std.warn)).toMatchInlineSnapshot(`
999
+ "▲ [WARNING] Processing wrangler.toml configuration:
1000
+
1001
+ - Because you've defined a [site] configuration, we're defaulting to \\"workers-site\\" for the
1002
+ deprecated \`site.entry-point\`field.
1003
+ Add the top level \`main\` field to your configuration file:
1004
+ \`\`\`
1005
+ main = \\"workers-site/index.js\\"
1006
+ \`\`\`
1007
+
1008
+ "
483
1009
  `);
484
- expect(std.warn).toMatchInlineSnapshot(`""`);
485
1010
  });
486
1011
 
487
1012
  it("should warn if there is a `site.entry-point` configuration", async () => {
@@ -507,48 +1032,35 @@ export default{
507
1032
  mockListKVNamespacesRequest(kvNamespace);
508
1033
  mockKeyListRequest(kvNamespace.id, []);
509
1034
  mockUploadAssetsToKVRequest(kvNamespace.id, assets);
510
-
511
1035
  await runWrangler("publish ./index.js");
512
1036
 
513
- expect(std.out).toMatchInlineSnapshot(`
514
- "reading assets/file-1.txt...
515
- uploading as assets/file-1.2ca234f380.txt...
516
- reading assets/file-2.txt...
517
- uploading as assets/file-2.5938485188.txt...
1037
+ expect(std).toMatchInlineSnapshot(`
1038
+ Object {
1039
+ "debug": "",
1040
+ "err": "",
1041
+ "out": "Reading assets/file-1.txt...
1042
+ Uploading as assets/file-1.2ca234f380.txt...
1043
+ Reading assets/file-2.txt...
1044
+ Uploading as assets/file-2.5938485188.txt...
1045
+ ↗️ Done syncing assets
518
1046
  Uploaded test-name (TIMINGS)
519
1047
  Published test-name (TIMINGS)
520
- test-name.test-sub-domain.workers.dev"
521
- `);
522
- expect(std.err).toMatchInlineSnapshot(`""`);
523
- expect(std.warn).toMatchInlineSnapshot(`
524
- "Deprecation notice: The \`site.entry-point\` config field is no longer used.
525
- The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`main\` config field.
526
- Please remove the \`site.entry-point\` field from the \`wrangler.toml\` file."
527
- `);
528
- });
529
-
530
- it("should error if there is no entry-point specified", async () => {
531
- writeWranglerToml();
532
- writeWorkerSource();
533
- mockUploadWorkerRequest();
534
- mockSubDomainRequest();
535
- await expect(
536
- runWrangler("publish")
537
- ).rejects.toThrowErrorMatchingInlineSnapshot(
538
- `"Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`main\` config field."`
539
- );
540
-
541
- expect(std.out).toMatchInlineSnapshot(`""`);
542
- expect(std.err).toMatchInlineSnapshot(`
543
- "Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`main\` config field.
544
-
545
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1048
+ test-name.test-sub-domain.workers.dev",
1049
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
1050
+
1051
+ - Deprecation: \\"site.entry-point\\":
1052
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration
1053
+ file:
1054
+ \`\`\`
1055
+ main = \\"index.js\\"
1056
+ \`\`\`
1057
+
1058
+ ",
1059
+ }
546
1060
  `);
547
1061
  });
548
- });
549
1062
 
550
- describe("asset upload", () => {
551
- it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
1063
+ it("should resolve site.entry-point relative to wrangler.toml", async () => {
552
1064
  const assets = [
553
1065
  { filePath: "assets/file-1.txt", content: "Content of file-1" },
554
1066
  { filePath: "assets/file-2.txt", content: "Content of file-2" },
@@ -557,35 +1069,131 @@ export default{
557
1069
  title: "__test-name-workers_sites_assets",
558
1070
  id: "__test-name-workers_sites_assets-id",
559
1071
  };
1072
+ fs.mkdirSync("my-site");
1073
+ process.chdir("my-site");
560
1074
  writeWranglerToml({
561
- main: "./index.js",
562
1075
  site: {
563
1076
  bucket: "assets",
1077
+ "entry-point": "my-entry",
564
1078
  },
565
1079
  });
566
- writeWorkerSource();
1080
+ fs.mkdirSync("my-entry");
1081
+ fs.writeFileSync("my-entry/index.js", "export default {}");
567
1082
  writeAssets(assets);
1083
+ process.chdir("..");
568
1084
  mockUploadWorkerRequest();
569
1085
  mockSubDomainRequest();
570
1086
  mockListKVNamespacesRequest(kvNamespace);
571
1087
  mockKeyListRequest(kvNamespace.id, []);
572
1088
  mockUploadAssetsToKVRequest(kvNamespace.id, assets);
573
- await runWrangler("publish");
1089
+ await runWrangler("publish --config ./my-site/wrangler.toml");
574
1090
 
575
1091
  expect(std.out).toMatchInlineSnapshot(`
576
- "reading assets/file-1.txt...
577
- uploading as assets/file-1.2ca234f380.txt...
578
- reading assets/file-2.txt...
579
- uploading as assets/file-2.5938485188.txt...
1092
+ "Reading assets/file-1.txt...
1093
+ Uploading as assets/file-1.2ca234f380.txt...
1094
+ Reading assets/file-2.txt...
1095
+ Uploading as assets/file-2.5938485188.txt...
1096
+ ↗️ Done syncing assets
580
1097
  Uploaded test-name (TIMINGS)
581
1098
  Published test-name (TIMINGS)
582
1099
  test-name.test-sub-domain.workers.dev"
583
1100
  `);
584
1101
  expect(std.err).toMatchInlineSnapshot(`""`);
1102
+ expect(normalizeSlashes(std.warn)).toMatchInlineSnapshot(`
1103
+ "▲ [WARNING] Processing my-site/wrangler.toml configuration:
1104
+
1105
+ - Deprecation: \\"site.entry-point\\":
1106
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration
1107
+ file:
1108
+ \`\`\`
1109
+ main = \\"my-entry/index.js\\"
1110
+ \`\`\`
1111
+
1112
+ "
1113
+ `);
585
1114
  });
586
1115
 
587
- it("when using a service worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
588
- const assets = [
1116
+ it("should error if both main and site.entry-point are specified", async () => {
1117
+ writeWranglerToml({
1118
+ main: "some-entry",
1119
+ site: {
1120
+ bucket: "some-bucket",
1121
+ "entry-point": "./index.js",
1122
+ },
1123
+ });
1124
+
1125
+ await expect(runWrangler("publish")).rejects
1126
+ .toThrowErrorMatchingInlineSnapshot(`
1127
+ "Processing wrangler.toml configuration:
1128
+ - Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.
1129
+ They serve the same purpose: to point to the entry-point of your worker.
1130
+ Delete the deprecated \`site.entry-point\` field from your config."
1131
+ `);
1132
+ });
1133
+
1134
+ it("should error if there is no entry-point specified", async () => {
1135
+ writeWranglerToml();
1136
+ writeWorkerSource();
1137
+ mockUploadWorkerRequest();
1138
+ mockSubDomainRequest();
1139
+ await expect(
1140
+ runWrangler("publish")
1141
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1142
+ `"Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`main\` config field."`
1143
+ );
1144
+
1145
+ expect(std.out).toMatchInlineSnapshot(`
1146
+ "
1147
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1148
+ `);
1149
+ expect(std.err).toMatchInlineSnapshot(`
1150
+ "X [ERROR] Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler publish path/to/script\`) or the \`main\` config field.
1151
+
1152
+ "
1153
+ `);
1154
+ });
1155
+ });
1156
+
1157
+ describe("asset upload", () => {
1158
+ it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
1159
+ const assets = [
1160
+ { filePath: "assets/file-1.txt", content: "Content of file-1" },
1161
+ { filePath: "assets/file-2.txt", content: "Content of file-2" },
1162
+ ];
1163
+ const kvNamespace = {
1164
+ title: "__test-name-workers_sites_assets",
1165
+ id: "__test-name-workers_sites_assets-id",
1166
+ };
1167
+ writeWranglerToml({
1168
+ main: "./index.js",
1169
+ site: {
1170
+ bucket: "assets",
1171
+ },
1172
+ });
1173
+ writeWorkerSource();
1174
+ writeAssets(assets);
1175
+ mockUploadWorkerRequest();
1176
+ mockSubDomainRequest();
1177
+ mockListKVNamespacesRequest(kvNamespace);
1178
+ mockKeyListRequest(kvNamespace.id, []);
1179
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1180
+ await runWrangler("publish");
1181
+
1182
+ expect(std.out).toMatchInlineSnapshot(`
1183
+ "Reading assets/file-1.txt...
1184
+ Uploading as assets/file-1.2ca234f380.txt...
1185
+ Reading assets/file-2.txt...
1186
+ Uploading as assets/file-2.5938485188.txt...
1187
+ ↗️ Done syncing assets
1188
+ Uploaded test-name (TIMINGS)
1189
+ Published test-name (TIMINGS)
1190
+ test-name.test-sub-domain.workers.dev"
1191
+ `);
1192
+ expect(std.err).toMatchInlineSnapshot(`""`);
1193
+ });
1194
+
1195
+ it("when using a service-worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
1196
+ const assets = [
589
1197
  { filePath: "assets/file-1.txt", content: "Content of file-1" },
590
1198
  { filePath: "assets/file-2.txt", content: "Content of file-2" },
591
1199
  ];
@@ -628,10 +1236,11 @@ export default{
628
1236
  await runWrangler("publish");
629
1237
 
630
1238
  expect(std.out).toMatchInlineSnapshot(`
631
- "reading assets/file-1.txt...
632
- uploading as assets/file-1.2ca234f380.txt...
633
- reading assets/file-2.txt...
634
- uploading as assets/file-2.5938485188.txt...
1239
+ "Reading assets/file-1.txt...
1240
+ Uploading as assets/file-1.2ca234f380.txt...
1241
+ Reading assets/file-2.txt...
1242
+ Uploading as assets/file-2.5938485188.txt...
1243
+ ↗️ Done syncing assets
635
1244
  Uploaded test-name (TIMINGS)
636
1245
  Published test-name (TIMINGS)
637
1246
  test-name.test-sub-domain.workers.dev"
@@ -677,10 +1286,11 @@ export default{
677
1286
  await runWrangler("publish");
678
1287
 
679
1288
  expect(std.out).toMatchInlineSnapshot(`
680
- "reading assets/file-1.txt...
681
- uploading as assets/file-1.2ca234f380.txt...
682
- reading assets/file-2.txt...
683
- uploading as assets/file-2.5938485188.txt...
1289
+ "Reading assets/file-1.txt...
1290
+ Uploading as assets/file-1.2ca234f380.txt...
1291
+ Reading assets/file-2.txt...
1292
+ Uploading as assets/file-2.5938485188.txt...
1293
+ ↗️ Done syncing assets
684
1294
  Uploaded test-name (TIMINGS)
685
1295
  Published test-name (TIMINGS)
686
1296
  test-name.test-sub-domain.workers.dev"
@@ -703,6 +1313,7 @@ export default{
703
1313
  site: {
704
1314
  bucket: "assets",
705
1315
  },
1316
+ env: { "some-env": {} },
706
1317
  });
707
1318
  writeWorkerSource();
708
1319
  writeAssets(assets);
@@ -723,10 +1334,11 @@ export default{
723
1334
  await runWrangler("publish --env some-env --legacy-env false");
724
1335
 
725
1336
  expect(std.out).toMatchInlineSnapshot(`
726
- "reading assets/file-1.txt...
727
- uploading as assets/file-1.2ca234f380.txt...
728
- reading assets/file-2.txt...
729
- uploading as assets/file-2.5938485188.txt...
1337
+ "Reading assets/file-1.txt...
1338
+ Uploading as assets/file-1.2ca234f380.txt...
1339
+ Reading assets/file-2.txt...
1340
+ Uploading as assets/file-2.5938485188.txt...
1341
+ ↗️ Done syncing assets
730
1342
  Uploaded test-name (some-env) (TIMINGS)
731
1343
  Published test-name (some-env) (TIMINGS)
732
1344
  some-env.test-name.test-sub-domain.workers.dev"
@@ -749,6 +1361,7 @@ export default{
749
1361
  site: {
750
1362
  bucket: "assets",
751
1363
  },
1364
+ env: { "some-env": {} },
752
1365
  });
753
1366
  writeWorkerSource();
754
1367
  writeAssets(assets);
@@ -770,10 +1383,11 @@ export default{
770
1383
  await runWrangler("publish --env some-env --legacy-env true");
771
1384
 
772
1385
  expect(std.out).toMatchInlineSnapshot(`
773
- "reading assets/file-1.txt...
774
- uploading as assets/file-1.2ca234f380.txt...
775
- reading assets/file-2.txt...
776
- uploading as assets/file-2.5938485188.txt...
1386
+ "Reading assets/file-1.txt...
1387
+ Uploading as assets/file-1.2ca234f380.txt...
1388
+ Reading assets/file-2.txt...
1389
+ Uploading as assets/file-2.5938485188.txt...
1390
+ ↗️ Done syncing assets
777
1391
  Uploaded test-name-some-env (TIMINGS)
778
1392
  Published test-name-some-env (TIMINGS)
779
1393
  test-name-some-env.test-sub-domain.workers.dev"
@@ -802,7 +1416,9 @@ export default{
802
1416
  mockSubDomainRequest();
803
1417
  mockListKVNamespacesRequest(kvNamespace);
804
1418
  // Put file-1 in the KV namespace
805
- mockKeyListRequest(kvNamespace.id, ["assets/file-1.2ca234f380.txt"]);
1419
+ mockKeyListRequest(kvNamespace.id, [
1420
+ { name: "assets/file-1.2ca234f380.txt" },
1421
+ ]);
806
1422
  // Check we do not upload file-1
807
1423
  mockUploadAssetsToKVRequest(
808
1424
  kvNamespace.id,
@@ -811,10 +1427,11 @@ export default{
811
1427
  await runWrangler("publish");
812
1428
 
813
1429
  expect(std.out).toMatchInlineSnapshot(`
814
- "reading assets/file-1.txt...
815
- skipping - already uploaded
816
- reading assets/file-2.txt...
817
- uploading as assets/file-2.5938485188.txt...
1430
+ "Reading assets/file-1.txt...
1431
+ Skipping - already uploaded.
1432
+ Reading assets/file-2.txt...
1433
+ Uploading as assets/file-2.5938485188.txt...
1434
+ ↗️ Done syncing assets
818
1435
  Uploaded test-name (TIMINGS)
819
1436
  Published test-name (TIMINGS)
820
1437
  test-name.test-sub-domain.workers.dev"
@@ -851,8 +1468,9 @@ export default{
851
1468
  await runWrangler("publish --site-include file-1.txt");
852
1469
 
853
1470
  expect(std.out).toMatchInlineSnapshot(`
854
- "reading assets/file-1.txt...
855
- uploading as assets/file-1.2ca234f380.txt...
1471
+ "Reading assets/file-1.txt...
1472
+ Uploading as assets/file-1.2ca234f380.txt...
1473
+ ↗️ Done syncing assets
856
1474
  Uploaded test-name (TIMINGS)
857
1475
  Published test-name (TIMINGS)
858
1476
  test-name.test-sub-domain.workers.dev"
@@ -889,8 +1507,9 @@ export default{
889
1507
  await runWrangler("publish --site-exclude file-2.txt");
890
1508
 
891
1509
  expect(std.out).toMatchInlineSnapshot(`
892
- "reading assets/file-1.txt...
893
- uploading as assets/file-1.2ca234f380.txt...
1510
+ "Reading assets/file-1.txt...
1511
+ Uploading as assets/file-1.2ca234f380.txt...
1512
+ ↗️ Done syncing assets
894
1513
  Uploaded test-name (TIMINGS)
895
1514
  Published test-name (TIMINGS)
896
1515
  test-name.test-sub-domain.workers.dev"
@@ -928,8 +1547,9 @@ export default{
928
1547
  await runWrangler("publish");
929
1548
 
930
1549
  expect(std.out).toMatchInlineSnapshot(`
931
- "reading assets/file-1.txt...
932
- uploading as assets/file-1.2ca234f380.txt...
1550
+ "Reading assets/file-1.txt...
1551
+ Uploading as assets/file-1.2ca234f380.txt...
1552
+ ↗️ Done syncing assets
933
1553
  Uploaded test-name (TIMINGS)
934
1554
  Published test-name (TIMINGS)
935
1555
  test-name.test-sub-domain.workers.dev"
@@ -967,8 +1587,9 @@ export default{
967
1587
  await runWrangler("publish");
968
1588
 
969
1589
  expect(std.out).toMatchInlineSnapshot(`
970
- "reading assets/file-1.txt...
971
- uploading as assets/file-1.2ca234f380.txt...
1590
+ "Reading assets/file-1.txt...
1591
+ Uploading as assets/file-1.2ca234f380.txt...
1592
+ ↗️ Done syncing assets
972
1593
  Uploaded test-name (TIMINGS)
973
1594
  Published test-name (TIMINGS)
974
1595
  test-name.test-sub-domain.workers.dev"
@@ -1006,8 +1627,9 @@ export default{
1006
1627
  await runWrangler("publish --site-include file-1.txt");
1007
1628
 
1008
1629
  expect(std.out).toMatchInlineSnapshot(`
1009
- "reading assets/file-1.txt...
1010
- uploading as assets/file-1.2ca234f380.txt...
1630
+ "Reading assets/file-1.txt...
1631
+ Uploading as assets/file-1.2ca234f380.txt...
1632
+ ↗️ Done syncing assets
1011
1633
  Uploaded test-name (TIMINGS)
1012
1634
  Published test-name (TIMINGS)
1013
1635
  test-name.test-sub-domain.workers.dev"
@@ -1045,8 +1667,9 @@ export default{
1045
1667
  await runWrangler("publish --site-exclude file-2.txt");
1046
1668
 
1047
1669
  expect(std.out).toMatchInlineSnapshot(`
1048
- "reading assets/file-1.txt...
1049
- uploading as assets/file-1.2ca234f380.txt...
1670
+ "Reading assets/file-1.txt...
1671
+ Uploading as assets/file-1.2ca234f380.txt...
1672
+ ↗️ Done syncing assets
1050
1673
  Uploaded test-name (TIMINGS)
1051
1674
  Published test-name (TIMINGS)
1052
1675
  test-name.test-sub-domain.workers.dev"
@@ -1086,8 +1709,9 @@ export default{
1086
1709
  await runWrangler("publish");
1087
1710
 
1088
1711
  expect(std.out).toMatchInlineSnapshot(`
1089
- "reading assets/directory-1/file-1.txt...
1090
- uploading as assets/directory-1/file-1.2ca234f380.txt...
1712
+ "Reading assets/directory-1/file-1.txt...
1713
+ Uploading as assets/directory-1/file-1.2ca234f380.txt...
1714
+ ↗️ Done syncing assets
1091
1715
  Uploaded test-name (TIMINGS)
1092
1716
  Published test-name (TIMINGS)
1093
1717
  test-name.test-sub-domain.workers.dev"
@@ -1131,8 +1755,9 @@ export default{
1131
1755
  await runWrangler("publish");
1132
1756
 
1133
1757
  expect(std.out).toMatchInlineSnapshot(`
1134
- "reading assets/.well-known/file-2.txt...
1135
- uploading as assets/.well-known/file-2.5938485188.txt...
1758
+ "Reading assets/.well-known/file-2.txt...
1759
+ Uploading as assets/.well-known/file-2.5938485188.txt...
1760
+ ↗️ Done syncing assets
1136
1761
  Uploaded test-name (TIMINGS)
1137
1762
  Published test-name (TIMINGS)
1138
1763
  test-name.test-sub-domain.workers.dev"
@@ -1177,13 +1802,15 @@ export default{
1177
1802
  );
1178
1803
 
1179
1804
  expect(std.out).toMatchInlineSnapshot(`
1180
- "reading assets/large-file.txt...
1181
- uploading as assets/large-file.0ea0637a45.txt..."
1805
+ "Reading assets/large-file.txt...
1806
+ Uploading as assets/large-file.0ea0637a45.txt...
1807
+
1808
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1182
1809
  `);
1183
1810
  expect(std.err).toMatchInlineSnapshot(`
1184
- "File assets/too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits
1811
+ "X [ERROR] File assets/too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits
1185
1812
 
1186
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1813
+ "
1187
1814
  `);
1188
1815
  });
1189
1816
 
@@ -1215,14 +1842,72 @@ export default{
1215
1842
  `"The asset path key \\"assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.3da0d0cd12.txt\\" exceeds the maximum key size limit of 512. See https://developers.cloudflare.com/workers/platform/limits#kv-limits\\","`
1216
1843
  );
1217
1844
 
1218
- expect(std.out).toMatchInlineSnapshot(
1219
- `"reading assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.txt..."`
1220
- );
1845
+ expect(std.out).toMatchInlineSnapshot(`
1846
+ "Reading assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.txt...
1847
+
1848
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1849
+ `);
1221
1850
  expect(std.err).toMatchInlineSnapshot(`
1222
- "The asset path key \\"assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.3da0d0cd12.txt\\" exceeds the maximum key size limit of 512. See https://developers.cloudflare.com/workers/platform/limits#kv-limits\\",
1851
+ "X [ERROR] The asset path key \\"assets/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/file.3da0d0cd12.txt\\" exceeds the maximum key size limit of 512. See https://developers.cloudflare.com/workers/platform/limits#kv-limits\\",
1852
+
1853
+ "
1854
+ `);
1855
+ });
1856
+
1857
+ it("should delete uploaded assets that aren't included anymore", async () => {
1858
+ const assets = [
1859
+ { filePath: "assets/file-1.txt", content: "Content of file-1" },
1860
+ { filePath: "assets/file-2.txt", content: "Content of file-2" },
1861
+ ];
1862
+ const kvNamespace = {
1863
+ title: "__test-name-workers_sites_assets",
1864
+ id: "__test-name-workers_sites_assets-id",
1865
+ };
1866
+ writeWranglerToml({
1867
+ main: "./index.js",
1868
+ site: {
1869
+ bucket: "assets",
1870
+ },
1871
+ });
1872
+ writeWorkerSource();
1873
+ writeAssets(assets);
1874
+ mockUploadWorkerRequest();
1875
+ mockSubDomainRequest();
1876
+ mockListKVNamespacesRequest(kvNamespace);
1877
+ mockKeyListRequest(kvNamespace.id, [
1878
+ // Put file-1 in the KV namespace
1879
+ { name: "assets/file-1.2ca234f380.txt" },
1880
+ // As well as a couple from a previous upload
1881
+ { name: "assets/file-3.somehash.txt" },
1882
+ { name: "assets/file-4.anotherhash.txt" },
1883
+ ]);
1884
+
1885
+ // we upload only file-1.txt
1886
+ mockUploadAssetsToKVRequest(kvNamespace.id, [
1887
+ ...assets.filter((a) => a.filePath !== "assets/file-1.txt"),
1888
+ ]);
1889
+
1890
+ // and mark file-3 and file-4 for deletion
1891
+ mockDeleteUnusedAssetsRequest(kvNamespace.id, [
1892
+ "assets/file-3.somehash.txt",
1893
+ "assets/file-4.anotherhash.txt",
1894
+ ]);
1895
+
1896
+ await runWrangler("publish");
1223
1897
 
1224
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1898
+ expect(std.out).toMatchInlineSnapshot(`
1899
+ "Reading assets/file-1.txt...
1900
+ Skipping - already uploaded.
1901
+ Reading assets/file-2.txt...
1902
+ Uploading as assets/file-2.5938485188.txt...
1903
+ Deleting assets/file-3.somehash.txt from the asset store...
1904
+ Deleting assets/file-4.anotherhash.txt from the asset store...
1905
+ ↗️ Done syncing assets
1906
+ Uploaded test-name (TIMINGS)
1907
+ Published test-name (TIMINGS)
1908
+ test-name.test-sub-domain.workers.dev"
1225
1909
  `);
1910
+ expect(std.err).toMatchInlineSnapshot(`""`);
1226
1911
  });
1227
1912
  });
1228
1913
 
@@ -1248,8 +1933,9 @@ export default{
1248
1933
  workers_dev: true,
1249
1934
  });
1250
1935
  writeWorkerSource();
1251
- mockUploadWorkerRequest();
1936
+ mockUploadWorkerRequest({ available_on_subdomain: false });
1252
1937
  mockSubDomainRequest();
1938
+ mockUpdateWorkerRequest({ enabled: true });
1253
1939
 
1254
1940
  await runWrangler("publish ./index");
1255
1941
 
@@ -1261,467 +1947,2217 @@ export default{
1261
1947
  expect(std.err).toMatchInlineSnapshot(`""`);
1262
1948
  });
1263
1949
 
1264
- it("should disable the workers.dev domain if workers_dev is `false`", async () => {
1950
+ it("should not try to enable the workers.dev domain if it has been enabled before", async () => {
1265
1951
  writeWranglerToml({
1266
- workers_dev: false,
1952
+ workers_dev: true,
1267
1953
  });
1268
1954
  writeWorkerSource();
1269
- mockUploadWorkerRequest();
1955
+ mockUploadWorkerRequest({ available_on_subdomain: true });
1270
1956
  mockSubDomainRequest();
1271
- mockUpdateWorkerRequest({ enabled: false });
1272
1957
 
1273
1958
  await runWrangler("publish ./index");
1274
1959
 
1275
1960
  expect(std.out).toMatchInlineSnapshot(`
1276
1961
  "Uploaded test-name (TIMINGS)
1277
- No publish targets for test-name (TIMINGS)"
1962
+ Published test-name (TIMINGS)
1963
+ test-name.test-sub-domain.workers.dev"
1278
1964
  `);
1279
1965
  expect(std.err).toMatchInlineSnapshot(`""`);
1280
1966
  });
1281
1967
 
1282
- it("should enable the workers.dev domain if workers_dev is undefined and subdomain is not already available", async () => {
1283
- writeWranglerToml();
1968
+ it("should disable the workers.dev domain if workers_dev is `false`", async () => {
1969
+ writeWranglerToml({
1970
+ workers_dev: false,
1971
+ });
1284
1972
  writeWorkerSource();
1285
- mockUploadWorkerRequest({ available_on_subdomain: false });
1286
- mockSubDomainRequest();
1287
- mockUpdateWorkerRequest({ enabled: true });
1973
+ mockUploadWorkerRequest();
1974
+ mockUpdateWorkerRequest({ enabled: false });
1288
1975
 
1289
1976
  await runWrangler("publish ./index");
1290
1977
 
1291
1978
  expect(std.out).toMatchInlineSnapshot(`
1292
1979
  "Uploaded test-name (TIMINGS)
1293
- Published test-name (TIMINGS)
1294
- test-name.test-sub-domain.workers.dev"
1980
+ No publish targets for test-name (TIMINGS)"
1295
1981
  `);
1296
1982
  expect(std.err).toMatchInlineSnapshot(`""`);
1297
1983
  });
1298
1984
 
1299
- it("should enable the workers.dev domain if workers_dev is true and subdomain is not already available", async () => {
1300
- writeWranglerToml({ workers_dev: true });
1985
+ it("should not try to disable the workers.dev domain if it is not already available", async () => {
1986
+ writeWranglerToml({
1987
+ workers_dev: false,
1988
+ });
1301
1989
  writeWorkerSource();
1990
+ mockSubDomainRequest("test-sub-domain", false);
1302
1991
  mockUploadWorkerRequest({ available_on_subdomain: false });
1303
- mockSubDomainRequest();
1304
- mockUpdateWorkerRequest({ enabled: true });
1992
+
1993
+ // note the lack of a mock for the subdomain disable request
1305
1994
 
1306
1995
  await runWrangler("publish ./index");
1307
1996
 
1308
1997
  expect(std.out).toMatchInlineSnapshot(`
1309
1998
  "Uploaded test-name (TIMINGS)
1310
- Published test-name (TIMINGS)
1311
- test-name.test-sub-domain.workers.dev"
1999
+ No publish targets for test-name (TIMINGS)"
1312
2000
  `);
1313
2001
  expect(std.err).toMatchInlineSnapshot(`""`);
1314
2002
  });
1315
- });
1316
2003
 
1317
- describe("custom builds", () => {
1318
- beforeEach(() => {
1319
- // @ts-expect-error disable the mock we'd setup earlier
1320
- // or else custom builds will timeout immediately
1321
- global.setTimeout.mockRestore();
1322
- });
1323
- it("should run a custom build before publishing", async () => {
2004
+ it("should disable the workers.dev domain if workers_dev is undefined but overwritten to `false` in environment", async () => {
1324
2005
  writeWranglerToml({
1325
- build: {
1326
- command: `node -e "console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')"`,
2006
+ env: {
2007
+ dev: {
2008
+ workers_dev: false,
2009
+ },
1327
2010
  },
1328
2011
  });
1329
-
2012
+ writeWorkerSource();
1330
2013
  mockUploadWorkerRequest({
1331
- expectedEntry: "return new Response(123)",
2014
+ env: "dev",
1332
2015
  });
1333
- mockSubDomainRequest();
2016
+ mockUpdateWorkerRequest({ enabled: false, env: "dev" });
2017
+
2018
+ await runWrangler("publish ./index --env dev --legacy-env false");
1334
2019
 
1335
- await runWrangler("publish index.js");
1336
2020
  expect(std.out).toMatchInlineSnapshot(`
1337
- "running: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
1338
- Uploaded test-name (TIMINGS)
1339
- Published test-name (TIMINGS)
1340
- test-name.test-sub-domain.workers.dev"
2021
+ "Uploaded test-name (dev) (TIMINGS)
2022
+ No publish targets for test-name (dev) (TIMINGS)"
1341
2023
  `);
1342
2024
  expect(std.err).toMatchInlineSnapshot(`""`);
1343
- expect(std.warn).toMatchInlineSnapshot(`""`);
1344
2025
  });
1345
2026
 
1346
- if (process.platform !== "win32") {
1347
- it("should run a custom build of multiple steps combined by && before publishing", async () => {
1348
- writeWranglerToml({
1349
- build: {
1350
- command: `echo "custom build" && echo "export default { fetch(){ return new Response(123) } }" > index.js`,
1351
- },
1352
- });
1353
-
1354
- mockUploadWorkerRequest({
1355
- expectedEntry: "return new Response(123)",
1356
- });
1357
- mockSubDomainRequest();
1358
-
1359
- await runWrangler("publish index.js");
1360
- expect(std.out).toMatchInlineSnapshot(`
1361
- "running: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
1362
- Uploaded test-name (TIMINGS)
1363
- Published test-name (TIMINGS)
1364
- test-name.test-sub-domain.workers.dev"
1365
- `);
1366
- expect(std.err).toMatchInlineSnapshot(`""`);
1367
- expect(std.warn).toMatchInlineSnapshot(`""`);
1368
- });
1369
- }
1370
- });
1371
-
1372
- describe("[wasm_modules]", () => {
1373
- it("should be able to define wasm modules for service-worker format workers", async () => {
2027
+ it("should disable the workers.dev domain if workers_dev is `true` but overwritten to `false` in environment", async () => {
1374
2028
  writeWranglerToml({
1375
- wasm_modules: {
1376
- TESTWASMNAME: "./path/to/test.wasm",
2029
+ workers_dev: true,
2030
+ env: {
2031
+ dev: {
2032
+ workers_dev: false,
2033
+ },
1377
2034
  },
1378
2035
  });
1379
- writeWorkerSource({ type: "sw" });
1380
- fs.mkdirSync("./path/to", { recursive: true });
1381
- fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
2036
+ writeWorkerSource();
1382
2037
  mockUploadWorkerRequest({
1383
- expectedType: "sw",
1384
- expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
1385
- expectedBindings: [
1386
- { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
1387
- ],
2038
+ env: "dev",
1388
2039
  });
1389
- mockSubDomainRequest();
1390
- await runWrangler("publish index.js");
2040
+ mockUpdateWorkerRequest({ enabled: false, env: "dev" });
2041
+
2042
+ await runWrangler("publish ./index --env dev --legacy-env false");
2043
+
1391
2044
  expect(std.out).toMatchInlineSnapshot(`
1392
- "Uploaded test-name (TIMINGS)
1393
- Published test-name (TIMINGS)
1394
- test-name.test-sub-domain.workers.dev"
2045
+ "Uploaded test-name (dev) (TIMINGS)
2046
+ No publish targets for test-name (dev) (TIMINGS)"
1395
2047
  `);
1396
2048
  expect(std.err).toMatchInlineSnapshot(`""`);
1397
- expect(std.warn).toMatchInlineSnapshot(`""`);
1398
2049
  });
1399
2050
 
1400
- it("should error when defining wasm modules for modules format workers", async () => {
2051
+ it("should publish to a workers.dev domain if workers_dev is undefined but overwritten to `true` in environment", async () => {
1401
2052
  writeWranglerToml({
1402
- wasm_modules: {
1403
- TESTWASMNAME: "./path/to/test.wasm",
2053
+ env: {
2054
+ dev: {
2055
+ workers_dev: true,
2056
+ },
1404
2057
  },
1405
2058
  });
1406
- writeWorkerSource({ type: "esm" });
1407
- fs.mkdirSync("./path/to", { recursive: true });
1408
- fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
2059
+ writeWorkerSource();
2060
+ mockUploadWorkerRequest({
2061
+ env: "dev",
2062
+ });
2063
+ mockSubDomainRequest();
2064
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
1409
2065
 
1410
- await expect(
1411
- runWrangler("publish index.js")
1412
- ).rejects.toThrowErrorMatchingInlineSnapshot(
1413
- `"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"`
1414
- );
1415
- expect(std.out).toMatchInlineSnapshot(`""`);
1416
- expect(std.err).toMatchInlineSnapshot(`
1417
- "You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
2066
+ await runWrangler("publish ./index --env dev --legacy-env false");
1418
2067
 
1419
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2068
+ expect(std.out).toMatchInlineSnapshot(`
2069
+ "Uploaded test-name (dev) (TIMINGS)
2070
+ Published test-name (dev) (TIMINGS)
2071
+ dev.test-name.test-sub-domain.workers.dev"
1420
2072
  `);
1421
- expect(std.warn).toMatchInlineSnapshot(`""`);
2073
+ expect(std.err).toMatchInlineSnapshot(`""`);
1422
2074
  });
1423
2075
 
1424
- it("should resolve wasm modules relative to the wrangler.toml file", async () => {
1425
- fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
1426
- fs.writeFileSync(
1427
- "./path/to/wrangler.toml",
1428
- TOML.stringify({
1429
- compatibility_date: "2022-01-12",
1430
- name: "test-name",
1431
- wasm_modules: {
1432
- TESTWASMNAME: "./and/the/path/to/test.wasm",
2076
+ it("should publish to a workers.dev domain if workers_dev is `false` but overwritten to `true` in environment", async () => {
2077
+ writeWranglerToml({
2078
+ workers_dev: false,
2079
+ env: {
2080
+ dev: {
2081
+ workers_dev: true,
1433
2082
  },
1434
- }),
1435
-
1436
- "utf-8"
1437
- );
1438
-
1439
- writeWorkerSource({ type: "sw" });
1440
- fs.writeFileSync(
1441
- "./path/to/and/the/path/to/test.wasm",
1442
- "SOME WASM CONTENT"
1443
- );
2083
+ },
2084
+ });
2085
+ writeWorkerSource();
1444
2086
  mockUploadWorkerRequest({
1445
- expectedType: "sw",
1446
- expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
1447
- expectedBindings: [
1448
- { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
1449
- ],
2087
+ env: "dev",
1450
2088
  });
1451
2089
  mockSubDomainRequest();
1452
- await runWrangler("publish index.js --config ./path/to/wrangler.toml");
2090
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
2091
+
2092
+ await runWrangler("publish ./index --env dev --legacy-env false");
2093
+
1453
2094
  expect(std.out).toMatchInlineSnapshot(`
1454
- "Uploaded test-name (TIMINGS)
1455
- Published test-name (TIMINGS)
1456
- test-name.test-sub-domain.workers.dev"
2095
+ "Uploaded test-name (dev) (TIMINGS)
2096
+ Published test-name (dev) (TIMINGS)
2097
+ dev.test-name.test-sub-domain.workers.dev"
1457
2098
  `);
1458
2099
  expect(std.err).toMatchInlineSnapshot(`""`);
1459
- expect(std.warn).toMatchInlineSnapshot(`""`);
1460
2100
  });
1461
2101
 
1462
- it("should be able to import .wasm modules from service-worker format workers", async () => {
1463
- writeWranglerToml();
1464
- fs.writeFileSync("./index.js", "import TESTWASMNAME from './test.wasm';");
1465
- fs.writeFileSync("./test.wasm", "SOME WASM CONTENT");
1466
- mockUploadWorkerRequest({
1467
- expectedType: "sw",
1468
- expectedModules: {
1469
- __94b240d0d692281e6467aa42043986e5c7eea034_test_wasm:
1470
- "SOME WASM CONTENT",
2102
+ it("should use the global compatibility_date and compatibility_flags if they are not overwritten by the environment", async () => {
2103
+ writeWranglerToml({
2104
+ compatibility_date: "2022-01-12",
2105
+ compatibility_flags: ["no_global_navigator"],
2106
+ env: {
2107
+ dev: {},
1471
2108
  },
1472
- expectedBindings: [
1473
- {
1474
- name: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
1475
- part: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
1476
- type: "wasm_module",
2109
+ });
2110
+ writeWorkerSource();
2111
+ mockUploadWorkerRequest({
2112
+ env: "dev",
2113
+ expectedCompatibilityDate: "2022-01-12",
2114
+ expectedCompatibilityFlags: ["no_global_navigator"],
2115
+ });
2116
+ mockSubDomainRequest();
2117
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
2118
+
2119
+ await runWrangler("publish ./index --env dev --legacy-env false");
2120
+
2121
+ expect(std.out).toMatchInlineSnapshot(`
2122
+ "Uploaded test-name (dev) (TIMINGS)
2123
+ Published test-name (dev) (TIMINGS)
2124
+ dev.test-name.test-sub-domain.workers.dev"
2125
+ `);
2126
+ expect(std.err).toMatchInlineSnapshot(`""`);
2127
+ });
2128
+
2129
+ it("should use the environment specific compatibility_date and compatibility_flags", async () => {
2130
+ writeWranglerToml({
2131
+ compatibility_date: "2022-01-12",
2132
+ compatibility_flags: ["no_global_navigator"],
2133
+ env: {
2134
+ dev: {
2135
+ compatibility_date: "2022-01-13",
2136
+ compatibility_flags: ["global_navigator"],
1477
2137
  },
1478
- ],
2138
+ },
2139
+ });
2140
+ writeWorkerSource();
2141
+ mockUploadWorkerRequest({
2142
+ env: "dev",
2143
+ expectedCompatibilityDate: "2022-01-13",
2144
+ expectedCompatibilityFlags: ["global_navigator"],
1479
2145
  });
1480
2146
  mockSubDomainRequest();
1481
- await runWrangler("publish index.js");
2147
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
2148
+
2149
+ await runWrangler("publish ./index --env dev --legacy-env false");
2150
+
2151
+ expect(std.out).toMatchInlineSnapshot(`
2152
+ "Uploaded test-name (dev) (TIMINGS)
2153
+ Published test-name (dev) (TIMINGS)
2154
+ dev.test-name.test-sub-domain.workers.dev"
2155
+ `);
2156
+ expect(std.err).toMatchInlineSnapshot(`""`);
2157
+ });
2158
+
2159
+ it("should use the command line --compatibility-date and --compatibility-flags if they are specified", async () => {
2160
+ writeWranglerToml({
2161
+ compatibility_date: "2022-01-12",
2162
+ compatibility_flags: ["no_global_navigator"],
2163
+ env: {
2164
+ dev: {
2165
+ compatibility_date: "2022-01-13",
2166
+ compatibility_flags: ["global_navigator"],
2167
+ },
2168
+ },
2169
+ });
2170
+ writeWorkerSource();
2171
+ mockUploadWorkerRequest({
2172
+ env: "dev",
2173
+ expectedCompatibilityDate: "2022-01-14",
2174
+ expectedCompatibilityFlags: ["url_standard"],
2175
+ });
2176
+ mockSubDomainRequest();
2177
+ mockUpdateWorkerRequest({ enabled: true, env: "dev" });
2178
+
2179
+ await runWrangler(
2180
+ "publish ./index --env dev --legacy-env false --compatibility-date 2022-01-14 --compatibility-flags url_standard"
2181
+ );
2182
+
2183
+ expect(std.out).toMatchInlineSnapshot(`
2184
+ "Uploaded test-name (dev) (TIMINGS)
2185
+ Published test-name (dev) (TIMINGS)
2186
+ dev.test-name.test-sub-domain.workers.dev"
2187
+ `);
2188
+ expect(std.err).toMatchInlineSnapshot(`""`);
2189
+ });
2190
+
2191
+ it("should enable the workers.dev domain if workers_dev is undefined and subdomain is not already available", async () => {
2192
+ writeWranglerToml();
2193
+ writeWorkerSource();
2194
+ mockUploadWorkerRequest({ available_on_subdomain: false });
2195
+ mockSubDomainRequest();
2196
+ mockUpdateWorkerRequest({ enabled: true });
2197
+
2198
+ await runWrangler("publish ./index");
2199
+
1482
2200
  expect(std.out).toMatchInlineSnapshot(`
1483
2201
  "Uploaded test-name (TIMINGS)
1484
2202
  Published test-name (TIMINGS)
1485
2203
  test-name.test-sub-domain.workers.dev"
1486
2204
  `);
1487
2205
  expect(std.err).toMatchInlineSnapshot(`""`);
1488
- expect(std.warn).toMatchInlineSnapshot(`""`);
1489
2206
  });
1490
- });
1491
2207
 
1492
- describe("[text_blobs]", () => {
1493
- it("should be able to define text blobs for service-worker format workers", async () => {
2208
+ it("should enable the workers.dev domain if workers_dev is true and subdomain is not already available", async () => {
2209
+ writeWranglerToml({ workers_dev: true });
2210
+ writeWorkerSource();
2211
+ mockUploadWorkerRequest({ available_on_subdomain: false });
2212
+ mockSubDomainRequest();
2213
+ mockUpdateWorkerRequest({ enabled: true });
2214
+
2215
+ await runWrangler("publish ./index");
2216
+
2217
+ expect(std.out).toMatchInlineSnapshot(`
2218
+ "Uploaded test-name (TIMINGS)
2219
+ Published test-name (TIMINGS)
2220
+ test-name.test-sub-domain.workers.dev"
2221
+ `);
2222
+ expect(std.err).toMatchInlineSnapshot(`""`);
2223
+ });
2224
+
2225
+ it("should error politely when publishing to workers_dev when there is no workers.dev subdomain", async () => {
1494
2226
  writeWranglerToml({
1495
- text_blobs: {
1496
- TESTTEXTBLOBNAME: "./path/to/text.file",
1497
- },
2227
+ workers_dev: true,
1498
2228
  });
1499
- writeWorkerSource({ type: "sw" });
1500
- fs.mkdirSync("./path/to", { recursive: true });
1501
- fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
1502
- mockUploadWorkerRequest({
1503
- expectedType: "sw",
1504
- expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
1505
- expectedBindings: [
1506
- {
1507
- name: "TESTTEXTBLOBNAME",
1508
- part: "TESTTEXTBLOBNAME",
1509
- type: "text_blob",
1510
- },
1511
- ],
2229
+ writeWorkerSource();
2230
+ mockUploadWorkerRequest();
2231
+ mockSubDomainRequest("does-not-exist", false);
2232
+
2233
+ await expect(runWrangler("publish ./index")).rejects
2234
+ .toThrowErrorMatchingInlineSnapshot(`
2235
+ "Error: You need to register a workers.dev subdomain before publishing to workers.dev
2236
+ You can either publish your worker to one or more routes by specifying them in wrangler.toml, or register a workers.dev subdomain here:
2237
+ https://dash.cloudflare.com/some-account-id/workers/onboarding"
2238
+ `);
2239
+ });
2240
+
2241
+ it("should not deploy to workers.dev if there are any routes defined", async () => {
2242
+ writeWranglerToml({
2243
+ routes: ["http://example.com/*"],
1512
2244
  });
2245
+ writeWorkerSource();
1513
2246
  mockSubDomainRequest();
2247
+ mockUploadWorkerRequest();
2248
+ mockUpdateWorkerRequest({
2249
+ enabled: false,
2250
+ });
2251
+ mockPublishRoutesRequest({ routes: ["http://example.com/*"] });
1514
2252
  await runWrangler("publish index.js");
2253
+
1515
2254
  expect(std.out).toMatchInlineSnapshot(`
1516
2255
  "Uploaded test-name (TIMINGS)
1517
2256
  Published test-name (TIMINGS)
1518
- test-name.test-sub-domain.workers.dev"
2257
+ http://example.com/*"
1519
2258
  `);
1520
2259
  expect(std.err).toMatchInlineSnapshot(`""`);
1521
2260
  expect(std.warn).toMatchInlineSnapshot(`""`);
1522
2261
  });
1523
2262
 
1524
- it("should error when defining text blobs for modules format workers", async () => {
2263
+ it("should not deploy to workers.dev if there are any routes defined (environments)", async () => {
1525
2264
  writeWranglerToml({
1526
- text_blobs: {
1527
- TESTTEXTBLOBNAME: "./path/to/text.file",
2265
+ routes: ["http://example.com/*"],
2266
+ env: {
2267
+ production: {
2268
+ routes: ["http://production.example.com/*"],
2269
+ },
1528
2270
  },
1529
2271
  });
1530
- writeWorkerSource({ type: "esm" });
1531
- fs.mkdirSync("./path/to", { recursive: true });
1532
- fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
1533
-
1534
- await expect(
1535
- runWrangler("publish index.js")
1536
- ).rejects.toThrowErrorMatchingInlineSnapshot(
1537
- `"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"`
1538
- );
1539
- expect(std.out).toMatchInlineSnapshot(`""`);
1540
- expect(std.err).toMatchInlineSnapshot(`
1541
- "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
2272
+ writeWorkerSource();
2273
+ mockSubDomainRequest();
2274
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2275
+ mockUpdateWorkerRequest({
2276
+ enabled: false,
2277
+ env: "production",
2278
+ legacyEnv: true,
2279
+ });
2280
+ mockPublishRoutesRequest({
2281
+ routes: ["http://production.example.com/*"],
2282
+ env: "production",
2283
+ legacyEnv: true,
2284
+ });
2285
+ await runWrangler("publish index.js --env production");
1542
2286
 
1543
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2287
+ expect(std.out).toMatchInlineSnapshot(`
2288
+ "Uploaded test-name-production (TIMINGS)
2289
+ Published test-name-production (TIMINGS)
2290
+ http://production.example.com/*"
1544
2291
  `);
2292
+ expect(std.err).toMatchInlineSnapshot(`""`);
1545
2293
  expect(std.warn).toMatchInlineSnapshot(`""`);
1546
2294
  });
1547
2295
 
1548
- it("should resolve text blobs relative to the wrangler.toml file", async () => {
1549
- fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
1550
- fs.writeFileSync(
1551
- "./path/to/wrangler.toml",
1552
- TOML.stringify({
1553
- compatibility_date: "2022-01-12",
1554
- name: "test-name",
1555
- text_blobs: {
1556
- TESTTEXTBLOBNAME: "./and/the/path/to/text.file",
2296
+ it("should not deploy to workers.dev if there are any routes defined (only in environments)", async () => {
2297
+ writeWranglerToml({
2298
+ env: {
2299
+ production: {
2300
+ routes: ["http://production.example.com/*"],
1557
2301
  },
1558
- }),
2302
+ },
2303
+ });
2304
+ writeWorkerSource();
2305
+ mockSubDomainRequest();
2306
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2307
+ mockUpdateWorkerRequest({
2308
+ enabled: false,
2309
+ env: "production",
2310
+ legacyEnv: true,
2311
+ });
2312
+ mockPublishRoutesRequest({
2313
+ routes: ["http://production.example.com/*"],
2314
+ env: "production",
2315
+ legacyEnv: true,
2316
+ });
2317
+ await runWrangler("publish index.js --env production");
1559
2318
 
1560
- "utf-8"
1561
- );
2319
+ expect(std.out).toMatchInlineSnapshot(`
2320
+ "Uploaded test-name-production (TIMINGS)
2321
+ Published test-name-production (TIMINGS)
2322
+ http://production.example.com/*"
2323
+ `);
2324
+ expect(std.err).toMatchInlineSnapshot(`""`);
2325
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2326
+ });
1562
2327
 
1563
- writeWorkerSource({ type: "sw" });
1564
- fs.writeFileSync(
1565
- "./path/to/and/the/path/to/text.file",
1566
- "SOME TEXT CONTENT"
1567
- );
1568
- mockUploadWorkerRequest({
1569
- expectedType: "sw",
1570
- expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
1571
- expectedBindings: [
1572
- {
1573
- name: "TESTTEXTBLOBNAME",
1574
- part: "TESTTEXTBLOBNAME",
1575
- type: "text_blob",
1576
- },
1577
- ],
2328
+ it("can deploy to both workers.dev and routes if both defined ", async () => {
2329
+ writeWranglerToml({
2330
+ workers_dev: true,
2331
+ routes: ["http://example.com/*"],
1578
2332
  });
2333
+ writeWorkerSource();
1579
2334
  mockSubDomainRequest();
1580
- await runWrangler("publish index.js --config ./path/to/wrangler.toml");
2335
+ mockUploadWorkerRequest();
2336
+ mockUpdateWorkerRequest({
2337
+ enabled: false,
2338
+ });
2339
+ mockPublishRoutesRequest({
2340
+ routes: ["http://example.com/*"],
2341
+ });
2342
+ await runWrangler("publish index.js");
2343
+
1581
2344
  expect(std.out).toMatchInlineSnapshot(`
1582
2345
  "Uploaded test-name (TIMINGS)
1583
2346
  Published test-name (TIMINGS)
1584
- test-name.test-sub-domain.workers.dev"
2347
+ test-name.test-sub-domain.workers.dev
2348
+ http://example.com/*"
1585
2349
  `);
1586
2350
  expect(std.err).toMatchInlineSnapshot(`""`);
1587
2351
  expect(std.warn).toMatchInlineSnapshot(`""`);
1588
2352
  });
1589
- });
1590
2353
 
1591
- describe("vars bindings", () => {
1592
- it("should support json bindings", async () => {
2354
+ it("can deploy to both workers.dev and routes if both defined (environments: 1)", async () => {
1593
2355
  writeWranglerToml({
1594
- vars: {
1595
- text: "plain ol' string",
1596
- count: 1,
1597
- complex: { enabled: true, id: 123 },
2356
+ workers_dev: true,
2357
+ env: {
2358
+ production: {
2359
+ routes: ["http://production.example.com/*"],
2360
+ },
1598
2361
  },
1599
2362
  });
1600
2363
  writeWorkerSource();
1601
2364
  mockSubDomainRequest();
1602
- mockUploadWorkerRequest({
1603
- expectedBindings: [
1604
- { name: "text", type: "plain_text", text: "plain ol' string" },
1605
- { name: "count", type: "json", json: 1 },
1606
- {
1607
- name: "complex",
1608
- type: "json",
1609
- json: { enabled: true, id: 123 },
2365
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2366
+ mockUpdateWorkerRequest({
2367
+ enabled: false,
2368
+ env: "production",
2369
+ legacyEnv: true,
2370
+ });
2371
+ mockPublishRoutesRequest({
2372
+ routes: ["http://production.example.com/*"],
2373
+ env: "production",
2374
+ legacyEnv: true,
2375
+ });
2376
+ await runWrangler("publish index.js --env production");
2377
+
2378
+ expect(std.out).toMatchInlineSnapshot(`
2379
+ "Uploaded test-name-production (TIMINGS)
2380
+ Published test-name-production (TIMINGS)
2381
+ test-name-production.test-sub-domain.workers.dev
2382
+ http://production.example.com/*"
2383
+ `);
2384
+ expect(std.err).toMatchInlineSnapshot(`""`);
2385
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2386
+ });
2387
+
2388
+ it("can deploy to both workers.dev and routes if both defined (environments: 2)", async () => {
2389
+ writeWranglerToml({
2390
+ env: {
2391
+ production: {
2392
+ workers_dev: true,
2393
+ routes: ["http://production.example.com/*"],
1610
2394
  },
1611
- ],
2395
+ },
2396
+ });
2397
+ writeWorkerSource();
2398
+ mockSubDomainRequest();
2399
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2400
+ mockUpdateWorkerRequest({
2401
+ enabled: false,
2402
+ env: "production",
2403
+ legacyEnv: true,
1612
2404
  });
2405
+ mockPublishRoutesRequest({
2406
+ routes: ["http://production.example.com/*"],
2407
+ env: "production",
2408
+ legacyEnv: true,
2409
+ });
2410
+ await runWrangler("publish index.js --env production");
1613
2411
 
1614
- await runWrangler("publish index.js");
1615
2412
  expect(std.out).toMatchInlineSnapshot(`
1616
- "Uploaded test-name (TIMINGS)
1617
- Published test-name (TIMINGS)
1618
- test-name.test-sub-domain.workers.dev"
2413
+ "Uploaded test-name-production (TIMINGS)
2414
+ Published test-name-production (TIMINGS)
2415
+ test-name-production.test-sub-domain.workers.dev
2416
+ http://production.example.com/*"
1619
2417
  `);
1620
2418
  expect(std.err).toMatchInlineSnapshot(`""`);
1621
2419
  expect(std.warn).toMatchInlineSnapshot(`""`);
1622
2420
  });
1623
- });
1624
2421
 
1625
- describe("r2 bucket bindings", () => {
1626
- it("should support r2 bucket bindings", async () => {
2422
+ it("will deploy only to routes when workers_dev is false (environments 1) ", async () => {
1627
2423
  writeWranglerToml({
1628
- r2_buckets: [{ binding: "FOO", bucket_name: "foo-bucket" }],
2424
+ workers_dev: false,
2425
+ env: {
2426
+ production: {
2427
+ routes: ["http://production.example.com/*"],
2428
+ },
2429
+ },
1629
2430
  });
1630
2431
  writeWorkerSource();
1631
2432
  mockSubDomainRequest();
1632
- mockUploadWorkerRequest({
1633
- expectedBindings: [
1634
- { bucket_name: "foo-bucket", name: "FOO", type: "r2_bucket" },
1635
- ],
2433
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2434
+ mockUpdateWorkerRequest({
2435
+ enabled: false,
2436
+ env: "production",
2437
+ legacyEnv: true,
1636
2438
  });
2439
+ mockPublishRoutesRequest({
2440
+ routes: ["http://production.example.com/*"],
2441
+ env: "production",
2442
+ legacyEnv: true,
2443
+ });
2444
+ await runWrangler("publish index.js --env production");
1637
2445
 
1638
- await runWrangler("publish index.js");
1639
2446
  expect(std.out).toMatchInlineSnapshot(`
1640
- "Uploaded test-name (TIMINGS)
1641
- Published test-name (TIMINGS)
1642
- test-name.test-sub-domain.workers.dev"
2447
+ "Uploaded test-name-production (TIMINGS)
2448
+ Published test-name-production (TIMINGS)
2449
+ http://production.example.com/*"
1643
2450
  `);
1644
2451
  expect(std.err).toMatchInlineSnapshot(`""`);
1645
2452
  expect(std.warn).toMatchInlineSnapshot(`""`);
1646
2453
  });
1647
- });
1648
2454
 
1649
- describe("unsafe bindings", () => {
1650
- it("should warn if using unsafe bindings", async () => {
2455
+ it("will deploy only to routes when workers_dev is false (environments 2) ", async () => {
1651
2456
  writeWranglerToml({
1652
- unsafe: {
1653
- bindings: [
1654
- {
1655
- name: "my-binding",
1656
- type: "binding-type",
1657
- param: "binding-param",
1658
- },
1659
- ],
2457
+ env: {
2458
+ production: {
2459
+ workers_dev: false,
2460
+ routes: ["http://production.example.com/*"],
2461
+ },
1660
2462
  },
1661
2463
  });
1662
- writeWorkerSource();
1663
- mockSubDomainRequest();
1664
- mockUploadWorkerRequest({
1665
- expectedBindings: [
1666
- {
1667
- name: "my-binding",
1668
- type: "binding-type",
1669
- param: "binding-param",
2464
+ writeWorkerSource();
2465
+ mockSubDomainRequest();
2466
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2467
+ mockUpdateWorkerRequest({
2468
+ enabled: false,
2469
+ env: "production",
2470
+ legacyEnv: true,
2471
+ });
2472
+ mockPublishRoutesRequest({
2473
+ routes: ["http://production.example.com/*"],
2474
+ env: "production",
2475
+ legacyEnv: true,
2476
+ });
2477
+ await runWrangler("publish index.js --env production");
2478
+
2479
+ expect(std.out).toMatchInlineSnapshot(`
2480
+ "Uploaded test-name-production (TIMINGS)
2481
+ Published test-name-production (TIMINGS)
2482
+ http://production.example.com/*"
2483
+ `);
2484
+ expect(std.err).toMatchInlineSnapshot(`""`);
2485
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2486
+ });
2487
+ });
2488
+
2489
+ describe("custom builds", () => {
2490
+ beforeEach(() => {
2491
+ // @ts-expect-error disable the mock we'd setup earlier
2492
+ // or else custom builds will timeout immediately
2493
+ global.setTimeout.mockRestore();
2494
+ });
2495
+ it("should run a custom build before publishing", async () => {
2496
+ writeWranglerToml({
2497
+ build: {
2498
+ command: `node -e "console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')"`,
2499
+ },
2500
+ });
2501
+
2502
+ mockUploadWorkerRequest({
2503
+ expectedEntry: "return new Response(123)",
2504
+ });
2505
+ mockSubDomainRequest();
2506
+
2507
+ await runWrangler("publish index.js");
2508
+ expect(std.out).toMatchInlineSnapshot(`
2509
+ "Running custom build: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
2510
+ Uploaded test-name (TIMINGS)
2511
+ Published test-name (TIMINGS)
2512
+ test-name.test-sub-domain.workers.dev"
2513
+ `);
2514
+ expect(std.err).toMatchInlineSnapshot(`""`);
2515
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2516
+ });
2517
+
2518
+ if (process.platform !== "win32") {
2519
+ it("should run a custom build of multiple steps combined by && before publishing", async () => {
2520
+ writeWranglerToml({
2521
+ build: {
2522
+ command: `echo "custom build" && echo "export default { fetch(){ return new Response(123) } }" > index.js`,
2523
+ },
2524
+ });
2525
+
2526
+ mockUploadWorkerRequest({
2527
+ expectedEntry: "return new Response(123)",
2528
+ });
2529
+ mockSubDomainRequest();
2530
+
2531
+ await runWrangler("publish index.js");
2532
+ expect(std.out).toMatchInlineSnapshot(`
2533
+ "Running custom build: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
2534
+ Uploaded test-name (TIMINGS)
2535
+ Published test-name (TIMINGS)
2536
+ test-name.test-sub-domain.workers.dev"
2537
+ `);
2538
+ expect(std.err).toMatchInlineSnapshot(`""`);
2539
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2540
+ });
2541
+ }
2542
+
2543
+ it("should throw an error if the entry doesn't exist after the build finishes", async () => {
2544
+ writeWranglerToml({
2545
+ main: "index.js",
2546
+ build: {
2547
+ command: `node -e "console.log('custom build');"`,
2548
+ },
2549
+ });
2550
+
2551
+ await expect(
2552
+ runWrangler("publish index.js")
2553
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
2554
+ `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
2555
+ );
2556
+ expect(std.out).toMatchInlineSnapshot(`
2557
+ "Running custom build: node -e \\"console.log('custom build');\\"
2558
+
2559
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2560
+ `);
2561
+ expect(std.err).toMatchInlineSnapshot(`
2562
+ "X [ERROR] Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
2563
+
2564
+ "
2565
+ `);
2566
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2567
+ });
2568
+
2569
+ it("should minify the script when `--minify` is true (sw)", async () => {
2570
+ writeWranglerToml({
2571
+ main: "./index.js",
2572
+ });
2573
+ fs.writeFileSync(
2574
+ "./index.js",
2575
+ `export
2576
+ default {
2577
+ fetch() {
2578
+ return new Response( "hello Cpt Picard" )
2579
+ }
2580
+ }
2581
+ `
2582
+ );
2583
+
2584
+ mockUploadWorkerRequest({
2585
+ expectedEntry: 'fetch(){return new Response("hello Cpt Picard")',
2586
+ });
2587
+
2588
+ mockSubDomainRequest();
2589
+ await runWrangler("publish index.js --minify");
2590
+ expect(std.out).toMatchInlineSnapshot(`
2591
+ "Uploaded test-name (TIMINGS)
2592
+ Published test-name (TIMINGS)
2593
+ test-name.test-sub-domain.workers.dev"
2594
+ `);
2595
+ expect(std.err).toMatchInlineSnapshot(`""`);
2596
+ });
2597
+
2598
+ it("should minify the script when `minify` in config is true (esm)", async () => {
2599
+ writeWranglerToml({
2600
+ main: "./index.js",
2601
+ legacy_env: false,
2602
+ env: {
2603
+ testEnv: {
2604
+ minify: true,
2605
+ },
2606
+ },
2607
+ });
2608
+ fs.writeFileSync(
2609
+ "./index.js",
2610
+ `export
2611
+ default {
2612
+ fetch() {
2613
+ return new Response( "hello Cpt Picard" )
2614
+ }
2615
+ }
2616
+ `
2617
+ );
2618
+
2619
+ mockUploadWorkerRequest({
2620
+ env: "testEnv",
2621
+ expectedType: "esm",
2622
+ legacyEnv: false,
2623
+ expectedEntry: `fetch(){return new Response("hello Cpt Picard")`,
2624
+ });
2625
+
2626
+ mockSubDomainRequest();
2627
+ await runWrangler("publish -e testEnv index.js");
2628
+ expect(std.out).toMatchInlineSnapshot(`
2629
+ "Uploaded test-name (testEnv) (TIMINGS)
2630
+ Published test-name (testEnv) (TIMINGS)
2631
+ testEnv.test-name.test-sub-domain.workers.dev"
2632
+ `);
2633
+ expect(std.err).toMatchInlineSnapshot(`""`);
2634
+ });
2635
+ });
2636
+
2637
+ describe("durable object migrations", () => {
2638
+ it("should warn when you try to publish durable objects without migrations", async () => {
2639
+ writeWranglerToml({
2640
+ durable_objects: {
2641
+ bindings: [{ name: "SOMENAME", class_name: "SomeClass" }],
2642
+ },
2643
+ });
2644
+ fs.writeFileSync(
2645
+ "index.js",
2646
+ `export class SomeClass{}; export default {};`
2647
+ );
2648
+ mockSubDomainRequest();
2649
+ mockUploadWorkerRequest();
2650
+ await runWrangler("publish index.js");
2651
+ expect(std.out).toMatchInlineSnapshot(`
2652
+ "Uploaded test-name (TIMINGS)
2653
+ Published test-name (TIMINGS)
2654
+ test-name.test-sub-domain.workers.dev"
2655
+ `);
2656
+ expect(std.err).toMatchInlineSnapshot(`""`);
2657
+ expect(std.warn).toMatchInlineSnapshot(`
2658
+ "▲ [WARNING] In wrangler.toml, you have configured [durable_objects] exported by this Worker (SomeClass), but no [migrations] for them. This may not work as expected until you add a [migrations] section to your wrangler.toml. Refer to https://developers.cloudflare.com/workers/learning/using-durable-objects/#durable-object-migrations-in-wranglertoml for more details.
2659
+
2660
+ "
2661
+ `);
2662
+ });
2663
+
2664
+ it("does not warn if all the durable object bindings are to external classes", async () => {
2665
+ writeWranglerToml({
2666
+ durable_objects: {
2667
+ bindings: [
2668
+ {
2669
+ name: "SOMENAME",
2670
+ class_name: "SomeClass",
2671
+ script_name: "some-script",
2672
+ },
2673
+ ],
2674
+ },
2675
+ });
2676
+ fs.writeFileSync(
2677
+ "index.js",
2678
+ `export class SomeClass{}; export default {};`
2679
+ );
2680
+ mockSubDomainRequest();
2681
+ mockUploadWorkerRequest();
2682
+ await runWrangler("publish index.js");
2683
+ expect(std.out).toMatchInlineSnapshot(`
2684
+ "Uploaded test-name (TIMINGS)
2685
+ Published test-name (TIMINGS)
2686
+ test-name.test-sub-domain.workers.dev"
2687
+ `);
2688
+ expect(std.err).toMatchInlineSnapshot(`""`);
2689
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2690
+ });
2691
+
2692
+ it("should publish all migrations on first publish", async () => {
2693
+ writeWranglerToml({
2694
+ durable_objects: {
2695
+ bindings: [
2696
+ { name: "SOMENAME", class_name: "SomeClass" },
2697
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2698
+ ],
2699
+ },
2700
+ migrations: [
2701
+ { tag: "v1", new_classes: ["SomeClass"] },
2702
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2703
+ ],
2704
+ });
2705
+ fs.writeFileSync(
2706
+ "index.js",
2707
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2708
+ );
2709
+ mockSubDomainRequest();
2710
+ mockLegacyScriptData({ scripts: [] }); // no previously uploaded scripts at all
2711
+ mockUploadWorkerRequest({
2712
+ expectedMigrations: {
2713
+ new_tag: "v2",
2714
+ steps: [
2715
+ { new_classes: ["SomeClass"] },
2716
+ { new_classes: ["SomeOtherClass"] },
2717
+ ],
2718
+ },
2719
+ });
2720
+
2721
+ await runWrangler("publish index.js");
2722
+ expect(std.out).toMatchInlineSnapshot(`
2723
+ "Uploaded test-name (TIMINGS)
2724
+ Published test-name (TIMINGS)
2725
+ test-name.test-sub-domain.workers.dev"
2726
+ `);
2727
+ expect(std.err).toMatchInlineSnapshot(`""`);
2728
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2729
+ });
2730
+
2731
+ it("should upload migrations past a previously uploaded tag", async () => {
2732
+ writeWranglerToml({
2733
+ durable_objects: {
2734
+ bindings: [
2735
+ { name: "SOMENAME", class_name: "SomeClass" },
2736
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2737
+ ],
2738
+ },
2739
+ migrations: [
2740
+ { tag: "v1", new_classes: ["SomeClass"] },
2741
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2742
+ ],
2743
+ });
2744
+ fs.writeFileSync(
2745
+ "index.js",
2746
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2747
+ );
2748
+ mockSubDomainRequest();
2749
+ mockLegacyScriptData({
2750
+ scripts: [{ id: "test-name", migration_tag: "v1" }],
2751
+ });
2752
+ mockUploadWorkerRequest({
2753
+ expectedMigrations: {
2754
+ old_tag: "v1",
2755
+ new_tag: "v2",
2756
+ steps: [
2757
+ {
2758
+ new_classes: ["SomeOtherClass"],
2759
+ },
2760
+ ],
2761
+ },
2762
+ });
2763
+
2764
+ await runWrangler("publish index.js");
2765
+ expect(std).toMatchInlineSnapshot(`
2766
+ Object {
2767
+ "debug": "",
2768
+ "err": "",
2769
+ "out": "Uploaded test-name (TIMINGS)
2770
+ Published test-name (TIMINGS)
2771
+ test-name.test-sub-domain.workers.dev",
2772
+ "warn": "",
2773
+ }
2774
+ `);
2775
+ });
2776
+
2777
+ it("should not send migrations if they've all already been sent", async () => {
2778
+ writeWranglerToml({
2779
+ durable_objects: {
2780
+ bindings: [
2781
+ { name: "SOMENAME", class_name: "SomeClass" },
2782
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2783
+ ],
2784
+ },
2785
+ migrations: [
2786
+ { tag: "v1", new_classes: ["SomeClass"] },
2787
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2788
+ { tag: "v3", new_classes: ["YetAnotherClass"] },
2789
+ ],
2790
+ });
2791
+ fs.writeFileSync(
2792
+ "index.js",
2793
+ `export class SomeClass{}; export class SomeOtherClass{}; export class YetAnotherClass{}; export default {};`
2794
+ );
2795
+ mockSubDomainRequest();
2796
+ mockLegacyScriptData({
2797
+ scripts: [{ id: "test-name", migration_tag: "v3" }],
2798
+ });
2799
+ mockUploadWorkerRequest({
2800
+ expectedMigrations: undefined,
2801
+ });
2802
+
2803
+ await runWrangler("publish index.js");
2804
+ expect(std).toMatchInlineSnapshot(`
2805
+ Object {
2806
+ "debug": "",
2807
+ "err": "",
2808
+ "out": "Uploaded test-name (TIMINGS)
2809
+ Published test-name (TIMINGS)
2810
+ test-name.test-sub-domain.workers.dev",
2811
+ "warn": "",
2812
+ }
2813
+ `);
2814
+ });
2815
+
2816
+ describe("service environments", () => {
2817
+ it("should publish all migrations on first publish", async () => {
2818
+ writeWranglerToml({
2819
+ durable_objects: {
2820
+ bindings: [
2821
+ { name: "SOMENAME", class_name: "SomeClass" },
2822
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2823
+ ],
2824
+ },
2825
+ migrations: [
2826
+ { tag: "v1", new_classes: ["SomeClass"] },
2827
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2828
+ ],
2829
+ });
2830
+ fs.writeFileSync(
2831
+ "index.js",
2832
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2833
+ );
2834
+ mockSubDomainRequest();
2835
+ mockServiceScriptData({}); // no scripts at all
2836
+ mockUploadWorkerRequest({
2837
+ legacyEnv: false,
2838
+ expectedMigrations: {
2839
+ new_tag: "v2",
2840
+ steps: [
2841
+ { new_classes: ["SomeClass"] },
2842
+ { new_classes: ["SomeOtherClass"] },
2843
+ ],
2844
+ },
2845
+ });
2846
+
2847
+ await runWrangler("publish index.js --legacy-env false");
2848
+ expect(std.out).toMatchInlineSnapshot(`
2849
+ "Uploaded test-name (TIMINGS)
2850
+ Published test-name (TIMINGS)
2851
+ test-name.test-sub-domain.workers.dev"
2852
+ `);
2853
+ expect(std.err).toMatchInlineSnapshot(`""`);
2854
+ expect(std.warn).toMatchInlineSnapshot(`
2855
+ "▲ [WARNING] Processing wrangler.toml configuration:
2856
+
2857
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
2858
+ the future. DO NOT USE IN PRODUCTION.
2859
+
2860
+ "
2861
+ `);
2862
+ });
2863
+
2864
+ it("should publish all migrations on first publish (--env)", async () => {
2865
+ writeWranglerToml({
2866
+ durable_objects: {
2867
+ bindings: [
2868
+ { name: "SOMENAME", class_name: "SomeClass" },
2869
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2870
+ ],
2871
+ },
2872
+ env: {
2873
+ xyz: {
2874
+ durable_objects: {
2875
+ bindings: [
2876
+ { name: "SOMENAME", class_name: "SomeClass" },
2877
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2878
+ ],
2879
+ },
2880
+ },
2881
+ },
2882
+ migrations: [
2883
+ { tag: "v1", new_classes: ["SomeClass"] },
2884
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2885
+ ],
2886
+ });
2887
+ fs.writeFileSync(
2888
+ "index.js",
2889
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2890
+ );
2891
+ mockSubDomainRequest();
2892
+ mockServiceScriptData({ env: "xyz" }); // no scripts at all
2893
+ mockUploadWorkerRequest({
2894
+ legacyEnv: false,
2895
+ env: "xyz",
2896
+ expectedMigrations: {
2897
+ new_tag: "v2",
2898
+ steps: [
2899
+ { new_classes: ["SomeClass"] },
2900
+ { new_classes: ["SomeOtherClass"] },
2901
+ ],
2902
+ },
2903
+ });
2904
+
2905
+ await runWrangler("publish index.js --legacy-env false --env xyz");
2906
+ expect(std.out).toMatchInlineSnapshot(`
2907
+ "Uploaded test-name (xyz) (TIMINGS)
2908
+ Published test-name (xyz) (TIMINGS)
2909
+ xyz.test-name.test-sub-domain.workers.dev"
2910
+ `);
2911
+ expect(std.err).toMatchInlineSnapshot(`""`);
2912
+ expect(std.warn).toMatchInlineSnapshot(`
2913
+ "▲ [WARNING] Processing wrangler.toml configuration:
2914
+
2915
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
2916
+ the future. DO NOT USE IN PRODUCTION.
2917
+
2918
+ "
2919
+ `);
2920
+ });
2921
+
2922
+ it("should use a script's current migration tag when publishing migrations", async () => {
2923
+ writeWranglerToml({
2924
+ durable_objects: {
2925
+ bindings: [
2926
+ { name: "SOMENAME", class_name: "SomeClass" },
2927
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2928
+ ],
2929
+ },
2930
+ migrations: [
2931
+ { tag: "v1", new_classes: ["SomeClass"] },
2932
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2933
+ ],
2934
+ });
2935
+ fs.writeFileSync(
2936
+ "index.js",
2937
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2938
+ );
2939
+ mockSubDomainRequest();
2940
+ mockServiceScriptData({
2941
+ script: { id: "test-name", migration_tag: "v1" },
2942
+ });
2943
+ mockUploadWorkerRequest({
2944
+ legacyEnv: false,
2945
+ expectedMigrations: {
2946
+ old_tag: "v1",
2947
+ new_tag: "v2",
2948
+ steps: [
2949
+ {
2950
+ new_classes: ["SomeOtherClass"],
2951
+ },
2952
+ ],
2953
+ },
2954
+ });
2955
+
2956
+ await runWrangler("publish index.js --legacy-env false");
2957
+ expect(std).toMatchInlineSnapshot(`
2958
+ Object {
2959
+ "debug": "",
2960
+ "err": "",
2961
+ "out": "Uploaded test-name (TIMINGS)
2962
+ Published test-name (TIMINGS)
2963
+ test-name.test-sub-domain.workers.dev",
2964
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
2965
+
2966
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
2967
+ the future. DO NOT USE IN PRODUCTION.
2968
+
2969
+ ",
2970
+ }
2971
+ `);
2972
+ });
2973
+
2974
+ it("should use an environment's current migration tag when publishing migrations", async () => {
2975
+ writeWranglerToml({
2976
+ durable_objects: {
2977
+ bindings: [
2978
+ { name: "SOMENAME", class_name: "SomeClass" },
2979
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2980
+ ],
2981
+ },
2982
+ env: {
2983
+ xyz: {
2984
+ durable_objects: {
2985
+ bindings: [
2986
+ { name: "SOMENAME", class_name: "SomeClass" },
2987
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2988
+ ],
2989
+ },
2990
+ },
2991
+ },
2992
+ migrations: [
2993
+ { tag: "v1", new_classes: ["SomeClass"] },
2994
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2995
+ ],
2996
+ });
2997
+ fs.writeFileSync(
2998
+ "index.js",
2999
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
3000
+ );
3001
+ mockSubDomainRequest();
3002
+ mockServiceScriptData({
3003
+ script: { id: "test-name", migration_tag: "v1" },
3004
+ env: "xyz",
3005
+ });
3006
+ mockUploadWorkerRequest({
3007
+ legacyEnv: false,
3008
+ env: "xyz",
3009
+ expectedMigrations: {
3010
+ old_tag: "v1",
3011
+ new_tag: "v2",
3012
+ steps: [
3013
+ {
3014
+ new_classes: ["SomeOtherClass"],
3015
+ },
3016
+ ],
3017
+ },
3018
+ });
3019
+
3020
+ await runWrangler("publish index.js --legacy-env false --env xyz");
3021
+ expect(std).toMatchInlineSnapshot(`
3022
+ Object {
3023
+ "debug": "",
3024
+ "err": "",
3025
+ "out": "Uploaded test-name (xyz) (TIMINGS)
3026
+ Published test-name (xyz) (TIMINGS)
3027
+ xyz.test-name.test-sub-domain.workers.dev",
3028
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
3029
+
3030
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
3031
+ the future. DO NOT USE IN PRODUCTION.
3032
+
3033
+ ",
3034
+ }
3035
+ `);
3036
+ });
3037
+ });
3038
+ });
3039
+
3040
+ describe("bindings", () => {
3041
+ it("should allow bindings with different names", async () => {
3042
+ writeWranglerToml({
3043
+ migrations: [
3044
+ {
3045
+ tag: "v1",
3046
+ new_classes: ["SomeDurableObject", "AnotherDurableObject"],
3047
+ },
3048
+ ],
3049
+ durable_objects: {
3050
+ bindings: [
3051
+ {
3052
+ name: "DURABLE_OBJECT_ONE",
3053
+ class_name: "SomeDurableObject",
3054
+ script_name: "some-durable-object-worker",
3055
+ },
3056
+ {
3057
+ name: "DURABLE_OBJECT_TWO",
3058
+ class_name: "AnotherDurableObject",
3059
+ script_name: "another-durable-object-worker",
3060
+ },
3061
+ ],
3062
+ },
3063
+ kv_namespaces: [
3064
+ { binding: "KV_NAMESPACE_ONE", id: "kv-ns-one-id" },
3065
+ { binding: "KV_NAMESPACE_TWO", id: "kv-ns-two-id" },
3066
+ ],
3067
+ r2_buckets: [
3068
+ { binding: "R2_BUCKET_ONE", bucket_name: "r2-bucket-one-name" },
3069
+ { binding: "R2_BUCKET_TWO", bucket_name: "r2-bucket-two-name" },
3070
+ ],
3071
+ text_blobs: {
3072
+ TEXT_BLOB_ONE: "./my-entire-app-depends-on-this.cfg",
3073
+ TEXT_BLOB_TWO: "./the-entirety-of-human-knowledge.txt",
3074
+ },
3075
+ unsafe: {
3076
+ bindings: [
3077
+ {
3078
+ name: "UNSAFE_BINDING_ONE",
3079
+ type: "some unsafe thing",
3080
+ data: { some: { unsafe: "thing" } },
3081
+ },
3082
+ {
3083
+ name: "UNSAFE_BINDING_TWO",
3084
+ type: "another unsafe thing",
3085
+ data: 1337,
3086
+ },
3087
+ ],
3088
+ },
3089
+ vars: {
3090
+ ENV_VAR_ONE: 123,
3091
+ ENV_VAR_TWO: "Hello, I'm an environment variable",
3092
+ },
3093
+ wasm_modules: {
3094
+ WASM_MODULE_ONE: "./some_wasm.wasm",
3095
+ WASM_MODULE_TWO: "./more_wasm.wasm",
3096
+ },
3097
+ data_blobs: {
3098
+ DATA_BLOB_ONE: "./some-data-blob.bin",
3099
+ DATA_BLOB_TWO: "./more-data-blob.bin",
3100
+ },
3101
+ });
3102
+
3103
+ writeWorkerSource({ type: "sw" });
3104
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
3105
+ fs.writeFileSync(
3106
+ "./the-entirety-of-human-knowledge.txt",
3107
+ "Everything's bigger in Texas"
3108
+ );
3109
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
3110
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
3111
+
3112
+ fs.writeFileSync("./some-data-blob.bin", "some data");
3113
+ fs.writeFileSync("./more-data-blob.bin", "more data");
3114
+
3115
+ mockUploadWorkerRequest({
3116
+ expectedType: "sw",
3117
+ expectedBindings: [
3118
+ {
3119
+ name: "KV_NAMESPACE_ONE",
3120
+ namespace_id: "kv-ns-one-id",
3121
+ type: "kv_namespace",
3122
+ },
3123
+ {
3124
+ name: "KV_NAMESPACE_TWO",
3125
+ namespace_id: "kv-ns-two-id",
3126
+ type: "kv_namespace",
3127
+ },
3128
+ {
3129
+ class_name: "SomeDurableObject",
3130
+ name: "DURABLE_OBJECT_ONE",
3131
+ script_name: "some-durable-object-worker",
3132
+ type: "durable_object_namespace",
3133
+ },
3134
+ {
3135
+ class_name: "AnotherDurableObject",
3136
+ name: "DURABLE_OBJECT_TWO",
3137
+ script_name: "another-durable-object-worker",
3138
+ type: "durable_object_namespace",
3139
+ },
3140
+ {
3141
+ bucket_name: "r2-bucket-one-name",
3142
+ name: "R2_BUCKET_ONE",
3143
+ type: "r2_bucket",
3144
+ },
3145
+ {
3146
+ bucket_name: "r2-bucket-two-name",
3147
+ name: "R2_BUCKET_TWO",
3148
+ type: "r2_bucket",
3149
+ },
3150
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
3151
+ {
3152
+ name: "ENV_VAR_TWO",
3153
+ text: "Hello, I'm an environment variable",
3154
+ type: "plain_text",
3155
+ },
3156
+ {
3157
+ name: "WASM_MODULE_ONE",
3158
+ part: "WASM_MODULE_ONE",
3159
+ type: "wasm_module",
3160
+ },
3161
+ {
3162
+ name: "WASM_MODULE_TWO",
3163
+ part: "WASM_MODULE_TWO",
3164
+ type: "wasm_module",
3165
+ },
3166
+ { name: "TEXT_BLOB_ONE", part: "TEXT_BLOB_ONE", type: "text_blob" },
3167
+ { name: "TEXT_BLOB_TWO", part: "TEXT_BLOB_TWO", type: "text_blob" },
3168
+ { name: "DATA_BLOB_ONE", part: "DATA_BLOB_ONE", type: "data_blob" },
3169
+ { name: "DATA_BLOB_TWO", part: "DATA_BLOB_TWO", type: "data_blob" },
3170
+ {
3171
+ data: { some: { unsafe: "thing" } },
3172
+ name: "UNSAFE_BINDING_ONE",
3173
+ type: "some unsafe thing",
3174
+ },
3175
+ {
3176
+ data: 1337,
3177
+ name: "UNSAFE_BINDING_TWO",
3178
+ type: "another unsafe thing",
3179
+ },
3180
+ ],
3181
+ });
3182
+ mockSubDomainRequest();
3183
+ mockLegacyScriptData({ scripts: [] });
3184
+
3185
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
3186
+ expect(std.out).toMatchInlineSnapshot(`
3187
+ "Uploaded test-name (TIMINGS)
3188
+ Published test-name (TIMINGS)
3189
+ test-name.test-sub-domain.workers.dev"
3190
+ `);
3191
+ expect(std.err).toMatchInlineSnapshot(`""`);
3192
+ expect(std.warn).toMatchInlineSnapshot(`
3193
+ "▲ [WARNING] Processing wrangler.toml configuration:
3194
+
3195
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3196
+
3197
+ "
3198
+ `);
3199
+ });
3200
+
3201
+ it("should error when bindings of different types have the same name", async () => {
3202
+ writeWranglerToml({
3203
+ durable_objects: {
3204
+ bindings: [
3205
+ {
3206
+ name: "CONFLICTING_NAME_ONE",
3207
+ class_name: "SomeDurableObject",
3208
+ script_name: "some-durable-object-worker",
3209
+ },
3210
+ {
3211
+ name: "CONFLICTING_NAME_TWO",
3212
+ class_name: "AnotherDurableObject",
3213
+ script_name: "another-durable-object-worker",
3214
+ },
3215
+ ],
3216
+ },
3217
+ kv_namespaces: [
3218
+ { binding: "CONFLICTING_NAME_ONE", id: "kv-ns-one-id" },
3219
+ { binding: "CONFLICTING_NAME_TWO", id: "kv-ns-two-id" },
3220
+ ],
3221
+ r2_buckets: [
3222
+ {
3223
+ binding: "CONFLICTING_NAME_ONE",
3224
+ bucket_name: "r2-bucket-one-name",
3225
+ },
3226
+ {
3227
+ binding: "CONFLICTING_NAME_THREE",
3228
+ bucket_name: "r2-bucket-two-name",
3229
+ },
3230
+ ],
3231
+ text_blobs: {
3232
+ CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
3233
+ CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
3234
+ },
3235
+ unsafe: {
3236
+ bindings: [
3237
+ {
3238
+ name: "CONFLICTING_NAME_THREE",
3239
+ type: "some unsafe thing",
3240
+ data: { some: { unsafe: "thing" } },
3241
+ },
3242
+ {
3243
+ name: "CONFLICTING_NAME_FOUR",
3244
+ type: "another unsafe thing",
3245
+ data: 1337,
3246
+ },
3247
+ ],
3248
+ },
3249
+ vars: {
3250
+ ENV_VAR_ONE: 123,
3251
+ CONFLICTING_NAME_THREE: "Hello, I'm an environment variable",
3252
+ },
3253
+ wasm_modules: {
3254
+ WASM_MODULE_ONE: "./some_wasm.wasm",
3255
+ CONFLICTING_NAME_THREE: "./more_wasm.wasm",
3256
+ },
3257
+ data_blobs: {
3258
+ DATA_BLOB_ONE: "./some_data.bin",
3259
+ CONFLICTING_NAME_THREE: "./more_data.bin",
3260
+ },
3261
+ });
3262
+
3263
+ writeWorkerSource({ type: "sw" });
3264
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
3265
+ fs.writeFileSync(
3266
+ "./the-entirety-of-human-knowledge.txt",
3267
+ "Everything's bigger in Texas"
3268
+ );
3269
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
3270
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
3271
+
3272
+ await expect(runWrangler("publish index.js")).rejects
3273
+ .toMatchInlineSnapshot(`
3274
+ [Error: Processing wrangler.toml configuration:
3275
+ - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
3276
+ - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
3277
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM Module, and Data Blob bindings.
3278
+ - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
3279
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3280
+ Please change your bindings to have unique names.]
3281
+ `);
3282
+ expect(std.out).toMatchInlineSnapshot(`
3283
+ "
3284
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3285
+ `);
3286
+ expect(std.err).toMatchInlineSnapshot(`
3287
+ "X [ERROR] Processing wrangler.toml configuration:
3288
+
3289
+ - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
3290
+ - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
3291
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM
3292
+ Module, and Data Blob bindings.
3293
+ - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
3294
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3295
+ Please change your bindings to have unique names.
3296
+
3297
+ "
3298
+ `);
3299
+ expect(std.warn).toMatchInlineSnapshot(`
3300
+ "▲ [WARNING] Processing wrangler.toml configuration:
3301
+
3302
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3303
+
3304
+ "
3305
+ `);
3306
+ });
3307
+
3308
+ it("should error when bindings of the same type have the same name", async () => {
3309
+ writeWranglerToml({
3310
+ durable_objects: {
3311
+ bindings: [
3312
+ {
3313
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
3314
+ class_name: "SomeDurableObject",
3315
+ script_name: "some-durable-object-worker",
3316
+ },
3317
+ {
3318
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
3319
+ class_name: "AnotherDurableObject",
3320
+ script_name: "another-durable-object-worker",
3321
+ },
3322
+ ],
3323
+ },
3324
+ kv_namespaces: [
3325
+ { binding: "CONFLICTING_KV_NAMESPACE_NAME", id: "kv-ns-one-id" },
3326
+ { binding: "CONFLICTING_KV_NAMESPACE_NAME", id: "kv-ns-two-id" },
3327
+ ],
3328
+ r2_buckets: [
3329
+ {
3330
+ binding: "CONFLICTING_R2_BUCKET_NAME",
3331
+ bucket_name: "r2-bucket-one-name",
3332
+ },
3333
+ {
3334
+ binding: "CONFLICTING_R2_BUCKET_NAME",
3335
+ bucket_name: "r2-bucket-two-name",
3336
+ },
3337
+ ],
3338
+ unsafe: {
3339
+ bindings: [
3340
+ {
3341
+ name: "CONFLICTING_UNSAFE_NAME",
3342
+ type: "some unsafe thing",
3343
+ data: { some: { unsafe: "thing" } },
3344
+ },
3345
+ {
3346
+ name: "CONFLICTING_UNSAFE_NAME",
3347
+ type: "another unsafe thing",
3348
+ data: 1337,
3349
+ },
3350
+ ],
3351
+ },
3352
+ // text_blobs, vars, wasm_modules and data_blobs are fine because they're object literals,
3353
+ // and by definition cannot have two keys of the same name
3354
+ //
3355
+ // text_blobs: {
3356
+ // CONFLICTING_TEXT_BLOB_NAME: "./my-entire-app-depends-on-this.cfg",
3357
+ // CONFLICTING_TEXT_BLOB_NAME: "./the-entirety-of-human-knowledge.txt",
3358
+ // },
3359
+ // vars: {
3360
+ // CONFLICTING_VARS_NAME: 123,
3361
+ // CONFLICTING_VARS_NAME: "Hello, I'm an environment variable",
3362
+ // },
3363
+ // wasm_modules: {
3364
+ // CONFLICTING_WASM_MODULE_NAME: "./some_wasm.wasm",
3365
+ // CONFLICTING_WASM_MODULE_NAME: "./more_wasm.wasm",
3366
+ // },
3367
+ });
3368
+
3369
+ writeWorkerSource({ type: "sw" });
3370
+
3371
+ await expect(runWrangler("publish index.js")).rejects
3372
+ .toMatchInlineSnapshot(`
3373
+ [Error: Processing wrangler.toml configuration:
3374
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
3375
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
3376
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
3377
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
3378
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3379
+ Please change your bindings to have unique names.]
3380
+ `);
3381
+ expect(std.out).toMatchInlineSnapshot(`
3382
+ "
3383
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3384
+ `);
3385
+ expect(std.err).toMatchInlineSnapshot(`
3386
+ "X [ERROR] Processing wrangler.toml configuration:
3387
+
3388
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
3389
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
3390
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
3391
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
3392
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3393
+ Please change your bindings to have unique names.
3394
+
3395
+ "
3396
+ `);
3397
+ expect(std.warn).toMatchInlineSnapshot(`
3398
+ "▲ [WARNING] Processing wrangler.toml configuration:
3399
+
3400
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3401
+
3402
+ "
3403
+ `);
3404
+ });
3405
+
3406
+ it("should error correctly when bindings of the same and different types use the same name", async () => {
3407
+ writeWranglerToml({
3408
+ durable_objects: {
3409
+ bindings: [
3410
+ {
3411
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
3412
+ class_name: "SomeDurableObject",
3413
+ script_name: "some-durable-object-worker",
3414
+ },
3415
+ {
3416
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
3417
+ class_name: "AnotherDurableObject",
3418
+ script_name: "another-durable-object-worker",
3419
+ },
3420
+ ],
3421
+ },
3422
+ kv_namespaces: [
3423
+ {
3424
+ binding: "CONFLICTING_KV_NAMESPACE_NAME",
3425
+ id: "kv-ns-one-id",
3426
+ },
3427
+ {
3428
+ binding: "CONFLICTING_KV_NAMESPACE_NAME",
3429
+ id: "kv-ns-two-id",
3430
+ },
3431
+ { binding: "CONFLICTING_NAME_ONE", id: "kv-ns-three-id" },
3432
+ { binding: "CONFLICTING_NAME_TWO", id: "kv-ns-four-id" },
3433
+ ],
3434
+ r2_buckets: [
3435
+ {
3436
+ binding: "CONFLICTING_R2_BUCKET_NAME",
3437
+ bucket_name: "r2-bucket-one-name",
3438
+ },
3439
+ {
3440
+ binding: "CONFLICTING_R2_BUCKET_NAME",
3441
+ bucket_name: "r2-bucket-two-name",
3442
+ },
3443
+ {
3444
+ binding: "CONFLICTING_NAME_THREE",
3445
+ bucket_name: "r2-bucket-three-name",
3446
+ },
3447
+ {
3448
+ binding: "CONFLICTING_NAME_FOUR",
3449
+ bucket_name: "r2-bucket-four-name",
3450
+ },
3451
+ ],
3452
+ text_blobs: {
3453
+ CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
3454
+ CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
3455
+ },
3456
+ unsafe: {
3457
+ bindings: [
3458
+ {
3459
+ name: "CONFLICTING_UNSAFE_NAME",
3460
+ type: "some unsafe thing",
3461
+ data: { some: { unsafe: "thing" } },
3462
+ },
3463
+ {
3464
+ name: "CONFLICTING_UNSAFE_NAME",
3465
+ type: "another unsafe thing",
3466
+ data: 1337,
3467
+ },
3468
+ {
3469
+ name: "CONFLICTING_NAME_THREE",
3470
+ type: "yet another unsafe thing",
3471
+ data: "how is a string unsafe?",
3472
+ },
3473
+ {
3474
+ name: "CONFLICTING_NAME_FOUR",
3475
+ type: "a fourth unsafe thing",
3476
+ data: null,
3477
+ },
3478
+ ],
3479
+ },
3480
+ vars: {
3481
+ ENV_VAR_ONE: 123,
3482
+ CONFLICTING_NAME_THREE: "Hello, I'm an environment variable",
3483
+ },
3484
+ wasm_modules: {
3485
+ WASM_MODULE_ONE: "./some_wasm.wasm",
3486
+ CONFLICTING_NAME_THREE: "./more_wasm.wasm",
3487
+ },
3488
+ data_blobs: {
3489
+ DATA_BLOB_ONE: "./some_data.bin",
3490
+ CONFLICTING_NAME_THREE: "./more_data.bin",
3491
+ },
3492
+ });
3493
+
3494
+ writeWorkerSource({ type: "sw" });
3495
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
3496
+ fs.writeFileSync(
3497
+ "./the-entirety-of-human-knowledge.txt",
3498
+ "Everything's bigger in Texas"
3499
+ );
3500
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
3501
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
3502
+
3503
+ await expect(runWrangler("publish index.js")).rejects
3504
+ .toMatchInlineSnapshot(`
3505
+ [Error: Processing wrangler.toml configuration:
3506
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
3507
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
3508
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
3509
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM Module, and Data Blob bindings.
3510
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
3511
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
3512
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3513
+ Please change your bindings to have unique names.]
3514
+ `);
3515
+ expect(std.out).toMatchInlineSnapshot(`
3516
+ "
3517
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3518
+ `);
3519
+ expect(std.err).toMatchInlineSnapshot(`
3520
+ "X [ERROR] Processing wrangler.toml configuration:
3521
+
3522
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
3523
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
3524
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
3525
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM
3526
+ Module, and Data Blob bindings.
3527
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
3528
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
3529
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3530
+ Please change your bindings to have unique names.
3531
+
3532
+ "
3533
+ `);
3534
+ expect(std.warn).toMatchInlineSnapshot(`
3535
+ "▲ [WARNING] Processing wrangler.toml configuration:
3536
+
3537
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3538
+
3539
+ "
3540
+ `);
3541
+ });
3542
+
3543
+ describe("[wasm_modules]", () => {
3544
+ it("should be able to define wasm modules for service-worker format workers", async () => {
3545
+ writeWranglerToml({
3546
+ wasm_modules: {
3547
+ TESTWASMNAME: "./path/to/test.wasm",
3548
+ },
3549
+ });
3550
+ writeWorkerSource({ type: "sw" });
3551
+ fs.mkdirSync("./path/to", { recursive: true });
3552
+ fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
3553
+ mockUploadWorkerRequest({
3554
+ expectedType: "sw",
3555
+ expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
3556
+ expectedBindings: [
3557
+ { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
3558
+ ],
3559
+ });
3560
+ mockSubDomainRequest();
3561
+ await runWrangler("publish index.js");
3562
+ expect(std.out).toMatchInlineSnapshot(`
3563
+ "Uploaded test-name (TIMINGS)
3564
+ Published test-name (TIMINGS)
3565
+ test-name.test-sub-domain.workers.dev"
3566
+ `);
3567
+ expect(std.err).toMatchInlineSnapshot(`""`);
3568
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3569
+ });
3570
+
3571
+ it("should error when defining wasm modules for modules format workers", async () => {
3572
+ writeWranglerToml({
3573
+ wasm_modules: {
3574
+ TESTWASMNAME: "./path/to/test.wasm",
3575
+ },
3576
+ });
3577
+ writeWorkerSource({ type: "esm" });
3578
+ fs.mkdirSync("./path/to", { recursive: true });
3579
+ fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
3580
+
3581
+ await expect(
3582
+ runWrangler("publish index.js")
3583
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
3584
+ `"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"`
3585
+ );
3586
+ expect(std.out).toMatchInlineSnapshot(`
3587
+ "
3588
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3589
+ `);
3590
+ expect(std.err).toMatchInlineSnapshot(`
3591
+ "X [ERROR] You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
3592
+
3593
+ "
3594
+ `);
3595
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3596
+ });
3597
+
3598
+ it("should resolve wasm modules relative to the wrangler.toml file", async () => {
3599
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
3600
+ fs.writeFileSync(
3601
+ "./path/to/wrangler.toml",
3602
+ TOML.stringify({
3603
+ compatibility_date: "2022-01-12",
3604
+ name: "test-name",
3605
+ wasm_modules: {
3606
+ TESTWASMNAME: "./and/the/path/to/test.wasm",
3607
+ },
3608
+ }),
3609
+
3610
+ "utf-8"
3611
+ );
3612
+
3613
+ writeWorkerSource({ type: "sw" });
3614
+ fs.writeFileSync(
3615
+ "./path/to/and/the/path/to/test.wasm",
3616
+ "SOME WASM CONTENT"
3617
+ );
3618
+ mockUploadWorkerRequest({
3619
+ expectedType: "sw",
3620
+ expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
3621
+ expectedBindings: [
3622
+ { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
3623
+ ],
3624
+ expectedCompatibilityDate: "2022-01-12",
3625
+ });
3626
+ mockSubDomainRequest();
3627
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3628
+ expect(std.out).toMatchInlineSnapshot(`
3629
+ "Uploaded test-name (TIMINGS)
3630
+ Published test-name (TIMINGS)
3631
+ test-name.test-sub-domain.workers.dev"
3632
+ `);
3633
+ expect(std.err).toMatchInlineSnapshot(`""`);
3634
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3635
+ });
3636
+
3637
+ it("should be able to import .wasm modules from service-worker format workers", async () => {
3638
+ writeWranglerToml();
3639
+ fs.writeFileSync(
3640
+ "./index.js",
3641
+ "import TESTWASMNAME from './test.wasm';"
3642
+ );
3643
+ fs.writeFileSync("./test.wasm", "SOME WASM CONTENT");
3644
+ mockUploadWorkerRequest({
3645
+ expectedType: "sw",
3646
+ expectedModules: {
3647
+ __94b240d0d692281e6467aa42043986e5c7eea034_test_wasm:
3648
+ "SOME WASM CONTENT",
3649
+ },
3650
+ expectedBindings: [
3651
+ {
3652
+ name: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
3653
+ part: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
3654
+ type: "wasm_module",
3655
+ },
3656
+ ],
3657
+ });
3658
+ mockSubDomainRequest();
3659
+ await runWrangler("publish index.js");
3660
+ expect(std.out).toMatchInlineSnapshot(`
3661
+ "Uploaded test-name (TIMINGS)
3662
+ Published test-name (TIMINGS)
3663
+ test-name.test-sub-domain.workers.dev"
3664
+ `);
3665
+ expect(std.err).toMatchInlineSnapshot(`""`);
3666
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3667
+ });
3668
+ });
3669
+
3670
+ describe("[text_blobs]", () => {
3671
+ it("should be able to define text blobs for service-worker format workers", async () => {
3672
+ writeWranglerToml({
3673
+ text_blobs: {
3674
+ TESTTEXTBLOBNAME: "./path/to/text.file",
3675
+ },
3676
+ });
3677
+ writeWorkerSource({ type: "sw" });
3678
+ fs.mkdirSync("./path/to", { recursive: true });
3679
+ fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
3680
+ mockUploadWorkerRequest({
3681
+ expectedType: "sw",
3682
+ expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
3683
+ expectedBindings: [
3684
+ {
3685
+ name: "TESTTEXTBLOBNAME",
3686
+ part: "TESTTEXTBLOBNAME",
3687
+ type: "text_blob",
3688
+ },
3689
+ ],
3690
+ });
3691
+ mockSubDomainRequest();
3692
+ await runWrangler("publish index.js");
3693
+ expect(std.out).toMatchInlineSnapshot(`
3694
+ "Uploaded test-name (TIMINGS)
3695
+ Published test-name (TIMINGS)
3696
+ test-name.test-sub-domain.workers.dev"
3697
+ `);
3698
+ expect(std.err).toMatchInlineSnapshot(`""`);
3699
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3700
+ });
3701
+
3702
+ it("should error when defining text blobs for modules format workers", async () => {
3703
+ writeWranglerToml({
3704
+ text_blobs: {
3705
+ TESTTEXTBLOBNAME: "./path/to/text.file",
3706
+ },
3707
+ });
3708
+ writeWorkerSource({ type: "esm" });
3709
+ fs.mkdirSync("./path/to", { recursive: true });
3710
+ fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
3711
+
3712
+ await expect(
3713
+ runWrangler("publish index.js")
3714
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
3715
+ `"You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[rules]\` in your wrangler.toml"`
3716
+ );
3717
+ expect(std.out).toMatchInlineSnapshot(`
3718
+ "
3719
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3720
+ `);
3721
+ expect(std.err).toMatchInlineSnapshot(`
3722
+ "X [ERROR] You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[rules]\` in your wrangler.toml
3723
+
3724
+ "
3725
+ `);
3726
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3727
+ });
3728
+
3729
+ it("should resolve text blobs relative to the wrangler.toml file", async () => {
3730
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
3731
+ fs.writeFileSync(
3732
+ "./path/to/wrangler.toml",
3733
+ TOML.stringify({
3734
+ compatibility_date: "2022-01-12",
3735
+ name: "test-name",
3736
+ text_blobs: {
3737
+ TESTTEXTBLOBNAME: "./and/the/path/to/text.file",
3738
+ },
3739
+ }),
3740
+
3741
+ "utf-8"
3742
+ );
3743
+
3744
+ writeWorkerSource({ type: "sw" });
3745
+ fs.writeFileSync(
3746
+ "./path/to/and/the/path/to/text.file",
3747
+ "SOME TEXT CONTENT"
3748
+ );
3749
+ mockUploadWorkerRequest({
3750
+ expectedType: "sw",
3751
+ expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
3752
+ expectedBindings: [
3753
+ {
3754
+ name: "TESTTEXTBLOBNAME",
3755
+ part: "TESTTEXTBLOBNAME",
3756
+ type: "text_blob",
3757
+ },
3758
+ ],
3759
+ expectedCompatibilityDate: "2022-01-12",
3760
+ });
3761
+ mockSubDomainRequest();
3762
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3763
+ expect(std.out).toMatchInlineSnapshot(`
3764
+ "Uploaded test-name (TIMINGS)
3765
+ Published test-name (TIMINGS)
3766
+ test-name.test-sub-domain.workers.dev"
3767
+ `);
3768
+ expect(std.err).toMatchInlineSnapshot(`""`);
3769
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3770
+ });
3771
+ });
3772
+
3773
+ describe("[data_blobs]", () => {
3774
+ it("should be able to define data blobs for service-worker format workers", async () => {
3775
+ writeWranglerToml({
3776
+ data_blobs: {
3777
+ TESTDATABLOBNAME: "./path/to/data.bin",
3778
+ },
3779
+ });
3780
+ writeWorkerSource({ type: "sw" });
3781
+ fs.mkdirSync("./path/to", { recursive: true });
3782
+ fs.writeFileSync("./path/to/data.bin", "SOME DATA CONTENT");
3783
+ mockUploadWorkerRequest({
3784
+ expectedType: "sw",
3785
+ expectedModules: { TESTDATABLOBNAME: "SOME DATA CONTENT" },
3786
+ expectedBindings: [
3787
+ {
3788
+ name: "TESTDATABLOBNAME",
3789
+ part: "TESTDATABLOBNAME",
3790
+ type: "data_blob",
3791
+ },
3792
+ ],
3793
+ });
3794
+ mockSubDomainRequest();
3795
+ await runWrangler("publish index.js");
3796
+ expect(std.out).toMatchInlineSnapshot(`
3797
+ "Uploaded test-name (TIMINGS)
3798
+ Published test-name (TIMINGS)
3799
+ test-name.test-sub-domain.workers.dev"
3800
+ `);
3801
+ expect(std.err).toMatchInlineSnapshot(`""`);
3802
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3803
+ });
3804
+
3805
+ it("should error when defining data blobs for modules format workers", async () => {
3806
+ writeWranglerToml({
3807
+ data_blobs: {
3808
+ TESTDATABLOBNAME: "./path/to/data.bin",
3809
+ },
3810
+ });
3811
+ writeWorkerSource({ type: "esm" });
3812
+ fs.mkdirSync("./path/to", { recursive: true });
3813
+ fs.writeFileSync("./path/to/data.bin", "SOME DATA CONTENT");
3814
+
3815
+ await expect(
3816
+ runWrangler("publish index.js")
3817
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
3818
+ `"You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[rules]\` in your wrangler.toml"`
3819
+ );
3820
+ expect(std.out).toMatchInlineSnapshot(`
3821
+ "
3822
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3823
+ `);
3824
+ expect(std.err).toMatchInlineSnapshot(`
3825
+ "X [ERROR] You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure \`[rules]\` in your wrangler.toml
3826
+
3827
+ "
3828
+ `);
3829
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3830
+ });
3831
+
3832
+ it("should resolve data blobs relative to the wrangler.toml file", async () => {
3833
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
3834
+ fs.writeFileSync(
3835
+ "./path/to/wrangler.toml",
3836
+ TOML.stringify({
3837
+ compatibility_date: "2022-01-12",
3838
+ name: "test-name",
3839
+ data_blobs: {
3840
+ TESTDATABLOBNAME: "./and/the/path/to/data.bin",
3841
+ },
3842
+ }),
3843
+
3844
+ "utf-8"
3845
+ );
3846
+
3847
+ writeWorkerSource({ type: "sw" });
3848
+ fs.writeFileSync(
3849
+ "./path/to/and/the/path/to/data.bin",
3850
+ "SOME DATA CONTENT"
3851
+ );
3852
+ mockUploadWorkerRequest({
3853
+ expectedType: "sw",
3854
+ expectedModules: { TESTDATABLOBNAME: "SOME DATA CONTENT" },
3855
+ expectedBindings: [
3856
+ {
3857
+ name: "TESTDATABLOBNAME",
3858
+ part: "TESTDATABLOBNAME",
3859
+ type: "data_blob",
3860
+ },
3861
+ ],
3862
+ expectedCompatibilityDate: "2022-01-12",
3863
+ });
3864
+ mockSubDomainRequest();
3865
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3866
+ expect(std.out).toMatchInlineSnapshot(`
3867
+ "Uploaded test-name (TIMINGS)
3868
+ Published test-name (TIMINGS)
3869
+ test-name.test-sub-domain.workers.dev"
3870
+ `);
3871
+ expect(std.err).toMatchInlineSnapshot(`""`);
3872
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3873
+ });
3874
+ });
3875
+
3876
+ describe("[vars]", () => {
3877
+ it("should support json bindings", async () => {
3878
+ writeWranglerToml({
3879
+ vars: {
3880
+ text: "plain ol' string",
3881
+ count: 1,
3882
+ complex: { enabled: true, id: 123 },
3883
+ },
3884
+ });
3885
+ writeWorkerSource();
3886
+ mockSubDomainRequest();
3887
+ mockUploadWorkerRequest({
3888
+ expectedBindings: [
3889
+ { name: "text", type: "plain_text", text: "plain ol' string" },
3890
+ { name: "count", type: "json", json: 1 },
3891
+ {
3892
+ name: "complex",
3893
+ type: "json",
3894
+ json: { enabled: true, id: 123 },
3895
+ },
3896
+ ],
3897
+ });
3898
+
3899
+ await runWrangler("publish index.js");
3900
+ expect(std.out).toMatchInlineSnapshot(`
3901
+ "Uploaded test-name (TIMINGS)
3902
+ Published test-name (TIMINGS)
3903
+ test-name.test-sub-domain.workers.dev"
3904
+ `);
3905
+ expect(std.err).toMatchInlineSnapshot(`""`);
3906
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3907
+ });
3908
+ });
3909
+
3910
+ describe("[r2_buckets]", () => {
3911
+ it("should support r2 bucket bindings", async () => {
3912
+ writeWranglerToml({
3913
+ r2_buckets: [{ binding: "FOO", bucket_name: "foo-bucket" }],
3914
+ });
3915
+ writeWorkerSource();
3916
+ mockSubDomainRequest();
3917
+ mockUploadWorkerRequest({
3918
+ expectedBindings: [
3919
+ { bucket_name: "foo-bucket", name: "FOO", type: "r2_bucket" },
3920
+ ],
3921
+ });
3922
+
3923
+ await runWrangler("publish index.js");
3924
+ expect(std.out).toMatchInlineSnapshot(`
3925
+ "Uploaded test-name (TIMINGS)
3926
+ Published test-name (TIMINGS)
3927
+ test-name.test-sub-domain.workers.dev"
3928
+ `);
3929
+ expect(std.err).toMatchInlineSnapshot(`""`);
3930
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3931
+ });
3932
+ });
3933
+
3934
+ describe("[durable_objects]", () => {
3935
+ it("should support durable object bindings", async () => {
3936
+ writeWranglerToml({
3937
+ durable_objects: {
3938
+ bindings: [
3939
+ {
3940
+ name: "EXAMPLE_DO_BINDING",
3941
+ class_name: "ExampleDurableObject",
3942
+ },
3943
+ ],
3944
+ },
3945
+ migrations: [{ tag: "v1", new_classes: ["ExampleDurableObject"] }],
3946
+ });
3947
+ fs.writeFileSync(
3948
+ "index.js",
3949
+ `export class ExampleDurableObject {}; export default{};`
3950
+ );
3951
+ mockSubDomainRequest();
3952
+ mockLegacyScriptData({
3953
+ scripts: [{ id: "test-name", migration_tag: "v1" }],
3954
+ });
3955
+ mockUploadWorkerRequest({
3956
+ expectedBindings: [
3957
+ {
3958
+ class_name: "ExampleDurableObject",
3959
+ name: "EXAMPLE_DO_BINDING",
3960
+ type: "durable_object_namespace",
3961
+ },
3962
+ ],
3963
+ });
3964
+
3965
+ await runWrangler("publish index.js");
3966
+ expect(std.out).toMatchInlineSnapshot(`
3967
+ "Uploaded test-name (TIMINGS)
3968
+ Published test-name (TIMINGS)
3969
+ test-name.test-sub-domain.workers.dev"
3970
+ `);
3971
+ expect(std.err).toMatchInlineSnapshot(`""`);
3972
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3973
+ });
3974
+
3975
+ it("should support service-workers binding to external durable objects", async () => {
3976
+ writeWranglerToml({
3977
+ durable_objects: {
3978
+ bindings: [
3979
+ {
3980
+ name: "EXAMPLE_DO_BINDING",
3981
+ class_name: "ExampleDurableObject",
3982
+ script_name: "example-do-binding-worker",
3983
+ },
3984
+ ],
3985
+ },
3986
+ });
3987
+ writeWorkerSource({ type: "sw" });
3988
+ mockSubDomainRequest();
3989
+ mockUploadWorkerRequest({
3990
+ expectedType: "sw",
3991
+ expectedBindings: [
3992
+ {
3993
+ name: "EXAMPLE_DO_BINDING",
3994
+ class_name: "ExampleDurableObject",
3995
+ script_name: "example-do-binding-worker",
3996
+ type: "durable_object_namespace",
3997
+ },
3998
+ ],
3999
+ });
4000
+
4001
+ await runWrangler("publish index.js");
4002
+ expect(std.out).toMatchInlineSnapshot(`
4003
+ "Uploaded test-name (TIMINGS)
4004
+ Published test-name (TIMINGS)
4005
+ test-name.test-sub-domain.workers.dev"
4006
+ `);
4007
+ expect(std.err).toMatchInlineSnapshot(`""`);
4008
+ expect(std.warn).toMatchInlineSnapshot(`""`);
4009
+ });
4010
+
4011
+ it("should support module workers implementing durable objects", async () => {
4012
+ writeWranglerToml({
4013
+ durable_objects: {
4014
+ bindings: [
4015
+ {
4016
+ name: "EXAMPLE_DO_BINDING",
4017
+ class_name: "ExampleDurableObject",
4018
+ },
4019
+ ],
4020
+ },
4021
+ migrations: [{ tag: "v1", new_classes: ["ExampleDurableObject"] }],
4022
+ });
4023
+ fs.writeFileSync(
4024
+ "index.js",
4025
+ `export class ExampleDurableObject {}; export default{};`
4026
+ );
4027
+ mockSubDomainRequest();
4028
+ mockLegacyScriptData({
4029
+ scripts: [{ id: "test-name", migration_tag: "v1" }],
4030
+ });
4031
+ mockUploadWorkerRequest({
4032
+ expectedType: "esm",
4033
+ expectedBindings: [
4034
+ {
4035
+ name: "EXAMPLE_DO_BINDING",
4036
+ class_name: "ExampleDurableObject",
4037
+ type: "durable_object_namespace",
4038
+ },
4039
+ ],
4040
+ });
4041
+
4042
+ await runWrangler("publish index.js");
4043
+ expect(std.out).toMatchInlineSnapshot(`
4044
+ "Uploaded test-name (TIMINGS)
4045
+ Published test-name (TIMINGS)
4046
+ test-name.test-sub-domain.workers.dev"
4047
+ `);
4048
+ expect(std.err).toMatchInlineSnapshot(`""`);
4049
+ expect(std.warn).toMatchInlineSnapshot(`""`);
4050
+ });
4051
+
4052
+ it("should error when detecting a service-worker worker implementing durable objects", async () => {
4053
+ writeWranglerToml({
4054
+ durable_objects: {
4055
+ bindings: [
4056
+ {
4057
+ name: "EXAMPLE_DO_BINDING",
4058
+ class_name: "ExampleDurableObject",
4059
+ },
4060
+ ],
4061
+ },
4062
+ });
4063
+ writeWorkerSource({ type: "sw" });
4064
+ mockSubDomainRequest();
4065
+
4066
+ await expect(runWrangler("publish index.js")).rejects
4067
+ .toThrowErrorMatchingInlineSnapshot(`
4068
+ "You seem to be trying to use Durable Objects in a Worker written as a service-worker.
4069
+ 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:
4070
+ { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject } ==> { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject, script_name = example-do-binding-worker }
4071
+ Alternatively, migrate your worker to ES Module syntax to implement a Durable Object in this Worker:
4072
+ https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
4073
+ `);
4074
+ });
4075
+ });
4076
+
4077
+ describe("[unsafe]", () => {
4078
+ it("should warn if using unsafe bindings", async () => {
4079
+ writeWranglerToml({
4080
+ unsafe: {
4081
+ bindings: [
4082
+ {
4083
+ name: "my-binding",
4084
+ type: "binding-type",
4085
+ param: "binding-param",
4086
+ },
4087
+ ],
4088
+ },
4089
+ });
4090
+ writeWorkerSource();
4091
+ mockSubDomainRequest();
4092
+ mockUploadWorkerRequest({
4093
+ expectedBindings: [
4094
+ {
4095
+ name: "my-binding",
4096
+ type: "binding-type",
4097
+ param: "binding-param",
4098
+ },
4099
+ ],
4100
+ });
4101
+
4102
+ await runWrangler("publish index.js");
4103
+ expect(std.out).toMatchInlineSnapshot(`
4104
+ "Uploaded test-name (TIMINGS)
4105
+ Published test-name (TIMINGS)
4106
+ test-name.test-sub-domain.workers.dev"
4107
+ `);
4108
+ expect(std.err).toMatchInlineSnapshot(`""`);
4109
+ expect(std.warn).toMatchInlineSnapshot(`
4110
+ "▲ [WARNING] Processing wrangler.toml configuration:
4111
+
4112
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
4113
+
4114
+ "
4115
+ `);
4116
+ });
4117
+ it("should warn if using unsafe bindings already handled by wrangler", async () => {
4118
+ writeWranglerToml({
4119
+ unsafe: {
4120
+ bindings: [
4121
+ {
4122
+ name: "my-binding",
4123
+ type: "plain_text",
4124
+ text: "text",
4125
+ },
4126
+ ],
1670
4127
  },
1671
- ],
1672
- });
1673
-
1674
- await runWrangler("publish index.js");
1675
- expect(std.out).toMatchInlineSnapshot(`
1676
- "Uploaded test-name (TIMINGS)
1677
- Published test-name (TIMINGS)
1678
- test-name.test-sub-domain.workers.dev"
1679
- `);
1680
- expect(std.err).toMatchInlineSnapshot(`""`);
1681
- expect(std.warn).toMatchInlineSnapshot(`
1682
- "Processing wrangler.toml configuration:
1683
- - \\"unsafe\\" fields are experimental and may change or break at any time."
1684
- `);
1685
- });
1686
- it("should warn if using unsafe bindings already handled by wrangler", async () => {
1687
- writeWranglerToml({
1688
- unsafe: {
1689
- bindings: [
4128
+ });
4129
+ writeWorkerSource();
4130
+ mockSubDomainRequest();
4131
+ mockUploadWorkerRequest({
4132
+ expectedBindings: [
1690
4133
  {
1691
4134
  name: "my-binding",
1692
4135
  type: "plain_text",
1693
4136
  text: "text",
1694
4137
  },
1695
4138
  ],
1696
- },
1697
- });
1698
- writeWorkerSource();
1699
- mockSubDomainRequest();
1700
- mockUploadWorkerRequest({
1701
- expectedBindings: [
1702
- {
1703
- name: "my-binding",
1704
- type: "plain_text",
1705
- text: "text",
1706
- },
1707
- ],
1708
- });
4139
+ });
1709
4140
 
1710
- await runWrangler("publish index.js");
1711
- expect(std.out).toMatchInlineSnapshot(`
1712
- "Uploaded test-name (TIMINGS)
1713
- Published test-name (TIMINGS)
1714
- test-name.test-sub-domain.workers.dev"
1715
- `);
1716
- expect(std.err).toMatchInlineSnapshot(`""`);
1717
- expect(std.warn).toMatchInlineSnapshot(`
1718
- "Processing wrangler.toml configuration:
1719
- - \\"unsafe\\" fields are experimental and may change or break at any time.
1720
- - \\"unsafe.bindings[0]\\": {\\"name\\":\\"my-binding\\",\\"type\\":\\"plain_text\\",\\"text\\":\\"text\\"}
1721
- - The binding type \\"plain_text\\" is directly supported by wrangler.
1722
- Consider migrating this unsafe binding to a format for 'plain_text' bindings that is supported by wrangler for optimal support.
1723
- For more details, see https://developers.cloudflare.com/workers/cli-wrangler/configuration"
1724
- `);
4141
+ await runWrangler("publish index.js");
4142
+ expect(std.out).toMatchInlineSnapshot(`
4143
+ "Uploaded test-name (TIMINGS)
4144
+ Published test-name (TIMINGS)
4145
+ test-name.test-sub-domain.workers.dev"
4146
+ `);
4147
+ expect(std.err).toMatchInlineSnapshot(`""`);
4148
+ expect(std.warn).toMatchInlineSnapshot(`
4149
+ "▲ [WARNING] Processing wrangler.toml configuration:
4150
+
4151
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
4152
+ - \\"unsafe.bindings[0]\\": {\\"name\\":\\"my-binding\\",\\"type\\":\\"plain_text\\",\\"text\\":\\"text\\"}
4153
+ - The binding type \\"plain_text\\" is directly supported by wrangler.
4154
+ Consider migrating this unsafe binding to a format for 'plain_text' bindings that is
4155
+ supported by wrangler for optimal support.
4156
+ For more details, see https://developers.cloudflare.com/workers/cli-wrangler/configuration
4157
+
4158
+ "
4159
+ `);
4160
+ });
1725
4161
  });
1726
4162
  });
1727
4163
 
@@ -1815,14 +4251,19 @@ export default{
1815
4251
  `);
1816
4252
  expect(std.err).toMatchInlineSnapshot(`""`);
1817
4253
  expect(std.warn).toMatchInlineSnapshot(`
1818
- "Processing wrangler.toml configuration:
1819
- - DEPRECATION: The \`build.upload.rules\` config field is no longer used, the rules should be specified via the \`rules\` config field. Delete the \`build.upload\` field from the configuration file, and add this:
1820
- \`\`\`
1821
- [[rules]]
1822
- type = \\"Text\\"
1823
- globs = [ \\"**/*.file\\" ]
1824
- fallthrough = true
1825
- \`\`\`"
4254
+ "▲ [WARNING] Processing wrangler.toml configuration:
4255
+
4256
+ - Deprecation: The \`build.upload.rules\` config field is no longer used, the rules should be
4257
+ specified via the \`rules\` config field. Delete the \`build.upload\` field from the configuration
4258
+ file, and add this:
4259
+ \`\`\`
4260
+ [[rules]]
4261
+ type = \\"Text\\"
4262
+ globs = [ \\"**/*.file\\" ]
4263
+ fallthrough = true
4264
+ \`\`\`
4265
+
4266
+ "
1826
4267
  `);
1827
4268
  });
1828
4269
 
@@ -1914,42 +4355,282 @@ export default{
1914
4355
  );
1915
4356
  // and the warnings because fallthrough was not explicitly set
1916
4357
  expect(std.warn).toMatchInlineSnapshot(`
1917
- "The module rule at position 1 ({\\"type\\":\\"Text\\",\\"globs\\":[\\"**/*.other\\"]}) 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 this one to also be used, or \`fallthrough = false\` to silence this warning.
1918
- 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."
4358
+ "▲ [WARNING] The module rule at position 1 ({\\"type\\":\\"Text\\",\\"globs\\":[\\"**/*.other\\"]}) 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 this one to also be used, or \`fallthrough = false\` to silence this warning.
4359
+
4360
+
4361
+ ▲ [WARNING] 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.
4362
+
4363
+ "
1919
4364
  `);
1920
4365
  });
4366
+
4367
+ describe("inject process.env.NODE_ENV", () => {
4368
+ let actualProcessEnvNodeEnv: string | undefined;
4369
+ beforeEach(() => {
4370
+ actualProcessEnvNodeEnv = process.env.NODE_ENV;
4371
+ process.env.NODE_ENV = "some-node-env";
4372
+ });
4373
+ afterEach(() => {
4374
+ process.env.NODE_ENV = actualProcessEnvNodeEnv;
4375
+ });
4376
+ it("should replace `process.env.NODE_ENV` in scripts", async () => {
4377
+ writeWranglerToml();
4378
+ fs.writeFileSync(
4379
+ "./index.js",
4380
+ `export default {
4381
+ fetch(){
4382
+ return new Response(process.env.NODE_ENV);
4383
+ }
4384
+ }`
4385
+ );
4386
+ mockSubDomainRequest();
4387
+ mockUploadWorkerRequest({
4388
+ expectedEntry: `return new Response("some-node-env");`,
4389
+ });
4390
+ await runWrangler("publish index.js");
4391
+ expect(std.out).toMatchInlineSnapshot(`
4392
+ "Uploaded test-name (TIMINGS)
4393
+ Published test-name (TIMINGS)
4394
+ test-name.test-sub-domain.workers.dev"
4395
+ `);
4396
+ expect(std.err).toMatchInlineSnapshot(`""`);
4397
+ expect(std.warn).toMatchInlineSnapshot(`""`);
4398
+ });
4399
+ });
1921
4400
  });
1922
- });
1923
4401
 
1924
- /** Write a mock Worker script to disk. */
1925
- function writeWorkerSource({
1926
- basePath = ".",
1927
- format = "js",
1928
- type = "esm",
1929
- }: {
1930
- basePath?: string;
1931
- format?: "js" | "ts" | "jsx" | "tsx" | "mjs";
1932
- type?: "esm" | "sw";
1933
- } = {}) {
1934
- if (basePath !== ".") {
1935
- fs.mkdirSync(basePath, { recursive: true });
1936
- }
1937
- fs.writeFileSync(
1938
- `${basePath}/index.${format}`,
1939
- type === "esm"
1940
- ? `import { foo } from "./another";
1941
- export default {
1942
- async fetch(request) {
1943
- return new Response('Hello' + foo);
1944
- },
1945
- };`
1946
- : `import { foo } from "./another";
1947
- addEventListener('fetch', event => {
1948
- event.respondWith(new Response('Hello' + foo));
1949
- })`
1950
- );
1951
- fs.writeFileSync(`${basePath}/another.${format}`, `export const foo = 100;`);
1952
- }
4402
+ describe("legacy module specifiers", () => {
4403
+ it("should work with legacy module specifiers, with a deprecation warning (1)", async () => {
4404
+ writeWranglerToml({
4405
+ rules: [{ type: "Text", globs: ["**/*.file"], fallthrough: false }],
4406
+ });
4407
+ fs.writeFileSync(
4408
+ "./index.js",
4409
+ `import TEXT from 'text.file'; export default {};`
4410
+ );
4411
+ fs.writeFileSync("./text.file", "SOME TEXT CONTENT");
4412
+ mockSubDomainRequest();
4413
+ mockUploadWorkerRequest({
4414
+ expectedModules: {
4415
+ "./2d91d1c4dd6e57d4f5432187ab7c25f45a8973f0-text.file":
4416
+ "SOME TEXT CONTENT",
4417
+ },
4418
+ });
4419
+ await runWrangler("publish index.js");
4420
+ expect(std.out).toMatchInlineSnapshot(`
4421
+ "Uploaded test-name (TIMINGS)
4422
+ Published test-name (TIMINGS)
4423
+ test-name.test-sub-domain.workers.dev"
4424
+ `);
4425
+ expect(std.err).toMatchInlineSnapshot(`""`);
4426
+ expect(std.warn).toMatchInlineSnapshot(`
4427
+ "▲ [WARNING] Deprecation: detected a legacy module import in \\"./index.js\\". This will stop working in the future. Replace references to \\"text.file\\" with \\"./text.file\\";
4428
+
4429
+ "
4430
+ `);
4431
+ });
4432
+
4433
+ it("should work with legacy module specifiers, with a deprecation warning (2)", async () => {
4434
+ writeWranglerToml();
4435
+ fs.writeFileSync(
4436
+ "./index.js",
4437
+ `import WASM from 'index.wasm'; export default {};`
4438
+ );
4439
+ fs.writeFileSync("./index.wasm", "SOME WASM CONTENT");
4440
+ mockSubDomainRequest();
4441
+ mockUploadWorkerRequest({
4442
+ expectedModules: {
4443
+ "./94b240d0d692281e6467aa42043986e5c7eea034-index.wasm":
4444
+ "SOME WASM CONTENT",
4445
+ },
4446
+ });
4447
+ await runWrangler("publish index.js");
4448
+ expect(std.out).toMatchInlineSnapshot(`
4449
+ "Uploaded test-name (TIMINGS)
4450
+ Published test-name (TIMINGS)
4451
+ test-name.test-sub-domain.workers.dev"
4452
+ `);
4453
+ expect(std.err).toMatchInlineSnapshot(`""`);
4454
+ expect(std.warn).toMatchInlineSnapshot(`
4455
+ "▲ [WARNING] Deprecation: detected a legacy module import in \\"./index.js\\". This will stop working in the future. Replace references to \\"index.wasm\\" with \\"./index.wasm\\";
4456
+
4457
+ "
4458
+ `);
4459
+ });
4460
+
4461
+ it("should not match regular module specifiers when there aren't any possible legacy module matches", async () => {
4462
+ // see https://github.com/cloudflare/wrangler2/issues/655 for bug details
4463
+
4464
+ fs.writeFileSync(
4465
+ "./index.js",
4466
+ `import inner from './inner/index.js'; export default {};`
4467
+ );
4468
+ fs.mkdirSync("./inner", { recursive: true });
4469
+ fs.writeFileSync("./inner/index.js", `export default 123`);
4470
+ mockSubDomainRequest();
4471
+ mockUploadWorkerRequest();
4472
+
4473
+ await runWrangler(
4474
+ "publish index.js --compatibility-date 2022-03-17 --name test-name"
4475
+ );
4476
+ expect(std.out).toMatchInlineSnapshot(`
4477
+ "Uploaded test-name (TIMINGS)
4478
+ Published test-name (TIMINGS)
4479
+ test-name.test-sub-domain.workers.dev"
4480
+ `);
4481
+ expect(std.err).toMatchInlineSnapshot(`""`);
4482
+ expect(std.warn).toMatchInlineSnapshot(`""`);
4483
+ });
4484
+ });
4485
+
4486
+ describe("tsconfig", () => {
4487
+ it("should use compilerOptions.paths to resolve modules", async () => {
4488
+ writeWranglerToml({
4489
+ main: "index.ts",
4490
+ });
4491
+ fs.writeFileSync(
4492
+ "index.ts",
4493
+ `import { foo } from '~lib/foo'; export default { fetch() { return new Response(foo)} }`
4494
+ );
4495
+ fs.mkdirSync("lib", { recursive: true });
4496
+ fs.writeFileSync("lib/foo.ts", `export const foo = 123;`);
4497
+ fs.writeFileSync(
4498
+ "tsconfig.json",
4499
+ JSON.stringify({
4500
+ compilerOptions: {
4501
+ baseUrl: ".",
4502
+ paths: {
4503
+ "~lib/*": ["lib/*"],
4504
+ },
4505
+ },
4506
+ })
4507
+ );
4508
+ mockSubDomainRequest();
4509
+ mockUploadWorkerRequest({
4510
+ expectedEntry: "var foo = 123;", // make sure it imported the module correctly
4511
+ });
4512
+ await runWrangler("publish index.ts");
4513
+ expect(std).toMatchInlineSnapshot(`
4514
+ Object {
4515
+ "debug": "",
4516
+ "err": "",
4517
+ "out": "Uploaded test-name (TIMINGS)
4518
+ Published test-name (TIMINGS)
4519
+ test-name.test-sub-domain.workers.dev",
4520
+ "warn": "",
4521
+ }
4522
+ `);
4523
+ });
4524
+
4525
+ it("should output to target es2020 even if tsconfig says otherwise", async () => {
4526
+ writeWranglerToml();
4527
+ writeWorkerSource();
4528
+ fs.writeFileSync(
4529
+ "tsconfig.json",
4530
+ JSON.stringify({
4531
+ compilerOptions: {
4532
+ target: "es5",
4533
+ module: "commonjs",
4534
+ },
4535
+ })
4536
+ );
4537
+ mockSubDomainRequest();
4538
+ mockUploadWorkerRequest({
4539
+ expectedEntry: "export {", // just check that the export is preserved
4540
+ });
4541
+ await runWrangler("publish index.js"); // this would throw if we tried to compile with es5
4542
+ expect(std).toMatchInlineSnapshot(`
4543
+ Object {
4544
+ "debug": "",
4545
+ "err": "",
4546
+ "out": "Uploaded test-name (TIMINGS)
4547
+ Published test-name (TIMINGS)
4548
+ test-name.test-sub-domain.workers.dev",
4549
+ "warn": "",
4550
+ }
4551
+ `);
4552
+ });
4553
+ });
4554
+
4555
+ describe("--outdir", () => {
4556
+ it("should generate built assets at --outdir if specified", async () => {
4557
+ writeWranglerToml();
4558
+ writeWorkerSource();
4559
+ mockSubDomainRequest();
4560
+ mockUploadWorkerRequest();
4561
+ await runWrangler("publish index.js --outdir some-dir");
4562
+ expect(fs.existsSync("some-dir/index.js")).toBe(true);
4563
+ expect(fs.existsSync("some-dir/index.js.map")).toBe(true);
4564
+ expect(std).toMatchInlineSnapshot(`
4565
+ Object {
4566
+ "debug": "",
4567
+ "err": "",
4568
+ "out": "Uploaded test-name (TIMINGS)
4569
+ Published test-name (TIMINGS)
4570
+ test-name.test-sub-domain.workers.dev",
4571
+ "warn": "",
4572
+ }
4573
+ `);
4574
+ });
4575
+ });
4576
+
4577
+ describe("--dry-run", () => {
4578
+ it("should not publish the worker if --dry-run is specified", async () => {
4579
+ writeWranglerToml();
4580
+ writeWorkerSource();
4581
+ await runWrangler("publish index.js --dry-run");
4582
+ expect(std).toMatchInlineSnapshot(`
4583
+ Object {
4584
+ "debug": "",
4585
+ "err": "",
4586
+ "out": "--dry-run: exiting now.",
4587
+ "warn": "",
4588
+ }
4589
+ `);
4590
+ });
4591
+ });
4592
+
4593
+ describe("--node-compat", () => {
4594
+ it("should warn when using node compatibility mode", async () => {
4595
+ writeWranglerToml();
4596
+ writeWorkerSource();
4597
+ await runWrangler("publish index.js --node-compat --dry-run");
4598
+ expect(std).toMatchInlineSnapshot(`
4599
+ Object {
4600
+ "debug": "",
4601
+ "err": "",
4602
+ "out": "--dry-run: exiting now.",
4603
+ "warn": "▲ [WARNING] Enabling node.js compatibility mode for builtins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details.
4604
+
4605
+ ",
4606
+ }
4607
+ `);
4608
+ });
4609
+
4610
+ it("should polyfill node builtins when enabled", async () => {
4611
+ writeWranglerToml();
4612
+ fs.writeFileSync(
4613
+ "index.js",
4614
+ `
4615
+ import path from 'path';
4616
+ console.log(path.join("some/path/to", "a/file.txt"));
4617
+ export default {}
4618
+ `
4619
+ );
4620
+ await runWrangler("publish index.js --node-compat --dry-run"); // this would throw if node compatibility didn't exist
4621
+ expect(std).toMatchInlineSnapshot(`
4622
+ Object {
4623
+ "debug": "",
4624
+ "err": "",
4625
+ "out": "--dry-run: exiting now.",
4626
+ "warn": "▲ [WARNING] Enabling node.js compatibility mode for builtins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details.
4627
+
4628
+ ",
4629
+ }
4630
+ `);
4631
+ });
4632
+ });
4633
+ });
1953
4634
 
1954
4635
  /** Write mock assets to the file system so they can be uploaded. */
1955
4636
  function writeAssets(assets: { filePath: string; content: string }[]) {
@@ -1960,23 +4641,32 @@ function writeAssets(assets: { filePath: string; content: string }[]) {
1960
4641
  }
1961
4642
 
1962
4643
  /** Create a mock handler for the request to upload a worker script. */
1963
- function mockUploadWorkerRequest({
1964
- available_on_subdomain = true,
1965
- expectedEntry,
1966
- expectedType = "esm",
1967
- expectedBindings,
1968
- expectedModules = {},
1969
- env = undefined,
1970
- legacyEnv = false,
1971
- }: {
1972
- available_on_subdomain?: boolean;
1973
- expectedEntry?: string;
1974
- expectedType?: "esm" | "sw";
1975
- expectedBindings?: unknown;
1976
- expectedModules?: Record<string, string>;
1977
- env?: string | undefined;
1978
- legacyEnv?: boolean | undefined;
1979
- } = {}) {
4644
+ function mockUploadWorkerRequest(
4645
+ options: {
4646
+ available_on_subdomain?: boolean;
4647
+ expectedEntry?: string;
4648
+ expectedType?: "esm" | "sw";
4649
+ expectedBindings?: unknown;
4650
+ expectedModules?: Record<string, string>;
4651
+ expectedCompatibilityDate?: string;
4652
+ expectedCompatibilityFlags?: string[];
4653
+ expectedMigrations?: CfWorkerInit["migrations"];
4654
+ env?: string;
4655
+ legacyEnv?: boolean;
4656
+ } = {}
4657
+ ) {
4658
+ const {
4659
+ available_on_subdomain = true,
4660
+ expectedEntry,
4661
+ expectedType = "esm",
4662
+ expectedBindings,
4663
+ expectedModules = {},
4664
+ expectedCompatibilityDate,
4665
+ expectedCompatibilityFlags,
4666
+ env = undefined,
4667
+ legacyEnv = false,
4668
+ expectedMigrations,
4669
+ } = options;
1980
4670
  setMockResponse(
1981
4671
  env && !legacyEnv
1982
4672
  ? "/accounts/:accountId/workers/services/:scriptName/environments/:envName"
@@ -1990,14 +4680,13 @@ function mockUploadWorkerRequest({
1990
4680
  if (!legacyEnv) {
1991
4681
  expect(envName).toEqual(env);
1992
4682
  }
1993
- expect(queryParams.get("available_on_subdomain")).toEqual("true");
4683
+ expect(queryParams.get("include_subdomain_availability")).toEqual("true");
1994
4684
  const formBody = body as FormData;
1995
4685
  if (expectedEntry !== undefined) {
1996
4686
  expect(await (formBody.get("index.js") as File).text()).toMatch(
1997
4687
  expectedEntry
1998
4688
  );
1999
4689
  }
2000
-
2001
4690
  const metadata = JSON.parse(
2002
4691
  formBody.get("metadata") as string
2003
4692
  ) as WorkerMetadata;
@@ -2006,9 +4695,20 @@ function mockUploadWorkerRequest({
2006
4695
  } else {
2007
4696
  expect(metadata.body_part).toEqual("index.js");
2008
4697
  }
2009
- if (expectedBindings !== undefined) {
4698
+ if ("expectedBindings" in options) {
2010
4699
  expect(metadata.bindings).toEqual(expectedBindings);
2011
4700
  }
4701
+ if ("expectedCompatibilityDate" in options) {
4702
+ expect(metadata.compatibility_date).toEqual(expectedCompatibilityDate);
4703
+ }
4704
+ if ("expectedCompatibilityFlags" in options) {
4705
+ expect(metadata.compatibility_flags).toEqual(
4706
+ expectedCompatibilityFlags
4707
+ );
4708
+ }
4709
+ if ("expectedMigrations" in options) {
4710
+ expect(metadata.migrations).toEqual(expectedMigrations);
4711
+ }
2012
4712
  for (const [name, content] of Object.entries(expectedModules)) {
2013
4713
  expect(await (formBody.get(name) as File).text()).toEqual(content);
2014
4714
  }
@@ -2019,10 +4719,21 @@ function mockUploadWorkerRequest({
2019
4719
  }
2020
4720
 
2021
4721
  /** Create a mock handler for the request to get the account's subdomain. */
2022
- function mockSubDomainRequest(subdomain = "test-sub-domain") {
2023
- setMockResponse("/accounts/:accountId/workers/subdomain", "GET", () => {
2024
- return { subdomain };
2025
- });
4722
+ function mockSubDomainRequest(
4723
+ subdomain = "test-sub-domain",
4724
+ registeredWorkersDev = true
4725
+ ) {
4726
+ if (registeredWorkersDev) {
4727
+ setMockResponse("/accounts/:accountId/workers/subdomain", "GET", () => {
4728
+ return { subdomain };
4729
+ });
4730
+ } else {
4731
+ setMockRawResponse("/accounts/:accountId/workers/subdomain", "GET", () => {
4732
+ return createFetchResult(null, false, [
4733
+ { code: 10007, message: "haven't registered workers.dev" },
4734
+ ]);
4735
+ });
4736
+ }
2026
4737
  }
2027
4738
 
2028
4739
  /** Create a mock handler to toggle a <script>.<user>.workers.dev subdomain */
@@ -2057,11 +4768,11 @@ function mockUpdateWorkerRequest({
2057
4768
  }
2058
4769
 
2059
4770
  function mockPublishRoutesRequest({
2060
- routes,
4771
+ routes = [],
2061
4772
  env = undefined,
2062
4773
  legacyEnv = false,
2063
4774
  }: {
2064
- routes: string[];
4775
+ routes: Config["routes"];
2065
4776
  env?: string | undefined;
2066
4777
  legacyEnv?: boolean | undefined;
2067
4778
  }) {
@@ -2081,7 +4792,9 @@ function mockPublishRoutesRequest({
2081
4792
  }
2082
4793
 
2083
4794
  expect(JSON.parse(body as string)).toEqual(
2084
- routes.map((pattern) => ({ pattern }))
4795
+ routes.map((route) =>
4796
+ typeof route !== "object" ? { pattern: route } : route
4797
+ )
2085
4798
  );
2086
4799
  return null;
2087
4800
  }
@@ -2103,7 +4816,12 @@ function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
2103
4816
  /** Create a mock handler for the request that tries to do a bulk upload of assets to a KV namespace. */
2104
4817
  function mockUploadAssetsToKVRequest(
2105
4818
  expectedNamespaceId: string,
2106
- assets: { filePath: string; content: string }[]
4819
+ assets: {
4820
+ filePath: string;
4821
+ content: string;
4822
+ expiration?: number;
4823
+ expiration_ttl?: number;
4824
+ }[]
2107
4825
  ) {
2108
4826
  setMockResponse(
2109
4827
  "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
@@ -2132,8 +4850,98 @@ function mockUploadAssetsToKVRequest(
2132
4850
  expect(Buffer.from(upload.value, "base64").toString()).toEqual(
2133
4851
  asset.content
2134
4852
  );
4853
+ expect(upload.expiration).toEqual(asset.expiration);
4854
+ expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
2135
4855
  }
2136
4856
  return null;
2137
4857
  }
2138
4858
  );
2139
4859
  }
4860
+
4861
+ /** Create a mock handler for thr request that does a bulk delete of unused assets */
4862
+ function mockDeleteUnusedAssetsRequest(
4863
+ expectedNamespaceId: string,
4864
+ assets: string[]
4865
+ ) {
4866
+ setMockResponse(
4867
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
4868
+ "DELETE",
4869
+ ([_url, accountId, namespaceId], { body }) => {
4870
+ expect(accountId).toEqual("some-account-id");
4871
+ expect(namespaceId).toEqual(expectedNamespaceId);
4872
+ const deletes = JSON.parse(body as string);
4873
+ expect(assets).toEqual(deletes);
4874
+ return null;
4875
+ }
4876
+ );
4877
+ }
4878
+
4879
+ type LegacyScriptInfo = { id: string; migration_tag?: string };
4880
+
4881
+ function mockLegacyScriptData(options: { scripts: LegacyScriptInfo[] }) {
4882
+ const { scripts } = options;
4883
+ setMockResponse(
4884
+ "/accounts/:accountId/workers/scripts",
4885
+ "GET",
4886
+ ([_url, accountId]) => {
4887
+ expect(accountId).toEqual("some-account-id");
4888
+ return scripts;
4889
+ }
4890
+ );
4891
+ }
4892
+
4893
+ type DurableScriptInfo = { id: string; migration_tag?: string };
4894
+
4895
+ function mockServiceScriptData(options: {
4896
+ script?: DurableScriptInfo;
4897
+ scriptName?: string;
4898
+ env?: string;
4899
+ }) {
4900
+ const { script } = options;
4901
+ if (options.env) {
4902
+ if (!script) {
4903
+ setMockRawResponse(
4904
+ "/accounts/:accountId/workers/services/:scriptName/environments/:envName",
4905
+ "GET",
4906
+ () => {
4907
+ return createFetchResult(null, false, [
4908
+ { code: 10092, message: "workers.api.error.environment_not_found" },
4909
+ ]);
4910
+ }
4911
+ );
4912
+ return;
4913
+ }
4914
+ setMockResponse(
4915
+ "/accounts/:accountId/workers/services/:scriptName/environments/:envName",
4916
+ "GET",
4917
+ ([_url, accountId, scriptName, envName]) => {
4918
+ expect(accountId).toEqual("some-account-id");
4919
+ expect(scriptName).toEqual(options.scriptName || "test-name");
4920
+ expect(envName).toEqual(options.env);
4921
+ return { script };
4922
+ }
4923
+ );
4924
+ } else {
4925
+ if (!script) {
4926
+ setMockRawResponse(
4927
+ "/accounts/:accountId/workers/services/:scriptName",
4928
+ "GET",
4929
+ () => {
4930
+ return createFetchResult(null, false, [
4931
+ { code: 10090, message: "workers.api.error.service_not_found" },
4932
+ ]);
4933
+ }
4934
+ );
4935
+ return;
4936
+ }
4937
+ setMockResponse(
4938
+ "/accounts/:accountId/workers/services/:scriptName",
4939
+ "GET",
4940
+ ([_url, accountId, scriptName]) => {
4941
+ expect(accountId).toEqual("some-account-id");
4942
+ expect(scriptName).toEqual(options.scriptName || "test-name");
4943
+ return { default_environment: { script } };
4944
+ }
4945
+ );
4946
+ }
4947
+ }