wrangler 0.0.0-e88a54e → 0.0.0-e95e5a0

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 (88) hide show
  1. package/README.md +25 -14
  2. package/bin/wrangler.js +13 -1
  3. package/miniflare-dist/index.mjs +4828 -21
  4. package/package.json +29 -24
  5. package/pages/functions/buildPlugin.ts +92 -0
  6. package/pages/functions/buildWorker.ts +80 -4
  7. package/pages/functions/filepath-routing.test.ts +11 -0
  8. package/pages/functions/filepath-routing.ts +8 -0
  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 +530 -201
  14. package/src/__tests__/dev.test.tsx +284 -18
  15. package/src/__tests__/guess-worker-format.test.ts +28 -1
  16. package/src/__tests__/helpers/mock-cfetch.ts +5 -1
  17. package/src/__tests__/helpers/mock-console.ts +20 -3
  18. package/src/__tests__/helpers/mock-dialogs.ts +26 -1
  19. package/src/__tests__/helpers/mock-http-server.ts +46 -0
  20. package/src/__tests__/helpers/mock-istty.ts +27 -0
  21. package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
  22. package/src/__tests__/helpers/run-in-tmp.ts +7 -0
  23. package/src/__tests__/helpers/write-worker-source.ts +31 -0
  24. package/src/__tests__/https-options.test.ts +5 -2
  25. package/src/__tests__/index.test.ts +27 -769
  26. package/src/__tests__/init.test.ts +1516 -0
  27. package/src/__tests__/jest.setup.ts +4 -4
  28. package/src/__tests__/kv.test.ts +133 -61
  29. package/src/__tests__/logger.test.ts +115 -0
  30. package/src/__tests__/pages.test.ts +311 -26
  31. package/src/__tests__/publish.test.ts +2789 -618
  32. package/src/__tests__/r2.test.ts +26 -10
  33. package/src/__tests__/route.test.ts +4 -4
  34. package/src/__tests__/secret.test.ts +55 -34
  35. package/src/__tests__/tail.test.ts +146 -20
  36. package/src/__tests__/user.test.ts +131 -0
  37. package/src/__tests__/whoami.test.tsx +14 -9
  38. package/src/bundle.ts +30 -3
  39. package/src/cfetch/internal.ts +0 -2
  40. package/src/cli.ts +5 -11
  41. package/src/config/README.md +1 -1
  42. package/src/config/config.ts +20 -4
  43. package/src/config/environment.ts +32 -4
  44. package/src/config/index.ts +4 -3
  45. package/src/config/validation-helpers.ts +96 -7
  46. package/src/config/validation.ts +388 -54
  47. package/src/config-cache.ts +45 -0
  48. package/src/create-worker-preview.ts +22 -13
  49. package/src/create-worker-upload-form.ts +32 -9
  50. package/src/dev/dev-vars.ts +36 -0
  51. package/src/dev/dev.tsx +132 -78
  52. package/src/dev/local.tsx +101 -21
  53. package/src/dev/remote.tsx +23 -13
  54. package/src/dev/use-esbuild.ts +23 -5
  55. package/src/dialogs.tsx +16 -6
  56. package/src/entry.ts +83 -24
  57. package/src/environment-variables.ts +3 -1
  58. package/src/errors.ts +11 -0
  59. package/src/https-options.ts +3 -2
  60. package/src/index.tsx +689 -394
  61. package/src/inspect.ts +17 -11
  62. package/src/intl-polyfill.d.ts +139 -0
  63. package/src/logger.ts +66 -0
  64. package/src/miniflare-cli/index.ts +4 -0
  65. package/src/miniflare-cli/request-context.ts +40 -0
  66. package/src/module-collection.ts +7 -7
  67. package/src/open-in-browser.ts +5 -4
  68. package/src/package-manager.ts +9 -8
  69. package/src/pages.tsx +875 -56
  70. package/src/parse.ts +1 -1
  71. package/src/proxy.ts +28 -19
  72. package/src/publish.ts +263 -141
  73. package/src/sites.tsx +27 -14
  74. package/src/tail/index.ts +2 -2
  75. package/src/tail/printing.ts +13 -8
  76. package/src/update-check.ts +19 -0
  77. package/src/user.tsx +116 -41
  78. package/src/whoami.tsx +2 -1
  79. package/src/worker.ts +15 -6
  80. package/templates/gitignore +171 -0
  81. package/templates/static-asset-facade.js +1 -1
  82. package/wrangler-dist/cli.js +21162 -50227
  83. package/miniflare-dist/index.mjs.map +0 -7
  84. package/src/__tests__/dev2.test.tsx +0 -154
  85. package/src/__tests__/logout.test.ts +0 -52
  86. package/src/__tests__/sentry.test.ts +0 -146
  87. package/src/reporting.ts +0 -131
  88. package/wrangler-dist/cli.js.map +0 -7
@@ -1,6 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import * as TOML from "@iarna/toml";
4
+ import { writeAuthConfigFile } from "../user";
4
5
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
5
6
  import {
6
7
  createFetchResult,
@@ -9,32 +10,264 @@ import {
9
10
  unsetAllMocks,
10
11
  unsetMockFetchKVGetValues,
11
12
  } from "./helpers/mock-cfetch";
12
- import { mockConsoleMethods } from "./helpers/mock-console";
13
+ import { mockConsoleMethods, normalizeSlashes } from "./helpers/mock-console";
14
+ import { useMockIsTTY } from "./helpers/mock-istty";
13
15
  import { mockKeyListRequest } from "./helpers/mock-kv";
16
+ import { mockOAuthFlow } from "./helpers/mock-oauth-flow";
14
17
  import { runInTempDir } from "./helpers/run-in-tmp";
15
18
  import { runWrangler } from "./helpers/run-wrangler";
19
+ import { writeWorkerSource } from "./helpers/write-worker-source";
16
20
  import writeWranglerToml from "./helpers/write-wrangler-toml";
21
+ import type { Config } from "../config";
17
22
  import type { WorkerMetadata } from "../create-worker-upload-form";
18
23
  import type { KVNamespaceInfo } from "../kv";
24
+ import type { CfWorkerInit } from "../worker";
19
25
  import type { FormData, File } from "undici";
20
26
 
21
27
  describe("publish", () => {
28
+ mockAccountId();
29
+ mockApiToken();
30
+ runInTempDir({ homedir: "./home" });
31
+ const { setIsTTY } = useMockIsTTY();
32
+ const std = mockConsoleMethods();
33
+ const {
34
+ mockOAuthServerCallback,
35
+ mockGrantAccessToken,
36
+ mockGrantAuthorization,
37
+ mockGetMemberships,
38
+ } = mockOAuthFlow();
39
+
22
40
  beforeEach(() => {
23
41
  // @ts-expect-error we're using a very simple setTimeout mock here
24
42
  jest.spyOn(global, "setTimeout").mockImplementation((fn, _period) => {
25
- fn();
43
+ setImmediate(fn);
26
44
  });
45
+ setIsTTY(true);
27
46
  });
28
- mockAccountId();
29
- mockApiToken();
30
- runInTempDir();
31
- const std = mockConsoleMethods();
32
47
 
33
48
  afterEach(() => {
34
49
  unsetAllMocks();
35
50
  unsetMockFetchKVGetValues();
36
51
  });
37
52
 
53
+ describe("authentication", () => {
54
+ mockApiToken({ apiToken: null });
55
+ beforeEach(() => {
56
+ // @ts-expect-error disable the mock we'd setup earlier
57
+ // or else our server won't bother listening for oauth requests
58
+ // and will timeout and fail
59
+ global.setTimeout.mockRestore();
60
+ });
61
+
62
+ it("drops a user into the login flow if they're unauthenticated", async () => {
63
+ writeWranglerToml();
64
+ writeWorkerSource();
65
+ mockSubDomainRequest();
66
+ mockUploadWorkerRequest();
67
+
68
+ mockOAuthServerCallback();
69
+ const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
70
+ mockGrantAuthorization({ respondWith: "success" });
71
+
72
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
73
+
74
+ expect(accessTokenRequest.actual.url).toEqual(
75
+ accessTokenRequest.expected.url
76
+ );
77
+
78
+ expect(std.out).toMatchInlineSnapshot(`
79
+ "Attempting to login via OAuth...
80
+ Successfully logged in.
81
+ Uploaded test-name (TIMINGS)
82
+ Published test-name (TIMINGS)
83
+ test-name.test-sub-domain.workers.dev"
84
+ `);
85
+ expect(std.warn).toMatchInlineSnapshot(`""`);
86
+ expect(std.err).toMatchInlineSnapshot(`""`);
87
+ });
88
+
89
+ it("warns a user when they're authenticated with an API token in wrangler config file", async () => {
90
+ writeWranglerToml();
91
+ writeWorkerSource();
92
+ mockSubDomainRequest();
93
+ mockUploadWorkerRequest();
94
+ writeAuthConfigFile({
95
+ api_token: "some-api-token",
96
+ });
97
+
98
+ const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
99
+ mockGrantAuthorization({ respondWith: "success" });
100
+
101
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
102
+
103
+ expect(accessTokenRequest.actual.url).toEqual(
104
+ accessTokenRequest.expected.url
105
+ );
106
+
107
+ expect(std.out).toMatchInlineSnapshot(`
108
+ "Attempting to login via OAuth...
109
+ Successfully logged in.
110
+ Uploaded test-name (TIMINGS)
111
+ Published test-name (TIMINGS)
112
+ test-name.test-sub-domain.workers.dev"
113
+ `);
114
+ expect(std.warn).toMatchInlineSnapshot(`
115
+ "▲ [WARNING] It looks like you have used Wrangler 1's \`config\` command to login with an API token.
116
+
117
+ This is no longer supported in the current version of Wrangler.
118
+ If you wish to authenticate via an API token then please set the \`CLOUDFLARE_API_TOKEN\`
119
+ environment variable.
120
+
121
+ "
122
+ `);
123
+ expect(std.err).toMatchInlineSnapshot(`""`);
124
+ });
125
+
126
+ describe("non-TTY", () => {
127
+ const ENV_COPY = process.env;
128
+
129
+ afterEach(() => {
130
+ process.env = ENV_COPY;
131
+ });
132
+
133
+ it("should not throw an error in non-TTY if 'CLOUDFLARE_API_TOKEN' & 'account_id' are in scope", async () => {
134
+ process.env = {
135
+ CLOUDFLARE_API_TOKEN: "123456789",
136
+ };
137
+ setIsTTY(false);
138
+ writeWranglerToml({
139
+ account_id: "some-account-id",
140
+ });
141
+ writeWorkerSource();
142
+ mockSubDomainRequest();
143
+ mockUploadWorkerRequest();
144
+ mockOAuthServerCallback();
145
+
146
+ await runWrangler("publish index.js");
147
+
148
+ expect(std.out).toMatchInlineSnapshot(`
149
+ "Uploaded test-name (TIMINGS)
150
+ Published test-name (TIMINGS)
151
+ test-name.test-sub-domain.workers.dev"
152
+ `);
153
+ expect(std.err).toMatchInlineSnapshot(`""`);
154
+ });
155
+
156
+ it("should not throw an error if 'CLOUDFLARE_ACCOUNT_ID' & 'CLOUDFLARE_API_TOKEN' are in scope", async () => {
157
+ process.env = {
158
+ CLOUDFLARE_API_TOKEN: "hunter2",
159
+ CLOUDFLARE_ACCOUNT_ID: "some-account-id",
160
+ };
161
+ setIsTTY(false);
162
+ writeWranglerToml();
163
+ writeWorkerSource();
164
+ mockSubDomainRequest();
165
+ mockUploadWorkerRequest();
166
+ mockOAuthServerCallback();
167
+ mockGetMemberships({
168
+ success: true,
169
+ result: [],
170
+ });
171
+
172
+ await runWrangler("publish index.js");
173
+
174
+ expect(std.out).toMatchInlineSnapshot(`
175
+ "Uploaded test-name (TIMINGS)
176
+ Published test-name (TIMINGS)
177
+ test-name.test-sub-domain.workers.dev"
178
+ `);
179
+ expect(std.err).toMatchInlineSnapshot(`""`);
180
+ });
181
+
182
+ it("should throw an error in non-TTY & there is more than one account associated with API token", async () => {
183
+ setIsTTY(false);
184
+ process.env = {
185
+ CLOUDFLARE_API_TOKEN: "hunter2",
186
+ CLOUDFLARE_ACCOUNT_ID: undefined,
187
+ };
188
+ writeWranglerToml({
189
+ account_id: undefined,
190
+ });
191
+ writeWorkerSource();
192
+ mockSubDomainRequest();
193
+ mockUploadWorkerRequest();
194
+ mockOAuthServerCallback();
195
+ mockGetMemberships({
196
+ success: true,
197
+ result: [
198
+ { id: "IG-88", account: { id: "1701", name: "enterprise" } },
199
+ { id: "R2-D2", account: { id: "nx01", name: "enterprise-nx" } },
200
+ ],
201
+ });
202
+
203
+ await expect(runWrangler("publish index.js")).rejects
204
+ .toMatchInlineSnapshot(`
205
+ [Error: More than one account available but unable to select one in non-interactive mode.
206
+ Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
207
+ Available accounts are ("<name>" - "<id>"):
208
+ "enterprise" - "1701")
209
+ "enterprise-nx" - "nx01")]
210
+ `);
211
+ });
212
+
213
+ it("should throw error in non-TTY if 'CLOUDFLARE_API_TOKEN' is missing", async () => {
214
+ setIsTTY(false);
215
+ writeWranglerToml({
216
+ account_id: undefined,
217
+ });
218
+ process.env = {
219
+ CLOUDFLARE_API_TOKEN: undefined,
220
+ CLOUDFLARE_ACCOUNT_ID: "badwolf",
221
+ };
222
+ writeWorkerSource();
223
+ mockSubDomainRequest();
224
+ mockUploadWorkerRequest();
225
+ mockOAuthServerCallback();
226
+ mockGetMemberships({
227
+ success: true,
228
+ result: [
229
+ { id: "IG-88", account: { id: "1701", name: "enterprise" } },
230
+ { id: "R2-D2", account: { id: "nx01", name: "enterprise-nx" } },
231
+ ],
232
+ });
233
+
234
+ await expect(runWrangler("publish index.js")).rejects.toThrowError();
235
+
236
+ expect(std.err).toMatchInlineSnapshot(`
237
+ "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.
238
+
239
+ "
240
+ `);
241
+ });
242
+ it("should throw error with no account ID provided and no members retrieved", async () => {
243
+ setIsTTY(false);
244
+ writeWranglerToml({
245
+ account_id: undefined,
246
+ });
247
+ process.env = {
248
+ CLOUDFLARE_API_TOKEN: "picard",
249
+ CLOUDFLARE_ACCOUNT_ID: undefined,
250
+ };
251
+ writeWorkerSource();
252
+ mockSubDomainRequest();
253
+ mockUploadWorkerRequest();
254
+ mockOAuthServerCallback();
255
+ mockGetMemberships({
256
+ success: false,
257
+ result: [],
258
+ });
259
+
260
+ await expect(runWrangler("publish index.js")).rejects.toThrowError();
261
+
262
+ expect(std.err).toMatchInlineSnapshot(`
263
+ "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.
264
+
265
+ "
266
+ `);
267
+ });
268
+ });
269
+ });
270
+
38
271
  describe("environments", () => {
39
272
  it("should use legacy environments by default", async () => {
40
273
  writeWranglerToml({ env: { "some-env": {} } });
@@ -72,7 +305,7 @@ describe("publish", () => {
72
305
  expect(std.warn).toMatchInlineSnapshot(`""`);
73
306
  });
74
307
 
75
- it("appends the environment name when provided", async () => {
308
+ it("appends the environment name when provided, and there is associated config", async () => {
76
309
  writeWranglerToml({ env: { "some-env": {} } });
77
310
  writeWorkerSource();
78
311
  mockSubDomainRequest();
@@ -89,6 +322,74 @@ describe("publish", () => {
89
322
  expect(std.err).toMatchInlineSnapshot(`""`);
90
323
  expect(std.warn).toMatchInlineSnapshot(`""`);
91
324
  });
325
+
326
+ it("appends the environment name when provided (with a warning), if there are no configured environments", async () => {
327
+ writeWranglerToml({});
328
+ writeWorkerSource();
329
+ mockSubDomainRequest();
330
+ mockUploadWorkerRequest({
331
+ env: "some-env",
332
+ legacyEnv: true,
333
+ });
334
+ await runWrangler("publish index.js --env some-env --legacy-env true");
335
+ expect(std.out).toMatchInlineSnapshot(`
336
+ "Uploaded test-name-some-env (TIMINGS)
337
+ Published test-name-some-env (TIMINGS)
338
+ test-name-some-env.test-sub-domain.workers.dev"
339
+ `);
340
+ expect(std.err).toMatchInlineSnapshot(`""`);
341
+ expect(std.warn).toMatchInlineSnapshot(`
342
+ "▲ [WARNING] Processing wrangler.toml configuration:
343
+
344
+ - No environment found in configuration with name \\"some-env\\".
345
+ Before using \`--env=some-env\` there should be an equivalent environment section in the
346
+ configuration.
347
+
348
+ Consider adding an environment configuration section to the wrangler.toml file:
349
+ \`\`\`
350
+ [env.some-env]
351
+ \`\`\`
352
+
353
+
354
+ "
355
+ `);
356
+ });
357
+
358
+ it("should throw an error when an environment name when provided, which doesn't match those in the config", async () => {
359
+ writeWranglerToml({ env: { "other-env": {} } });
360
+ writeWorkerSource();
361
+ mockSubDomainRequest();
362
+ await expect(
363
+ runWrangler("publish index.js --env some-env --legacy-env true")
364
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`
365
+ "Processing wrangler.toml configuration:
366
+ - No environment found in configuration with name \\"some-env\\".
367
+ Before using \`--env=some-env\` there should be an equivalent environment section in the configuration.
368
+ The available configured environment names are: [\\"other-env\\"]
369
+
370
+ Consider adding an environment configuration section to the wrangler.toml file:
371
+ \`\`\`
372
+ [env.some-env]
373
+ \`\`\`
374
+ "
375
+ `);
376
+ });
377
+
378
+ it("should throw an error w/ helpful message when using --env --name", async () => {
379
+ writeWranglerToml({ env: { "some-env": {} } });
380
+ writeWorkerSource();
381
+ mockSubDomainRequest();
382
+ await runWrangler(
383
+ "publish index.js --name voyager --env some-env --legacy-env true"
384
+ ).catch((err) =>
385
+ expect(err).toMatchInlineSnapshot(`
386
+ [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:
387
+ [env.some-env]
388
+ name = "voyager"
389
+ ]
390
+ `)
391
+ );
392
+ });
92
393
  });
93
394
 
94
395
  describe("services", () => {
@@ -99,14 +400,21 @@ describe("publish", () => {
99
400
  mockUploadWorkerRequest({
100
401
  legacyEnv: false,
101
402
  });
102
- await runWrangler("publish index.js");
403
+ await runWrangler("publish index.js --legacy-env false");
103
404
  expect(std.out).toMatchInlineSnapshot(`
104
405
  "Uploaded test-name (TIMINGS)
105
406
  Published test-name (TIMINGS)
106
407
  test-name.test-sub-domain.workers.dev"
107
408
  `);
108
409
  expect(std.err).toMatchInlineSnapshot(`""`);
109
- expect(std.warn).toMatchInlineSnapshot(`""`);
410
+ expect(std.warn).toMatchInlineSnapshot(`
411
+ "▲ [WARNING] Processing wrangler.toml configuration:
412
+
413
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
414
+ the future. DO NOT USE IN PRODUCTION.
415
+
416
+ "
417
+ `);
110
418
  });
111
419
 
112
420
  it("publishes as an environment when provided", async () => {
@@ -124,7 +432,14 @@ describe("publish", () => {
124
432
  some-env.test-name.test-sub-domain.workers.dev"
125
433
  `);
126
434
  expect(std.err).toMatchInlineSnapshot(`""`);
127
- expect(std.warn).toMatchInlineSnapshot(`""`);
435
+ expect(std.warn).toMatchInlineSnapshot(`
436
+ "▲ [WARNING] Processing wrangler.toml configuration:
437
+
438
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
439
+ the future. DO NOT USE IN PRODUCTION.
440
+
441
+ "
442
+ `);
128
443
  });
129
444
  });
130
445
  });
@@ -173,6 +488,116 @@ describe("publish", () => {
173
488
  await runWrangler("publish ./index");
174
489
  });
175
490
 
491
+ it("should publish to a route with a pattern/{zone_id|zone_name} combo", async () => {
492
+ writeWranglerToml({
493
+ routes: [
494
+ "some-example.com/some-route/*",
495
+ { pattern: "*a-boring-website.com", zone_id: "54sdf7fsda" },
496
+ {
497
+ pattern: "*another-boring-website.com",
498
+ zone_name: "some-zone.com",
499
+ },
500
+ { pattern: "example.com/some-route/*", zone_id: "JGHFHG654gjcj" },
501
+ "more-examples.com/*",
502
+ ],
503
+ });
504
+ writeWorkerSource();
505
+ mockUpdateWorkerRequest({ enabled: false });
506
+ mockUploadWorkerRequest({ expectedType: "esm" });
507
+ mockPublishRoutesRequest({
508
+ routes: [
509
+ "some-example.com/some-route/*",
510
+ { pattern: "*a-boring-website.com", zone_id: "54sdf7fsda" },
511
+ {
512
+ pattern: "*another-boring-website.com",
513
+ zone_name: "some-zone.com",
514
+ },
515
+ { pattern: "example.com/some-route/*", zone_id: "JGHFHG654gjcj" },
516
+ "more-examples.com/*",
517
+ ],
518
+ });
519
+ await runWrangler("publish ./index");
520
+ expect(std).toMatchInlineSnapshot(`
521
+ Object {
522
+ "debug": "",
523
+ "err": "",
524
+ "out": "Uploaded test-name (TIMINGS)
525
+ Published test-name (TIMINGS)
526
+ some-example.com/some-route/*
527
+ *a-boring-website.com (zone id: 54sdf7fsda)
528
+ *another-boring-website.com (zone name: some-zone.com)
529
+ example.com/some-route/* (zone id: JGHFHG654gjcj)
530
+ more-examples.com/*",
531
+ "warn": "",
532
+ }
533
+ `);
534
+ });
535
+
536
+ it("should publish to a route with a pattern/{zone_id|zone_name} combo (service environments)", async () => {
537
+ writeWranglerToml({
538
+ env: {
539
+ staging: {
540
+ routes: [
541
+ "some-example.com/some-route/*",
542
+ { pattern: "*a-boring-website.com", zone_id: "54sdf7fsda" },
543
+ {
544
+ pattern: "*another-boring-website.com",
545
+ zone_name: "some-zone.com",
546
+ },
547
+ { pattern: "example.com/some-route/*", zone_id: "JGHFHG654gjcj" },
548
+ "more-examples.com/*",
549
+ ],
550
+ },
551
+ },
552
+ });
553
+ mockSubDomainRequest();
554
+ writeWorkerSource();
555
+ mockUpdateWorkerRequest({
556
+ enabled: false,
557
+ env: "staging",
558
+ legacyEnv: false,
559
+ });
560
+ mockUploadWorkerRequest({
561
+ expectedType: "esm",
562
+ env: "staging",
563
+ legacyEnv: false,
564
+ });
565
+ mockPublishRoutesRequest({
566
+ routes: [
567
+ "some-example.com/some-route/*",
568
+ { pattern: "*a-boring-website.com", zone_id: "54sdf7fsda" },
569
+ {
570
+ pattern: "*another-boring-website.com",
571
+ zone_name: "some-zone.com",
572
+ },
573
+ { pattern: "example.com/some-route/*", zone_id: "JGHFHG654gjcj" },
574
+ "more-examples.com/*",
575
+ ],
576
+ env: "staging",
577
+ legacyEnv: false,
578
+ });
579
+ await runWrangler("publish ./index --legacy-env false --env staging");
580
+ expect(std).toMatchInlineSnapshot(`
581
+ Object {
582
+ "debug": "",
583
+ "err": "",
584
+ "out": "Uploaded test-name (staging) (TIMINGS)
585
+ Published test-name (staging) (TIMINGS)
586
+ some-example.com/some-route/*
587
+ *a-boring-website.com (zone id: 54sdf7fsda)
588
+ *another-boring-website.com (zone name: some-zone.com)
589
+ example.com/some-route/* (zone id: JGHFHG654gjcj)
590
+ more-examples.com/*",
591
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
592
+
593
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
594
+ the future. DO NOT USE IN PRODUCTION.
595
+
596
+ ",
597
+ }
598
+ `);
599
+ });
600
+
176
601
  it("should publish to legacy environment specific routes", async () => {
177
602
  writeWranglerToml({
178
603
  routes: ["example.com/some-route/*"],
@@ -304,13 +729,16 @@ describe("publish", () => {
304
729
  `);
305
730
  expect(std.err).toMatchInlineSnapshot(`""`);
306
731
  expect(std.warn).toMatchInlineSnapshot(`
307
- "Processing wrangler.toml configuration:
308
- - DEPRECATION: \\"build.upload.main\\":
309
- Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
310
- Then add the top level \`main\` field to your configuration file:
311
- \`\`\`
312
- main = \\"dist/index.js\\"
313
- \`\`\`"
732
+ "▲ [WARNING] Processing wrangler.toml configuration:
733
+
734
+ - Deprecation: \\"build.upload.main\\":
735
+ Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
736
+ Then add the top level \`main\` field to your configuration file:
737
+ \`\`\`
738
+ main = \\"dist/index.js\\"
739
+ \`\`\`
740
+
741
+ "
314
742
  `);
315
743
  });
316
744
 
@@ -336,15 +764,19 @@ describe("publish", () => {
336
764
  `);
337
765
  expect(std.err).toMatchInlineSnapshot(`""`);
338
766
  expect(std.warn).toMatchInlineSnapshot(`
339
- "Processing ../wrangler.toml configuration:
340
- - DEPRECATION: \\"build.upload.main\\":
341
- Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
342
- Then add the top level \`main\` field to your configuration file:
343
- \`\`\`
344
- main = \\"foo/index.js\\"
345
- \`\`\`
346
- - DEPRECATION: \\"build.upload.dir\\":
347
- Use the top level \\"main\\" field or a command-line argument to specify the entry-point for the Worker."
767
+ "▲ [WARNING] Processing ../wrangler.toml configuration:
768
+
769
+ - Deprecation: \\"build.upload.main\\":
770
+ Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
771
+ Then add the top level \`main\` field to your configuration file:
772
+ \`\`\`
773
+ main = \\"foo/index.js\\"
774
+ \`\`\`
775
+ - Deprecation: \\"build.upload.dir\\":
776
+ Use the top level \\"main\\" field or a command-line argument to specify the entry-point for the
777
+ Worker.
778
+
779
+ "
348
780
  `);
349
781
  });
350
782
 
@@ -480,17 +912,32 @@ export default{
480
912
  - \\"site.bucket\\" is a required field."
481
913
  `);
482
914
 
483
- expect(std.out).toMatchInlineSnapshot(`""`);
915
+ expect(std.out).toMatchInlineSnapshot(`
916
+ "
917
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
918
+ `);
484
919
  expect(std.err).toMatchInlineSnapshot(`
485
- "Processing wrangler.toml configuration:
486
- - \\"site.bucket\\" is a required field.
920
+ "X [ERROR] Processing wrangler.toml configuration:
487
921
 
488
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
922
+ - \\"site.bucket\\" is a required field.
923
+
924
+ "
925
+ `);
926
+ expect(normalizeSlashes(std.warn)).toMatchInlineSnapshot(`
927
+ "▲ [WARNING] Processing wrangler.toml configuration:
928
+
929
+ - Because you've defined a [site] configuration, we're defaulting to \\"workers-site\\" for the
930
+ deprecated \`site.entry-point\`field.
931
+ Add the top level \`main\` field to your configuration file:
932
+ \`\`\`
933
+ main = \\"workers-site/index.js\\"
934
+ \`\`\`
935
+
936
+ "
489
937
  `);
490
- expect(std.warn).toMatchInlineSnapshot(`""`);
491
938
  });
492
939
 
493
- it("should error if there is a `site.entry-point` configuration", async () => {
940
+ it("should warn if there is a `site.entry-point` configuration", async () => {
494
941
  const assets = [
495
942
  { filePath: "assets/file-1.txt", content: "Content of file-1" },
496
943
  { filePath: "assets/file-2.txt", content: "Content of file-2" },
@@ -513,52 +960,35 @@ export default{
513
960
  mockListKVNamespacesRequest(kvNamespace);
514
961
  mockKeyListRequest(kvNamespace.id, []);
515
962
  mockUploadAssetsToKVRequest(kvNamespace.id, assets);
516
-
517
- await expect(runWrangler("publish ./index.js")).rejects
518
- .toThrowErrorMatchingInlineSnapshot(`
519
- "Processing wrangler.toml configuration:
520
- - DEPRECATION: \\"site.entry-point\\":
521
- The \`site.entry-point\` config field is no longer used.
522
- The entry-point should be specified via the command line or the \`main\` config field."
523
- `);
524
-
525
- expect(std.out).toMatchInlineSnapshot(`""`);
526
- expect(std.err).toMatchInlineSnapshot(`
527
- "Processing wrangler.toml configuration:
528
- - DEPRECATION: \\"site.entry-point\\":
529
- The \`site.entry-point\` config field is no longer used.
530
- The entry-point should be specified via the command line or the \`main\` config field.
531
-
532
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
533
- `);
534
- expect(std.warn).toMatchInlineSnapshot(`
535
- "Processing wrangler.toml configuration:
536
- - Unexpected fields found in site field: \\"entry-point\\""
537
- `);
538
- });
539
-
540
- it("should error if there is no entry-point specified", async () => {
541
- writeWranglerToml();
542
- writeWorkerSource();
543
- mockUploadWorkerRequest();
544
- mockSubDomainRequest();
545
- await expect(
546
- runWrangler("publish")
547
- ).rejects.toThrowErrorMatchingInlineSnapshot(
548
- `"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."`
549
- );
550
-
551
- expect(std.out).toMatchInlineSnapshot(`""`);
552
- expect(std.err).toMatchInlineSnapshot(`
553
- "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.
554
-
555
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
963
+ await runWrangler("publish ./index.js");
964
+
965
+ expect(std).toMatchInlineSnapshot(`
966
+ Object {
967
+ "debug": "",
968
+ "err": "",
969
+ "out": "Reading assets/file-1.txt...
970
+ Uploading as assets/file-1.2ca234f380.txt...
971
+ Reading assets/file-2.txt...
972
+ Uploading as assets/file-2.5938485188.txt...
973
+ ↗️ Done syncing assets
974
+ Uploaded test-name (TIMINGS)
975
+ Published test-name (TIMINGS)
976
+ test-name.test-sub-domain.workers.dev",
977
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
978
+
979
+ - Deprecation: \\"site.entry-point\\":
980
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration
981
+ file:
982
+ \`\`\`
983
+ main = \\"index.js\\"
984
+ \`\`\`
985
+
986
+ ",
987
+ }
556
988
  `);
557
989
  });
558
- });
559
990
 
560
- describe("asset upload", () => {
561
- it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
991
+ it("should resolve site.entry-point relative to wrangler.toml", async () => {
562
992
  const assets = [
563
993
  { filePath: "assets/file-1.txt", content: "Content of file-1" },
564
994
  { filePath: "assets/file-2.txt", content: "Content of file-2" },
@@ -567,53 +997,148 @@ export default{
567
997
  title: "__test-name-workers_sites_assets",
568
998
  id: "__test-name-workers_sites_assets-id",
569
999
  };
1000
+ fs.mkdirSync("my-site");
1001
+ process.chdir("my-site");
570
1002
  writeWranglerToml({
571
- main: "./index.js",
572
1003
  site: {
573
1004
  bucket: "assets",
1005
+ "entry-point": "my-entry",
574
1006
  },
575
1007
  });
576
- writeWorkerSource();
1008
+ fs.mkdirSync("my-entry");
1009
+ fs.writeFileSync("my-entry/index.js", "export default {}");
577
1010
  writeAssets(assets);
1011
+ process.chdir("..");
578
1012
  mockUploadWorkerRequest();
579
1013
  mockSubDomainRequest();
580
1014
  mockListKVNamespacesRequest(kvNamespace);
581
1015
  mockKeyListRequest(kvNamespace.id, []);
582
1016
  mockUploadAssetsToKVRequest(kvNamespace.id, assets);
583
- await runWrangler("publish");
1017
+ await runWrangler("publish --config ./my-site/wrangler.toml");
584
1018
 
585
1019
  expect(std.out).toMatchInlineSnapshot(`
586
- "reading assets/file-1.txt...
587
- uploading as assets/file-1.2ca234f380.txt...
588
- reading assets/file-2.txt...
589
- uploading as assets/file-2.5938485188.txt...
1020
+ "Reading assets/file-1.txt...
1021
+ Uploading as assets/file-1.2ca234f380.txt...
1022
+ Reading assets/file-2.txt...
1023
+ Uploading as assets/file-2.5938485188.txt...
590
1024
  ↗️ Done syncing assets
591
1025
  Uploaded test-name (TIMINGS)
592
1026
  Published test-name (TIMINGS)
593
1027
  test-name.test-sub-domain.workers.dev"
594
1028
  `);
595
1029
  expect(std.err).toMatchInlineSnapshot(`""`);
1030
+ expect(normalizeSlashes(std.warn)).toMatchInlineSnapshot(`
1031
+ "▲ [WARNING] Processing my-site/wrangler.toml configuration:
1032
+
1033
+ - Deprecation: \\"site.entry-point\\":
1034
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration
1035
+ file:
1036
+ \`\`\`
1037
+ main = \\"my-entry/index.js\\"
1038
+ \`\`\`
1039
+
1040
+ "
1041
+ `);
596
1042
  });
597
1043
 
598
- it("when using a service worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
599
- const assets = [
600
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
601
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
602
- ];
603
- const kvNamespace = {
604
- title: "__test-name-workers_sites_assets",
605
- id: "__test-name-workers_sites_assets-id",
606
- };
1044
+ it("should error if both main and site.entry-point are specified", async () => {
607
1045
  writeWranglerToml({
608
- main: "./index.js",
1046
+ main: "some-entry",
609
1047
  site: {
610
- bucket: "assets",
1048
+ bucket: "some-bucket",
1049
+ "entry-point": "./index.js",
611
1050
  },
612
1051
  });
613
- writeWorkerSource({ type: "sw" });
614
- writeAssets(assets);
615
- mockUploadWorkerRequest({
616
- expectedType: "sw",
1052
+
1053
+ await expect(runWrangler("publish")).rejects
1054
+ .toThrowErrorMatchingInlineSnapshot(`
1055
+ "Processing wrangler.toml configuration:
1056
+ - Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.
1057
+ They serve the same purpose: to point to the entry-point of your worker.
1058
+ Delete the deprecated \`site.entry-point\` field from your config."
1059
+ `);
1060
+ });
1061
+
1062
+ it("should error if there is no entry-point specified", async () => {
1063
+ writeWranglerToml();
1064
+ writeWorkerSource();
1065
+ mockUploadWorkerRequest();
1066
+ mockSubDomainRequest();
1067
+ await expect(
1068
+ runWrangler("publish")
1069
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1070
+ `"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."`
1071
+ );
1072
+
1073
+ expect(std.out).toMatchInlineSnapshot(`
1074
+ "
1075
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1076
+ `);
1077
+ expect(std.err).toMatchInlineSnapshot(`
1078
+ "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.
1079
+
1080
+ "
1081
+ `);
1082
+ });
1083
+ });
1084
+
1085
+ describe("asset upload", () => {
1086
+ it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
1087
+ const assets = [
1088
+ { filePath: "assets/file-1.txt", content: "Content of file-1" },
1089
+ { filePath: "assets/file-2.txt", content: "Content of file-2" },
1090
+ ];
1091
+ const kvNamespace = {
1092
+ title: "__test-name-workers_sites_assets",
1093
+ id: "__test-name-workers_sites_assets-id",
1094
+ };
1095
+ writeWranglerToml({
1096
+ main: "./index.js",
1097
+ site: {
1098
+ bucket: "assets",
1099
+ },
1100
+ });
1101
+ writeWorkerSource();
1102
+ writeAssets(assets);
1103
+ mockUploadWorkerRequest();
1104
+ mockSubDomainRequest();
1105
+ mockListKVNamespacesRequest(kvNamespace);
1106
+ mockKeyListRequest(kvNamespace.id, []);
1107
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1108
+ await runWrangler("publish");
1109
+
1110
+ expect(std.out).toMatchInlineSnapshot(`
1111
+ "Reading assets/file-1.txt...
1112
+ Uploading as assets/file-1.2ca234f380.txt...
1113
+ Reading assets/file-2.txt...
1114
+ Uploading as assets/file-2.5938485188.txt...
1115
+ ↗️ Done syncing assets
1116
+ Uploaded test-name (TIMINGS)
1117
+ Published test-name (TIMINGS)
1118
+ test-name.test-sub-domain.workers.dev"
1119
+ `);
1120
+ expect(std.err).toMatchInlineSnapshot(`""`);
1121
+ });
1122
+
1123
+ it("when using a service-worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
1124
+ const assets = [
1125
+ { filePath: "assets/file-1.txt", content: "Content of file-1" },
1126
+ { filePath: "assets/file-2.txt", content: "Content of file-2" },
1127
+ ];
1128
+ const kvNamespace = {
1129
+ title: "__test-name-workers_sites_assets",
1130
+ id: "__test-name-workers_sites_assets-id",
1131
+ };
1132
+ writeWranglerToml({
1133
+ main: "./index.js",
1134
+ site: {
1135
+ bucket: "assets",
1136
+ },
1137
+ });
1138
+ writeWorkerSource({ type: "sw" });
1139
+ writeAssets(assets);
1140
+ mockUploadWorkerRequest({
1141
+ expectedType: "sw",
617
1142
  expectedModules: {
618
1143
  __STATIC_CONTENT_MANIFEST:
619
1144
  '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
@@ -639,10 +1164,10 @@ export default{
639
1164
  await runWrangler("publish");
640
1165
 
641
1166
  expect(std.out).toMatchInlineSnapshot(`
642
- "reading assets/file-1.txt...
643
- uploading as assets/file-1.2ca234f380.txt...
644
- reading assets/file-2.txt...
645
- uploading as assets/file-2.5938485188.txt...
1167
+ "Reading assets/file-1.txt...
1168
+ Uploading as assets/file-1.2ca234f380.txt...
1169
+ Reading assets/file-2.txt...
1170
+ Uploading as assets/file-2.5938485188.txt...
646
1171
  ↗️ Done syncing assets
647
1172
  Uploaded test-name (TIMINGS)
648
1173
  Published test-name (TIMINGS)
@@ -689,10 +1214,10 @@ export default{
689
1214
  await runWrangler("publish");
690
1215
 
691
1216
  expect(std.out).toMatchInlineSnapshot(`
692
- "reading assets/file-1.txt...
693
- uploading as assets/file-1.2ca234f380.txt...
694
- reading assets/file-2.txt...
695
- uploading as assets/file-2.5938485188.txt...
1217
+ "Reading assets/file-1.txt...
1218
+ Uploading as assets/file-1.2ca234f380.txt...
1219
+ Reading assets/file-2.txt...
1220
+ Uploading as assets/file-2.5938485188.txt...
696
1221
  ↗️ Done syncing assets
697
1222
  Uploaded test-name (TIMINGS)
698
1223
  Published test-name (TIMINGS)
@@ -737,10 +1262,10 @@ export default{
737
1262
  await runWrangler("publish --env some-env --legacy-env false");
738
1263
 
739
1264
  expect(std.out).toMatchInlineSnapshot(`
740
- "reading assets/file-1.txt...
741
- uploading as assets/file-1.2ca234f380.txt...
742
- reading assets/file-2.txt...
743
- uploading as assets/file-2.5938485188.txt...
1265
+ "Reading assets/file-1.txt...
1266
+ Uploading as assets/file-1.2ca234f380.txt...
1267
+ Reading assets/file-2.txt...
1268
+ Uploading as assets/file-2.5938485188.txt...
744
1269
  ↗️ Done syncing assets
745
1270
  Uploaded test-name (some-env) (TIMINGS)
746
1271
  Published test-name (some-env) (TIMINGS)
@@ -786,10 +1311,10 @@ export default{
786
1311
  await runWrangler("publish --env some-env --legacy-env true");
787
1312
 
788
1313
  expect(std.out).toMatchInlineSnapshot(`
789
- "reading assets/file-1.txt...
790
- uploading as assets/file-1.2ca234f380.txt...
791
- reading assets/file-2.txt...
792
- uploading as assets/file-2.5938485188.txt...
1314
+ "Reading assets/file-1.txt...
1315
+ Uploading as assets/file-1.2ca234f380.txt...
1316
+ Reading assets/file-2.txt...
1317
+ Uploading as assets/file-2.5938485188.txt...
793
1318
  ↗️ Done syncing assets
794
1319
  Uploaded test-name-some-env (TIMINGS)
795
1320
  Published test-name-some-env (TIMINGS)
@@ -830,10 +1355,10 @@ export default{
830
1355
  await runWrangler("publish");
831
1356
 
832
1357
  expect(std.out).toMatchInlineSnapshot(`
833
- "reading assets/file-1.txt...
834
- skipping - already uploaded
835
- reading assets/file-2.txt...
836
- uploading as assets/file-2.5938485188.txt...
1358
+ "Reading assets/file-1.txt...
1359
+ Skipping - already uploaded.
1360
+ Reading assets/file-2.txt...
1361
+ Uploading as assets/file-2.5938485188.txt...
837
1362
  ↗️ Done syncing assets
838
1363
  Uploaded test-name (TIMINGS)
839
1364
  Published test-name (TIMINGS)
@@ -871,8 +1396,8 @@ export default{
871
1396
  await runWrangler("publish --site-include file-1.txt");
872
1397
 
873
1398
  expect(std.out).toMatchInlineSnapshot(`
874
- "reading assets/file-1.txt...
875
- uploading as assets/file-1.2ca234f380.txt...
1399
+ "Reading assets/file-1.txt...
1400
+ Uploading as assets/file-1.2ca234f380.txt...
876
1401
  ↗️ Done syncing assets
877
1402
  Uploaded test-name (TIMINGS)
878
1403
  Published test-name (TIMINGS)
@@ -910,8 +1435,8 @@ export default{
910
1435
  await runWrangler("publish --site-exclude file-2.txt");
911
1436
 
912
1437
  expect(std.out).toMatchInlineSnapshot(`
913
- "reading assets/file-1.txt...
914
- uploading as assets/file-1.2ca234f380.txt...
1438
+ "Reading assets/file-1.txt...
1439
+ Uploading as assets/file-1.2ca234f380.txt...
915
1440
  ↗️ Done syncing assets
916
1441
  Uploaded test-name (TIMINGS)
917
1442
  Published test-name (TIMINGS)
@@ -950,8 +1475,8 @@ export default{
950
1475
  await runWrangler("publish");
951
1476
 
952
1477
  expect(std.out).toMatchInlineSnapshot(`
953
- "reading assets/file-1.txt...
954
- uploading as assets/file-1.2ca234f380.txt...
1478
+ "Reading assets/file-1.txt...
1479
+ Uploading as assets/file-1.2ca234f380.txt...
955
1480
  ↗️ Done syncing assets
956
1481
  Uploaded test-name (TIMINGS)
957
1482
  Published test-name (TIMINGS)
@@ -990,8 +1515,8 @@ export default{
990
1515
  await runWrangler("publish");
991
1516
 
992
1517
  expect(std.out).toMatchInlineSnapshot(`
993
- "reading assets/file-1.txt...
994
- uploading as assets/file-1.2ca234f380.txt...
1518
+ "Reading assets/file-1.txt...
1519
+ Uploading as assets/file-1.2ca234f380.txt...
995
1520
  ↗️ Done syncing assets
996
1521
  Uploaded test-name (TIMINGS)
997
1522
  Published test-name (TIMINGS)
@@ -1030,8 +1555,8 @@ export default{
1030
1555
  await runWrangler("publish --site-include file-1.txt");
1031
1556
 
1032
1557
  expect(std.out).toMatchInlineSnapshot(`
1033
- "reading assets/file-1.txt...
1034
- uploading as assets/file-1.2ca234f380.txt...
1558
+ "Reading assets/file-1.txt...
1559
+ Uploading as assets/file-1.2ca234f380.txt...
1035
1560
  ↗️ Done syncing assets
1036
1561
  Uploaded test-name (TIMINGS)
1037
1562
  Published test-name (TIMINGS)
@@ -1070,8 +1595,8 @@ export default{
1070
1595
  await runWrangler("publish --site-exclude file-2.txt");
1071
1596
 
1072
1597
  expect(std.out).toMatchInlineSnapshot(`
1073
- "reading assets/file-1.txt...
1074
- uploading as assets/file-1.2ca234f380.txt...
1598
+ "Reading assets/file-1.txt...
1599
+ Uploading as assets/file-1.2ca234f380.txt...
1075
1600
  ↗️ Done syncing assets
1076
1601
  Uploaded test-name (TIMINGS)
1077
1602
  Published test-name (TIMINGS)
@@ -1112,8 +1637,8 @@ export default{
1112
1637
  await runWrangler("publish");
1113
1638
 
1114
1639
  expect(std.out).toMatchInlineSnapshot(`
1115
- "reading assets/directory-1/file-1.txt...
1116
- uploading as assets/directory-1/file-1.2ca234f380.txt...
1640
+ "Reading assets/directory-1/file-1.txt...
1641
+ Uploading as assets/directory-1/file-1.2ca234f380.txt...
1117
1642
  ↗️ Done syncing assets
1118
1643
  Uploaded test-name (TIMINGS)
1119
1644
  Published test-name (TIMINGS)
@@ -1158,8 +1683,8 @@ export default{
1158
1683
  await runWrangler("publish");
1159
1684
 
1160
1685
  expect(std.out).toMatchInlineSnapshot(`
1161
- "reading assets/.well-known/file-2.txt...
1162
- uploading as assets/.well-known/file-2.5938485188.txt...
1686
+ "Reading assets/.well-known/file-2.txt...
1687
+ Uploading as assets/.well-known/file-2.5938485188.txt...
1163
1688
  ↗️ Done syncing assets
1164
1689
  Uploaded test-name (TIMINGS)
1165
1690
  Published test-name (TIMINGS)
@@ -1205,13 +1730,15 @@ export default{
1205
1730
  );
1206
1731
 
1207
1732
  expect(std.out).toMatchInlineSnapshot(`
1208
- "reading assets/large-file.txt...
1209
- uploading as assets/large-file.0ea0637a45.txt..."
1733
+ "Reading assets/large-file.txt...
1734
+ Uploading as assets/large-file.0ea0637a45.txt...
1735
+
1736
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1210
1737
  `);
1211
1738
  expect(std.err).toMatchInlineSnapshot(`
1212
- "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
1739
+ "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
1213
1740
 
1214
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1741
+ "
1215
1742
  `);
1216
1743
  });
1217
1744
 
@@ -1243,13 +1770,15 @@ export default{
1243
1770
  `"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\\","`
1244
1771
  );
1245
1772
 
1246
- expect(std.out).toMatchInlineSnapshot(
1247
- `"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..."`
1248
- );
1773
+ expect(std.out).toMatchInlineSnapshot(`
1774
+ "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...
1775
+
1776
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1777
+ `);
1249
1778
  expect(std.err).toMatchInlineSnapshot(`
1250
- "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\\",
1779
+ "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\\",
1251
1780
 
1252
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1781
+ "
1253
1782
  `);
1254
1783
  });
1255
1784
 
@@ -1295,12 +1824,12 @@ export default{
1295
1824
  await runWrangler("publish");
1296
1825
 
1297
1826
  expect(std.out).toMatchInlineSnapshot(`
1298
- "reading assets/file-1.txt...
1299
- skipping - already uploaded
1300
- reading assets/file-2.txt...
1301
- uploading as assets/file-2.5938485188.txt...
1302
- deleting assets/file-3.somehash.txt from the asset store...
1303
- deleting assets/file-4.anotherhash.txt from the asset store...
1827
+ "Reading assets/file-1.txt...
1828
+ Skipping - already uploaded.
1829
+ Reading assets/file-2.txt...
1830
+ Uploading as assets/file-2.5938485188.txt...
1831
+ Deleting assets/file-3.somehash.txt from the asset store...
1832
+ Deleting assets/file-4.anotherhash.txt from the asset store...
1304
1833
  ↗️ Done syncing assets
1305
1834
  Uploaded test-name (TIMINGS)
1306
1835
  Published test-name (TIMINGS)
@@ -1332,7 +1861,26 @@ export default{
1332
1861
  workers_dev: true,
1333
1862
  });
1334
1863
  writeWorkerSource();
1335
- mockUploadWorkerRequest();
1864
+ mockUploadWorkerRequest({ available_on_subdomain: false });
1865
+ mockSubDomainRequest();
1866
+ mockUpdateWorkerRequest({ enabled: true });
1867
+
1868
+ await runWrangler("publish ./index");
1869
+
1870
+ expect(std.out).toMatchInlineSnapshot(`
1871
+ "Uploaded test-name (TIMINGS)
1872
+ Published test-name (TIMINGS)
1873
+ test-name.test-sub-domain.workers.dev"
1874
+ `);
1875
+ expect(std.err).toMatchInlineSnapshot(`""`);
1876
+ });
1877
+
1878
+ it("should not try to enable the workers.dev domain if it has been enabled before", async () => {
1879
+ writeWranglerToml({
1880
+ workers_dev: true,
1881
+ });
1882
+ writeWorkerSource();
1883
+ mockUploadWorkerRequest({ available_on_subdomain: true });
1336
1884
  mockSubDomainRequest();
1337
1885
 
1338
1886
  await runWrangler("publish ./index");
@@ -1362,6 +1910,25 @@ export default{
1362
1910
  expect(std.err).toMatchInlineSnapshot(`""`);
1363
1911
  });
1364
1912
 
1913
+ it("should not try to disable the workers.dev domain if it is not already available", async () => {
1914
+ writeWranglerToml({
1915
+ workers_dev: false,
1916
+ });
1917
+ writeWorkerSource();
1918
+ mockSubDomainRequest("test-sub-domain", false);
1919
+ mockUploadWorkerRequest({ available_on_subdomain: false });
1920
+
1921
+ // note the lack of a mock for the subdomain disable request
1922
+
1923
+ await runWrangler("publish ./index");
1924
+
1925
+ expect(std.out).toMatchInlineSnapshot(`
1926
+ "Uploaded test-name (TIMINGS)
1927
+ No publish targets for test-name (TIMINGS)"
1928
+ `);
1929
+ expect(std.err).toMatchInlineSnapshot(`""`);
1930
+ });
1931
+
1365
1932
  it("should disable the workers.dev domain if workers_dev is undefined but overwritten to `false` in environment", async () => {
1366
1933
  writeWranglerToml({
1367
1934
  env: {
@@ -1598,233 +2165,277 @@ export default{
1598
2165
  https://dash.cloudflare.com/some-account-id/workers/onboarding"
1599
2166
  `);
1600
2167
  });
1601
- });
1602
2168
 
1603
- describe("custom builds", () => {
1604
- beforeEach(() => {
1605
- // @ts-expect-error disable the mock we'd setup earlier
1606
- // or else custom builds will timeout immediately
1607
- global.setTimeout.mockRestore();
1608
- });
1609
- it("should run a custom build before publishing", async () => {
2169
+ it("should not deploy to workers.dev if there are any routes defined", async () => {
1610
2170
  writeWranglerToml({
1611
- build: {
1612
- command: `node -e "console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')"`,
1613
- },
1614
- });
1615
-
1616
- mockUploadWorkerRequest({
1617
- expectedEntry: "return new Response(123)",
2171
+ routes: ["http://example.com/*"],
1618
2172
  });
2173
+ writeWorkerSource();
1619
2174
  mockSubDomainRequest();
1620
-
2175
+ mockUploadWorkerRequest();
2176
+ mockUpdateWorkerRequest({
2177
+ enabled: false,
2178
+ });
2179
+ mockPublishRoutesRequest({ routes: ["http://example.com/*"] });
1621
2180
  await runWrangler("publish index.js");
2181
+
1622
2182
  expect(std.out).toMatchInlineSnapshot(`
1623
- "running: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
1624
- Uploaded test-name (TIMINGS)
2183
+ "Uploaded test-name (TIMINGS)
1625
2184
  Published test-name (TIMINGS)
1626
- test-name.test-sub-domain.workers.dev"
2185
+ http://example.com/*"
1627
2186
  `);
1628
2187
  expect(std.err).toMatchInlineSnapshot(`""`);
1629
2188
  expect(std.warn).toMatchInlineSnapshot(`""`);
1630
2189
  });
1631
2190
 
1632
- if (process.platform !== "win32") {
1633
- it("should run a custom build of multiple steps combined by && before publishing", async () => {
1634
- writeWranglerToml({
1635
- build: {
1636
- command: `echo "custom build" && echo "export default { fetch(){ return new Response(123) } }" > index.js`,
2191
+ it("should not deploy to workers.dev if there are any routes defined (environments)", async () => {
2192
+ writeWranglerToml({
2193
+ routes: ["http://example.com/*"],
2194
+ env: {
2195
+ production: {
2196
+ routes: ["http://production.example.com/*"],
1637
2197
  },
1638
- });
1639
-
1640
- mockUploadWorkerRequest({
1641
- expectedEntry: "return new Response(123)",
1642
- });
1643
- mockSubDomainRequest();
1644
-
1645
- await runWrangler("publish index.js");
1646
- expect(std.out).toMatchInlineSnapshot(`
1647
- "running: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
1648
- Uploaded test-name (TIMINGS)
1649
- Published test-name (TIMINGS)
1650
- test-name.test-sub-domain.workers.dev"
1651
- `);
1652
- expect(std.err).toMatchInlineSnapshot(`""`);
1653
- expect(std.warn).toMatchInlineSnapshot(`""`);
2198
+ },
1654
2199
  });
1655
- }
2200
+ writeWorkerSource();
2201
+ mockSubDomainRequest();
2202
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2203
+ mockUpdateWorkerRequest({
2204
+ enabled: false,
2205
+ env: "production",
2206
+ legacyEnv: true,
2207
+ });
2208
+ mockPublishRoutesRequest({
2209
+ routes: ["http://production.example.com/*"],
2210
+ env: "production",
2211
+ legacyEnv: true,
2212
+ });
2213
+ await runWrangler("publish index.js --env production");
1656
2214
 
1657
- it("should throw an error if the entry doesn't exist after the build finishes", async () => {
2215
+ expect(std.out).toMatchInlineSnapshot(`
2216
+ "Uploaded test-name-production (TIMINGS)
2217
+ Published test-name-production (TIMINGS)
2218
+ http://production.example.com/*"
2219
+ `);
2220
+ expect(std.err).toMatchInlineSnapshot(`""`);
2221
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2222
+ });
2223
+
2224
+ it("should not deploy to workers.dev if there are any routes defined (only in environments)", async () => {
1658
2225
  writeWranglerToml({
1659
- main: "index.js",
1660
- build: {
1661
- command: `node -e "console.log('custom build');"`,
2226
+ env: {
2227
+ production: {
2228
+ routes: ["http://production.example.com/*"],
2229
+ },
1662
2230
  },
1663
2231
  });
2232
+ writeWorkerSource();
2233
+ mockSubDomainRequest();
2234
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2235
+ mockUpdateWorkerRequest({
2236
+ enabled: false,
2237
+ env: "production",
2238
+ legacyEnv: true,
2239
+ });
2240
+ mockPublishRoutesRequest({
2241
+ routes: ["http://production.example.com/*"],
2242
+ env: "production",
2243
+ legacyEnv: true,
2244
+ });
2245
+ await runWrangler("publish index.js --env production");
1664
2246
 
1665
- await expect(
1666
- runWrangler("publish index.js")
1667
- ).rejects.toThrowErrorMatchingInlineSnapshot(
1668
- `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
1669
- );
1670
- expect(std.out).toMatchInlineSnapshot(
1671
- `"running: node -e \\"console.log('custom build');\\""`
1672
- );
1673
- expect(std.err).toMatchInlineSnapshot(`
1674
- "Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
1675
-
1676
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2247
+ expect(std.out).toMatchInlineSnapshot(`
2248
+ "Uploaded test-name-production (TIMINGS)
2249
+ Published test-name-production (TIMINGS)
2250
+ http://production.example.com/*"
1677
2251
  `);
2252
+ expect(std.err).toMatchInlineSnapshot(`""`);
1678
2253
  expect(std.warn).toMatchInlineSnapshot(`""`);
1679
2254
  });
1680
- });
1681
2255
 
1682
- describe("[wasm_modules]", () => {
1683
- it("should be able to define wasm modules for service-worker format workers", async () => {
2256
+ it("can deploy to both workers.dev and routes if both defined ", async () => {
1684
2257
  writeWranglerToml({
1685
- wasm_modules: {
1686
- TESTWASMNAME: "./path/to/test.wasm",
1687
- },
1688
- });
1689
- writeWorkerSource({ type: "sw" });
1690
- fs.mkdirSync("./path/to", { recursive: true });
1691
- fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
1692
- mockUploadWorkerRequest({
1693
- expectedType: "sw",
1694
- expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
1695
- expectedBindings: [
1696
- { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
1697
- ],
2258
+ workers_dev: true,
2259
+ routes: ["http://example.com/*"],
1698
2260
  });
2261
+ writeWorkerSource();
1699
2262
  mockSubDomainRequest();
2263
+ mockUploadWorkerRequest();
2264
+ mockUpdateWorkerRequest({
2265
+ enabled: false,
2266
+ });
2267
+ mockPublishRoutesRequest({
2268
+ routes: ["http://example.com/*"],
2269
+ });
1700
2270
  await runWrangler("publish index.js");
2271
+
1701
2272
  expect(std.out).toMatchInlineSnapshot(`
1702
2273
  "Uploaded test-name (TIMINGS)
1703
2274
  Published test-name (TIMINGS)
1704
- test-name.test-sub-domain.workers.dev"
2275
+ test-name.test-sub-domain.workers.dev
2276
+ http://example.com/*"
1705
2277
  `);
1706
2278
  expect(std.err).toMatchInlineSnapshot(`""`);
1707
2279
  expect(std.warn).toMatchInlineSnapshot(`""`);
1708
2280
  });
1709
2281
 
1710
- it("should error when defining wasm modules for modules format workers", async () => {
2282
+ it("can deploy to both workers.dev and routes if both defined (environments: 1)", async () => {
1711
2283
  writeWranglerToml({
1712
- wasm_modules: {
1713
- TESTWASMNAME: "./path/to/test.wasm",
2284
+ workers_dev: true,
2285
+ env: {
2286
+ production: {
2287
+ routes: ["http://production.example.com/*"],
2288
+ },
1714
2289
  },
1715
2290
  });
1716
- writeWorkerSource({ type: "esm" });
1717
- fs.mkdirSync("./path/to", { recursive: true });
1718
- fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
1719
-
1720
- await expect(
1721
- runWrangler("publish index.js")
1722
- ).rejects.toThrowErrorMatchingInlineSnapshot(
1723
- `"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"`
1724
- );
1725
- expect(std.out).toMatchInlineSnapshot(`""`);
1726
- expect(std.err).toMatchInlineSnapshot(`
1727
- "You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
2291
+ writeWorkerSource();
2292
+ mockSubDomainRequest();
2293
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2294
+ mockUpdateWorkerRequest({
2295
+ enabled: false,
2296
+ env: "production",
2297
+ legacyEnv: true,
2298
+ });
2299
+ mockPublishRoutesRequest({
2300
+ routes: ["http://production.example.com/*"],
2301
+ env: "production",
2302
+ legacyEnv: true,
2303
+ });
2304
+ await runWrangler("publish index.js --env production");
1728
2305
 
1729
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2306
+ expect(std.out).toMatchInlineSnapshot(`
2307
+ "Uploaded test-name-production (TIMINGS)
2308
+ Published test-name-production (TIMINGS)
2309
+ test-name-production.test-sub-domain.workers.dev
2310
+ http://production.example.com/*"
1730
2311
  `);
2312
+ expect(std.err).toMatchInlineSnapshot(`""`);
1731
2313
  expect(std.warn).toMatchInlineSnapshot(`""`);
1732
2314
  });
1733
2315
 
1734
- it("should resolve wasm modules relative to the wrangler.toml file", async () => {
1735
- fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
1736
- fs.writeFileSync(
1737
- "./path/to/wrangler.toml",
1738
- TOML.stringify({
1739
- compatibility_date: "2022-01-12",
1740
- name: "test-name",
1741
- wasm_modules: {
1742
- TESTWASMNAME: "./and/the/path/to/test.wasm",
2316
+ it("can deploy to both workers.dev and routes if both defined (environments: 2)", async () => {
2317
+ writeWranglerToml({
2318
+ env: {
2319
+ production: {
2320
+ workers_dev: true,
2321
+ routes: ["http://production.example.com/*"],
1743
2322
  },
1744
- }),
1745
-
1746
- "utf-8"
1747
- );
1748
-
1749
- writeWorkerSource({ type: "sw" });
1750
- fs.writeFileSync(
1751
- "./path/to/and/the/path/to/test.wasm",
1752
- "SOME WASM CONTENT"
1753
- );
1754
- mockUploadWorkerRequest({
1755
- expectedType: "sw",
1756
- expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
1757
- expectedBindings: [
1758
- { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
1759
- ],
1760
- expectedCompatibilityDate: "2022-01-12",
2323
+ },
1761
2324
  });
2325
+ writeWorkerSource();
1762
2326
  mockSubDomainRequest();
1763
- await runWrangler("publish index.js --config ./path/to/wrangler.toml");
2327
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2328
+ mockUpdateWorkerRequest({
2329
+ enabled: false,
2330
+ env: "production",
2331
+ legacyEnv: true,
2332
+ });
2333
+ mockPublishRoutesRequest({
2334
+ routes: ["http://production.example.com/*"],
2335
+ env: "production",
2336
+ legacyEnv: true,
2337
+ });
2338
+ await runWrangler("publish index.js --env production");
2339
+
1764
2340
  expect(std.out).toMatchInlineSnapshot(`
1765
- "Uploaded test-name (TIMINGS)
1766
- Published test-name (TIMINGS)
1767
- test-name.test-sub-domain.workers.dev"
2341
+ "Uploaded test-name-production (TIMINGS)
2342
+ Published test-name-production (TIMINGS)
2343
+ test-name-production.test-sub-domain.workers.dev
2344
+ http://production.example.com/*"
1768
2345
  `);
1769
2346
  expect(std.err).toMatchInlineSnapshot(`""`);
1770
2347
  expect(std.warn).toMatchInlineSnapshot(`""`);
1771
2348
  });
1772
2349
 
1773
- it("should be able to import .wasm modules from service-worker format workers", async () => {
1774
- writeWranglerToml();
1775
- fs.writeFileSync("./index.js", "import TESTWASMNAME from './test.wasm';");
1776
- fs.writeFileSync("./test.wasm", "SOME WASM CONTENT");
1777
- mockUploadWorkerRequest({
1778
- expectedType: "sw",
1779
- expectedModules: {
1780
- __94b240d0d692281e6467aa42043986e5c7eea034_test_wasm:
1781
- "SOME WASM CONTENT",
2350
+ it("will deploy only to routes when workers_dev is false (environments 1) ", async () => {
2351
+ writeWranglerToml({
2352
+ workers_dev: false,
2353
+ env: {
2354
+ production: {
2355
+ routes: ["http://production.example.com/*"],
2356
+ },
1782
2357
  },
1783
- expectedBindings: [
1784
- {
1785
- name: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
1786
- part: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
1787
- type: "wasm_module",
2358
+ });
2359
+ writeWorkerSource();
2360
+ mockSubDomainRequest();
2361
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2362
+ mockUpdateWorkerRequest({
2363
+ enabled: false,
2364
+ env: "production",
2365
+ legacyEnv: true,
2366
+ });
2367
+ mockPublishRoutesRequest({
2368
+ routes: ["http://production.example.com/*"],
2369
+ env: "production",
2370
+ legacyEnv: true,
2371
+ });
2372
+ await runWrangler("publish index.js --env production");
2373
+
2374
+ expect(std.out).toMatchInlineSnapshot(`
2375
+ "Uploaded test-name-production (TIMINGS)
2376
+ Published test-name-production (TIMINGS)
2377
+ http://production.example.com/*"
2378
+ `);
2379
+ expect(std.err).toMatchInlineSnapshot(`""`);
2380
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2381
+ });
2382
+
2383
+ it("will deploy only to routes when workers_dev is false (environments 2) ", async () => {
2384
+ writeWranglerToml({
2385
+ env: {
2386
+ production: {
2387
+ workers_dev: false,
2388
+ routes: ["http://production.example.com/*"],
1788
2389
  },
1789
- ],
2390
+ },
1790
2391
  });
2392
+ writeWorkerSource();
1791
2393
  mockSubDomainRequest();
1792
- await runWrangler("publish index.js");
2394
+ mockUploadWorkerRequest({ env: "production", legacyEnv: true });
2395
+ mockUpdateWorkerRequest({
2396
+ enabled: false,
2397
+ env: "production",
2398
+ legacyEnv: true,
2399
+ });
2400
+ mockPublishRoutesRequest({
2401
+ routes: ["http://production.example.com/*"],
2402
+ env: "production",
2403
+ legacyEnv: true,
2404
+ });
2405
+ await runWrangler("publish index.js --env production");
2406
+
1793
2407
  expect(std.out).toMatchInlineSnapshot(`
1794
- "Uploaded test-name (TIMINGS)
1795
- Published test-name (TIMINGS)
1796
- test-name.test-sub-domain.workers.dev"
2408
+ "Uploaded test-name-production (TIMINGS)
2409
+ Published test-name-production (TIMINGS)
2410
+ http://production.example.com/*"
1797
2411
  `);
1798
2412
  expect(std.err).toMatchInlineSnapshot(`""`);
1799
2413
  expect(std.warn).toMatchInlineSnapshot(`""`);
1800
2414
  });
1801
2415
  });
1802
2416
 
1803
- describe("[text_blobs]", () => {
1804
- it("should be able to define text blobs for service-worker format workers", async () => {
2417
+ describe("custom builds", () => {
2418
+ beforeEach(() => {
2419
+ // @ts-expect-error disable the mock we'd setup earlier
2420
+ // or else custom builds will timeout immediately
2421
+ global.setTimeout.mockRestore();
2422
+ });
2423
+ it("should run a custom build before publishing", async () => {
1805
2424
  writeWranglerToml({
1806
- text_blobs: {
1807
- TESTTEXTBLOBNAME: "./path/to/text.file",
2425
+ build: {
2426
+ command: `node -e "console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')"`,
1808
2427
  },
1809
2428
  });
1810
- writeWorkerSource({ type: "sw" });
1811
- fs.mkdirSync("./path/to", { recursive: true });
1812
- fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
2429
+
1813
2430
  mockUploadWorkerRequest({
1814
- expectedType: "sw",
1815
- expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
1816
- expectedBindings: [
1817
- {
1818
- name: "TESTTEXTBLOBNAME",
1819
- part: "TESTTEXTBLOBNAME",
1820
- type: "text_blob",
1821
- },
1822
- ],
2431
+ expectedEntry: "return new Response(123)",
1823
2432
  });
1824
2433
  mockSubDomainRequest();
2434
+
1825
2435
  await runWrangler("publish index.js");
1826
2436
  expect(std.out).toMatchInlineSnapshot(`
1827
- "Uploaded test-name (TIMINGS)
2437
+ "Running custom build: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
2438
+ Uploaded test-name (TIMINGS)
1828
2439
  Published test-name (TIMINGS)
1829
2440
  test-name.test-sub-domain.workers.dev"
1830
2441
  `);
@@ -1832,121 +2443,138 @@ export default{
1832
2443
  expect(std.warn).toMatchInlineSnapshot(`""`);
1833
2444
  });
1834
2445
 
1835
- it("should error when defining text blobs for modules format workers", async () => {
2446
+ if (process.platform !== "win32") {
2447
+ it("should run a custom build of multiple steps combined by && before publishing", async () => {
2448
+ writeWranglerToml({
2449
+ build: {
2450
+ command: `echo "custom build" && echo "export default { fetch(){ return new Response(123) } }" > index.js`,
2451
+ },
2452
+ });
2453
+
2454
+ mockUploadWorkerRequest({
2455
+ expectedEntry: "return new Response(123)",
2456
+ });
2457
+ mockSubDomainRequest();
2458
+
2459
+ await runWrangler("publish index.js");
2460
+ expect(std.out).toMatchInlineSnapshot(`
2461
+ "Running custom build: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
2462
+ Uploaded test-name (TIMINGS)
2463
+ Published test-name (TIMINGS)
2464
+ test-name.test-sub-domain.workers.dev"
2465
+ `);
2466
+ expect(std.err).toMatchInlineSnapshot(`""`);
2467
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2468
+ });
2469
+ }
2470
+
2471
+ it("should throw an error if the entry doesn't exist after the build finishes", async () => {
1836
2472
  writeWranglerToml({
1837
- text_blobs: {
1838
- TESTTEXTBLOBNAME: "./path/to/text.file",
2473
+ main: "index.js",
2474
+ build: {
2475
+ command: `node -e "console.log('custom build');"`,
1839
2476
  },
1840
2477
  });
1841
- writeWorkerSource({ type: "esm" });
1842
- fs.mkdirSync("./path/to", { recursive: true });
1843
- fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
1844
2478
 
1845
2479
  await expect(
1846
2480
  runWrangler("publish index.js")
1847
2481
  ).rejects.toThrowErrorMatchingInlineSnapshot(
1848
- `"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"`
2482
+ `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
1849
2483
  );
1850
- expect(std.out).toMatchInlineSnapshot(`""`);
2484
+ expect(std.out).toMatchInlineSnapshot(`
2485
+ "Running custom build: node -e \\"console.log('custom build');\\"
2486
+
2487
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2488
+ `);
1851
2489
  expect(std.err).toMatchInlineSnapshot(`
1852
- "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
2490
+ "X [ERROR] Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
1853
2491
 
1854
- %s If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2492
+ "
1855
2493
  `);
1856
2494
  expect(std.warn).toMatchInlineSnapshot(`""`);
1857
2495
  });
1858
2496
 
1859
- it("should resolve text blobs relative to the wrangler.toml file", async () => {
1860
- fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
2497
+ it("should minify the script when `--minify` is true (sw)", async () => {
2498
+ writeWranglerToml({
2499
+ main: "./index.js",
2500
+ });
1861
2501
  fs.writeFileSync(
1862
- "./path/to/wrangler.toml",
1863
- TOML.stringify({
1864
- compatibility_date: "2022-01-12",
1865
- name: "test-name",
1866
- text_blobs: {
1867
- TESTTEXTBLOBNAME: "./and/the/path/to/text.file",
1868
- },
1869
- }),
1870
-
1871
- "utf-8"
2502
+ "./index.js",
2503
+ `export
2504
+ default {
2505
+ fetch() {
2506
+ return new Response( "hello Cpt Picard" )
2507
+ }
2508
+ }
2509
+ `
1872
2510
  );
1873
2511
 
1874
- writeWorkerSource({ type: "sw" });
1875
- fs.writeFileSync(
1876
- "./path/to/and/the/path/to/text.file",
1877
- "SOME TEXT CONTENT"
1878
- );
1879
2512
  mockUploadWorkerRequest({
1880
- expectedType: "sw",
1881
- expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
1882
- expectedBindings: [
1883
- {
1884
- name: "TESTTEXTBLOBNAME",
1885
- part: "TESTTEXTBLOBNAME",
1886
- type: "text_blob",
1887
- },
1888
- ],
1889
- expectedCompatibilityDate: "2022-01-12",
2513
+ expectedEntry: 'fetch(){return new Response("hello Cpt Picard")',
1890
2514
  });
2515
+
1891
2516
  mockSubDomainRequest();
1892
- await runWrangler("publish index.js --config ./path/to/wrangler.toml");
2517
+ await runWrangler("publish index.js --minify");
1893
2518
  expect(std.out).toMatchInlineSnapshot(`
1894
2519
  "Uploaded test-name (TIMINGS)
1895
2520
  Published test-name (TIMINGS)
1896
2521
  test-name.test-sub-domain.workers.dev"
1897
2522
  `);
1898
2523
  expect(std.err).toMatchInlineSnapshot(`""`);
1899
- expect(std.warn).toMatchInlineSnapshot(`""`);
1900
2524
  });
1901
- });
1902
2525
 
1903
- describe("vars bindings", () => {
1904
- it("should support json bindings", async () => {
2526
+ it("should minify the script when `minify` in config is true (esm)", async () => {
1905
2527
  writeWranglerToml({
1906
- vars: {
1907
- text: "plain ol' string",
1908
- count: 1,
1909
- complex: { enabled: true, id: 123 },
2528
+ main: "./index.js",
2529
+ legacy_env: false,
2530
+ env: {
2531
+ testEnv: {
2532
+ minify: true,
2533
+ },
1910
2534
  },
1911
2535
  });
1912
- writeWorkerSource();
1913
- mockSubDomainRequest();
2536
+ fs.writeFileSync(
2537
+ "./index.js",
2538
+ `export
2539
+ default {
2540
+ fetch() {
2541
+ return new Response( "hello Cpt Picard" )
2542
+ }
2543
+ }
2544
+ `
2545
+ );
2546
+
1914
2547
  mockUploadWorkerRequest({
1915
- expectedBindings: [
1916
- { name: "text", type: "plain_text", text: "plain ol' string" },
1917
- { name: "count", type: "json", json: 1 },
1918
- {
1919
- name: "complex",
1920
- type: "json",
1921
- json: { enabled: true, id: 123 },
1922
- },
1923
- ],
2548
+ env: "testEnv",
2549
+ expectedType: "esm",
2550
+ legacyEnv: false,
2551
+ expectedEntry: `fetch(){return new Response("hello Cpt Picard")`,
1924
2552
  });
1925
2553
 
1926
- await runWrangler("publish index.js");
2554
+ mockSubDomainRequest();
2555
+ await runWrangler("publish -e testEnv index.js");
1927
2556
  expect(std.out).toMatchInlineSnapshot(`
1928
- "Uploaded test-name (TIMINGS)
1929
- Published test-name (TIMINGS)
1930
- test-name.test-sub-domain.workers.dev"
2557
+ "Uploaded test-name (testEnv) (TIMINGS)
2558
+ Published test-name (testEnv) (TIMINGS)
2559
+ testEnv.test-name.test-sub-domain.workers.dev"
1931
2560
  `);
1932
2561
  expect(std.err).toMatchInlineSnapshot(`""`);
1933
- expect(std.warn).toMatchInlineSnapshot(`""`);
1934
2562
  });
1935
2563
  });
1936
2564
 
1937
- describe("r2 bucket bindings", () => {
1938
- it("should support r2 bucket bindings", async () => {
2565
+ describe("durable object migrations", () => {
2566
+ it("should warn when you try to publish durable objects without migrations", async () => {
1939
2567
  writeWranglerToml({
1940
- r2_buckets: [{ binding: "FOO", bucket_name: "foo-bucket" }],
2568
+ durable_objects: {
2569
+ bindings: [{ name: "SOMENAME", class_name: "SomeClass" }],
2570
+ },
1941
2571
  });
1942
- writeWorkerSource();
2572
+ fs.writeFileSync(
2573
+ "index.js",
2574
+ `export class SomeClass{}; export default {};`
2575
+ );
1943
2576
  mockSubDomainRequest();
1944
- mockUploadWorkerRequest({
1945
- expectedBindings: [
1946
- { bucket_name: "foo-bucket", name: "FOO", type: "r2_bucket" },
1947
- ],
1948
- });
1949
-
2577
+ mockUploadWorkerRequest();
1950
2578
  await runWrangler("publish index.js");
1951
2579
  expect(std.out).toMatchInlineSnapshot(`
1952
2580
  "Uploaded test-name (TIMINGS)
@@ -1954,31 +2582,31 @@ export default{
1954
2582
  test-name.test-sub-domain.workers.dev"
1955
2583
  `);
1956
2584
  expect(std.err).toMatchInlineSnapshot(`""`);
1957
- expect(std.warn).toMatchInlineSnapshot(`""`);
2585
+ expect(std.warn).toMatchInlineSnapshot(`
2586
+ "▲ [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.
2587
+
2588
+ "
2589
+ `);
1958
2590
  });
1959
- });
1960
2591
 
1961
- describe("durable object bindings", () => {
1962
- it("should support durable object bindings", async () => {
2592
+ it("does not warn if all the durable object bindings are to external classes", async () => {
1963
2593
  writeWranglerToml({
1964
2594
  durable_objects: {
1965
2595
  bindings: [
1966
- { name: "EXAMPLE_DO_BINDING", class_name: "ExampleDurableObject" },
2596
+ {
2597
+ name: "SOMENAME",
2598
+ class_name: "SomeClass",
2599
+ script_name: "some-script",
2600
+ },
1967
2601
  ],
1968
2602
  },
1969
2603
  });
1970
- writeWorkerSource({ type: "esm" });
2604
+ fs.writeFileSync(
2605
+ "index.js",
2606
+ `export class SomeClass{}; export default {};`
2607
+ );
1971
2608
  mockSubDomainRequest();
1972
- mockUploadWorkerRequest({
1973
- expectedBindings: [
1974
- {
1975
- class_name: "ExampleDurableObject",
1976
- name: "EXAMPLE_DO_BINDING",
1977
- type: "durable_object_namespace",
1978
- },
1979
- ],
1980
- });
1981
-
2609
+ mockUploadWorkerRequest();
1982
2610
  await runWrangler("publish index.js");
1983
2611
  expect(std.out).toMatchInlineSnapshot(`
1984
2612
  "Uploaded test-name (TIMINGS)
@@ -1989,30 +2617,33 @@ export default{
1989
2617
  expect(std.warn).toMatchInlineSnapshot(`""`);
1990
2618
  });
1991
2619
 
1992
- it("should support service-workers binding to external durable objects", async () => {
2620
+ it("should publish all migrations on first publish", async () => {
1993
2621
  writeWranglerToml({
1994
2622
  durable_objects: {
1995
2623
  bindings: [
1996
- {
1997
- name: "EXAMPLE_DO_BINDING",
1998
- class_name: "ExampleDurableObject",
1999
- script_name: "example-do-binding-worker",
2000
- },
2624
+ { name: "SOMENAME", class_name: "SomeClass" },
2625
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2001
2626
  ],
2002
2627
  },
2628
+ migrations: [
2629
+ { tag: "v1", new_classes: ["SomeClass"] },
2630
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2631
+ ],
2003
2632
  });
2004
- writeWorkerSource({ type: "sw" });
2633
+ fs.writeFileSync(
2634
+ "index.js",
2635
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2636
+ );
2005
2637
  mockSubDomainRequest();
2638
+ mockLegacyScriptData({ scripts: [] }); // no previously uploaded scripts at all
2006
2639
  mockUploadWorkerRequest({
2007
- expectedType: "sw",
2008
- expectedBindings: [
2009
- {
2010
- name: "EXAMPLE_DO_BINDING",
2011
- class_name: "ExampleDurableObject",
2012
- script_name: "example-do-binding-worker",
2013
- type: "durable_object_namespace",
2014
- },
2015
- ],
2640
+ expectedMigrations: {
2641
+ new_tag: "v2",
2642
+ steps: [
2643
+ { new_classes: ["SomeClass"] },
2644
+ { new_classes: ["SomeOtherClass"] },
2645
+ ],
2646
+ },
2016
2647
  });
2017
2648
 
2018
2649
  await runWrangler("publish index.js");
@@ -2025,141 +2656,1436 @@ export default{
2025
2656
  expect(std.warn).toMatchInlineSnapshot(`""`);
2026
2657
  });
2027
2658
 
2028
- it("should support module workers implementing durable objects", async () => {
2659
+ it("should upload migrations past a previously uploaded tag", async () => {
2029
2660
  writeWranglerToml({
2030
2661
  durable_objects: {
2031
2662
  bindings: [
2032
- {
2033
- name: "EXAMPLE_DO_BINDING",
2034
- class_name: "ExampleDurableObject",
2035
- },
2663
+ { name: "SOMENAME", class_name: "SomeClass" },
2664
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2036
2665
  ],
2037
2666
  },
2667
+ migrations: [
2668
+ { tag: "v1", new_classes: ["SomeClass"] },
2669
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2670
+ ],
2038
2671
  });
2039
- writeWorkerSource({ type: "esm" });
2672
+ fs.writeFileSync(
2673
+ "index.js",
2674
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2675
+ );
2040
2676
  mockSubDomainRequest();
2677
+ mockLegacyScriptData({
2678
+ scripts: [{ id: "test-name", migration_tag: "v1" }],
2679
+ });
2041
2680
  mockUploadWorkerRequest({
2042
- expectedType: "esm",
2043
- expectedBindings: [
2044
- {
2045
- name: "EXAMPLE_DO_BINDING",
2046
- class_name: "ExampleDurableObject",
2047
- type: "durable_object_namespace",
2048
- },
2049
- ],
2681
+ expectedMigrations: {
2682
+ old_tag: "v1",
2683
+ new_tag: "v2",
2684
+ steps: [
2685
+ {
2686
+ new_classes: ["SomeOtherClass"],
2687
+ },
2688
+ ],
2689
+ },
2050
2690
  });
2051
2691
 
2052
2692
  await runWrangler("publish index.js");
2053
- expect(std.out).toMatchInlineSnapshot(`
2054
- "Uploaded test-name (TIMINGS)
2693
+ expect(std).toMatchInlineSnapshot(`
2694
+ Object {
2695
+ "debug": "",
2696
+ "err": "",
2697
+ "out": "Uploaded test-name (TIMINGS)
2055
2698
  Published test-name (TIMINGS)
2056
- test-name.test-sub-domain.workers.dev"
2699
+ test-name.test-sub-domain.workers.dev",
2700
+ "warn": "",
2701
+ }
2057
2702
  `);
2058
- expect(std.err).toMatchInlineSnapshot(`""`);
2059
- expect(std.warn).toMatchInlineSnapshot(`""`);
2060
2703
  });
2061
2704
 
2062
- it("should error when detecting service workers implementing durable objects", async () => {
2705
+ it("should not send migrations if they've all already been sent", async () => {
2063
2706
  writeWranglerToml({
2064
2707
  durable_objects: {
2065
2708
  bindings: [
2066
- {
2067
- name: "EXAMPLE_DO_BINDING",
2068
- class_name: "ExampleDurableObject",
2069
- },
2709
+ { name: "SOMENAME", class_name: "SomeClass" },
2710
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2070
2711
  ],
2071
2712
  },
2713
+ migrations: [
2714
+ { tag: "v1", new_classes: ["SomeClass"] },
2715
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2716
+ { tag: "v3", new_classes: ["YetAnotherClass"] },
2717
+ ],
2718
+ });
2719
+ fs.writeFileSync(
2720
+ "index.js",
2721
+ `export class SomeClass{}; export class SomeOtherClass{}; export class YetAnotherClass{}; export default {};`
2722
+ );
2723
+ mockSubDomainRequest();
2724
+ mockLegacyScriptData({
2725
+ scripts: [{ id: "test-name", migration_tag: "v3" }],
2726
+ });
2727
+ mockUploadWorkerRequest({
2728
+ expectedMigrations: undefined,
2729
+ });
2730
+
2731
+ await runWrangler("publish index.js");
2732
+ expect(std).toMatchInlineSnapshot(`
2733
+ Object {
2734
+ "debug": "",
2735
+ "err": "",
2736
+ "out": "Uploaded test-name (TIMINGS)
2737
+ Published test-name (TIMINGS)
2738
+ test-name.test-sub-domain.workers.dev",
2739
+ "warn": "",
2740
+ }
2741
+ `);
2742
+ });
2743
+
2744
+ describe("service environments", () => {
2745
+ it("should publish all migrations on first publish", async () => {
2746
+ writeWranglerToml({
2747
+ durable_objects: {
2748
+ bindings: [
2749
+ { name: "SOMENAME", class_name: "SomeClass" },
2750
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2751
+ ],
2752
+ },
2753
+ migrations: [
2754
+ { tag: "v1", new_classes: ["SomeClass"] },
2755
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2756
+ ],
2757
+ });
2758
+ fs.writeFileSync(
2759
+ "index.js",
2760
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2761
+ );
2762
+ mockSubDomainRequest();
2763
+ mockServiceScriptData({}); // no scripts at all
2764
+ mockUploadWorkerRequest({
2765
+ legacyEnv: false,
2766
+ expectedMigrations: {
2767
+ new_tag: "v2",
2768
+ steps: [
2769
+ { new_classes: ["SomeClass"] },
2770
+ { new_classes: ["SomeOtherClass"] },
2771
+ ],
2772
+ },
2773
+ });
2774
+
2775
+ await runWrangler("publish index.js --legacy-env false");
2776
+ expect(std.out).toMatchInlineSnapshot(`
2777
+ "Uploaded test-name (TIMINGS)
2778
+ Published test-name (TIMINGS)
2779
+ test-name.test-sub-domain.workers.dev"
2780
+ `);
2781
+ expect(std.err).toMatchInlineSnapshot(`""`);
2782
+ expect(std.warn).toMatchInlineSnapshot(`
2783
+ "▲ [WARNING] Processing wrangler.toml configuration:
2784
+
2785
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
2786
+ the future. DO NOT USE IN PRODUCTION.
2787
+
2788
+ "
2789
+ `);
2790
+ });
2791
+
2792
+ it("should publish all migrations on first publish (--env)", async () => {
2793
+ writeWranglerToml({
2794
+ durable_objects: {
2795
+ bindings: [
2796
+ { name: "SOMENAME", class_name: "SomeClass" },
2797
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2798
+ ],
2799
+ },
2800
+ env: {
2801
+ xyz: {
2802
+ durable_objects: {
2803
+ bindings: [
2804
+ { name: "SOMENAME", class_name: "SomeClass" },
2805
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2806
+ ],
2807
+ },
2808
+ },
2809
+ },
2810
+ migrations: [
2811
+ { tag: "v1", new_classes: ["SomeClass"] },
2812
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2813
+ ],
2814
+ });
2815
+ fs.writeFileSync(
2816
+ "index.js",
2817
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2818
+ );
2819
+ mockSubDomainRequest();
2820
+ mockServiceScriptData({ env: "xyz" }); // no scripts at all
2821
+ mockUploadWorkerRequest({
2822
+ legacyEnv: false,
2823
+ env: "xyz",
2824
+ expectedMigrations: {
2825
+ new_tag: "v2",
2826
+ steps: [
2827
+ { new_classes: ["SomeClass"] },
2828
+ { new_classes: ["SomeOtherClass"] },
2829
+ ],
2830
+ },
2831
+ });
2832
+
2833
+ await runWrangler("publish index.js --legacy-env false --env xyz");
2834
+ expect(std.out).toMatchInlineSnapshot(`
2835
+ "Uploaded test-name (xyz) (TIMINGS)
2836
+ Published test-name (xyz) (TIMINGS)
2837
+ xyz.test-name.test-sub-domain.workers.dev"
2838
+ `);
2839
+ expect(std.err).toMatchInlineSnapshot(`""`);
2840
+ expect(std.warn).toMatchInlineSnapshot(`
2841
+ "▲ [WARNING] Processing wrangler.toml configuration:
2842
+
2843
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
2844
+ the future. DO NOT USE IN PRODUCTION.
2845
+
2846
+ "
2847
+ `);
2848
+ });
2849
+
2850
+ it("should use a script's current migration tag when publishing migrations", async () => {
2851
+ writeWranglerToml({
2852
+ durable_objects: {
2853
+ bindings: [
2854
+ { name: "SOMENAME", class_name: "SomeClass" },
2855
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2856
+ ],
2857
+ },
2858
+ migrations: [
2859
+ { tag: "v1", new_classes: ["SomeClass"] },
2860
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2861
+ ],
2862
+ });
2863
+ fs.writeFileSync(
2864
+ "index.js",
2865
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2866
+ );
2867
+ mockSubDomainRequest();
2868
+ mockServiceScriptData({
2869
+ script: { id: "test-name", migration_tag: "v1" },
2870
+ });
2871
+ mockUploadWorkerRequest({
2872
+ legacyEnv: false,
2873
+ expectedMigrations: {
2874
+ old_tag: "v1",
2875
+ new_tag: "v2",
2876
+ steps: [
2877
+ {
2878
+ new_classes: ["SomeOtherClass"],
2879
+ },
2880
+ ],
2881
+ },
2882
+ });
2883
+
2884
+ await runWrangler("publish index.js --legacy-env false");
2885
+ expect(std).toMatchInlineSnapshot(`
2886
+ Object {
2887
+ "debug": "",
2888
+ "err": "",
2889
+ "out": "Uploaded test-name (TIMINGS)
2890
+ Published test-name (TIMINGS)
2891
+ test-name.test-sub-domain.workers.dev",
2892
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
2893
+
2894
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
2895
+ the future. DO NOT USE IN PRODUCTION.
2896
+
2897
+ ",
2898
+ }
2899
+ `);
2900
+ });
2901
+
2902
+ it("should use an environment's current migration tag when publishing migrations", async () => {
2903
+ writeWranglerToml({
2904
+ durable_objects: {
2905
+ bindings: [
2906
+ { name: "SOMENAME", class_name: "SomeClass" },
2907
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2908
+ ],
2909
+ },
2910
+ env: {
2911
+ xyz: {
2912
+ durable_objects: {
2913
+ bindings: [
2914
+ { name: "SOMENAME", class_name: "SomeClass" },
2915
+ { name: "SOMEOTHERNAME", class_name: "SomeOtherClass" },
2916
+ ],
2917
+ },
2918
+ },
2919
+ },
2920
+ migrations: [
2921
+ { tag: "v1", new_classes: ["SomeClass"] },
2922
+ { tag: "v2", new_classes: ["SomeOtherClass"] },
2923
+ ],
2924
+ });
2925
+ fs.writeFileSync(
2926
+ "index.js",
2927
+ `export class SomeClass{}; export class SomeOtherClass{}; export default {};`
2928
+ );
2929
+ mockSubDomainRequest();
2930
+ mockServiceScriptData({
2931
+ script: { id: "test-name", migration_tag: "v1" },
2932
+ env: "xyz",
2933
+ });
2934
+ mockUploadWorkerRequest({
2935
+ legacyEnv: false,
2936
+ env: "xyz",
2937
+ expectedMigrations: {
2938
+ old_tag: "v1",
2939
+ new_tag: "v2",
2940
+ steps: [
2941
+ {
2942
+ new_classes: ["SomeOtherClass"],
2943
+ },
2944
+ ],
2945
+ },
2946
+ });
2947
+
2948
+ await runWrangler("publish index.js --legacy-env false --env xyz");
2949
+ expect(std).toMatchInlineSnapshot(`
2950
+ Object {
2951
+ "debug": "",
2952
+ "err": "",
2953
+ "out": "Uploaded test-name (xyz) (TIMINGS)
2954
+ Published test-name (xyz) (TIMINGS)
2955
+ xyz.test-name.test-sub-domain.workers.dev",
2956
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
2957
+
2958
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in
2959
+ the future. DO NOT USE IN PRODUCTION.
2960
+
2961
+ ",
2962
+ }
2963
+ `);
2964
+ });
2965
+ });
2966
+ });
2967
+
2968
+ describe("bindings", () => {
2969
+ it("should allow bindings with different names", async () => {
2970
+ writeWranglerToml({
2971
+ migrations: [
2972
+ {
2973
+ tag: "v1",
2974
+ new_classes: ["SomeDurableObject", "AnotherDurableObject"],
2975
+ },
2976
+ ],
2977
+ durable_objects: {
2978
+ bindings: [
2979
+ {
2980
+ name: "DURABLE_OBJECT_ONE",
2981
+ class_name: "SomeDurableObject",
2982
+ script_name: "some-durable-object-worker",
2983
+ },
2984
+ {
2985
+ name: "DURABLE_OBJECT_TWO",
2986
+ class_name: "AnotherDurableObject",
2987
+ script_name: "another-durable-object-worker",
2988
+ },
2989
+ ],
2990
+ },
2991
+ kv_namespaces: [
2992
+ { binding: "KV_NAMESPACE_ONE", id: "kv-ns-one-id" },
2993
+ { binding: "KV_NAMESPACE_TWO", id: "kv-ns-two-id" },
2994
+ ],
2995
+ r2_buckets: [
2996
+ { binding: "R2_BUCKET_ONE", bucket_name: "r2-bucket-one-name" },
2997
+ { binding: "R2_BUCKET_TWO", bucket_name: "r2-bucket-two-name" },
2998
+ ],
2999
+ text_blobs: {
3000
+ TEXT_BLOB_ONE: "./my-entire-app-depends-on-this.cfg",
3001
+ TEXT_BLOB_TWO: "./the-entirety-of-human-knowledge.txt",
3002
+ },
3003
+ unsafe: {
3004
+ bindings: [
3005
+ {
3006
+ name: "UNSAFE_BINDING_ONE",
3007
+ type: "some unsafe thing",
3008
+ data: { some: { unsafe: "thing" } },
3009
+ },
3010
+ {
3011
+ name: "UNSAFE_BINDING_TWO",
3012
+ type: "another unsafe thing",
3013
+ data: 1337,
3014
+ },
3015
+ ],
3016
+ },
3017
+ vars: {
3018
+ ENV_VAR_ONE: 123,
3019
+ ENV_VAR_TWO: "Hello, I'm an environment variable",
3020
+ },
3021
+ wasm_modules: {
3022
+ WASM_MODULE_ONE: "./some_wasm.wasm",
3023
+ WASM_MODULE_TWO: "./more_wasm.wasm",
3024
+ },
3025
+ data_blobs: {
3026
+ DATA_BLOB_ONE: "./some-data-blob.bin",
3027
+ DATA_BLOB_TWO: "./more-data-blob.bin",
3028
+ },
3029
+ });
3030
+
3031
+ writeWorkerSource({ type: "sw" });
3032
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
3033
+ fs.writeFileSync(
3034
+ "./the-entirety-of-human-knowledge.txt",
3035
+ "Everything's bigger in Texas"
3036
+ );
3037
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
3038
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
3039
+
3040
+ fs.writeFileSync("./some-data-blob.bin", "some data");
3041
+ fs.writeFileSync("./more-data-blob.bin", "more data");
3042
+
3043
+ mockUploadWorkerRequest({
3044
+ expectedType: "sw",
3045
+ expectedBindings: [
3046
+ {
3047
+ name: "KV_NAMESPACE_ONE",
3048
+ namespace_id: "kv-ns-one-id",
3049
+ type: "kv_namespace",
3050
+ },
3051
+ {
3052
+ name: "KV_NAMESPACE_TWO",
3053
+ namespace_id: "kv-ns-two-id",
3054
+ type: "kv_namespace",
3055
+ },
3056
+ {
3057
+ class_name: "SomeDurableObject",
3058
+ name: "DURABLE_OBJECT_ONE",
3059
+ script_name: "some-durable-object-worker",
3060
+ type: "durable_object_namespace",
3061
+ },
3062
+ {
3063
+ class_name: "AnotherDurableObject",
3064
+ name: "DURABLE_OBJECT_TWO",
3065
+ script_name: "another-durable-object-worker",
3066
+ type: "durable_object_namespace",
3067
+ },
3068
+ {
3069
+ bucket_name: "r2-bucket-one-name",
3070
+ name: "R2_BUCKET_ONE",
3071
+ type: "r2_bucket",
3072
+ },
3073
+ {
3074
+ bucket_name: "r2-bucket-two-name",
3075
+ name: "R2_BUCKET_TWO",
3076
+ type: "r2_bucket",
3077
+ },
3078
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
3079
+ {
3080
+ name: "ENV_VAR_TWO",
3081
+ text: "Hello, I'm an environment variable",
3082
+ type: "plain_text",
3083
+ },
3084
+ {
3085
+ name: "WASM_MODULE_ONE",
3086
+ part: "WASM_MODULE_ONE",
3087
+ type: "wasm_module",
3088
+ },
3089
+ {
3090
+ name: "WASM_MODULE_TWO",
3091
+ part: "WASM_MODULE_TWO",
3092
+ type: "wasm_module",
3093
+ },
3094
+ { name: "TEXT_BLOB_ONE", part: "TEXT_BLOB_ONE", type: "text_blob" },
3095
+ { name: "TEXT_BLOB_TWO", part: "TEXT_BLOB_TWO", type: "text_blob" },
3096
+ { name: "DATA_BLOB_ONE", part: "DATA_BLOB_ONE", type: "data_blob" },
3097
+ { name: "DATA_BLOB_TWO", part: "DATA_BLOB_TWO", type: "data_blob" },
3098
+ {
3099
+ data: { some: { unsafe: "thing" } },
3100
+ name: "UNSAFE_BINDING_ONE",
3101
+ type: "some unsafe thing",
3102
+ },
3103
+ {
3104
+ data: 1337,
3105
+ name: "UNSAFE_BINDING_TWO",
3106
+ type: "another unsafe thing",
3107
+ },
3108
+ ],
3109
+ });
3110
+ mockSubDomainRequest();
3111
+ mockLegacyScriptData({ scripts: [] });
3112
+
3113
+ await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
3114
+ expect(std.out).toMatchInlineSnapshot(`
3115
+ "Uploaded test-name (TIMINGS)
3116
+ Published test-name (TIMINGS)
3117
+ test-name.test-sub-domain.workers.dev"
3118
+ `);
3119
+ expect(std.err).toMatchInlineSnapshot(`""`);
3120
+ expect(std.warn).toMatchInlineSnapshot(`
3121
+ "▲ [WARNING] Processing wrangler.toml configuration:
3122
+
3123
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3124
+
3125
+ "
3126
+ `);
3127
+ });
3128
+
3129
+ it("should error when bindings of different types have the same name", async () => {
3130
+ writeWranglerToml({
3131
+ durable_objects: {
3132
+ bindings: [
3133
+ {
3134
+ name: "CONFLICTING_NAME_ONE",
3135
+ class_name: "SomeDurableObject",
3136
+ script_name: "some-durable-object-worker",
3137
+ },
3138
+ {
3139
+ name: "CONFLICTING_NAME_TWO",
3140
+ class_name: "AnotherDurableObject",
3141
+ script_name: "another-durable-object-worker",
3142
+ },
3143
+ ],
3144
+ },
3145
+ kv_namespaces: [
3146
+ { binding: "CONFLICTING_NAME_ONE", id: "kv-ns-one-id" },
3147
+ { binding: "CONFLICTING_NAME_TWO", id: "kv-ns-two-id" },
3148
+ ],
3149
+ r2_buckets: [
3150
+ {
3151
+ binding: "CONFLICTING_NAME_ONE",
3152
+ bucket_name: "r2-bucket-one-name",
3153
+ },
3154
+ {
3155
+ binding: "CONFLICTING_NAME_THREE",
3156
+ bucket_name: "r2-bucket-two-name",
3157
+ },
3158
+ ],
3159
+ text_blobs: {
3160
+ CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
3161
+ CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
3162
+ },
3163
+ unsafe: {
3164
+ bindings: [
3165
+ {
3166
+ name: "CONFLICTING_NAME_THREE",
3167
+ type: "some unsafe thing",
3168
+ data: { some: { unsafe: "thing" } },
3169
+ },
3170
+ {
3171
+ name: "CONFLICTING_NAME_FOUR",
3172
+ type: "another unsafe thing",
3173
+ data: 1337,
3174
+ },
3175
+ ],
3176
+ },
3177
+ vars: {
3178
+ ENV_VAR_ONE: 123,
3179
+ CONFLICTING_NAME_THREE: "Hello, I'm an environment variable",
3180
+ },
3181
+ wasm_modules: {
3182
+ WASM_MODULE_ONE: "./some_wasm.wasm",
3183
+ CONFLICTING_NAME_THREE: "./more_wasm.wasm",
3184
+ },
3185
+ data_blobs: {
3186
+ DATA_BLOB_ONE: "./some_data.bin",
3187
+ CONFLICTING_NAME_THREE: "./more_data.bin",
3188
+ },
3189
+ });
3190
+
3191
+ writeWorkerSource({ type: "sw" });
3192
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
3193
+ fs.writeFileSync(
3194
+ "./the-entirety-of-human-knowledge.txt",
3195
+ "Everything's bigger in Texas"
3196
+ );
3197
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
3198
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
3199
+
3200
+ await expect(runWrangler("publish index.js")).rejects
3201
+ .toMatchInlineSnapshot(`
3202
+ [Error: Processing wrangler.toml configuration:
3203
+ - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
3204
+ - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
3205
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM Module, and Data Blob bindings.
3206
+ - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
3207
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3208
+ Please change your bindings to have unique names.]
3209
+ `);
3210
+ expect(std.out).toMatchInlineSnapshot(`
3211
+ "
3212
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3213
+ `);
3214
+ expect(std.err).toMatchInlineSnapshot(`
3215
+ "X [ERROR] Processing wrangler.toml configuration:
3216
+
3217
+ - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
3218
+ - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
3219
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM
3220
+ Module, and Data Blob bindings.
3221
+ - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
3222
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3223
+ Please change your bindings to have unique names.
3224
+
3225
+ "
3226
+ `);
3227
+ expect(std.warn).toMatchInlineSnapshot(`
3228
+ "▲ [WARNING] Processing wrangler.toml configuration:
3229
+
3230
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3231
+
3232
+ "
3233
+ `);
3234
+ });
3235
+
3236
+ it("should error when bindings of the same type have the same name", async () => {
3237
+ writeWranglerToml({
3238
+ durable_objects: {
3239
+ bindings: [
3240
+ {
3241
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
3242
+ class_name: "SomeDurableObject",
3243
+ script_name: "some-durable-object-worker",
3244
+ },
3245
+ {
3246
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
3247
+ class_name: "AnotherDurableObject",
3248
+ script_name: "another-durable-object-worker",
3249
+ },
3250
+ ],
3251
+ },
3252
+ kv_namespaces: [
3253
+ { binding: "CONFLICTING_KV_NAMESPACE_NAME", id: "kv-ns-one-id" },
3254
+ { binding: "CONFLICTING_KV_NAMESPACE_NAME", id: "kv-ns-two-id" },
3255
+ ],
3256
+ r2_buckets: [
3257
+ {
3258
+ binding: "CONFLICTING_R2_BUCKET_NAME",
3259
+ bucket_name: "r2-bucket-one-name",
3260
+ },
3261
+ {
3262
+ binding: "CONFLICTING_R2_BUCKET_NAME",
3263
+ bucket_name: "r2-bucket-two-name",
3264
+ },
3265
+ ],
3266
+ unsafe: {
3267
+ bindings: [
3268
+ {
3269
+ name: "CONFLICTING_UNSAFE_NAME",
3270
+ type: "some unsafe thing",
3271
+ data: { some: { unsafe: "thing" } },
3272
+ },
3273
+ {
3274
+ name: "CONFLICTING_UNSAFE_NAME",
3275
+ type: "another unsafe thing",
3276
+ data: 1337,
3277
+ },
3278
+ ],
3279
+ },
3280
+ // text_blobs, vars, wasm_modules and data_blobs are fine because they're object literals,
3281
+ // and by definition cannot have two keys of the same name
3282
+ //
3283
+ // text_blobs: {
3284
+ // CONFLICTING_TEXT_BLOB_NAME: "./my-entire-app-depends-on-this.cfg",
3285
+ // CONFLICTING_TEXT_BLOB_NAME: "./the-entirety-of-human-knowledge.txt",
3286
+ // },
3287
+ // vars: {
3288
+ // CONFLICTING_VARS_NAME: 123,
3289
+ // CONFLICTING_VARS_NAME: "Hello, I'm an environment variable",
3290
+ // },
3291
+ // wasm_modules: {
3292
+ // CONFLICTING_WASM_MODULE_NAME: "./some_wasm.wasm",
3293
+ // CONFLICTING_WASM_MODULE_NAME: "./more_wasm.wasm",
3294
+ // },
3295
+ });
3296
+
3297
+ writeWorkerSource({ type: "sw" });
3298
+
3299
+ await expect(runWrangler("publish index.js")).rejects
3300
+ .toMatchInlineSnapshot(`
3301
+ [Error: Processing wrangler.toml configuration:
3302
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
3303
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
3304
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
3305
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
3306
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3307
+ Please change your bindings to have unique names.]
3308
+ `);
3309
+ expect(std.out).toMatchInlineSnapshot(`
3310
+ "
3311
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3312
+ `);
3313
+ expect(std.err).toMatchInlineSnapshot(`
3314
+ "X [ERROR] Processing wrangler.toml configuration:
3315
+
3316
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
3317
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
3318
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
3319
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
3320
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3321
+ Please change your bindings to have unique names.
3322
+
3323
+ "
3324
+ `);
3325
+ expect(std.warn).toMatchInlineSnapshot(`
3326
+ "▲ [WARNING] Processing wrangler.toml configuration:
3327
+
3328
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3329
+
3330
+ "
3331
+ `);
3332
+ });
3333
+
3334
+ it("should error correctly when bindings of the same and different types use the same name", async () => {
3335
+ writeWranglerToml({
3336
+ durable_objects: {
3337
+ bindings: [
3338
+ {
3339
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
3340
+ class_name: "SomeDurableObject",
3341
+ script_name: "some-durable-object-worker",
3342
+ },
3343
+ {
3344
+ name: "CONFLICTING_DURABLE_OBJECT_NAME",
3345
+ class_name: "AnotherDurableObject",
3346
+ script_name: "another-durable-object-worker",
3347
+ },
3348
+ ],
3349
+ },
3350
+ kv_namespaces: [
3351
+ {
3352
+ binding: "CONFLICTING_KV_NAMESPACE_NAME",
3353
+ id: "kv-ns-one-id",
3354
+ },
3355
+ {
3356
+ binding: "CONFLICTING_KV_NAMESPACE_NAME",
3357
+ id: "kv-ns-two-id",
3358
+ },
3359
+ { binding: "CONFLICTING_NAME_ONE", id: "kv-ns-three-id" },
3360
+ { binding: "CONFLICTING_NAME_TWO", id: "kv-ns-four-id" },
3361
+ ],
3362
+ r2_buckets: [
3363
+ {
3364
+ binding: "CONFLICTING_R2_BUCKET_NAME",
3365
+ bucket_name: "r2-bucket-one-name",
3366
+ },
3367
+ {
3368
+ binding: "CONFLICTING_R2_BUCKET_NAME",
3369
+ bucket_name: "r2-bucket-two-name",
3370
+ },
3371
+ {
3372
+ binding: "CONFLICTING_NAME_THREE",
3373
+ bucket_name: "r2-bucket-three-name",
3374
+ },
3375
+ {
3376
+ binding: "CONFLICTING_NAME_FOUR",
3377
+ bucket_name: "r2-bucket-four-name",
3378
+ },
3379
+ ],
3380
+ text_blobs: {
3381
+ CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
3382
+ CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
3383
+ },
3384
+ unsafe: {
3385
+ bindings: [
3386
+ {
3387
+ name: "CONFLICTING_UNSAFE_NAME",
3388
+ type: "some unsafe thing",
3389
+ data: { some: { unsafe: "thing" } },
3390
+ },
3391
+ {
3392
+ name: "CONFLICTING_UNSAFE_NAME",
3393
+ type: "another unsafe thing",
3394
+ data: 1337,
3395
+ },
3396
+ {
3397
+ name: "CONFLICTING_NAME_THREE",
3398
+ type: "yet another unsafe thing",
3399
+ data: "how is a string unsafe?",
3400
+ },
3401
+ {
3402
+ name: "CONFLICTING_NAME_FOUR",
3403
+ type: "a fourth unsafe thing",
3404
+ data: null,
3405
+ },
3406
+ ],
3407
+ },
3408
+ vars: {
3409
+ ENV_VAR_ONE: 123,
3410
+ CONFLICTING_NAME_THREE: "Hello, I'm an environment variable",
3411
+ },
3412
+ wasm_modules: {
3413
+ WASM_MODULE_ONE: "./some_wasm.wasm",
3414
+ CONFLICTING_NAME_THREE: "./more_wasm.wasm",
3415
+ },
3416
+ data_blobs: {
3417
+ DATA_BLOB_ONE: "./some_data.bin",
3418
+ CONFLICTING_NAME_THREE: "./more_data.bin",
3419
+ },
3420
+ });
3421
+
3422
+ writeWorkerSource({ type: "sw" });
3423
+ fs.writeFileSync("./my-entire-app-depends-on-this.cfg", "config = value");
3424
+ fs.writeFileSync(
3425
+ "./the-entirety-of-human-knowledge.txt",
3426
+ "Everything's bigger in Texas"
3427
+ );
3428
+ fs.writeFileSync("./some_wasm.wasm", "some wasm");
3429
+ fs.writeFileSync("./more_wasm.wasm", "more wasm");
3430
+
3431
+ await expect(runWrangler("publish index.js")).rejects
3432
+ .toMatchInlineSnapshot(`
3433
+ [Error: Processing wrangler.toml configuration:
3434
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
3435
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
3436
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
3437
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM Module, and Data Blob bindings.
3438
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
3439
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
3440
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3441
+ Please change your bindings to have unique names.]
3442
+ `);
3443
+ expect(std.out).toMatchInlineSnapshot(`
3444
+ "
3445
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3446
+ `);
3447
+ expect(std.err).toMatchInlineSnapshot(`
3448
+ "X [ERROR] Processing wrangler.toml configuration:
3449
+
3450
+ - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
3451
+ - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
3452
+ - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
3453
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM
3454
+ Module, and Data Blob bindings.
3455
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
3456
+ - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
3457
+ - Bindings must have unique names, so that they can all be referenced in the worker.
3458
+ Please change your bindings to have unique names.
3459
+
3460
+ "
3461
+ `);
3462
+ expect(std.warn).toMatchInlineSnapshot(`
3463
+ "▲ [WARNING] Processing wrangler.toml configuration:
3464
+
3465
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
3466
+
3467
+ "
3468
+ `);
3469
+ });
3470
+
3471
+ describe("[wasm_modules]", () => {
3472
+ it("should be able to define wasm modules for service-worker format workers", async () => {
3473
+ writeWranglerToml({
3474
+ wasm_modules: {
3475
+ TESTWASMNAME: "./path/to/test.wasm",
3476
+ },
3477
+ });
3478
+ writeWorkerSource({ type: "sw" });
3479
+ fs.mkdirSync("./path/to", { recursive: true });
3480
+ fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
3481
+ mockUploadWorkerRequest({
3482
+ expectedType: "sw",
3483
+ expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
3484
+ expectedBindings: [
3485
+ { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
3486
+ ],
3487
+ });
3488
+ mockSubDomainRequest();
3489
+ await runWrangler("publish index.js");
3490
+ expect(std.out).toMatchInlineSnapshot(`
3491
+ "Uploaded test-name (TIMINGS)
3492
+ Published test-name (TIMINGS)
3493
+ test-name.test-sub-domain.workers.dev"
3494
+ `);
3495
+ expect(std.err).toMatchInlineSnapshot(`""`);
3496
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3497
+ });
3498
+
3499
+ it("should error when defining wasm modules for modules format workers", async () => {
3500
+ writeWranglerToml({
3501
+ wasm_modules: {
3502
+ TESTWASMNAME: "./path/to/test.wasm",
3503
+ },
3504
+ });
3505
+ writeWorkerSource({ type: "esm" });
3506
+ fs.mkdirSync("./path/to", { recursive: true });
3507
+ fs.writeFileSync("./path/to/test.wasm", "SOME WASM CONTENT");
3508
+
3509
+ await expect(
3510
+ runWrangler("publish index.js")
3511
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
3512
+ `"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"`
3513
+ );
3514
+ expect(std.out).toMatchInlineSnapshot(`
3515
+ "
3516
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3517
+ `);
3518
+ expect(std.err).toMatchInlineSnapshot(`
3519
+ "X [ERROR] You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
3520
+
3521
+ "
3522
+ `);
3523
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3524
+ });
3525
+
3526
+ it("should resolve wasm modules relative to the wrangler.toml file", async () => {
3527
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
3528
+ fs.writeFileSync(
3529
+ "./path/to/wrangler.toml",
3530
+ TOML.stringify({
3531
+ compatibility_date: "2022-01-12",
3532
+ name: "test-name",
3533
+ wasm_modules: {
3534
+ TESTWASMNAME: "./and/the/path/to/test.wasm",
3535
+ },
3536
+ }),
3537
+
3538
+ "utf-8"
3539
+ );
3540
+
3541
+ writeWorkerSource({ type: "sw" });
3542
+ fs.writeFileSync(
3543
+ "./path/to/and/the/path/to/test.wasm",
3544
+ "SOME WASM CONTENT"
3545
+ );
3546
+ mockUploadWorkerRequest({
3547
+ expectedType: "sw",
3548
+ expectedModules: { TESTWASMNAME: "SOME WASM CONTENT" },
3549
+ expectedBindings: [
3550
+ { name: "TESTWASMNAME", part: "TESTWASMNAME", type: "wasm_module" },
3551
+ ],
3552
+ expectedCompatibilityDate: "2022-01-12",
3553
+ });
3554
+ mockSubDomainRequest();
3555
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3556
+ expect(std.out).toMatchInlineSnapshot(`
3557
+ "Uploaded test-name (TIMINGS)
3558
+ Published test-name (TIMINGS)
3559
+ test-name.test-sub-domain.workers.dev"
3560
+ `);
3561
+ expect(std.err).toMatchInlineSnapshot(`""`);
3562
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3563
+ });
3564
+
3565
+ it("should be able to import .wasm modules from service-worker format workers", async () => {
3566
+ writeWranglerToml();
3567
+ fs.writeFileSync(
3568
+ "./index.js",
3569
+ "import TESTWASMNAME from './test.wasm';"
3570
+ );
3571
+ fs.writeFileSync("./test.wasm", "SOME WASM CONTENT");
3572
+ mockUploadWorkerRequest({
3573
+ expectedType: "sw",
3574
+ expectedModules: {
3575
+ __94b240d0d692281e6467aa42043986e5c7eea034_test_wasm:
3576
+ "SOME WASM CONTENT",
3577
+ },
3578
+ expectedBindings: [
3579
+ {
3580
+ name: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
3581
+ part: "__94b240d0d692281e6467aa42043986e5c7eea034_test_wasm",
3582
+ type: "wasm_module",
3583
+ },
3584
+ ],
3585
+ });
3586
+ mockSubDomainRequest();
3587
+ await runWrangler("publish index.js");
3588
+ expect(std.out).toMatchInlineSnapshot(`
3589
+ "Uploaded test-name (TIMINGS)
3590
+ Published test-name (TIMINGS)
3591
+ test-name.test-sub-domain.workers.dev"
3592
+ `);
3593
+ expect(std.err).toMatchInlineSnapshot(`""`);
3594
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3595
+ });
3596
+ });
3597
+
3598
+ describe("[text_blobs]", () => {
3599
+ it("should be able to define text blobs for service-worker format workers", async () => {
3600
+ writeWranglerToml({
3601
+ text_blobs: {
3602
+ TESTTEXTBLOBNAME: "./path/to/text.file",
3603
+ },
3604
+ });
3605
+ writeWorkerSource({ type: "sw" });
3606
+ fs.mkdirSync("./path/to", { recursive: true });
3607
+ fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
3608
+ mockUploadWorkerRequest({
3609
+ expectedType: "sw",
3610
+ expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
3611
+ expectedBindings: [
3612
+ {
3613
+ name: "TESTTEXTBLOBNAME",
3614
+ part: "TESTTEXTBLOBNAME",
3615
+ type: "text_blob",
3616
+ },
3617
+ ],
3618
+ });
3619
+ mockSubDomainRequest();
3620
+ await runWrangler("publish index.js");
3621
+ expect(std.out).toMatchInlineSnapshot(`
3622
+ "Uploaded test-name (TIMINGS)
3623
+ Published test-name (TIMINGS)
3624
+ test-name.test-sub-domain.workers.dev"
3625
+ `);
3626
+ expect(std.err).toMatchInlineSnapshot(`""`);
3627
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3628
+ });
3629
+
3630
+ it("should error when defining text blobs for modules format workers", async () => {
3631
+ writeWranglerToml({
3632
+ text_blobs: {
3633
+ TESTTEXTBLOBNAME: "./path/to/text.file",
3634
+ },
3635
+ });
3636
+ writeWorkerSource({ type: "esm" });
3637
+ fs.mkdirSync("./path/to", { recursive: true });
3638
+ fs.writeFileSync("./path/to/text.file", "SOME TEXT CONTENT");
3639
+
3640
+ await expect(
3641
+ runWrangler("publish index.js")
3642
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
3643
+ `"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"`
3644
+ );
3645
+ expect(std.out).toMatchInlineSnapshot(`
3646
+ "
3647
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3648
+ `);
3649
+ expect(std.err).toMatchInlineSnapshot(`
3650
+ "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
3651
+
3652
+ "
3653
+ `);
3654
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3655
+ });
3656
+
3657
+ it("should resolve text blobs relative to the wrangler.toml file", async () => {
3658
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
3659
+ fs.writeFileSync(
3660
+ "./path/to/wrangler.toml",
3661
+ TOML.stringify({
3662
+ compatibility_date: "2022-01-12",
3663
+ name: "test-name",
3664
+ text_blobs: {
3665
+ TESTTEXTBLOBNAME: "./and/the/path/to/text.file",
3666
+ },
3667
+ }),
3668
+
3669
+ "utf-8"
3670
+ );
3671
+
3672
+ writeWorkerSource({ type: "sw" });
3673
+ fs.writeFileSync(
3674
+ "./path/to/and/the/path/to/text.file",
3675
+ "SOME TEXT CONTENT"
3676
+ );
3677
+ mockUploadWorkerRequest({
3678
+ expectedType: "sw",
3679
+ expectedModules: { TESTTEXTBLOBNAME: "SOME TEXT CONTENT" },
3680
+ expectedBindings: [
3681
+ {
3682
+ name: "TESTTEXTBLOBNAME",
3683
+ part: "TESTTEXTBLOBNAME",
3684
+ type: "text_blob",
3685
+ },
3686
+ ],
3687
+ expectedCompatibilityDate: "2022-01-12",
3688
+ });
3689
+ mockSubDomainRequest();
3690
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3691
+ expect(std.out).toMatchInlineSnapshot(`
3692
+ "Uploaded test-name (TIMINGS)
3693
+ Published test-name (TIMINGS)
3694
+ test-name.test-sub-domain.workers.dev"
3695
+ `);
3696
+ expect(std.err).toMatchInlineSnapshot(`""`);
3697
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3698
+ });
3699
+ });
3700
+
3701
+ describe("[data_blobs]", () => {
3702
+ it("should be able to define data blobs for service-worker format workers", async () => {
3703
+ writeWranglerToml({
3704
+ data_blobs: {
3705
+ TESTDATABLOBNAME: "./path/to/data.bin",
3706
+ },
3707
+ });
3708
+ writeWorkerSource({ type: "sw" });
3709
+ fs.mkdirSync("./path/to", { recursive: true });
3710
+ fs.writeFileSync("./path/to/data.bin", "SOME DATA CONTENT");
3711
+ mockUploadWorkerRequest({
3712
+ expectedType: "sw",
3713
+ expectedModules: { TESTDATABLOBNAME: "SOME DATA CONTENT" },
3714
+ expectedBindings: [
3715
+ {
3716
+ name: "TESTDATABLOBNAME",
3717
+ part: "TESTDATABLOBNAME",
3718
+ type: "data_blob",
3719
+ },
3720
+ ],
3721
+ });
3722
+ mockSubDomainRequest();
3723
+ await runWrangler("publish index.js");
3724
+ expect(std.out).toMatchInlineSnapshot(`
3725
+ "Uploaded test-name (TIMINGS)
3726
+ Published test-name (TIMINGS)
3727
+ test-name.test-sub-domain.workers.dev"
3728
+ `);
3729
+ expect(std.err).toMatchInlineSnapshot(`""`);
3730
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3731
+ });
3732
+
3733
+ it("should error when defining data blobs for modules format workers", async () => {
3734
+ writeWranglerToml({
3735
+ data_blobs: {
3736
+ TESTDATABLOBNAME: "./path/to/data.bin",
3737
+ },
3738
+ });
3739
+ writeWorkerSource({ type: "esm" });
3740
+ fs.mkdirSync("./path/to", { recursive: true });
3741
+ fs.writeFileSync("./path/to/data.bin", "SOME DATA CONTENT");
3742
+
3743
+ await expect(
3744
+ runWrangler("publish index.js")
3745
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
3746
+ `"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"`
3747
+ );
3748
+ expect(std.out).toMatchInlineSnapshot(`
3749
+ "
3750
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3751
+ `);
3752
+ expect(std.err).toMatchInlineSnapshot(`
3753
+ "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
3754
+
3755
+ "
3756
+ `);
3757
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3758
+ });
3759
+
3760
+ it("should resolve data blobs relative to the wrangler.toml file", async () => {
3761
+ fs.mkdirSync("./path/to/and/the/path/to/", { recursive: true });
3762
+ fs.writeFileSync(
3763
+ "./path/to/wrangler.toml",
3764
+ TOML.stringify({
3765
+ compatibility_date: "2022-01-12",
3766
+ name: "test-name",
3767
+ data_blobs: {
3768
+ TESTDATABLOBNAME: "./and/the/path/to/data.bin",
3769
+ },
3770
+ }),
3771
+
3772
+ "utf-8"
3773
+ );
3774
+
3775
+ writeWorkerSource({ type: "sw" });
3776
+ fs.writeFileSync(
3777
+ "./path/to/and/the/path/to/data.bin",
3778
+ "SOME DATA CONTENT"
3779
+ );
3780
+ mockUploadWorkerRequest({
3781
+ expectedType: "sw",
3782
+ expectedModules: { TESTDATABLOBNAME: "SOME DATA CONTENT" },
3783
+ expectedBindings: [
3784
+ {
3785
+ name: "TESTDATABLOBNAME",
3786
+ part: "TESTDATABLOBNAME",
3787
+ type: "data_blob",
3788
+ },
3789
+ ],
3790
+ expectedCompatibilityDate: "2022-01-12",
3791
+ });
3792
+ mockSubDomainRequest();
3793
+ await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3794
+ expect(std.out).toMatchInlineSnapshot(`
3795
+ "Uploaded test-name (TIMINGS)
3796
+ Published test-name (TIMINGS)
3797
+ test-name.test-sub-domain.workers.dev"
3798
+ `);
3799
+ expect(std.err).toMatchInlineSnapshot(`""`);
3800
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3801
+ });
3802
+ });
3803
+
3804
+ describe("[vars]", () => {
3805
+ it("should support json bindings", async () => {
3806
+ writeWranglerToml({
3807
+ vars: {
3808
+ text: "plain ol' string",
3809
+ count: 1,
3810
+ complex: { enabled: true, id: 123 },
3811
+ },
3812
+ });
3813
+ writeWorkerSource();
3814
+ mockSubDomainRequest();
3815
+ mockUploadWorkerRequest({
3816
+ expectedBindings: [
3817
+ { name: "text", type: "plain_text", text: "plain ol' string" },
3818
+ { name: "count", type: "json", json: 1 },
3819
+ {
3820
+ name: "complex",
3821
+ type: "json",
3822
+ json: { enabled: true, id: 123 },
3823
+ },
3824
+ ],
3825
+ });
3826
+
3827
+ await runWrangler("publish index.js");
3828
+ expect(std.out).toMatchInlineSnapshot(`
3829
+ "Uploaded test-name (TIMINGS)
3830
+ Published test-name (TIMINGS)
3831
+ test-name.test-sub-domain.workers.dev"
3832
+ `);
3833
+ expect(std.err).toMatchInlineSnapshot(`""`);
3834
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3835
+ });
3836
+ });
3837
+
3838
+ describe("[r2_buckets]", () => {
3839
+ it("should support r2 bucket bindings", async () => {
3840
+ writeWranglerToml({
3841
+ r2_buckets: [{ binding: "FOO", bucket_name: "foo-bucket" }],
3842
+ });
3843
+ writeWorkerSource();
3844
+ mockSubDomainRequest();
3845
+ mockUploadWorkerRequest({
3846
+ expectedBindings: [
3847
+ { bucket_name: "foo-bucket", name: "FOO", type: "r2_bucket" },
3848
+ ],
3849
+ });
3850
+
3851
+ await runWrangler("publish index.js");
3852
+ expect(std.out).toMatchInlineSnapshot(`
3853
+ "Uploaded test-name (TIMINGS)
3854
+ Published test-name (TIMINGS)
3855
+ test-name.test-sub-domain.workers.dev"
3856
+ `);
3857
+ expect(std.err).toMatchInlineSnapshot(`""`);
3858
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3859
+ });
3860
+ });
3861
+
3862
+ describe("[durable_objects]", () => {
3863
+ it("should support durable object bindings", async () => {
3864
+ writeWranglerToml({
3865
+ durable_objects: {
3866
+ bindings: [
3867
+ {
3868
+ name: "EXAMPLE_DO_BINDING",
3869
+ class_name: "ExampleDurableObject",
3870
+ },
3871
+ ],
3872
+ },
3873
+ migrations: [{ tag: "v1", new_classes: ["ExampleDurableObject"] }],
3874
+ });
3875
+ fs.writeFileSync(
3876
+ "index.js",
3877
+ `export class ExampleDurableObject {}; export default{};`
3878
+ );
3879
+ mockSubDomainRequest();
3880
+ mockLegacyScriptData({
3881
+ scripts: [{ id: "test-name", migration_tag: "v1" }],
3882
+ });
3883
+ mockUploadWorkerRequest({
3884
+ expectedBindings: [
3885
+ {
3886
+ class_name: "ExampleDurableObject",
3887
+ name: "EXAMPLE_DO_BINDING",
3888
+ type: "durable_object_namespace",
3889
+ },
3890
+ ],
3891
+ });
3892
+
3893
+ await runWrangler("publish index.js");
3894
+ expect(std.out).toMatchInlineSnapshot(`
3895
+ "Uploaded test-name (TIMINGS)
3896
+ Published test-name (TIMINGS)
3897
+ test-name.test-sub-domain.workers.dev"
3898
+ `);
3899
+ expect(std.err).toMatchInlineSnapshot(`""`);
3900
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3901
+ });
3902
+
3903
+ it("should support service-workers binding to external durable objects", async () => {
3904
+ writeWranglerToml({
3905
+ durable_objects: {
3906
+ bindings: [
3907
+ {
3908
+ name: "EXAMPLE_DO_BINDING",
3909
+ class_name: "ExampleDurableObject",
3910
+ script_name: "example-do-binding-worker",
3911
+ },
3912
+ ],
3913
+ },
3914
+ });
3915
+ writeWorkerSource({ type: "sw" });
3916
+ mockSubDomainRequest();
3917
+ mockUploadWorkerRequest({
3918
+ expectedType: "sw",
3919
+ expectedBindings: [
3920
+ {
3921
+ name: "EXAMPLE_DO_BINDING",
3922
+ class_name: "ExampleDurableObject",
3923
+ script_name: "example-do-binding-worker",
3924
+ type: "durable_object_namespace",
3925
+ },
3926
+ ],
3927
+ });
3928
+
3929
+ await runWrangler("publish index.js");
3930
+ expect(std.out).toMatchInlineSnapshot(`
3931
+ "Uploaded test-name (TIMINGS)
3932
+ Published test-name (TIMINGS)
3933
+ test-name.test-sub-domain.workers.dev"
3934
+ `);
3935
+ expect(std.err).toMatchInlineSnapshot(`""`);
3936
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3937
+ });
3938
+
3939
+ it("should support module workers implementing durable objects", async () => {
3940
+ writeWranglerToml({
3941
+ durable_objects: {
3942
+ bindings: [
3943
+ {
3944
+ name: "EXAMPLE_DO_BINDING",
3945
+ class_name: "ExampleDurableObject",
3946
+ },
3947
+ ],
3948
+ },
3949
+ migrations: [{ tag: "v1", new_classes: ["ExampleDurableObject"] }],
3950
+ });
3951
+ fs.writeFileSync(
3952
+ "index.js",
3953
+ `export class ExampleDurableObject {}; export default{};`
3954
+ );
3955
+ mockSubDomainRequest();
3956
+ mockLegacyScriptData({
3957
+ scripts: [{ id: "test-name", migration_tag: "v1" }],
3958
+ });
3959
+ mockUploadWorkerRequest({
3960
+ expectedType: "esm",
3961
+ expectedBindings: [
3962
+ {
3963
+ name: "EXAMPLE_DO_BINDING",
3964
+ class_name: "ExampleDurableObject",
3965
+ type: "durable_object_namespace",
3966
+ },
3967
+ ],
3968
+ });
3969
+
3970
+ await runWrangler("publish index.js");
3971
+ expect(std.out).toMatchInlineSnapshot(`
3972
+ "Uploaded test-name (TIMINGS)
3973
+ Published test-name (TIMINGS)
3974
+ test-name.test-sub-domain.workers.dev"
3975
+ `);
3976
+ expect(std.err).toMatchInlineSnapshot(`""`);
3977
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2072
3978
  });
2073
- writeWorkerSource({ type: "sw" });
2074
- mockSubDomainRequest();
2075
3979
 
2076
- await expect(runWrangler("publish index.js")).rejects
2077
- .toThrowErrorMatchingInlineSnapshot(`
2078
- "You seem to be trying to use Durable Objects in a Worker written with Service Worker syntax.
2079
- 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:
2080
- { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject } ==> { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject, script_name = example-do-binding-worker }
2081
- Alternatively, migrate your worker to ES Module syntax to implement a Durable Object in this Worker:
2082
- https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
2083
- `);
3980
+ it("should error when detecting a service-worker worker implementing durable objects", async () => {
3981
+ writeWranglerToml({
3982
+ durable_objects: {
3983
+ bindings: [
3984
+ {
3985
+ name: "EXAMPLE_DO_BINDING",
3986
+ class_name: "ExampleDurableObject",
3987
+ },
3988
+ ],
3989
+ },
3990
+ });
3991
+ writeWorkerSource({ type: "sw" });
3992
+ mockSubDomainRequest();
3993
+
3994
+ await expect(runWrangler("publish index.js")).rejects
3995
+ .toThrowErrorMatchingInlineSnapshot(`
3996
+ "You seem to be trying to use Durable Objects in a Worker written as a service-worker.
3997
+ 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:
3998
+ { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject } ==> { name = EXAMPLE_DO_BINDING, class_name = ExampleDurableObject, script_name = example-do-binding-worker }
3999
+ Alternatively, migrate your worker to ES Module syntax to implement a Durable Object in this Worker:
4000
+ https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
4001
+ `);
4002
+ });
2084
4003
  });
2085
- });
2086
4004
 
2087
- describe("unsafe bindings", () => {
2088
- it("should warn if using unsafe bindings", async () => {
2089
- writeWranglerToml({
2090
- unsafe: {
2091
- bindings: [
4005
+ describe("[unsafe]", () => {
4006
+ it("should warn if using unsafe bindings", async () => {
4007
+ writeWranglerToml({
4008
+ unsafe: {
4009
+ bindings: [
4010
+ {
4011
+ name: "my-binding",
4012
+ type: "binding-type",
4013
+ param: "binding-param",
4014
+ },
4015
+ ],
4016
+ },
4017
+ });
4018
+ writeWorkerSource();
4019
+ mockSubDomainRequest();
4020
+ mockUploadWorkerRequest({
4021
+ expectedBindings: [
2092
4022
  {
2093
4023
  name: "my-binding",
2094
4024
  type: "binding-type",
2095
4025
  param: "binding-param",
2096
4026
  },
2097
4027
  ],
2098
- },
4028
+ });
4029
+
4030
+ await runWrangler("publish index.js");
4031
+ expect(std.out).toMatchInlineSnapshot(`
4032
+ "Uploaded test-name (TIMINGS)
4033
+ Published test-name (TIMINGS)
4034
+ test-name.test-sub-domain.workers.dev"
4035
+ `);
4036
+ expect(std.err).toMatchInlineSnapshot(`""`);
4037
+ expect(std.warn).toMatchInlineSnapshot(`
4038
+ "▲ [WARNING] Processing wrangler.toml configuration:
4039
+
4040
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
4041
+
4042
+ "
4043
+ `);
2099
4044
  });
2100
- writeWorkerSource();
2101
- mockSubDomainRequest();
2102
- mockUploadWorkerRequest({
2103
- expectedBindings: [
2104
- {
2105
- name: "my-binding",
2106
- type: "binding-type",
2107
- param: "binding-param",
4045
+ it("should warn if using unsafe bindings already handled by wrangler", async () => {
4046
+ writeWranglerToml({
4047
+ unsafe: {
4048
+ bindings: [
4049
+ {
4050
+ name: "my-binding",
4051
+ type: "plain_text",
4052
+ text: "text",
4053
+ },
4054
+ ],
2108
4055
  },
2109
- ],
2110
- });
2111
-
2112
- await runWrangler("publish index.js");
2113
- expect(std.out).toMatchInlineSnapshot(`
2114
- "Uploaded test-name (TIMINGS)
2115
- Published test-name (TIMINGS)
2116
- test-name.test-sub-domain.workers.dev"
2117
- `);
2118
- expect(std.err).toMatchInlineSnapshot(`""`);
2119
- expect(std.warn).toMatchInlineSnapshot(`
2120
- "Processing wrangler.toml configuration:
2121
- - \\"unsafe\\" fields are experimental and may change or break at any time."
2122
- `);
2123
- });
2124
- it("should warn if using unsafe bindings already handled by wrangler", async () => {
2125
- writeWranglerToml({
2126
- unsafe: {
2127
- bindings: [
4056
+ });
4057
+ writeWorkerSource();
4058
+ mockSubDomainRequest();
4059
+ mockUploadWorkerRequest({
4060
+ expectedBindings: [
2128
4061
  {
2129
4062
  name: "my-binding",
2130
4063
  type: "plain_text",
2131
4064
  text: "text",
2132
4065
  },
2133
4066
  ],
2134
- },
2135
- });
2136
- writeWorkerSource();
2137
- mockSubDomainRequest();
2138
- mockUploadWorkerRequest({
2139
- expectedBindings: [
2140
- {
2141
- name: "my-binding",
2142
- type: "plain_text",
2143
- text: "text",
2144
- },
2145
- ],
2146
- });
4067
+ });
2147
4068
 
2148
- await runWrangler("publish index.js");
2149
- expect(std.out).toMatchInlineSnapshot(`
2150
- "Uploaded test-name (TIMINGS)
2151
- Published test-name (TIMINGS)
2152
- test-name.test-sub-domain.workers.dev"
2153
- `);
2154
- expect(std.err).toMatchInlineSnapshot(`""`);
2155
- expect(std.warn).toMatchInlineSnapshot(`
2156
- "Processing wrangler.toml configuration:
2157
- - \\"unsafe\\" fields are experimental and may change or break at any time.
2158
- - \\"unsafe.bindings[0]\\": {\\"name\\":\\"my-binding\\",\\"type\\":\\"plain_text\\",\\"text\\":\\"text\\"}
2159
- - The binding type \\"plain_text\\" is directly supported by wrangler.
2160
- Consider migrating this unsafe binding to a format for 'plain_text' bindings that is supported by wrangler for optimal support.
2161
- For more details, see https://developers.cloudflare.com/workers/cli-wrangler/configuration"
2162
- `);
4069
+ await runWrangler("publish index.js");
4070
+ expect(std.out).toMatchInlineSnapshot(`
4071
+ "Uploaded test-name (TIMINGS)
4072
+ Published test-name (TIMINGS)
4073
+ test-name.test-sub-domain.workers.dev"
4074
+ `);
4075
+ expect(std.err).toMatchInlineSnapshot(`""`);
4076
+ expect(std.warn).toMatchInlineSnapshot(`
4077
+ "▲ [WARNING] Processing wrangler.toml configuration:
4078
+
4079
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
4080
+ - \\"unsafe.bindings[0]\\": {\\"name\\":\\"my-binding\\",\\"type\\":\\"plain_text\\",\\"text\\":\\"text\\"}
4081
+ - The binding type \\"plain_text\\" is directly supported by wrangler.
4082
+ Consider migrating this unsafe binding to a format for 'plain_text' bindings that is
4083
+ supported by wrangler for optimal support.
4084
+ For more details, see https://developers.cloudflare.com/workers/cli-wrangler/configuration
4085
+
4086
+ "
4087
+ `);
4088
+ });
2163
4089
  });
2164
4090
  });
2165
4091
 
@@ -2253,14 +4179,19 @@ export default{
2253
4179
  `);
2254
4180
  expect(std.err).toMatchInlineSnapshot(`""`);
2255
4181
  expect(std.warn).toMatchInlineSnapshot(`
2256
- "Processing wrangler.toml configuration:
2257
- - 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:
2258
- \`\`\`
2259
- [[rules]]
2260
- type = \\"Text\\"
2261
- globs = [ \\"**/*.file\\" ]
2262
- fallthrough = true
2263
- \`\`\`"
4182
+ "▲ [WARNING] Processing wrangler.toml configuration:
4183
+
4184
+ - Deprecation: The \`build.upload.rules\` config field is no longer used, the rules should be
4185
+ specified via the \`rules\` config field. Delete the \`build.upload\` field from the configuration
4186
+ file, and add this:
4187
+ \`\`\`
4188
+ [[rules]]
4189
+ type = \\"Text\\"
4190
+ globs = [ \\"**/*.file\\" ]
4191
+ fallthrough = true
4192
+ \`\`\`
4193
+
4194
+ "
2264
4195
  `);
2265
4196
  });
2266
4197
 
@@ -2352,10 +4283,48 @@ export default{
2352
4283
  );
2353
4284
  // and the warnings because fallthrough was not explicitly set
2354
4285
  expect(std.warn).toMatchInlineSnapshot(`
2355
- "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.
2356
- 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."
4286
+ "▲ [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.
4287
+
4288
+
4289
+ ▲ [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.
4290
+
4291
+ "
2357
4292
  `);
2358
4293
  });
4294
+
4295
+ describe("inject process.env.NODE_ENV", () => {
4296
+ let actualProcessEnvNodeEnv: string | undefined;
4297
+ beforeEach(() => {
4298
+ actualProcessEnvNodeEnv = process.env.NODE_ENV;
4299
+ process.env.NODE_ENV = "some-node-env";
4300
+ });
4301
+ afterEach(() => {
4302
+ process.env.NODE_ENV = actualProcessEnvNodeEnv;
4303
+ });
4304
+ it("should replace `process.env.NODE_ENV` in scripts", async () => {
4305
+ writeWranglerToml();
4306
+ fs.writeFileSync(
4307
+ "./index.js",
4308
+ `export default {
4309
+ fetch(){
4310
+ return new Response(process.env.NODE_ENV);
4311
+ }
4312
+ }`
4313
+ );
4314
+ mockSubDomainRequest();
4315
+ mockUploadWorkerRequest({
4316
+ expectedEntry: `return new Response("some-node-env");`,
4317
+ });
4318
+ await runWrangler("publish index.js");
4319
+ expect(std.out).toMatchInlineSnapshot(`
4320
+ "Uploaded test-name (TIMINGS)
4321
+ Published test-name (TIMINGS)
4322
+ test-name.test-sub-domain.workers.dev"
4323
+ `);
4324
+ expect(std.err).toMatchInlineSnapshot(`""`);
4325
+ expect(std.warn).toMatchInlineSnapshot(`""`);
4326
+ });
4327
+ });
2359
4328
  });
2360
4329
 
2361
4330
  describe("legacy module specifiers", () => {
@@ -2382,93 +4351,215 @@ export default{
2382
4351
  test-name.test-sub-domain.workers.dev"
2383
4352
  `);
2384
4353
  expect(std.err).toMatchInlineSnapshot(`""`);
2385
- expect(std.warn).toMatchInlineSnapshot(
2386
- `"Deprecation warning: detected a legacy module import in \\"./index.js\\". This will stop working in the future. Replace references to \\"text.file\\" with \\"./text.file\\";"`
4354
+ expect(std.warn).toMatchInlineSnapshot(`
4355
+ "▲ [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\\";
4356
+
4357
+ "
4358
+ `);
4359
+ });
4360
+
4361
+ it("should work with legacy module specifiers, with a deprecation warning (2)", async () => {
4362
+ writeWranglerToml();
4363
+ fs.writeFileSync(
4364
+ "./index.js",
4365
+ `import WASM from 'index.wasm'; export default {};`
4366
+ );
4367
+ fs.writeFileSync("./index.wasm", "SOME WASM CONTENT");
4368
+ mockSubDomainRequest();
4369
+ mockUploadWorkerRequest({
4370
+ expectedModules: {
4371
+ "./94b240d0d692281e6467aa42043986e5c7eea034-index.wasm":
4372
+ "SOME WASM CONTENT",
4373
+ },
4374
+ });
4375
+ await runWrangler("publish index.js");
4376
+ expect(std.out).toMatchInlineSnapshot(`
4377
+ "Uploaded test-name (TIMINGS)
4378
+ Published test-name (TIMINGS)
4379
+ test-name.test-sub-domain.workers.dev"
4380
+ `);
4381
+ expect(std.err).toMatchInlineSnapshot(`""`);
4382
+ expect(std.warn).toMatchInlineSnapshot(`
4383
+ "▲ [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\\";
4384
+
4385
+ "
4386
+ `);
4387
+ });
4388
+
4389
+ it("should not match regular module specifiers when there aren't any possible legacy module matches", async () => {
4390
+ // see https://github.com/cloudflare/wrangler2/issues/655 for bug details
4391
+
4392
+ fs.writeFileSync(
4393
+ "./index.js",
4394
+ `import inner from './inner/index.js'; export default {};`
4395
+ );
4396
+ fs.mkdirSync("./inner", { recursive: true });
4397
+ fs.writeFileSync("./inner/index.js", `export default 123`);
4398
+ mockSubDomainRequest();
4399
+ mockUploadWorkerRequest();
4400
+
4401
+ await runWrangler(
4402
+ "publish index.js --compatibility-date 2022-03-17 --name test-name"
2387
4403
  );
4404
+ expect(std.out).toMatchInlineSnapshot(`
4405
+ "Uploaded test-name (TIMINGS)
4406
+ Published test-name (TIMINGS)
4407
+ test-name.test-sub-domain.workers.dev"
4408
+ `);
4409
+ expect(std.err).toMatchInlineSnapshot(`""`);
4410
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2388
4411
  });
2389
4412
  });
2390
4413
 
2391
- it("should work with legacy module specifiers, with a deprecation warning (2)", async () => {
2392
- writeWranglerToml();
2393
- fs.writeFileSync(
2394
- "./index.js",
2395
- `import WASM from 'index.wasm'; export default {};`
2396
- );
2397
- fs.writeFileSync("./index.wasm", "SOME WASM CONTENT");
2398
- mockSubDomainRequest();
2399
- mockUploadWorkerRequest({
2400
- expectedModules: {
2401
- "./94b240d0d692281e6467aa42043986e5c7eea034-index.wasm":
2402
- "SOME WASM CONTENT",
2403
- },
4414
+ describe("tsconfig", () => {
4415
+ it("should use compilerOptions.paths to resolve modules", async () => {
4416
+ writeWranglerToml({
4417
+ main: "index.ts",
4418
+ });
4419
+ fs.writeFileSync(
4420
+ "index.ts",
4421
+ `import { foo } from '~lib/foo'; export default { fetch() { return new Response(foo)} }`
4422
+ );
4423
+ fs.mkdirSync("lib", { recursive: true });
4424
+ fs.writeFileSync("lib/foo.ts", `export const foo = 123;`);
4425
+ fs.writeFileSync(
4426
+ "tsconfig.json",
4427
+ JSON.stringify({
4428
+ compilerOptions: {
4429
+ baseUrl: ".",
4430
+ paths: {
4431
+ "~lib/*": ["lib/*"],
4432
+ },
4433
+ },
4434
+ })
4435
+ );
4436
+ mockSubDomainRequest();
4437
+ mockUploadWorkerRequest({
4438
+ expectedEntry: "var foo = 123;", // make sure it imported the module correctly
4439
+ });
4440
+ await runWrangler("publish index.ts");
4441
+ expect(std).toMatchInlineSnapshot(`
4442
+ Object {
4443
+ "debug": "",
4444
+ "err": "",
4445
+ "out": "Uploaded test-name (TIMINGS)
4446
+ Published test-name (TIMINGS)
4447
+ test-name.test-sub-domain.workers.dev",
4448
+ "warn": "",
4449
+ }
4450
+ `);
4451
+ });
4452
+
4453
+ it("should output to target es2020 even if tsconfig says otherwise", async () => {
4454
+ writeWranglerToml();
4455
+ writeWorkerSource();
4456
+ fs.writeFileSync(
4457
+ "tsconfig.json",
4458
+ JSON.stringify({
4459
+ compilerOptions: {
4460
+ target: "es5",
4461
+ module: "commonjs",
4462
+ },
4463
+ })
4464
+ );
4465
+ mockSubDomainRequest();
4466
+ mockUploadWorkerRequest({
4467
+ expectedEntry: "export {", // just check that the export is preserved
4468
+ });
4469
+ await runWrangler("publish index.js"); // this would throw if we tried to compile with es5
4470
+ expect(std).toMatchInlineSnapshot(`
4471
+ Object {
4472
+ "debug": "",
4473
+ "err": "",
4474
+ "out": "Uploaded test-name (TIMINGS)
4475
+ Published test-name (TIMINGS)
4476
+ test-name.test-sub-domain.workers.dev",
4477
+ "warn": "",
4478
+ }
4479
+ `);
4480
+ });
4481
+ });
4482
+
4483
+ describe("--outdir", () => {
4484
+ it("should generate built assets at --outdir if specified", async () => {
4485
+ writeWranglerToml();
4486
+ writeWorkerSource();
4487
+ mockSubDomainRequest();
4488
+ mockUploadWorkerRequest();
4489
+ await runWrangler("publish index.js --outdir some-dir");
4490
+ expect(fs.existsSync("some-dir/index.js")).toBe(true);
4491
+ expect(fs.existsSync("some-dir/index.js.map")).toBe(true);
4492
+ expect(std).toMatchInlineSnapshot(`
4493
+ Object {
4494
+ "debug": "",
4495
+ "err": "",
4496
+ "out": "Uploaded test-name (TIMINGS)
4497
+ Published test-name (TIMINGS)
4498
+ test-name.test-sub-domain.workers.dev",
4499
+ "warn": "",
4500
+ }
4501
+ `);
2404
4502
  });
2405
- await runWrangler("publish index.js");
2406
- expect(std.out).toMatchInlineSnapshot(`
2407
- "Uploaded test-name (TIMINGS)
2408
- Published test-name (TIMINGS)
2409
- test-name.test-sub-domain.workers.dev"
2410
- `);
2411
- expect(std.err).toMatchInlineSnapshot(`""`);
2412
- expect(std.warn).toMatchInlineSnapshot(
2413
- `"Deprecation warning: detected a legacy module import in \\"./index.js\\". This will stop working in the future. Replace references to \\"index.wasm\\" with \\"./index.wasm\\";"`
2414
- );
2415
4503
  });
2416
4504
 
2417
- it("should not match regular module specifiers when there aren't any possible legacy module matches", async () => {
2418
- // see https://github.com/cloudflare/wrangler2/issues/655 for bug details
4505
+ describe("--dry-run", () => {
4506
+ it("should not publish the worker if --dry-run is specified", async () => {
4507
+ writeWranglerToml();
4508
+ writeWorkerSource();
4509
+ await runWrangler("publish index.js --dry-run");
4510
+ expect(std).toMatchInlineSnapshot(`
4511
+ Object {
4512
+ "debug": "",
4513
+ "err": "",
4514
+ "out": "--dry-run: exiting now.",
4515
+ "warn": "",
4516
+ }
4517
+ `);
4518
+ });
4519
+ });
2419
4520
 
2420
- fs.writeFileSync(
2421
- "./index.js",
2422
- `import inner from './inner/index.js'; export default {};`
2423
- );
2424
- fs.mkdirSync("./inner", { recursive: true });
2425
- fs.writeFileSync("./inner/index.js", `export default 123`);
2426
- mockSubDomainRequest();
2427
- mockUploadWorkerRequest();
4521
+ describe("--node-compat", () => {
4522
+ it("should warn when using node compatibility mode", async () => {
4523
+ writeWranglerToml();
4524
+ writeWorkerSource();
4525
+ await runWrangler("publish index.js --node-compat --dry-run");
4526
+ expect(std).toMatchInlineSnapshot(`
4527
+ Object {
4528
+ "debug": "",
4529
+ "err": "",
4530
+ "out": "--dry-run: exiting now.",
4531
+ "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.
4532
+
4533
+ ",
4534
+ }
4535
+ `);
4536
+ });
2428
4537
 
2429
- await runWrangler(
2430
- "publish index.js --compatibility-date 2022-03-17 --name test-name"
2431
- );
2432
- expect(std.out).toMatchInlineSnapshot(`
2433
- "Uploaded test-name (TIMINGS)
2434
- Published test-name (TIMINGS)
2435
- test-name.test-sub-domain.workers.dev"
2436
- `);
2437
- expect(std.err).toMatchInlineSnapshot(`""`);
2438
- expect(std.warn).toMatchInlineSnapshot(`""`);
4538
+ it("should polyfill node builtins when enabled", async () => {
4539
+ writeWranglerToml();
4540
+ fs.writeFileSync(
4541
+ "index.js",
4542
+ `
4543
+ import path from 'path';
4544
+ console.log(path.join("some/path/to", "a/file.txt"));
4545
+ export default {}
4546
+ `
4547
+ );
4548
+ await runWrangler("publish index.js --node-compat --dry-run"); // this would throw if node compatibility didn't exist
4549
+ expect(std).toMatchInlineSnapshot(`
4550
+ Object {
4551
+ "debug": "",
4552
+ "err": "",
4553
+ "out": "--dry-run: exiting now.",
4554
+ "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.
4555
+
4556
+ ",
4557
+ }
4558
+ `);
4559
+ });
2439
4560
  });
2440
4561
  });
2441
4562
 
2442
- /** Write a mock Worker script to disk. */
2443
- function writeWorkerSource({
2444
- basePath = ".",
2445
- format = "js",
2446
- type = "esm",
2447
- }: {
2448
- basePath?: string;
2449
- format?: "js" | "ts" | "jsx" | "tsx" | "mjs";
2450
- type?: "esm" | "sw";
2451
- } = {}) {
2452
- if (basePath !== ".") {
2453
- fs.mkdirSync(basePath, { recursive: true });
2454
- }
2455
- fs.writeFileSync(
2456
- `${basePath}/index.${format}`,
2457
- type === "esm"
2458
- ? `import { foo } from "./another";
2459
- export default {
2460
- async fetch(request) {
2461
- return new Response('Hello' + foo);
2462
- },
2463
- };`
2464
- : `import { foo } from "./another";
2465
- addEventListener('fetch', event => {
2466
- event.respondWith(new Response('Hello' + foo));
2467
- })`
2468
- );
2469
- fs.writeFileSync(`${basePath}/another.${format}`, `export const foo = 100;`);
2470
- }
2471
-
2472
4563
  /** Write mock assets to the file system so they can be uploaded. */
2473
4564
  function writeAssets(assets: { filePath: string; content: string }[]) {
2474
4565
  for (const asset of assets) {
@@ -2478,27 +4569,32 @@ function writeAssets(assets: { filePath: string; content: string }[]) {
2478
4569
  }
2479
4570
 
2480
4571
  /** Create a mock handler for the request to upload a worker script. */
2481
- function mockUploadWorkerRequest({
2482
- available_on_subdomain = true,
2483
- expectedEntry,
2484
- expectedType = "esm",
2485
- expectedBindings,
2486
- expectedModules = {},
2487
- expectedCompatibilityDate,
2488
- expectedCompatibilityFlags,
2489
- env = undefined,
2490
- legacyEnv = false,
2491
- }: {
2492
- available_on_subdomain?: boolean;
2493
- expectedEntry?: string;
2494
- expectedType?: "esm" | "sw";
2495
- expectedBindings?: unknown;
2496
- expectedModules?: Record<string, string>;
2497
- expectedCompatibilityDate?: string;
2498
- expectedCompatibilityFlags?: string[];
2499
- env?: string;
2500
- legacyEnv?: boolean;
2501
- } = {}) {
4572
+ function mockUploadWorkerRequest(
4573
+ options: {
4574
+ available_on_subdomain?: boolean;
4575
+ expectedEntry?: string;
4576
+ expectedType?: "esm" | "sw";
4577
+ expectedBindings?: unknown;
4578
+ expectedModules?: Record<string, string>;
4579
+ expectedCompatibilityDate?: string;
4580
+ expectedCompatibilityFlags?: string[];
4581
+ expectedMigrations?: CfWorkerInit["migrations"];
4582
+ env?: string;
4583
+ legacyEnv?: boolean;
4584
+ } = {}
4585
+ ) {
4586
+ const {
4587
+ available_on_subdomain = true,
4588
+ expectedEntry,
4589
+ expectedType = "esm",
4590
+ expectedBindings,
4591
+ expectedModules = {},
4592
+ expectedCompatibilityDate,
4593
+ expectedCompatibilityFlags,
4594
+ env = undefined,
4595
+ legacyEnv = false,
4596
+ expectedMigrations,
4597
+ } = options;
2502
4598
  setMockResponse(
2503
4599
  env && !legacyEnv
2504
4600
  ? "/accounts/:accountId/workers/services/:scriptName/environments/:envName"
@@ -2512,7 +4608,7 @@ function mockUploadWorkerRequest({
2512
4608
  if (!legacyEnv) {
2513
4609
  expect(envName).toEqual(env);
2514
4610
  }
2515
- expect(queryParams.get("available_on_subdomain")).toEqual("true");
4611
+ expect(queryParams.get("include_subdomain_availability")).toEqual("true");
2516
4612
  const formBody = body as FormData;
2517
4613
  if (expectedEntry !== undefined) {
2518
4614
  expect(await (formBody.get("index.js") as File).text()).toMatch(
@@ -2527,17 +4623,20 @@ function mockUploadWorkerRequest({
2527
4623
  } else {
2528
4624
  expect(metadata.body_part).toEqual("index.js");
2529
4625
  }
2530
- if (expectedBindings !== undefined) {
4626
+ if ("expectedBindings" in options) {
2531
4627
  expect(metadata.bindings).toEqual(expectedBindings);
2532
4628
  }
2533
- if (expectedCompatibilityDate !== undefined) {
4629
+ if ("expectedCompatibilityDate" in options) {
2534
4630
  expect(metadata.compatibility_date).toEqual(expectedCompatibilityDate);
2535
4631
  }
2536
- if (expectedCompatibilityFlags !== undefined) {
4632
+ if ("expectedCompatibilityFlags" in options) {
2537
4633
  expect(metadata.compatibility_flags).toEqual(
2538
4634
  expectedCompatibilityFlags
2539
4635
  );
2540
4636
  }
4637
+ if ("expectedMigrations" in options) {
4638
+ expect(metadata.migrations).toEqual(expectedMigrations);
4639
+ }
2541
4640
  for (const [name, content] of Object.entries(expectedModules)) {
2542
4641
  expect(await (formBody.get(name) as File).text()).toEqual(content);
2543
4642
  }
@@ -2597,11 +4696,11 @@ function mockUpdateWorkerRequest({
2597
4696
  }
2598
4697
 
2599
4698
  function mockPublishRoutesRequest({
2600
- routes,
4699
+ routes = [],
2601
4700
  env = undefined,
2602
4701
  legacyEnv = false,
2603
4702
  }: {
2604
- routes: string[];
4703
+ routes: Config["routes"];
2605
4704
  env?: string | undefined;
2606
4705
  legacyEnv?: boolean | undefined;
2607
4706
  }) {
@@ -2621,7 +4720,9 @@ function mockPublishRoutesRequest({
2621
4720
  }
2622
4721
 
2623
4722
  expect(JSON.parse(body as string)).toEqual(
2624
- routes.map((pattern) => ({ pattern }))
4723
+ routes.map((route) =>
4724
+ typeof route !== "object" ? { pattern: route } : route
4725
+ )
2625
4726
  );
2626
4727
  return null;
2627
4728
  }
@@ -2702,3 +4803,73 @@ function mockDeleteUnusedAssetsRequest(
2702
4803
  }
2703
4804
  );
2704
4805
  }
4806
+
4807
+ type LegacyScriptInfo = { id: string; migration_tag?: string };
4808
+
4809
+ function mockLegacyScriptData(options: { scripts: LegacyScriptInfo[] }) {
4810
+ const { scripts } = options;
4811
+ setMockResponse(
4812
+ "/accounts/:accountId/workers/scripts",
4813
+ "GET",
4814
+ ([_url, accountId]) => {
4815
+ expect(accountId).toEqual("some-account-id");
4816
+ return scripts;
4817
+ }
4818
+ );
4819
+ }
4820
+
4821
+ type DurableScriptInfo = { id: string; migration_tag?: string };
4822
+
4823
+ function mockServiceScriptData(options: {
4824
+ script?: DurableScriptInfo;
4825
+ scriptName?: string;
4826
+ env?: string;
4827
+ }) {
4828
+ const { script } = options;
4829
+ if (options.env) {
4830
+ if (!script) {
4831
+ setMockRawResponse(
4832
+ "/accounts/:accountId/workers/services/:scriptName/environments/:envName",
4833
+ "GET",
4834
+ () => {
4835
+ return createFetchResult(null, false, [
4836
+ { code: 10092, message: "workers.api.error.environment_not_found" },
4837
+ ]);
4838
+ }
4839
+ );
4840
+ return;
4841
+ }
4842
+ setMockResponse(
4843
+ "/accounts/:accountId/workers/services/:scriptName/environments/:envName",
4844
+ "GET",
4845
+ ([_url, accountId, scriptName, envName]) => {
4846
+ expect(accountId).toEqual("some-account-id");
4847
+ expect(scriptName).toEqual(options.scriptName || "test-name");
4848
+ expect(envName).toEqual(options.env);
4849
+ return { script };
4850
+ }
4851
+ );
4852
+ } else {
4853
+ if (!script) {
4854
+ setMockRawResponse(
4855
+ "/accounts/:accountId/workers/services/:scriptName",
4856
+ "GET",
4857
+ () => {
4858
+ return createFetchResult(null, false, [
4859
+ { code: 10090, message: "workers.api.error.service_not_found" },
4860
+ ]);
4861
+ }
4862
+ );
4863
+ return;
4864
+ }
4865
+ setMockResponse(
4866
+ "/accounts/:accountId/workers/services/:scriptName",
4867
+ "GET",
4868
+ ([_url, accountId, scriptName]) => {
4869
+ expect(accountId).toEqual("some-account-id");
4870
+ expect(scriptName).toEqual(options.scriptName || "test-name");
4871
+ return { default_environment: { script } };
4872
+ }
4873
+ );
4874
+ }
4875
+ }