wrangler 0.0.0-e2f9bb2 → 0.0.0-e322475

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 (103) hide show
  1. package/Cloudflare_CA.pem +18 -0
  2. package/README.md +3 -1
  3. package/bin/wrangler.js +36 -4
  4. package/kv-asset-handler.js +1 -0
  5. package/package.json +15 -7
  6. package/pages/functions/buildPlugin.ts +13 -0
  7. package/pages/functions/buildWorker.ts +14 -1
  8. package/pages/functions/template-plugin.ts +3 -2
  9. package/src/__tests__/configuration.test.ts +652 -229
  10. package/src/__tests__/dev.test.tsx +372 -79
  11. package/src/__tests__/helpers/mock-cfetch.ts +2 -2
  12. package/src/__tests__/helpers/mock-console.ts +11 -1
  13. package/src/__tests__/helpers/mock-dialogs.ts +75 -11
  14. package/src/__tests__/helpers/mock-process.ts +24 -0
  15. package/src/__tests__/index.test.ts +81 -72
  16. package/src/__tests__/init.test.ts +1360 -410
  17. package/src/__tests__/jest.setup.ts +38 -0
  18. package/src/__tests__/kv.test.ts +218 -152
  19. package/src/__tests__/logger.test.ts +26 -0
  20. package/src/__tests__/package-manager.test.ts +154 -7
  21. package/src/__tests__/pages.test.ts +478 -53
  22. package/src/__tests__/parse.test.ts +8 -0
  23. package/src/__tests__/publish.test.ts +1614 -333
  24. package/src/__tests__/r2.test.ts +55 -36
  25. package/src/__tests__/secret.test.ts +39 -4
  26. package/src/__tests__/user.test.ts +1 -0
  27. package/src/__tests__/whoami.test.tsx +34 -0
  28. package/src/abort.d.ts +3 -0
  29. package/src/bundle-reporter.tsx +29 -0
  30. package/src/bundle.ts +42 -7
  31. package/src/cfetch/index.ts +21 -4
  32. package/src/cfetch/internal.ts +25 -20
  33. package/src/config/config.ts +11 -2
  34. package/src/config/environment.ts +41 -15
  35. package/src/config/index.ts +162 -0
  36. package/src/config/validation-helpers.ts +10 -1
  37. package/src/config/validation.ts +234 -78
  38. package/src/create-worker-preview.ts +32 -22
  39. package/src/create-worker-upload-form.ts +22 -8
  40. package/src/dev/dev.tsx +48 -67
  41. package/src/dev/local.tsx +16 -7
  42. package/src/dev/remote.tsx +57 -21
  43. package/src/dev/use-esbuild.ts +1 -7
  44. package/src/dialogs.tsx +48 -0
  45. package/src/durable.ts +102 -0
  46. package/src/entry.ts +71 -10
  47. package/src/generate-auth-url.ts +33 -0
  48. package/src/generate-random-state.ts +16 -0
  49. package/src/git-client.ts +42 -0
  50. package/src/index.tsx +619 -338
  51. package/src/inspect.ts +39 -0
  52. package/src/kv.ts +116 -27
  53. package/src/logger.ts +8 -1
  54. package/src/open-in-browser.ts +3 -12
  55. package/src/package-manager.ts +50 -3
  56. package/src/pages.tsx +434 -207
  57. package/src/parse.ts +44 -5
  58. package/src/proxy.ts +66 -44
  59. package/src/publish.ts +407 -137
  60. package/src/sites.tsx +103 -28
  61. package/src/user.tsx +35 -26
  62. package/src/whoami.tsx +3 -2
  63. package/src/worker.ts +10 -1
  64. package/src/zones.ts +73 -0
  65. package/templates/new-worker-scheduled.js +17 -0
  66. package/templates/new-worker-scheduled.ts +32 -0
  67. package/templates/new-worker.ts +16 -1
  68. package/templates/no-op-worker.js +10 -0
  69. package/templates/static-asset-facade.js +2 -6
  70. package/wrangler-dist/cli.js +46122 -32396
  71. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  72. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  73. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  74. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  75. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  76. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  77. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  78. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  79. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  80. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  81. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  82. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  83. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  84. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  85. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  86. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  87. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  88. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  89. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  90. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  91. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  92. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  93. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  94. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  95. package/vendor/wrangler-mime/LICENSE +0 -21
  96. package/vendor/wrangler-mime/Mime.js +0 -97
  97. package/vendor/wrangler-mime/README.md +0 -187
  98. package/vendor/wrangler-mime/cli.js +0 -46
  99. package/vendor/wrangler-mime/index.js +0 -4
  100. package/vendor/wrangler-mime/lite.js +0 -4
  101. package/vendor/wrangler-mime/package.json +0 -52
  102. package/vendor/wrangler-mime/types/other.js +0 -1
  103. package/vendor/wrangler-mime/types/standard.js +0 -1
@@ -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 * as esbuild from "esbuild";
4
5
  import { writeAuthConfigFile } from "../user";
5
6
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
6
7
  import {
@@ -11,6 +12,7 @@ import {
11
12
  unsetMockFetchKVGetValues,
12
13
  } from "./helpers/mock-cfetch";
13
14
  import { mockConsoleMethods, normalizeSlashes } from "./helpers/mock-console";
15
+ import { mockConfirm } from "./helpers/mock-dialogs";
14
16
  import { useMockIsTTY } from "./helpers/mock-istty";
15
17
  import { mockKeyListRequest } from "./helpers/mock-kv";
16
18
  import { mockOAuthFlow } from "./helpers/mock-oauth-flow";
@@ -64,7 +66,6 @@ describe("publish", () => {
64
66
  writeWorkerSource();
65
67
  mockSubDomainRequest();
66
68
  mockUploadWorkerRequest();
67
-
68
69
  mockOAuthServerCallback();
69
70
  const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
70
71
  mockGrantAuthorization({ respondWith: "success" });
@@ -77,7 +78,9 @@ describe("publish", () => {
77
78
 
78
79
  expect(std.out).toMatchInlineSnapshot(`
79
80
  "Attempting to login via OAuth...
81
+ Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20pages%3Awrite%20zone%3Aread%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
80
82
  Successfully logged in.
83
+ Total Upload: 0xx KiB / gzip: 0xx KiB
81
84
  Uploaded test-name (TIMINGS)
82
85
  Published test-name (TIMINGS)
83
86
  test-name.test-sub-domain.workers.dev"
@@ -106,7 +109,9 @@ describe("publish", () => {
106
109
 
107
110
  expect(std.out).toMatchInlineSnapshot(`
108
111
  "Attempting to login via OAuth...
112
+ Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20pages%3Awrite%20zone%3Aread%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
109
113
  Successfully logged in.
114
+ Total Upload: 0xx KiB / gzip: 0xx KiB
110
115
  Uploaded test-name (TIMINGS)
111
116
  Published test-name (TIMINGS)
112
117
  test-name.test-sub-domain.workers.dev"
@@ -146,7 +151,8 @@ describe("publish", () => {
146
151
  await runWrangler("publish index.js");
147
152
 
148
153
  expect(std.out).toMatchInlineSnapshot(`
149
- "Uploaded test-name (TIMINGS)
154
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
155
+ Uploaded test-name (TIMINGS)
150
156
  Published test-name (TIMINGS)
151
157
  test-name.test-sub-domain.workers.dev"
152
158
  `);
@@ -172,7 +178,8 @@ describe("publish", () => {
172
178
  await runWrangler("publish index.js");
173
179
 
174
180
  expect(std.out).toMatchInlineSnapshot(`
175
- "Uploaded test-name (TIMINGS)
181
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
182
+ Uploaded test-name (TIMINGS)
176
183
  Published test-name (TIMINGS)
177
184
  test-name.test-sub-domain.workers.dev"
178
185
  `);
@@ -279,7 +286,8 @@ describe("publish", () => {
279
286
  });
280
287
  await runWrangler("publish index.js --env some-env");
281
288
  expect(std.out).toMatchInlineSnapshot(`
282
- "Uploaded test-name-some-env (TIMINGS)
289
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
290
+ Uploaded test-name-some-env (TIMINGS)
283
291
  Published test-name-some-env (TIMINGS)
284
292
  test-name-some-env.test-sub-domain.workers.dev"
285
293
  `);
@@ -297,7 +305,8 @@ describe("publish", () => {
297
305
  });
298
306
  await runWrangler("publish index.js --legacy-env true");
299
307
  expect(std.out).toMatchInlineSnapshot(`
300
- "Uploaded test-name (TIMINGS)
308
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
309
+ Uploaded test-name (TIMINGS)
301
310
  Published test-name (TIMINGS)
302
311
  test-name.test-sub-domain.workers.dev"
303
312
  `);
@@ -315,7 +324,8 @@ describe("publish", () => {
315
324
  });
316
325
  await runWrangler("publish index.js --env some-env --legacy-env true");
317
326
  expect(std.out).toMatchInlineSnapshot(`
318
- "Uploaded test-name-some-env (TIMINGS)
327
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
328
+ Uploaded test-name-some-env (TIMINGS)
319
329
  Published test-name-some-env (TIMINGS)
320
330
  test-name-some-env.test-sub-domain.workers.dev"
321
331
  `);
@@ -333,7 +343,8 @@ describe("publish", () => {
333
343
  });
334
344
  await runWrangler("publish index.js --env some-env --legacy-env true");
335
345
  expect(std.out).toMatchInlineSnapshot(`
336
- "Uploaded test-name-some-env (TIMINGS)
346
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
347
+ Uploaded test-name-some-env (TIMINGS)
337
348
  Published test-name-some-env (TIMINGS)
338
349
  test-name-some-env.test-sub-domain.workers.dev"
339
350
  `);
@@ -402,7 +413,8 @@ describe("publish", () => {
402
413
  });
403
414
  await runWrangler("publish index.js --legacy-env false");
404
415
  expect(std.out).toMatchInlineSnapshot(`
405
- "Uploaded test-name (TIMINGS)
416
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
417
+ Uploaded test-name (TIMINGS)
406
418
  Published test-name (TIMINGS)
407
419
  test-name.test-sub-domain.workers.dev"
408
420
  `);
@@ -427,7 +439,8 @@ describe("publish", () => {
427
439
  });
428
440
  await runWrangler("publish index.js --env some-env --legacy-env false");
429
441
  expect(std.out).toMatchInlineSnapshot(`
430
- "Uploaded test-name (some-env) (TIMINGS)
442
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
443
+ Uploaded test-name (some-env) (TIMINGS)
431
444
  Published test-name (some-env) (TIMINGS)
432
445
  some-env.test-name.test-sub-domain.workers.dev"
433
446
  `);
@@ -469,7 +482,11 @@ describe("publish", () => {
469
482
  mockSubDomainRequest();
470
483
  await runWrangler("publish ./some-path/worker/index.js");
471
484
  expect(std.out).toMatchInlineSnapshot(`
472
- "Uploaded test-name (TIMINGS)
485
+ "Your worker has access to the following bindings:
486
+ - Vars:
487
+ - xyz: \\"123\\"
488
+ Total Upload: 0xx KiB / gzip: 0xx KiB
489
+ Uploaded test-name (TIMINGS)
473
490
  Published test-name (TIMINGS)
474
491
  test-name.test-sub-domain.workers.dev"
475
492
  `);
@@ -521,7 +538,8 @@ describe("publish", () => {
521
538
  Object {
522
539
  "debug": "",
523
540
  "err": "",
524
- "out": "Uploaded test-name (TIMINGS)
541
+ "out": "Total Upload: 0xx KiB / gzip: 0xx KiB
542
+ Uploaded test-name (TIMINGS)
525
543
  Published test-name (TIMINGS)
526
544
  some-example.com/some-route/*
527
545
  *a-boring-website.com (zone id: 54sdf7fsda)
@@ -581,7 +599,8 @@ describe("publish", () => {
581
599
  Object {
582
600
  "debug": "",
583
601
  "err": "",
584
- "out": "Uploaded test-name (staging) (TIMINGS)
602
+ "out": "Total Upload: 0xx KiB / gzip: 0xx KiB
603
+ Uploaded test-name (staging) (TIMINGS)
585
604
  Published test-name (staging) (TIMINGS)
586
605
  some-example.com/some-route/*
587
606
  *a-boring-website.com (zone id: 54sdf7fsda)
@@ -644,6 +663,214 @@ describe("publish", () => {
644
663
  await runWrangler("publish ./index --env dev --legacy-env false");
645
664
  });
646
665
 
666
+ it("should fallback to the Wrangler 1 zone-based API if the bulk-routes API fails", async () => {
667
+ writeWranglerToml({
668
+ routes: ["example.com/some-route/*"],
669
+ });
670
+ writeWorkerSource();
671
+ mockUpdateWorkerRequest({ enabled: false });
672
+ mockUploadWorkerRequest({ expectedType: "esm" });
673
+ // Simulate the bulk-routes API failing with a not authorized error.
674
+ mockUnauthorizedPublishRoutesRequest();
675
+ // Simulate that the worker has already been deployed to another route in this zone.
676
+ mockCollectKnownRoutesRequest([
677
+ {
678
+ pattern: "foo.example.com/other-route",
679
+ script: "test-name",
680
+ },
681
+ ]);
682
+ mockGetZoneFromHostRequest("example.com", "some-zone-id");
683
+ mockPublishRoutesFallbackRequest({
684
+ pattern: "example.com/some-route/*",
685
+ script: "test-name",
686
+ });
687
+ await runWrangler("publish ./index");
688
+
689
+ expect(std.err).toMatchInlineSnapshot(`""`);
690
+ expect(std.warn).toMatchInlineSnapshot(`
691
+ "▲ [WARNING] The current authentication token does not have 'All Zones' permissions.
692
+
693
+ Falling back to using the zone-based API endpoint to update each route individually.
694
+ Note that there is no access to routes associated with zones that the API token does not have
695
+ permission for.
696
+ Existing routes for this Worker in such zones will not be deleted.
697
+
698
+
699
+ ▲ [WARNING] Previously deployed routes:
700
+
701
+ The following routes were already associated with this worker, and have not been deleted:
702
+ - \\"foo.example.com/other-route\\"
703
+ If these routes are not wanted then you can remove them in the dashboard.
704
+
705
+ "
706
+ `);
707
+ expect(std.out).toMatchInlineSnapshot(`
708
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
709
+ Uploaded test-name (TIMINGS)
710
+ Published test-name (TIMINGS)
711
+ example.com/some-route/*"
712
+ `);
713
+ });
714
+
715
+ it("should error if the bulk-routes API fails and trying to push to a non-production environment", async () => {
716
+ writeWranglerToml({
717
+ routes: ["example.com/some-route/*"],
718
+ legacy_env: false,
719
+ });
720
+ writeWorkerSource();
721
+ mockUpdateWorkerRequest({ env: "staging", enabled: false });
722
+ mockUploadWorkerRequest({ env: "staging", expectedType: "esm" });
723
+ // Simulate the bulk-routes API failing with a not authorized error.
724
+ mockUnauthorizedPublishRoutesRequest({ env: "staging" });
725
+ // Simulate that the worker has already been deployed to another route in this zone.
726
+ mockCollectKnownRoutesRequest([
727
+ {
728
+ pattern: "foo.example.com/other-route",
729
+ script: "test-name",
730
+ },
731
+ ]);
732
+ mockGetZoneFromHostRequest("example.com", "some-zone-id");
733
+ mockPublishRoutesFallbackRequest({
734
+ pattern: "example.com/some-route/*",
735
+ script: "test-name",
736
+ });
737
+ await expect(runWrangler("publish ./index --env=staging")).rejects
738
+ .toThrowErrorMatchingInlineSnapshot(`
739
+ "Service environments combined with an API token that doesn't have 'All Zones' permissions is not supported.
740
+ Either turn off service environments by setting \`legacy_env = true\`, creating an API token with 'All Zones' permissions, or logging in via OAuth"
741
+ `);
742
+ });
743
+
744
+ describe("custom domains", () => {
745
+ it("should publish routes marked with 'custom_domain' as separate custom domains", async () => {
746
+ writeWranglerToml({
747
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
748
+ });
749
+ writeWorkerSource();
750
+ mockUpdateWorkerRequest({ enabled: false });
751
+ mockUploadWorkerRequest({ expectedType: "esm" });
752
+ mockPublishCustomDomainsRequest({
753
+ publishFlags: {
754
+ override_scope: true,
755
+ override_existing_origin: false,
756
+ override_existing_dns_record: false,
757
+ },
758
+ domains: [{ hostname: "api.example.com" }],
759
+ });
760
+ await runWrangler("publish ./index");
761
+ expect(std.out).toContain("api.example.com (custom domain)");
762
+ });
763
+
764
+ it("should allow retrying if publish fails with a conflicting custom domain error", async () => {
765
+ writeWranglerToml({
766
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
767
+ });
768
+ writeWorkerSource();
769
+ mockUpdateWorkerRequest({ enabled: false });
770
+ mockUploadWorkerRequest({ expectedType: "esm" });
771
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
772
+ originConflicts: true,
773
+ domains: [{ hostname: "api.example.com" }],
774
+ });
775
+ mockConfirm({
776
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
777
+ result: true,
778
+ });
779
+ await runWrangler("publish ./index");
780
+ expect(std.out).toContain("api.example.com (custom domain)");
781
+ });
782
+
783
+ it("should allow retrying if publish fails with a conflicting DNS record error", async () => {
784
+ writeWranglerToml({
785
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
786
+ });
787
+ writeWorkerSource();
788
+ mockUpdateWorkerRequest({ enabled: false });
789
+ mockUploadWorkerRequest({ expectedType: "esm" });
790
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
791
+ dnsRecordConflicts: true,
792
+ domains: [{ hostname: "api.example.com" }],
793
+ });
794
+ mockConfirm({
795
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
796
+ result: true,
797
+ });
798
+ await runWrangler("publish ./index");
799
+ expect(std.out).toContain("api.example.com (custom domain)");
800
+ });
801
+
802
+ it("should allow retrying for conflicting custom domains and then again for conflicting dns", async () => {
803
+ writeWranglerToml({
804
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
805
+ });
806
+ writeWorkerSource();
807
+ mockUpdateWorkerRequest({ enabled: false });
808
+ mockUploadWorkerRequest({ expectedType: "esm" });
809
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
810
+ originConflicts: true,
811
+ dnsRecordConflicts: true,
812
+ domains: [{ hostname: "api.example.com" }],
813
+ });
814
+ mockConfirm(
815
+ {
816
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
817
+ result: true,
818
+ },
819
+ {
820
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
821
+ result: true,
822
+ }
823
+ );
824
+ await runWrangler("publish ./index");
825
+ expect(std.out).toContain("api.example.com (custom domain)");
826
+ });
827
+
828
+ it("should throw if an invalid custom domain is requested", async () => {
829
+ writeWranglerToml({
830
+ routes: [{ pattern: "*.example.com", custom_domain: true }],
831
+ });
832
+ writeWorkerSource();
833
+ await expect(
834
+ runWrangler("publish ./index")
835
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
836
+ `"Cannot use \\"*.example.com\\" as a Custom Domain; wildcard operators (*) are not allowed"`
837
+ );
838
+
839
+ writeWranglerToml({
840
+ routes: [
841
+ { pattern: "api.example.com/at/a/path", custom_domain: true },
842
+ ],
843
+ });
844
+ writeWorkerSource();
845
+ await expect(
846
+ runWrangler("publish ./index")
847
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
848
+ `"Cannot use \\"api.example.com/at/a/path\\" as a Custom Domain; paths are not allowed"`
849
+ );
850
+ });
851
+
852
+ it("should not retry publish on error if user does not confirm", async () => {
853
+ writeWranglerToml({
854
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
855
+ });
856
+ writeWorkerSource();
857
+ mockUpdateWorkerRequest({ enabled: false });
858
+ mockUploadWorkerRequest({ expectedType: "esm" });
859
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
860
+ dnsRecordConflicts: true,
861
+ domains: [{ hostname: "api.example.com" }],
862
+ });
863
+ mockConfirm({
864
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
865
+ result: false,
866
+ });
867
+ await runWrangler("publish ./index");
868
+ expect(std.out).toContain(
869
+ 'Publishing to Custom Domain "api.example.com" was skipped, fix conflict and try again'
870
+ );
871
+ });
872
+ });
873
+
647
874
  it.todo("should error if it's a workers.dev route");
648
875
  });
649
876
 
@@ -657,7 +884,8 @@ describe("publish", () => {
657
884
  await runWrangler("publish ./index");
658
885
 
659
886
  expect(std.out).toMatchInlineSnapshot(`
660
- "Uploaded test-name (TIMINGS)
887
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
888
+ Uploaded test-name (TIMINGS)
661
889
  Published test-name (TIMINGS)
662
890
  test-name.test-sub-domain.workers.dev"
663
891
  `);
@@ -673,7 +901,8 @@ describe("publish", () => {
673
901
  await runWrangler("publish ./index");
674
902
 
675
903
  expect(std.out).toMatchInlineSnapshot(`
676
- "Uploaded test-name (TIMINGS)
904
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
905
+ Uploaded test-name (TIMINGS)
677
906
  Published test-name (TIMINGS)
678
907
  test-name.test-sub-domain.workers.dev"
679
908
  `);
@@ -689,7 +918,8 @@ describe("publish", () => {
689
918
  await runWrangler("publish");
690
919
 
691
920
  expect(std.out).toMatchInlineSnapshot(`
692
- "Uploaded test-name (TIMINGS)
921
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
922
+ Uploaded test-name (TIMINGS)
693
923
  Published test-name (TIMINGS)
694
924
  test-name.test-sub-domain.workers.dev"
695
925
  `);
@@ -707,7 +937,8 @@ describe("publish", () => {
707
937
  await runWrangler("publish");
708
938
 
709
939
  expect(std.out).toMatchInlineSnapshot(`
710
- "Uploaded test-name (TIMINGS)
940
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
941
+ Uploaded test-name (TIMINGS)
711
942
  Published test-name (TIMINGS)
712
943
  test-name.test-sub-domain.workers.dev"
713
944
  `);
@@ -723,7 +954,8 @@ describe("publish", () => {
723
954
  await runWrangler("publish");
724
955
 
725
956
  expect(std.out).toMatchInlineSnapshot(`
726
- "Uploaded test-name (TIMINGS)
957
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
958
+ Uploaded test-name (TIMINGS)
727
959
  Published test-name (TIMINGS)
728
960
  test-name.test-sub-domain.workers.dev"
729
961
  `);
@@ -758,7 +990,8 @@ describe("publish", () => {
758
990
  await runWrangler("publish");
759
991
 
760
992
  expect(std.out).toMatchInlineSnapshot(`
761
- "Uploaded test-name (TIMINGS)
993
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
994
+ Uploaded test-name (TIMINGS)
762
995
  Published test-name (TIMINGS)
763
996
  test-name.test-sub-domain.workers.dev"
764
997
  `);
@@ -807,7 +1040,8 @@ describe("publish", () => {
807
1040
  await runWrangler("publish index.ts");
808
1041
 
809
1042
  expect(std.out).toMatchInlineSnapshot(`
810
- "Uploaded test-name (TIMINGS)
1043
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
1044
+ Uploaded test-name (TIMINGS)
811
1045
  Published test-name (TIMINGS)
812
1046
  test-name.test-sub-domain.workers.dev"
813
1047
  `);
@@ -825,7 +1059,8 @@ describe("publish", () => {
825
1059
  await runWrangler("publish index.ts");
826
1060
 
827
1061
  expect(std.out).toMatchInlineSnapshot(`
828
- "Uploaded test-name (TIMINGS)
1062
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
1063
+ Uploaded test-name (TIMINGS)
829
1064
  Published test-name (TIMINGS)
830
1065
  test-name.test-sub-domain.workers.dev"
831
1066
  `);
@@ -855,7 +1090,8 @@ export default{
855
1090
  mockSubDomainRequest();
856
1091
  await runWrangler("publish index.js");
857
1092
  expect(std.out).toMatchInlineSnapshot(`
858
- "Uploaded test-name (TIMINGS)
1093
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
1094
+ Uploaded test-name (TIMINGS)
859
1095
  Published test-name (TIMINGS)
860
1096
  test-name.test-sub-domain.workers.dev"
861
1097
  `);
@@ -871,13 +1107,88 @@ export default{
871
1107
  await runWrangler("publish ./src/index.js");
872
1108
 
873
1109
  expect(std.out).toMatchInlineSnapshot(`
874
- "Uploaded test-name (TIMINGS)
1110
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
1111
+ Uploaded test-name (TIMINGS)
875
1112
  Published test-name (TIMINGS)
876
1113
  test-name.test-sub-domain.workers.dev"
877
1114
  `);
878
1115
  expect(std.err).toMatchInlineSnapshot(`""`);
879
1116
  });
880
1117
 
1118
+ it("should preserve exports on a module format worker", async () => {
1119
+ writeWranglerToml();
1120
+ fs.writeFileSync(
1121
+ "index.js",
1122
+ `
1123
+ export const abc = 123;
1124
+ export const def = "show me the money";
1125
+ export default {};`
1126
+ );
1127
+
1128
+ await runWrangler("publish index.js --dry-run --outdir out");
1129
+
1130
+ expect(
1131
+ (
1132
+ await esbuild.build({
1133
+ entryPoints: [path.resolve("./out/index.js")],
1134
+ metafile: true,
1135
+ write: false,
1136
+ })
1137
+ ).metafile?.outputs["index.js"].exports
1138
+ ).toMatchInlineSnapshot(`
1139
+ Array [
1140
+ "abc",
1141
+ "def",
1142
+ "default",
1143
+ ]
1144
+ `);
1145
+
1146
+ expect(std).toMatchInlineSnapshot(`
1147
+ Object {
1148
+ "debug": "",
1149
+ "err": "",
1150
+ "out": "--dry-run: exiting now.
1151
+ Total Upload: 0xx KiB / gzip: 0xx KiB",
1152
+ "warn": "",
1153
+ }
1154
+ `);
1155
+ });
1156
+
1157
+ it("should not preserve exports on a service-worker format worker", async () => {
1158
+ writeWranglerToml();
1159
+ fs.writeFileSync(
1160
+ "index.js",
1161
+ `
1162
+ export const abc = 123;
1163
+ export const def = "show me the money";
1164
+ addEventListener('fetch', event => {});`
1165
+ );
1166
+
1167
+ await runWrangler("publish index.js --dry-run --outdir out");
1168
+
1169
+ expect(
1170
+ (
1171
+ await esbuild.build({
1172
+ entryPoints: [path.resolve("./out/index.js")],
1173
+ metafile: true,
1174
+ write: false,
1175
+ })
1176
+ ).metafile?.outputs["index.js"].exports
1177
+ ).toMatchInlineSnapshot(`Array []`);
1178
+
1179
+ expect(std).toMatchInlineSnapshot(`
1180
+ Object {
1181
+ "debug": "",
1182
+ "err": "",
1183
+ "out": "--dry-run: exiting now.
1184
+ Total Upload: 0xx KiB / gzip: 0xx KiB",
1185
+ "warn": "▲ [WARNING] The entrypoint index.js has exports like an ES Module, but hasn't defined a default export like a module worker normally would. Building the worker using \\"service-worker\\" format...
1186
+
1187
+ ",
1188
+ }
1189
+ `);
1190
+ });
1191
+
881
1192
  it("should be able to transpile entry-points in sub-directories (sw)", async () => {
882
1193
  writeWranglerToml();
883
1194
  writeWorkerSource({ basePath: "./src", type: "sw" });
@@ -890,7 +1201,8 @@ export default{
890
1201
  await runWrangler("publish ./src/index.js");
891
1202
 
892
1203
  expect(std.out).toMatchInlineSnapshot(`
893
- "Uploaded test-name (TIMINGS)
1204
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
1205
+ Uploaded test-name (TIMINGS)
894
1206
  Published test-name (TIMINGS)
895
1207
  test-name.test-sub-domain.workers.dev"
896
1208
  `);
@@ -914,7 +1226,7 @@ export default{
914
1226
 
915
1227
  expect(std.out).toMatchInlineSnapshot(`
916
1228
  "
917
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1229
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
918
1230
  `);
919
1231
  expect(std.err).toMatchInlineSnapshot(`
920
1232
  "X [ERROR] Processing wrangler.toml configuration:
@@ -939,8 +1251,8 @@ export default{
939
1251
 
940
1252
  it("should warn if there is a `site.entry-point` configuration", async () => {
941
1253
  const assets = [
942
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
943
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1254
+ { filePath: "file-1.txt", content: "Content of file-1" },
1255
+ { filePath: "file-2.txt", content: "Content of file-2" },
944
1256
  ];
945
1257
  const kvNamespace = {
946
1258
  title: "__test-name-workers_sites_assets",
@@ -966,11 +1278,12 @@ export default{
966
1278
  Object {
967
1279
  "debug": "",
968
1280
  "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...
1281
+ "out": "Reading file-1.txt...
1282
+ Uploading as file-1.2ca234f380.txt...
1283
+ Reading file-2.txt...
1284
+ Uploading as file-2.5938485188.txt...
973
1285
  ↗️ Done syncing assets
1286
+ Total Upload: 0xx KiB / gzip: 0xx KiB
974
1287
  Uploaded test-name (TIMINGS)
975
1288
  Published test-name (TIMINGS)
976
1289
  test-name.test-sub-domain.workers.dev",
@@ -990,8 +1303,8 @@ export default{
990
1303
 
991
1304
  it("should resolve site.entry-point relative to wrangler.toml", async () => {
992
1305
  const assets = [
993
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
994
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1306
+ { filePath: "file-1.txt", content: "Content of file-1" },
1307
+ { filePath: "file-2.txt", content: "Content of file-2" },
995
1308
  ];
996
1309
  const kvNamespace = {
997
1310
  title: "__test-name-workers_sites_assets",
@@ -1017,11 +1330,12 @@ export default{
1017
1330
  await runWrangler("publish --config ./my-site/wrangler.toml");
1018
1331
 
1019
1332
  expect(std.out).toMatchInlineSnapshot(`
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...
1333
+ "Reading file-1.txt...
1334
+ Uploading as file-1.2ca234f380.txt...
1335
+ Reading file-2.txt...
1336
+ Uploading as file-2.5938485188.txt...
1024
1337
  ↗️ Done syncing assets
1338
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1025
1339
  Uploaded test-name (TIMINGS)
1026
1340
  Published test-name (TIMINGS)
1027
1341
  test-name.test-sub-domain.workers.dev"
@@ -1037,56 +1351,311 @@ export default{
1037
1351
  main = \\"my-entry/index.js\\"
1038
1352
  \`\`\`
1039
1353
 
1040
- "
1354
+ "
1355
+ `);
1356
+ });
1357
+
1358
+ it("should error if both main and site.entry-point are specified", async () => {
1359
+ writeWranglerToml({
1360
+ main: "some-entry",
1361
+ site: {
1362
+ bucket: "some-bucket",
1363
+ "entry-point": "./index.js",
1364
+ },
1365
+ });
1366
+
1367
+ await expect(runWrangler("publish")).rejects
1368
+ .toThrowErrorMatchingInlineSnapshot(`
1369
+ "Processing wrangler.toml configuration:
1370
+ - Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.
1371
+ They serve the same purpose: to point to the entry-point of your worker.
1372
+ Delete the deprecated \`site.entry-point\` field from your config."
1373
+ `);
1374
+ });
1375
+
1376
+ it("should error if there is no entry-point specified", async () => {
1377
+ writeWranglerToml();
1378
+ writeWorkerSource();
1379
+ mockUploadWorkerRequest();
1380
+ mockSubDomainRequest();
1381
+ await expect(
1382
+ runWrangler("publish")
1383
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1384
+ `"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."`
1385
+ );
1386
+
1387
+ expect(std.out).toMatchInlineSnapshot(`
1388
+ "
1389
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1390
+ `);
1391
+ expect(std.err).toMatchInlineSnapshot(`
1392
+ "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.
1393
+
1394
+ "
1395
+ `);
1396
+ });
1397
+
1398
+ it("should not require an explicit entry point when using --assets", async () => {
1399
+ const assets = [
1400
+ { filePath: "file-1.txt", content: "Content of file-1" },
1401
+ { filePath: "file-2.txt", content: "Content of file-2" },
1402
+ ];
1403
+ const kvNamespace = {
1404
+ title: "__test-name-workers_sites_assets",
1405
+ id: "__test-name-workers_sites_assets-id",
1406
+ };
1407
+ writeAssets(assets);
1408
+ mockUploadWorkerRequest({ expectedMainModule: "stdin.js" });
1409
+ mockSubDomainRequest();
1410
+ mockListKVNamespacesRequest(kvNamespace);
1411
+ mockKeyListRequest(kvNamespace.id, []);
1412
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1413
+
1414
+ await runWrangler("publish --assets assets --latest --name test-name");
1415
+
1416
+ expect(std).toMatchInlineSnapshot(`
1417
+ Object {
1418
+ "debug": "",
1419
+ "err": "",
1420
+ "out": "Reading file-1.txt...
1421
+ Uploading as file-1.2ca234f380.txt...
1422
+ Reading file-2.txt...
1423
+ Uploading as file-2.5938485188.txt...
1424
+ ↗️ Done syncing assets
1425
+ Total Upload: 52xx KiB / gzip: 13xx KiB
1426
+ Uploaded test-name (TIMINGS)
1427
+ Published test-name (TIMINGS)
1428
+ test-name.test-sub-domain.workers.dev",
1429
+ "warn": "▲ [WARNING] Using the latest version of the Workers runtime. To silence this warning, please choose a specific version of the runtime with --compatibility-date, or add a compatibility_date to your wrangler.toml.
1430
+
1431
+
1432
+
1433
+ ",
1434
+ }
1435
+ `);
1436
+ });
1437
+ });
1438
+
1439
+ describe("asset upload", () => {
1440
+ it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
1441
+ const assets = [
1442
+ { filePath: "file-1.txt", content: "Content of file-1" },
1443
+ { filePath: "file-2.txt", content: "Content of file-2" },
1444
+ ];
1445
+ const kvNamespace = {
1446
+ title: "__test-name-workers_sites_assets",
1447
+ id: "__test-name-workers_sites_assets-id",
1448
+ };
1449
+ writeWranglerToml({
1450
+ main: "./index.js",
1451
+ site: {
1452
+ bucket: "assets",
1453
+ },
1454
+ });
1455
+ writeWorkerSource();
1456
+ writeAssets(assets);
1457
+ mockUploadWorkerRequest();
1458
+ mockSubDomainRequest();
1459
+ mockListKVNamespacesRequest(kvNamespace);
1460
+ mockKeyListRequest(kvNamespace.id, []);
1461
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1462
+ await runWrangler("publish");
1463
+
1464
+ expect(std.out).toMatchInlineSnapshot(`
1465
+ "Reading file-1.txt...
1466
+ Uploading as file-1.2ca234f380.txt...
1467
+ Reading file-2.txt...
1468
+ Uploading as file-2.5938485188.txt...
1469
+ ↗️ Done syncing assets
1470
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1471
+ Uploaded test-name (TIMINGS)
1472
+ Published test-name (TIMINGS)
1473
+ test-name.test-sub-domain.workers.dev"
1474
+ `);
1475
+ expect(std.err).toMatchInlineSnapshot(`""`);
1476
+ });
1477
+
1478
+ it("should upload all the files in the directory specified by `--assets`", async () => {
1479
+ const assets = [
1480
+ { filePath: "file-1.txt", content: "Content of file-1" },
1481
+ { filePath: "file-2.txt", content: "Content of file-2" },
1482
+ ];
1483
+ const kvNamespace = {
1484
+ title: "__test-name-workers_sites_assets",
1485
+ id: "__test-name-workers_sites_assets-id",
1486
+ };
1487
+ writeWranglerToml({
1488
+ main: "./index.js",
1489
+ });
1490
+ writeWorkerSource();
1491
+ writeAssets(assets);
1492
+ mockUploadWorkerRequest({
1493
+ expectedMainModule: "stdin.js",
1494
+ });
1495
+ mockSubDomainRequest();
1496
+ mockListKVNamespacesRequest(kvNamespace);
1497
+ mockKeyListRequest(kvNamespace.id, []);
1498
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1499
+ await runWrangler("publish --assets assets");
1500
+
1501
+ expect(std).toMatchInlineSnapshot(`
1502
+ Object {
1503
+ "debug": "",
1504
+ "err": "",
1505
+ "out": "Reading file-1.txt...
1506
+ Uploading as file-1.2ca234f380.txt...
1507
+ Reading file-2.txt...
1508
+ Uploading as file-2.5938485188.txt...
1509
+ ↗️ Done syncing assets
1510
+ Total Upload: 52xx KiB / gzip: 13xx KiB
1511
+ Uploaded test-name (TIMINGS)
1512
+ Published test-name (TIMINGS)
1513
+ test-name.test-sub-domain.workers.dev",
1514
+ "warn": "",
1515
+ }
1516
+ `);
1517
+ });
1518
+
1519
+ it("should error when trying to use --assets with a service-worker Worker", async () => {
1520
+ writeWranglerToml({
1521
+ main: "./index.js",
1522
+ });
1523
+ writeWorkerSource({ type: "sw" });
1524
+ await expect(
1525
+ runWrangler("publish --assets abc")
1526
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1527
+ `"You cannot use the service-worker format with an \`assets\` directory yet. For information on how to migrate to the module-worker format, see: https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"`
1528
+ );
1529
+
1530
+ expect(std).toMatchInlineSnapshot(`
1531
+ Object {
1532
+ "debug": "",
1533
+ "err": "X [ERROR] You cannot use the service-worker format with an \`assets\` directory yet. For information on how to migrate to the module-worker format, see: https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/
1534
+
1535
+ ",
1536
+ "out": "
1537
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1538
+ "warn": "",
1539
+ }
1540
+ `);
1541
+ });
1542
+
1543
+ it("should error if --assets and --site are used together", async () => {
1544
+ writeWranglerToml({
1545
+ main: "./index.js",
1546
+ });
1547
+ writeWorkerSource();
1548
+ await expect(
1549
+ runWrangler("publish --assets abc --site xyz")
1550
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1551
+ `"Cannot use Assets and Workers Sites in the same Worker."`
1552
+ );
1553
+
1554
+ expect(std).toMatchInlineSnapshot(`
1555
+ Object {
1556
+ "debug": "",
1557
+ "err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
1558
+
1559
+ ",
1560
+ "out": "
1561
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1562
+ "warn": "",
1563
+ }
1041
1564
  `);
1042
1565
  });
1043
1566
 
1044
- it("should error if both main and site.entry-point are specified", async () => {
1567
+ it("should error if --assets and config.site are used together", async () => {
1045
1568
  writeWranglerToml({
1046
- main: "some-entry",
1569
+ main: "./index.js",
1047
1570
  site: {
1048
- bucket: "some-bucket",
1049
- "entry-point": "./index.js",
1571
+ bucket: "xyz",
1050
1572
  },
1051
1573
  });
1574
+ writeWorkerSource();
1575
+ await expect(
1576
+ runWrangler("publish --assets abc")
1577
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1578
+ `"Cannot use Assets and Workers Sites in the same Worker."`
1579
+ );
1052
1580
 
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
- `);
1581
+ expect(std).toMatchInlineSnapshot(`
1582
+ Object {
1583
+ "debug": "",
1584
+ "err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
1585
+
1586
+ ",
1587
+ "out": "
1588
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1589
+ "warn": "",
1590
+ }
1591
+ `);
1060
1592
  });
1061
1593
 
1062
- it("should error if there is no entry-point specified", async () => {
1063
- writeWranglerToml();
1594
+ it("should error if config.assets and --site are used together", async () => {
1595
+ writeWranglerToml({
1596
+ main: "./index.js",
1597
+ assets: "abc",
1598
+ });
1064
1599
  writeWorkerSource();
1065
- mockUploadWorkerRequest();
1066
- mockSubDomainRequest();
1067
1600
  await expect(
1068
- runWrangler("publish")
1601
+ runWrangler("publish --site xyz")
1069
1602
  ).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."`
1603
+ `"Cannot use Assets and Workers Sites in the same Worker."`
1071
1604
  );
1072
1605
 
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."
1606
+ expect(std).toMatchInlineSnapshot(`
1607
+ Object {
1608
+ "debug": "",
1609
+ "err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
1610
+
1611
+ ",
1612
+ "out": "
1613
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1614
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
1615
+
1616
+ - \\"assets\\" fields are experimental and may change or break at any time.
1617
+
1618
+ ",
1619
+ }
1076
1620
  `);
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.
1621
+ });
1079
1622
 
1080
- "
1623
+ it("should error if config.assets and config.site are used together", async () => {
1624
+ writeWranglerToml({
1625
+ main: "./index.js",
1626
+ assets: "abc",
1627
+ site: {
1628
+ bucket: "xyz",
1629
+ },
1630
+ });
1631
+ writeWorkerSource();
1632
+ await expect(
1633
+ runWrangler("publish")
1634
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1635
+ `"Cannot use Assets and Workers Sites in the same Worker."`
1636
+ );
1637
+
1638
+ expect(std).toMatchInlineSnapshot(`
1639
+ Object {
1640
+ "debug": "",
1641
+ "err": "X [ERROR] Cannot use Assets and Workers Sites in the same Worker.
1642
+
1643
+ ",
1644
+ "out": "
1645
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose",
1646
+ "warn": "▲ [WARNING] Processing wrangler.toml configuration:
1647
+
1648
+ - \\"assets\\" fields are experimental and may change or break at any time.
1649
+
1650
+ ",
1651
+ }
1081
1652
  `);
1082
1653
  });
1083
- });
1084
1654
 
1085
- describe("asset upload", () => {
1086
- it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
1655
+ it("should not contain backslash for assets with nested directories", async () => {
1087
1656
  const assets = [
1088
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1089
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1657
+ { filePath: "subdir/file-1.txt", content: "Content of file-1" },
1658
+ { filePath: "subdir/file-2.txt", content: "Content of file-2" },
1090
1659
  ];
1091
1660
  const kvNamespace = {
1092
1661
  title: "__test-name-workers_sites_assets",
@@ -1100,19 +1669,33 @@ export default{
1100
1669
  });
1101
1670
  writeWorkerSource();
1102
1671
  writeAssets(assets);
1103
- mockUploadWorkerRequest();
1672
+ mockUploadWorkerRequest({
1673
+ expectedBindings: [
1674
+ {
1675
+ name: "__STATIC_CONTENT",
1676
+ namespace_id: "__test-name-workers_sites_assets-id",
1677
+ type: "kv_namespace",
1678
+ },
1679
+ ],
1680
+ expectedModules: {
1681
+ __STATIC_CONTENT_MANIFEST:
1682
+ '{"subdir/file-1.txt":"subdir/file-1.2ca234f380.txt","subdir/file-2.txt":"subdir/file-2.5938485188.txt"}',
1683
+ },
1684
+ });
1104
1685
  mockSubDomainRequest();
1105
1686
  mockListKVNamespacesRequest(kvNamespace);
1106
1687
  mockKeyListRequest(kvNamespace.id, []);
1107
1688
  mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1689
+
1108
1690
  await runWrangler("publish");
1109
1691
 
1110
1692
  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...
1693
+ "Reading subdir/file-1.txt...
1694
+ Uploading as subdir/file-1.2ca234f380.txt...
1695
+ Reading subdir/file-2.txt...
1696
+ Uploading as subdir/file-2.5938485188.txt...
1115
1697
  ↗️ Done syncing assets
1698
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1116
1699
  Uploaded test-name (TIMINGS)
1117
1700
  Published test-name (TIMINGS)
1118
1701
  test-name.test-sub-domain.workers.dev"
@@ -1122,8 +1705,8 @@ export default{
1122
1705
 
1123
1706
  it("when using a service-worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
1124
1707
  const assets = [
1125
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1126
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1708
+ { filePath: "file-1.txt", content: "Content of file-1" },
1709
+ { filePath: "file-2.txt", content: "Content of file-2" },
1127
1710
  ];
1128
1711
  const kvNamespace = {
1129
1712
  title: "__test-name-workers_sites_assets",
@@ -1141,7 +1724,7 @@ export default{
1141
1724
  expectedType: "sw",
1142
1725
  expectedModules: {
1143
1726
  __STATIC_CONTENT_MANIFEST:
1144
- '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
1727
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
1145
1728
  },
1146
1729
  expectedBindings: [
1147
1730
  {
@@ -1164,11 +1747,12 @@ export default{
1164
1747
  await runWrangler("publish");
1165
1748
 
1166
1749
  expect(std.out).toMatchInlineSnapshot(`
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...
1750
+ "Reading file-1.txt...
1751
+ Uploading as file-1.2ca234f380.txt...
1752
+ Reading file-2.txt...
1753
+ Uploading as file-2.5938485188.txt...
1171
1754
  ↗️ Done syncing assets
1755
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1172
1756
  Uploaded test-name (TIMINGS)
1173
1757
  Published test-name (TIMINGS)
1174
1758
  test-name.test-sub-domain.workers.dev"
@@ -1178,8 +1762,8 @@ export default{
1178
1762
 
1179
1763
  it("when using a module worker type, it should add an asset manifest module, and bind to a namespace", async () => {
1180
1764
  const assets = [
1181
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1182
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1765
+ { filePath: "file-1.txt", content: "Content of file-1" },
1766
+ { filePath: "file-2.txt", content: "Content of file-2" },
1183
1767
  ];
1184
1768
  const kvNamespace = {
1185
1769
  title: "__test-name-workers_sites_assets",
@@ -1203,7 +1787,7 @@ export default{
1203
1787
  ],
1204
1788
  expectedModules: {
1205
1789
  __STATIC_CONTENT_MANIFEST:
1206
- '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
1790
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
1207
1791
  },
1208
1792
  });
1209
1793
  mockSubDomainRequest();
@@ -1214,11 +1798,12 @@ export default{
1214
1798
  await runWrangler("publish");
1215
1799
 
1216
1800
  expect(std.out).toMatchInlineSnapshot(`
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...
1801
+ "Reading file-1.txt...
1802
+ Uploading as file-1.2ca234f380.txt...
1803
+ Reading file-2.txt...
1804
+ Uploading as file-2.5938485188.txt...
1221
1805
  ↗️ Done syncing assets
1806
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1222
1807
  Uploaded test-name (TIMINGS)
1223
1808
  Published test-name (TIMINGS)
1224
1809
  test-name.test-sub-domain.workers.dev"
@@ -1229,8 +1814,8 @@ export default{
1229
1814
  it("should make environment specific kv namespace for assets, even for service envs", async () => {
1230
1815
  // This is the same test as the one before this, but with an env arg
1231
1816
  const assets = [
1232
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1233
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1817
+ { filePath: "file-1.txt", content: "Content of file-1" },
1818
+ { filePath: "file-2.txt", content: "Content of file-2" },
1234
1819
  ];
1235
1820
  const kvNamespace = {
1236
1821
  title: "__test-name-some-env-workers_sites_assets",
@@ -1262,11 +1847,12 @@ export default{
1262
1847
  await runWrangler("publish --env some-env --legacy-env false");
1263
1848
 
1264
1849
  expect(std.out).toMatchInlineSnapshot(`
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...
1850
+ "Reading file-1.txt...
1851
+ Uploading as file-1.2ca234f380.txt...
1852
+ Reading file-2.txt...
1853
+ Uploading as file-2.5938485188.txt...
1269
1854
  ↗️ Done syncing assets
1855
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1270
1856
  Uploaded test-name (some-env) (TIMINGS)
1271
1857
  Published test-name (some-env) (TIMINGS)
1272
1858
  some-env.test-name.test-sub-domain.workers.dev"
@@ -1277,8 +1863,8 @@ export default{
1277
1863
  it("should make environment specific kv namespace for assets, even for legacy envs", async () => {
1278
1864
  // And this is the same test as the one before this, but with legacyEnv:true
1279
1865
  const assets = [
1280
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1281
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1866
+ { filePath: "file-1.txt", content: "Content of file-1" },
1867
+ { filePath: "file-2.txt", content: "Content of file-2" },
1282
1868
  ];
1283
1869
  const kvNamespace = {
1284
1870
  title: "__test-name-some-env-workers_sites_assets",
@@ -1311,11 +1897,12 @@ export default{
1311
1897
  await runWrangler("publish --env some-env --legacy-env true");
1312
1898
 
1313
1899
  expect(std.out).toMatchInlineSnapshot(`
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...
1900
+ "Reading file-1.txt...
1901
+ Uploading as file-1.2ca234f380.txt...
1902
+ Reading file-2.txt...
1903
+ Uploading as file-2.5938485188.txt...
1318
1904
  ↗️ Done syncing assets
1905
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1319
1906
  Uploaded test-name-some-env (TIMINGS)
1320
1907
  Published test-name-some-env (TIMINGS)
1321
1908
  test-name-some-env.test-sub-domain.workers.dev"
@@ -1325,8 +1912,8 @@ export default{
1325
1912
 
1326
1913
  it("should only upload files that are not already in the KV namespace", async () => {
1327
1914
  const assets = [
1328
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1329
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1915
+ { filePath: "file-1.txt", content: "Content of file-1" },
1916
+ { filePath: "file-2.txt", content: "Content of file-2" },
1330
1917
  ];
1331
1918
  const kvNamespace = {
1332
1919
  title: "__test-name-workers_sites_assets",
@@ -1344,22 +1931,21 @@ export default{
1344
1931
  mockSubDomainRequest();
1345
1932
  mockListKVNamespacesRequest(kvNamespace);
1346
1933
  // Put file-1 in the KV namespace
1347
- mockKeyListRequest(kvNamespace.id, [
1348
- { name: "assets/file-1.2ca234f380.txt" },
1349
- ]);
1934
+ mockKeyListRequest(kvNamespace.id, [{ name: "file-1.2ca234f380.txt" }]);
1350
1935
  // Check we do not upload file-1
1351
1936
  mockUploadAssetsToKVRequest(
1352
1937
  kvNamespace.id,
1353
- assets.filter((a) => a.filePath !== "assets/file-1.txt")
1938
+ assets.filter((a) => a.filePath !== "file-1.txt")
1354
1939
  );
1355
1940
  await runWrangler("publish");
1356
1941
 
1357
1942
  expect(std.out).toMatchInlineSnapshot(`
1358
- "Reading assets/file-1.txt...
1943
+ "Reading file-1.txt...
1359
1944
  Skipping - already uploaded.
1360
- Reading assets/file-2.txt...
1361
- Uploading as assets/file-2.5938485188.txt...
1945
+ Reading file-2.txt...
1946
+ Uploading as file-2.5938485188.txt...
1362
1947
  ↗️ Done syncing assets
1948
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1363
1949
  Uploaded test-name (TIMINGS)
1364
1950
  Published test-name (TIMINGS)
1365
1951
  test-name.test-sub-domain.workers.dev"
@@ -1369,8 +1955,8 @@ export default{
1369
1955
 
1370
1956
  it("should only upload files that match the `site-include` arg", async () => {
1371
1957
  const assets = [
1372
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1373
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1958
+ { filePath: "file-1.txt", content: "Content of file-1" },
1959
+ { filePath: "file-2.txt", content: "Content of file-2" },
1374
1960
  ];
1375
1961
  const kvNamespace = {
1376
1962
  title: "__test-name-workers_sites_assets",
@@ -1391,14 +1977,15 @@ export default{
1391
1977
  // Check we only upload file-1
1392
1978
  mockUploadAssetsToKVRequest(
1393
1979
  kvNamespace.id,
1394
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1980
+ assets.filter((a) => a.filePath === "file-1.txt")
1395
1981
  );
1396
1982
  await runWrangler("publish --site-include file-1.txt");
1397
1983
 
1398
1984
  expect(std.out).toMatchInlineSnapshot(`
1399
- "Reading assets/file-1.txt...
1400
- Uploading as assets/file-1.2ca234f380.txt...
1985
+ "Reading file-1.txt...
1986
+ Uploading as file-1.2ca234f380.txt...
1401
1987
  ↗️ Done syncing assets
1988
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1402
1989
  Uploaded test-name (TIMINGS)
1403
1990
  Published test-name (TIMINGS)
1404
1991
  test-name.test-sub-domain.workers.dev"
@@ -1408,8 +1995,8 @@ export default{
1408
1995
 
1409
1996
  it("should not upload files that match the `site-exclude` arg", async () => {
1410
1997
  const assets = [
1411
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1412
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1998
+ { filePath: "file-1.txt", content: "Content of file-1" },
1999
+ { filePath: "file-2.txt", content: "Content of file-2" },
1413
2000
  ];
1414
2001
  const kvNamespace = {
1415
2002
  title: "__test-name-workers_sites_assets",
@@ -1430,14 +2017,15 @@ export default{
1430
2017
  // Check we only upload file-1
1431
2018
  mockUploadAssetsToKVRequest(
1432
2019
  kvNamespace.id,
1433
- assets.filter((a) => a.filePath === "assets/file-1.txt")
2020
+ assets.filter((a) => a.filePath === "file-1.txt")
1434
2021
  );
1435
2022
  await runWrangler("publish --site-exclude file-2.txt");
1436
2023
 
1437
2024
  expect(std.out).toMatchInlineSnapshot(`
1438
- "Reading assets/file-1.txt...
1439
- Uploading as assets/file-1.2ca234f380.txt...
2025
+ "Reading file-1.txt...
2026
+ Uploading as file-1.2ca234f380.txt...
1440
2027
  ↗️ Done syncing assets
2028
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1441
2029
  Uploaded test-name (TIMINGS)
1442
2030
  Published test-name (TIMINGS)
1443
2031
  test-name.test-sub-domain.workers.dev"
@@ -1447,8 +2035,8 @@ export default{
1447
2035
 
1448
2036
  it("should only upload files that match the `site.include` config", async () => {
1449
2037
  const assets = [
1450
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1451
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
2038
+ { filePath: "file-1.txt", content: "Content of file-1" },
2039
+ { filePath: "file-2.txt", content: "Content of file-2" },
1452
2040
  ];
1453
2041
  const kvNamespace = {
1454
2042
  title: "__test-name-workers_sites_assets",
@@ -1470,14 +2058,15 @@ export default{
1470
2058
  // Check we only upload file-1
1471
2059
  mockUploadAssetsToKVRequest(
1472
2060
  kvNamespace.id,
1473
- assets.filter((a) => a.filePath === "assets/file-1.txt")
2061
+ assets.filter((a) => a.filePath === "file-1.txt")
1474
2062
  );
1475
2063
  await runWrangler("publish");
1476
2064
 
1477
2065
  expect(std.out).toMatchInlineSnapshot(`
1478
- "Reading assets/file-1.txt...
1479
- Uploading as assets/file-1.2ca234f380.txt...
2066
+ "Reading file-1.txt...
2067
+ Uploading as file-1.2ca234f380.txt...
1480
2068
  ↗️ Done syncing assets
2069
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1481
2070
  Uploaded test-name (TIMINGS)
1482
2071
  Published test-name (TIMINGS)
1483
2072
  test-name.test-sub-domain.workers.dev"
@@ -1487,8 +2076,8 @@ export default{
1487
2076
 
1488
2077
  it("should not upload files that match the `site.exclude` config", async () => {
1489
2078
  const assets = [
1490
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1491
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
2079
+ { filePath: "file-1.txt", content: "Content of file-1" },
2080
+ { filePath: "file-2.txt", content: "Content of file-2" },
1492
2081
  ];
1493
2082
  const kvNamespace = {
1494
2083
  title: "__test-name-workers_sites_assets",
@@ -1510,14 +2099,15 @@ export default{
1510
2099
  // Check we only upload file-1
1511
2100
  mockUploadAssetsToKVRequest(
1512
2101
  kvNamespace.id,
1513
- assets.filter((a) => a.filePath === "assets/file-1.txt")
2102
+ assets.filter((a) => a.filePath === "file-1.txt")
1514
2103
  );
1515
2104
  await runWrangler("publish");
1516
2105
 
1517
2106
  expect(std.out).toMatchInlineSnapshot(`
1518
- "Reading assets/file-1.txt...
1519
- Uploading as assets/file-1.2ca234f380.txt...
2107
+ "Reading file-1.txt...
2108
+ Uploading as file-1.2ca234f380.txt...
1520
2109
  ↗️ Done syncing assets
2110
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1521
2111
  Uploaded test-name (TIMINGS)
1522
2112
  Published test-name (TIMINGS)
1523
2113
  test-name.test-sub-domain.workers.dev"
@@ -1527,8 +2117,8 @@ export default{
1527
2117
 
1528
2118
  it("should use `site-include` arg over `site.include` config", async () => {
1529
2119
  const assets = [
1530
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1531
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
2120
+ { filePath: "file-1.txt", content: "Content of file-1" },
2121
+ { filePath: "file-2.txt", content: "Content of file-2" },
1532
2122
  ];
1533
2123
  const kvNamespace = {
1534
2124
  title: "__test-name-workers_sites_assets",
@@ -1550,14 +2140,15 @@ export default{
1550
2140
  // Check we only upload file-1
1551
2141
  mockUploadAssetsToKVRequest(
1552
2142
  kvNamespace.id,
1553
- assets.filter((a) => a.filePath === "assets/file-1.txt")
2143
+ assets.filter((a) => a.filePath === "file-1.txt")
1554
2144
  );
1555
2145
  await runWrangler("publish --site-include file-1.txt");
1556
2146
 
1557
2147
  expect(std.out).toMatchInlineSnapshot(`
1558
- "Reading assets/file-1.txt...
1559
- Uploading as assets/file-1.2ca234f380.txt...
2148
+ "Reading file-1.txt...
2149
+ Uploading as file-1.2ca234f380.txt...
1560
2150
  ↗️ Done syncing assets
2151
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1561
2152
  Uploaded test-name (TIMINGS)
1562
2153
  Published test-name (TIMINGS)
1563
2154
  test-name.test-sub-domain.workers.dev"
@@ -1567,8 +2158,8 @@ export default{
1567
2158
 
1568
2159
  it("should use `site-exclude` arg over `site.exclude` config", async () => {
1569
2160
  const assets = [
1570
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1571
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
2161
+ { filePath: "file-1.txt", content: "Content of file-1" },
2162
+ { filePath: "file-2.txt", content: "Content of file-2" },
1572
2163
  ];
1573
2164
  const kvNamespace = {
1574
2165
  title: "__test-name-workers_sites_assets",
@@ -1578,7 +2169,7 @@ export default{
1578
2169
  main: "./index.js",
1579
2170
  site: {
1580
2171
  bucket: "assets",
1581
- exclude: ["assets/file-1.txt"],
2172
+ exclude: ["file-1.txt"],
1582
2173
  },
1583
2174
  });
1584
2175
  writeWorkerSource();
@@ -1590,14 +2181,15 @@ export default{
1590
2181
  // Check we only upload file-1
1591
2182
  mockUploadAssetsToKVRequest(
1592
2183
  kvNamespace.id,
1593
- assets.filter((a) => a.filePath.endsWith("assets/file-1.txt"))
2184
+ assets.filter((a) => a.filePath.endsWith("file-1.txt"))
1594
2185
  );
1595
2186
  await runWrangler("publish --site-exclude file-2.txt");
1596
2187
 
1597
2188
  expect(std.out).toMatchInlineSnapshot(`
1598
- "Reading assets/file-1.txt...
1599
- Uploading as assets/file-1.2ca234f380.txt...
2189
+ "Reading file-1.txt...
2190
+ Uploading as file-1.2ca234f380.txt...
1600
2191
  ↗️ Done syncing assets
2192
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1601
2193
  Uploaded test-name (TIMINGS)
1602
2194
  Published test-name (TIMINGS)
1603
2195
  test-name.test-sub-domain.workers.dev"
@@ -1608,11 +2200,11 @@ export default{
1608
2200
  it("should walk directories except node_modules", async () => {
1609
2201
  const assets = [
1610
2202
  {
1611
- filePath: "assets/directory-1/file-1.txt",
2203
+ filePath: "directory-1/file-1.txt",
1612
2204
  content: "Content of file-1",
1613
2205
  },
1614
2206
  {
1615
- filePath: "assets/node_modules/file-2.txt",
2207
+ filePath: "node_modules/file-2.txt",
1616
2208
  content: "Content of file-2",
1617
2209
  },
1618
2210
  ];
@@ -1637,9 +2229,10 @@ export default{
1637
2229
  await runWrangler("publish");
1638
2230
 
1639
2231
  expect(std.out).toMatchInlineSnapshot(`
1640
- "Reading assets/directory-1/file-1.txt...
1641
- Uploading as assets/directory-1/file-1.2ca234f380.txt...
2232
+ "Reading directory-1/file-1.txt...
2233
+ Uploading as directory-1/file-1.2ca234f380.txt...
1642
2234
  ↗️ Done syncing assets
2235
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1643
2236
  Uploaded test-name (TIMINGS)
1644
2237
  Published test-name (TIMINGS)
1645
2238
  test-name.test-sub-domain.workers.dev"
@@ -1650,15 +2243,15 @@ export default{
1650
2243
  it("should skip hidden files and directories except `.well-known`", async () => {
1651
2244
  const assets = [
1652
2245
  {
1653
- filePath: "assets/.hidden-file.txt",
2246
+ filePath: ".hidden-file.txt",
1654
2247
  content: "Content of hidden-file",
1655
2248
  },
1656
2249
  {
1657
- filePath: "assets/.hidden/file-1.txt",
2250
+ filePath: ".hidden/file-1.txt",
1658
2251
  content: "Content of file-1",
1659
2252
  },
1660
2253
  {
1661
- filePath: "assets/.well-known/file-2.txt",
2254
+ filePath: ".well-known/file-2.txt",
1662
2255
  content: "Content of file-2",
1663
2256
  },
1664
2257
  ];
@@ -1683,9 +2276,10 @@ export default{
1683
2276
  await runWrangler("publish");
1684
2277
 
1685
2278
  expect(std.out).toMatchInlineSnapshot(`
1686
- "Reading assets/.well-known/file-2.txt...
1687
- Uploading as assets/.well-known/file-2.5938485188.txt...
2279
+ "Reading .well-known/file-2.txt...
2280
+ Uploading as .well-known/file-2.5938485188.txt...
1688
2281
  ↗️ Done syncing assets
2282
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1689
2283
  Uploaded test-name (TIMINGS)
1690
2284
  Published test-name (TIMINGS)
1691
2285
  test-name.test-sub-domain.workers.dev"
@@ -1696,12 +2290,12 @@ export default{
1696
2290
  it("should error if the asset is over 25Mb", async () => {
1697
2291
  const assets = [
1698
2292
  {
1699
- filePath: "assets/large-file.txt",
2293
+ filePath: "large-file.txt",
1700
2294
  // This file is greater than 25MiB when base64 encoded but small enough to be uploaded.
1701
2295
  content: "X".repeat(25 * 1024 * 1024 * 0.8 + 1),
1702
2296
  },
1703
2297
  {
1704
- filePath: "assets/too-large-file.txt",
2298
+ filePath: "too-large-file.txt",
1705
2299
  content: "X".repeat(25 * 1024 * 1024 + 1),
1706
2300
  },
1707
2301
  ];
@@ -1713,7 +2307,7 @@ export default{
1713
2307
  main: "./index.js",
1714
2308
  site: {
1715
2309
  bucket: "assets",
1716
- exclude: ["assets/file-1.txt"],
2310
+ exclude: ["file-1.txt"],
1717
2311
  },
1718
2312
  });
1719
2313
  writeWorkerSource();
@@ -1726,25 +2320,123 @@ export default{
1726
2320
  await expect(
1727
2321
  runWrangler("publish")
1728
2322
  ).rejects.toThrowErrorMatchingInlineSnapshot(
1729
- `"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"`
2323
+ `"File too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits"`
1730
2324
  );
1731
2325
 
1732
2326
  expect(std.out).toMatchInlineSnapshot(`
1733
- "Reading assets/large-file.txt...
1734
- Uploading as assets/large-file.0ea0637a45.txt...
2327
+ "Reading large-file.txt...
2328
+ Uploading as large-file.0ea0637a45.txt...
2329
+ Reading too-large-file.txt...
1735
2330
 
1736
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2331
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1737
2332
  `);
1738
2333
  expect(std.err).toMatchInlineSnapshot(`
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
2334
+ "X [ERROR] File too-large-file.txt is too big, it should be under 25 MiB. See https://developers.cloudflare.com/workers/platform/limits#kv-limits
1740
2335
 
1741
2336
  "
1742
2337
  `);
1743
2338
  });
1744
2339
 
2340
+ it("should batch assets in groups <100 mb", async () => {
2341
+ // Let's have 20 files, from size 1 - 20 mb
2342
+ const assets = Array.from({ length: 20 }, (_, index) => ({
2343
+ filePath: `file-${`${index}`.padStart(2, "0")}.txt`,
2344
+ content: "X".repeat(1024 * 1024 * (index + 1)),
2345
+ }));
2346
+
2347
+ const kvNamespace = {
2348
+ title: "__test-name-workers_sites_assets",
2349
+ id: "__test-name-workers_sites_assets-id",
2350
+ };
2351
+ writeWranglerToml({
2352
+ main: "./index.js",
2353
+ site: {
2354
+ bucket: "assets",
2355
+ },
2356
+ });
2357
+ writeWorkerSource();
2358
+ writeAssets(assets);
2359
+ mockUploadWorkerRequest();
2360
+ mockSubDomainRequest();
2361
+ mockListKVNamespacesRequest(kvNamespace);
2362
+ mockKeyListRequest(kvNamespace.id, []);
2363
+ const requests = mockUploadAssetsToKVRequest(kvNamespace.id);
2364
+
2365
+ await runWrangler("publish");
2366
+
2367
+ // We expect this to be uploaded in 3 batches
2368
+ // The first batch has 11 files (88mb)
2369
+ expect(requests[0].uploads.length).toEqual(11);
2370
+ // The next batch has 5 files (93mb)
2371
+ expect(requests[1].uploads.length).toEqual(5);
2372
+ // And the last one has 4 files (98mb)
2373
+ expect(requests[2].uploads.length).toEqual(4);
2374
+
2375
+ let assetIndex = 0;
2376
+ for (const request of requests) {
2377
+ for (const upload of request.uploads) {
2378
+ checkAssetUpload(assets[assetIndex], upload);
2379
+ assetIndex++;
2380
+ }
2381
+ }
2382
+
2383
+ expect(std).toMatchInlineSnapshot(`
2384
+ Object {
2385
+ "debug": "",
2386
+ "err": "",
2387
+ "out": "Reading file-00.txt...
2388
+ Uploading as file-00.be5be5dd26.txt...
2389
+ Reading file-01.txt...
2390
+ Uploading as file-01.4842d35994.txt...
2391
+ Reading file-02.txt...
2392
+ Uploading as file-02.990572ec63.txt...
2393
+ Reading file-03.txt...
2394
+ Uploading as file-03.9d7dda9045.txt...
2395
+ Reading file-04.txt...
2396
+ Uploading as file-04.2b6fac6382.txt...
2397
+ Reading file-05.txt...
2398
+ Uploading as file-05.55762dc758.txt...
2399
+ Reading file-06.txt...
2400
+ Uploading as file-06.f408a6b020.txt...
2401
+ Reading file-07.txt...
2402
+ Uploading as file-07.64c051715b.txt...
2403
+ Reading file-08.txt...
2404
+ Uploading as file-08.d286789adb.txt...
2405
+ Reading file-09.txt...
2406
+ Uploading as file-09.6838c183a8.txt...
2407
+ Reading file-10.txt...
2408
+ Uploading as file-10.6e03221d2a.txt...
2409
+ Reading file-11.txt...
2410
+ Uploading as file-11.37d3fb2eff.txt...
2411
+ Reading file-12.txt...
2412
+ Uploading as file-12.b3556942f8.txt...
2413
+ Reading file-13.txt...
2414
+ Uploading as file-13.680caf51b1.txt...
2415
+ Reading file-14.txt...
2416
+ Uploading as file-14.51e88468f0.txt...
2417
+ Reading file-15.txt...
2418
+ Uploading as file-15.8e3fedb394.txt...
2419
+ Reading file-16.txt...
2420
+ Uploading as file-16.c81c5e426f.txt...
2421
+ Reading file-17.txt...
2422
+ Uploading as file-17.4b2ae3c47b.txt...
2423
+ Reading file-18.txt...
2424
+ Uploading as file-18.07f245e02b.txt...
2425
+ Reading file-19.txt...
2426
+ Uploading as file-19.f0d69f705d.txt...
2427
+ ↗️ Done syncing assets
2428
+ Total Upload: 1xx KiB / gzip: 0xx KiB
2429
+ Uploaded test-name (TIMINGS)
2430
+ Published test-name (TIMINGS)
2431
+ test-name.test-sub-domain.workers.dev",
2432
+ "warn": "",
2433
+ }
2434
+ `);
2435
+ });
2436
+
1745
2437
  it("should error if the asset key is over 512 characters", async () => {
1746
2438
  const longFilePathAsset = {
1747
- filePath: "assets/" + "folder/".repeat(100) + "file.txt",
2439
+ filePath: "folder/".repeat(100) + "file.txt",
1748
2440
  content: "content of file",
1749
2441
  };
1750
2442
  const kvNamespace = {
@@ -1767,16 +2459,16 @@ export default{
1767
2459
  await expect(
1768
2460
  runWrangler("publish")
1769
2461
  ).rejects.toThrowErrorMatchingInlineSnapshot(
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\\","`
2462
+ `"The asset path key \\"folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/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\\","`
1771
2463
  );
1772
2464
 
1773
2465
  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...
2466
+ "Reading folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/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
2467
 
1776
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2468
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1777
2469
  `);
1778
2470
  expect(std.err).toMatchInlineSnapshot(`
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\\",
2471
+ "X [ERROR] The asset path key \\"folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/folder/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\\",
1780
2472
 
1781
2473
  "
1782
2474
  `);
@@ -1784,8 +2476,8 @@ export default{
1784
2476
 
1785
2477
  it("should delete uploaded assets that aren't included anymore", async () => {
1786
2478
  const assets = [
1787
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1788
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
2479
+ { filePath: "file-1.txt", content: "Content of file-1" },
2480
+ { filePath: "file-2.txt", content: "Content of file-2" },
1789
2481
  ];
1790
2482
  const kvNamespace = {
1791
2483
  title: "__test-name-workers_sites_assets",
@@ -1804,33 +2496,89 @@ export default{
1804
2496
  mockListKVNamespacesRequest(kvNamespace);
1805
2497
  mockKeyListRequest(kvNamespace.id, [
1806
2498
  // Put file-1 in the KV namespace
1807
- { name: "assets/file-1.2ca234f380.txt" },
2499
+ { name: "file-1.2ca234f380.txt" },
1808
2500
  // As well as a couple from a previous upload
1809
- { name: "assets/file-3.somehash.txt" },
1810
- { name: "assets/file-4.anotherhash.txt" },
2501
+ { name: "file-3.somehash.txt" },
2502
+ { name: "file-4.anotherhash.txt" },
1811
2503
  ]);
1812
2504
 
1813
2505
  // we upload only file-1.txt
1814
- mockUploadAssetsToKVRequest(kvNamespace.id, [
1815
- ...assets.filter((a) => a.filePath !== "assets/file-1.txt"),
1816
- ]);
2506
+ mockUploadAssetsToKVRequest(
2507
+ kvNamespace.id,
2508
+ assets.filter((a) => a.filePath !== "file-1.txt")
2509
+ );
1817
2510
 
1818
2511
  // and mark file-3 and file-4 for deletion
1819
2512
  mockDeleteUnusedAssetsRequest(kvNamespace.id, [
1820
- "assets/file-3.somehash.txt",
1821
- "assets/file-4.anotherhash.txt",
2513
+ "file-3.somehash.txt",
2514
+ "file-4.anotherhash.txt",
1822
2515
  ]);
1823
2516
 
1824
2517
  await runWrangler("publish");
1825
2518
 
1826
2519
  expect(std.out).toMatchInlineSnapshot(`
1827
- "Reading assets/file-1.txt...
2520
+ "Reading file-1.txt...
1828
2521
  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...
2522
+ Reading file-2.txt...
2523
+ Uploading as file-2.5938485188.txt...
2524
+ Deleting file-3.somehash.txt from the asset store...
2525
+ Deleting file-4.anotherhash.txt from the asset store...
2526
+ ↗️ Done syncing assets
2527
+ Total Upload: 0xx KiB / gzip: 0xx KiB
2528
+ Uploaded test-name (TIMINGS)
2529
+ Published test-name (TIMINGS)
2530
+ test-name.test-sub-domain.workers.dev"
2531
+ `);
2532
+ expect(std.err).toMatchInlineSnapshot(`""`);
2533
+ });
2534
+
2535
+ it("should generate an asset manifest with keys relative to site.bucket", async () => {
2536
+ const assets = [
2537
+ { filePath: "file-1.txt", content: "Content of file-1" },
2538
+ { filePath: "file-2.txt", content: "Content of file-2" },
2539
+ ];
2540
+ const kvNamespace = {
2541
+ title: "__test-name-workers_sites_assets",
2542
+ id: "__test-name-workers_sites_assets-id",
2543
+ };
2544
+
2545
+ writeWranglerToml({
2546
+ main: "./src/index.js",
2547
+ site: {
2548
+ bucket: "assets",
2549
+ },
2550
+ });
2551
+ writeWorkerSource({ basePath: "src", type: "esm" });
2552
+ writeAssets(assets);
2553
+ mockUploadWorkerRequest({
2554
+ expectedBindings: [
2555
+ {
2556
+ name: "__STATIC_CONTENT",
2557
+ namespace_id: "__test-name-workers_sites_assets-id",
2558
+ type: "kv_namespace",
2559
+ },
2560
+ ],
2561
+ expectedModules: {
2562
+ __STATIC_CONTENT_MANIFEST:
2563
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
2564
+ },
2565
+ });
2566
+ mockSubDomainRequest();
2567
+ mockListKVNamespacesRequest(kvNamespace);
2568
+ mockKeyListRequest(kvNamespace.id, []);
2569
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
2570
+
2571
+ process.chdir("./src");
2572
+ await runWrangler("publish");
2573
+ process.chdir("../");
2574
+
2575
+ expect(std.out).toMatchInlineSnapshot(`
2576
+ "Reading file-1.txt...
2577
+ Uploading as file-1.2ca234f380.txt...
2578
+ Reading file-2.txt...
2579
+ Uploading as file-2.5938485188.txt...
1833
2580
  ↗️ Done syncing assets
2581
+ Total Upload: 0xx KiB / gzip: 0xx KiB
1834
2582
  Uploaded test-name (TIMINGS)
1835
2583
  Published test-name (TIMINGS)
1836
2584
  test-name.test-sub-domain.workers.dev"
@@ -1849,7 +2597,8 @@ export default{
1849
2597
  await runWrangler("publish ./index");
1850
2598
 
1851
2599
  expect(std.out).toMatchInlineSnapshot(`
1852
- "Uploaded test-name (TIMINGS)
2600
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2601
+ Uploaded test-name (TIMINGS)
1853
2602
  Published test-name (TIMINGS)
1854
2603
  test-name.test-sub-domain.workers.dev"
1855
2604
  `);
@@ -1868,7 +2617,8 @@ export default{
1868
2617
  await runWrangler("publish ./index");
1869
2618
 
1870
2619
  expect(std.out).toMatchInlineSnapshot(`
1871
- "Uploaded test-name (TIMINGS)
2620
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2621
+ Uploaded test-name (TIMINGS)
1872
2622
  Published test-name (TIMINGS)
1873
2623
  test-name.test-sub-domain.workers.dev"
1874
2624
  `);
@@ -1886,7 +2636,8 @@ export default{
1886
2636
  await runWrangler("publish ./index");
1887
2637
 
1888
2638
  expect(std.out).toMatchInlineSnapshot(`
1889
- "Uploaded test-name (TIMINGS)
2639
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2640
+ Uploaded test-name (TIMINGS)
1890
2641
  Published test-name (TIMINGS)
1891
2642
  test-name.test-sub-domain.workers.dev"
1892
2643
  `);
@@ -1904,7 +2655,8 @@ export default{
1904
2655
  await runWrangler("publish ./index");
1905
2656
 
1906
2657
  expect(std.out).toMatchInlineSnapshot(`
1907
- "Uploaded test-name (TIMINGS)
2658
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2659
+ Uploaded test-name (TIMINGS)
1908
2660
  No publish targets for test-name (TIMINGS)"
1909
2661
  `);
1910
2662
  expect(std.err).toMatchInlineSnapshot(`""`);
@@ -1923,7 +2675,8 @@ export default{
1923
2675
  await runWrangler("publish ./index");
1924
2676
 
1925
2677
  expect(std.out).toMatchInlineSnapshot(`
1926
- "Uploaded test-name (TIMINGS)
2678
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2679
+ Uploaded test-name (TIMINGS)
1927
2680
  No publish targets for test-name (TIMINGS)"
1928
2681
  `);
1929
2682
  expect(std.err).toMatchInlineSnapshot(`""`);
@@ -1946,7 +2699,8 @@ export default{
1946
2699
  await runWrangler("publish ./index --env dev --legacy-env false");
1947
2700
 
1948
2701
  expect(std.out).toMatchInlineSnapshot(`
1949
- "Uploaded test-name (dev) (TIMINGS)
2702
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2703
+ Uploaded test-name (dev) (TIMINGS)
1950
2704
  No publish targets for test-name (dev) (TIMINGS)"
1951
2705
  `);
1952
2706
  expect(std.err).toMatchInlineSnapshot(`""`);
@@ -1970,7 +2724,8 @@ export default{
1970
2724
  await runWrangler("publish ./index --env dev --legacy-env false");
1971
2725
 
1972
2726
  expect(std.out).toMatchInlineSnapshot(`
1973
- "Uploaded test-name (dev) (TIMINGS)
2727
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2728
+ Uploaded test-name (dev) (TIMINGS)
1974
2729
  No publish targets for test-name (dev) (TIMINGS)"
1975
2730
  `);
1976
2731
  expect(std.err).toMatchInlineSnapshot(`""`);
@@ -1994,7 +2749,8 @@ export default{
1994
2749
  await runWrangler("publish ./index --env dev --legacy-env false");
1995
2750
 
1996
2751
  expect(std.out).toMatchInlineSnapshot(`
1997
- "Uploaded test-name (dev) (TIMINGS)
2752
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2753
+ Uploaded test-name (dev) (TIMINGS)
1998
2754
  Published test-name (dev) (TIMINGS)
1999
2755
  dev.test-name.test-sub-domain.workers.dev"
2000
2756
  `);
@@ -2020,7 +2776,8 @@ export default{
2020
2776
  await runWrangler("publish ./index --env dev --legacy-env false");
2021
2777
 
2022
2778
  expect(std.out).toMatchInlineSnapshot(`
2023
- "Uploaded test-name (dev) (TIMINGS)
2779
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2780
+ Uploaded test-name (dev) (TIMINGS)
2024
2781
  Published test-name (dev) (TIMINGS)
2025
2782
  dev.test-name.test-sub-domain.workers.dev"
2026
2783
  `);
@@ -2047,7 +2804,8 @@ export default{
2047
2804
  await runWrangler("publish ./index --env dev --legacy-env false");
2048
2805
 
2049
2806
  expect(std.out).toMatchInlineSnapshot(`
2050
- "Uploaded test-name (dev) (TIMINGS)
2807
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2808
+ Uploaded test-name (dev) (TIMINGS)
2051
2809
  Published test-name (dev) (TIMINGS)
2052
2810
  dev.test-name.test-sub-domain.workers.dev"
2053
2811
  `);
@@ -2077,7 +2835,8 @@ export default{
2077
2835
  await runWrangler("publish ./index --env dev --legacy-env false");
2078
2836
 
2079
2837
  expect(std.out).toMatchInlineSnapshot(`
2080
- "Uploaded test-name (dev) (TIMINGS)
2838
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2839
+ Uploaded test-name (dev) (TIMINGS)
2081
2840
  Published test-name (dev) (TIMINGS)
2082
2841
  dev.test-name.test-sub-domain.workers.dev"
2083
2842
  `);
@@ -2109,13 +2868,33 @@ export default{
2109
2868
  );
2110
2869
 
2111
2870
  expect(std.out).toMatchInlineSnapshot(`
2112
- "Uploaded test-name (dev) (TIMINGS)
2871
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2872
+ Uploaded test-name (dev) (TIMINGS)
2113
2873
  Published test-name (dev) (TIMINGS)
2114
2874
  dev.test-name.test-sub-domain.workers.dev"
2115
2875
  `);
2116
2876
  expect(std.err).toMatchInlineSnapshot(`""`);
2117
2877
  });
2118
2878
 
2879
+ it("should error if a compatibility_date is not available in wrangler.toml or cli args", async () => {
2880
+ writeWorkerSource();
2881
+ let err: undefined | Error;
2882
+ try {
2883
+ await runWrangler("publish ./index.js");
2884
+ } catch (e) {
2885
+ err = e as Error;
2886
+ }
2887
+
2888
+ expect(err?.message.replaceAll(/\d/g, "X")).toMatchInlineSnapshot(`
2889
+ "A compatibility_date is required when publishing. Add the following to your wrangler.toml file:.
2890
+ \`\`\`
2891
+ compatibility_date = \\"XXXX-XX-XX\\"
2892
+ \`\`\`
2893
+ Or you could pass it in your terminal as \`--compatibility-date XXXX-XX-XX\`
2894
+ See https://developers.cloudflare.com/workers/platform/compatibility-dates for more information."
2895
+ `);
2896
+ });
2897
+
2119
2898
  it("should enable the workers.dev domain if workers_dev is undefined and subdomain is not already available", async () => {
2120
2899
  writeWranglerToml();
2121
2900
  writeWorkerSource();
@@ -2126,7 +2905,8 @@ export default{
2126
2905
  await runWrangler("publish ./index");
2127
2906
 
2128
2907
  expect(std.out).toMatchInlineSnapshot(`
2129
- "Uploaded test-name (TIMINGS)
2908
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2909
+ Uploaded test-name (TIMINGS)
2130
2910
  Published test-name (TIMINGS)
2131
2911
  test-name.test-sub-domain.workers.dev"
2132
2912
  `);
@@ -2143,7 +2923,8 @@ export default{
2143
2923
  await runWrangler("publish ./index");
2144
2924
 
2145
2925
  expect(std.out).toMatchInlineSnapshot(`
2146
- "Uploaded test-name (TIMINGS)
2926
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2927
+ Uploaded test-name (TIMINGS)
2147
2928
  Published test-name (TIMINGS)
2148
2929
  test-name.test-sub-domain.workers.dev"
2149
2930
  `);
@@ -2180,7 +2961,8 @@ export default{
2180
2961
  await runWrangler("publish index.js");
2181
2962
 
2182
2963
  expect(std.out).toMatchInlineSnapshot(`
2183
- "Uploaded test-name (TIMINGS)
2964
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2965
+ Uploaded test-name (TIMINGS)
2184
2966
  Published test-name (TIMINGS)
2185
2967
  http://example.com/*"
2186
2968
  `);
@@ -2213,7 +2995,8 @@ export default{
2213
2995
  await runWrangler("publish index.js --env production");
2214
2996
 
2215
2997
  expect(std.out).toMatchInlineSnapshot(`
2216
- "Uploaded test-name-production (TIMINGS)
2998
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
2999
+ Uploaded test-name-production (TIMINGS)
2217
3000
  Published test-name-production (TIMINGS)
2218
3001
  http://production.example.com/*"
2219
3002
  `);
@@ -2245,7 +3028,8 @@ export default{
2245
3028
  await runWrangler("publish index.js --env production");
2246
3029
 
2247
3030
  expect(std.out).toMatchInlineSnapshot(`
2248
- "Uploaded test-name-production (TIMINGS)
3031
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
3032
+ Uploaded test-name-production (TIMINGS)
2249
3033
  Published test-name-production (TIMINGS)
2250
3034
  http://production.example.com/*"
2251
3035
  `);
@@ -2270,7 +3054,8 @@ export default{
2270
3054
  await runWrangler("publish index.js");
2271
3055
 
2272
3056
  expect(std.out).toMatchInlineSnapshot(`
2273
- "Uploaded test-name (TIMINGS)
3057
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
3058
+ Uploaded test-name (TIMINGS)
2274
3059
  Published test-name (TIMINGS)
2275
3060
  test-name.test-sub-domain.workers.dev
2276
3061
  http://example.com/*"
@@ -2304,7 +3089,8 @@ export default{
2304
3089
  await runWrangler("publish index.js --env production");
2305
3090
 
2306
3091
  expect(std.out).toMatchInlineSnapshot(`
2307
- "Uploaded test-name-production (TIMINGS)
3092
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
3093
+ Uploaded test-name-production (TIMINGS)
2308
3094
  Published test-name-production (TIMINGS)
2309
3095
  test-name-production.test-sub-domain.workers.dev
2310
3096
  http://production.example.com/*"
@@ -2338,7 +3124,8 @@ export default{
2338
3124
  await runWrangler("publish index.js --env production");
2339
3125
 
2340
3126
  expect(std.out).toMatchInlineSnapshot(`
2341
- "Uploaded test-name-production (TIMINGS)
3127
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
3128
+ Uploaded test-name-production (TIMINGS)
2342
3129
  Published test-name-production (TIMINGS)
2343
3130
  test-name-production.test-sub-domain.workers.dev
2344
3131
  http://production.example.com/*"
@@ -2372,7 +3159,8 @@ export default{
2372
3159
  await runWrangler("publish index.js --env production");
2373
3160
 
2374
3161
  expect(std.out).toMatchInlineSnapshot(`
2375
- "Uploaded test-name-production (TIMINGS)
3162
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
3163
+ Uploaded test-name-production (TIMINGS)
2376
3164
  Published test-name-production (TIMINGS)
2377
3165
  http://production.example.com/*"
2378
3166
  `);
@@ -2405,7 +3193,8 @@ export default{
2405
3193
  await runWrangler("publish index.js --env production");
2406
3194
 
2407
3195
  expect(std.out).toMatchInlineSnapshot(`
2408
- "Uploaded test-name-production (TIMINGS)
3196
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
3197
+ Uploaded test-name-production (TIMINGS)
2409
3198
  Published test-name-production (TIMINGS)
2410
3199
  http://production.example.com/*"
2411
3200
  `);
@@ -2435,6 +3224,7 @@ export default{
2435
3224
  await runWrangler("publish index.js");
2436
3225
  expect(std.out).toMatchInlineSnapshot(`
2437
3226
  "Running custom build: node -e \\"console.log('custom build'); require('fs').writeFileSync('index.js', 'export default { fetch(){ return new Response(123) } }')\\"
3227
+ Total Upload: 0xx KiB / gzip: 0xx KiB
2438
3228
  Uploaded test-name (TIMINGS)
2439
3229
  Published test-name (TIMINGS)
2440
3230
  test-name.test-sub-domain.workers.dev"
@@ -2459,6 +3249,7 @@ export default{
2459
3249
  await runWrangler("publish index.js");
2460
3250
  expect(std.out).toMatchInlineSnapshot(`
2461
3251
  "Running custom build: echo \\"custom build\\" && echo \\"export default { fetch(){ return new Response(123) } }\\" > index.js
3252
+ Total Upload: 0xx KiB / gzip: 0xx KiB
2462
3253
  Uploaded test-name (TIMINGS)
2463
3254
  Published test-name (TIMINGS)
2464
3255
  test-name.test-sub-domain.workers.dev"
@@ -2476,18 +3267,66 @@ export default{
2476
3267
  },
2477
3268
  });
2478
3269
 
2479
- await expect(
2480
- runWrangler("publish index.js")
2481
- ).rejects.toThrowErrorMatchingInlineSnapshot(
2482
- `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
2483
- );
3270
+ await expect(runWrangler("publish index.js")).rejects
3271
+ .toThrowErrorMatchingInlineSnapshot(`
3272
+ "The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
3273
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build."
3274
+ `);
3275
+ expect(std.out).toMatchInlineSnapshot(`
3276
+ "Running custom build: node -e \\"console.log('custom build');\\"
3277
+
3278
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3279
+ `);
3280
+ expect(std.err).toMatchInlineSnapshot(`
3281
+ "X [ERROR] The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
3282
+
3283
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
3284
+
3285
+ "
3286
+ `);
3287
+ expect(std.warn).toMatchInlineSnapshot(`""`);
3288
+ });
3289
+
3290
+ it("should throw an error if the entry is a directory after the build finishes", async () => {
3291
+ writeWranglerToml({
3292
+ main: "./",
3293
+ build: {
3294
+ command: `node -e "console.log('custom build');"`,
3295
+ },
3296
+ });
3297
+
3298
+ fs.writeFileSync("./worker.js", "some content", "utf-8");
3299
+ fs.mkdirSync("./dist");
3300
+ fs.writeFileSync("./dist/index.ts", "some content", "utf-8");
3301
+
3302
+ await expect(runWrangler("publish")).rejects
3303
+ .toThrowErrorMatchingInlineSnapshot(`
3304
+ "The expected output file at \\".\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
3305
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
3306
+ The provided entry-point path, \\".\\", points to a directory, rather than a file.
3307
+
3308
+ Did you mean to set the main field to one of:
3309
+ \`\`\`
3310
+ main = \\"./worker.js\\"
3311
+ main = \\"./dist/index.ts\\"
3312
+ \`\`\`"
3313
+ `);
2484
3314
  expect(std.out).toMatchInlineSnapshot(`
2485
3315
  "Running custom build: node -e \\"console.log('custom build');\\"
2486
3316
 
2487
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3317
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
2488
3318
  `);
2489
3319
  expect(std.err).toMatchInlineSnapshot(`
2490
- "X [ERROR] Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
3320
+ "X [ERROR] The expected output file at \\".\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
3321
+
3322
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
3323
+ The provided entry-point path, \\".\\", points to a directory, rather than a file.
3324
+
3325
+ Did you mean to set the main field to one of:
3326
+ \`\`\`
3327
+ main = \\"./worker.js\\"
3328
+ main = \\"./dist/index.ts\\"
3329
+ \`\`\`
2491
3330
 
2492
3331
  "
2493
3332
  `);
@@ -2516,7 +3355,8 @@ export default{
2516
3355
  mockSubDomainRequest();
2517
3356
  await runWrangler("publish index.js --minify");
2518
3357
  expect(std.out).toMatchInlineSnapshot(`
2519
- "Uploaded test-name (TIMINGS)
3358
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
3359
+ Uploaded test-name (TIMINGS)
2520
3360
  Published test-name (TIMINGS)
2521
3361
  test-name.test-sub-domain.workers.dev"
2522
3362
  `);
@@ -2554,7 +3394,8 @@ export default{
2554
3394
  mockSubDomainRequest();
2555
3395
  await runWrangler("publish -e testEnv index.js");
2556
3396
  expect(std.out).toMatchInlineSnapshot(`
2557
- "Uploaded test-name (testEnv) (TIMINGS)
3397
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
3398
+ Uploaded test-name (testEnv) (TIMINGS)
2558
3399
  Published test-name (testEnv) (TIMINGS)
2559
3400
  testEnv.test-name.test-sub-domain.workers.dev"
2560
3401
  `);
@@ -2577,13 +3418,31 @@ export default{
2577
3418
  mockUploadWorkerRequest();
2578
3419
  await runWrangler("publish index.js");
2579
3420
  expect(std.out).toMatchInlineSnapshot(`
2580
- "Uploaded test-name (TIMINGS)
3421
+ "Your worker has access to the following bindings:
3422
+ - Durable Objects:
3423
+ - SOMENAME: SomeClass
3424
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3425
+ Uploaded test-name (TIMINGS)
2581
3426
  Published test-name (TIMINGS)
2582
3427
  test-name.test-sub-domain.workers.dev"
2583
3428
  `);
2584
3429
  expect(std.err).toMatchInlineSnapshot(`""`);
2585
3430
  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.
3431
+ "▲ [WARNING] Processing wrangler.toml configuration:
3432
+
3433
+ - In wrangler.toml, you have configured [durable_objects] exported by this Worker (SomeClass),
3434
+ but no [migrations] for them. This may not work as expected until you add a [migrations] section
3435
+ to your wrangler.toml. Add this configuration to your wrangler.toml:
3436
+
3437
+ \`\`\`
3438
+ [[migrations]]
3439
+ tag = \\"v1\\" # Should be unique for each entry
3440
+ new_classes = [\\"SomeClass\\"]
3441
+ \`\`\`
3442
+
3443
+ Refer to
3444
+ https://developers.cloudflare.com/workers/learning/using-durable-objects/#durable-object-migrations-in-wranglertoml
3445
+ for more details.
2587
3446
 
2588
3447
  "
2589
3448
  `);
@@ -2609,7 +3468,11 @@ export default{
2609
3468
  mockUploadWorkerRequest();
2610
3469
  await runWrangler("publish index.js");
2611
3470
  expect(std.out).toMatchInlineSnapshot(`
2612
- "Uploaded test-name (TIMINGS)
3471
+ "Your worker has access to the following bindings:
3472
+ - Durable Objects:
3473
+ - SOMENAME: SomeClass (defined in some-script)
3474
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3475
+ Uploaded test-name (TIMINGS)
2613
3476
  Published test-name (TIMINGS)
2614
3477
  test-name.test-sub-domain.workers.dev"
2615
3478
  `);
@@ -2648,7 +3511,12 @@ export default{
2648
3511
 
2649
3512
  await runWrangler("publish index.js");
2650
3513
  expect(std.out).toMatchInlineSnapshot(`
2651
- "Uploaded test-name (TIMINGS)
3514
+ "Your worker has access to the following bindings:
3515
+ - Durable Objects:
3516
+ - SOMENAME: SomeClass
3517
+ - SOMEOTHERNAME: SomeOtherClass
3518
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3519
+ Uploaded test-name (TIMINGS)
2652
3520
  Published test-name (TIMINGS)
2653
3521
  test-name.test-sub-domain.workers.dev"
2654
3522
  `);
@@ -2694,7 +3562,12 @@ export default{
2694
3562
  Object {
2695
3563
  "debug": "",
2696
3564
  "err": "",
2697
- "out": "Uploaded test-name (TIMINGS)
3565
+ "out": "Your worker has access to the following bindings:
3566
+ - Durable Objects:
3567
+ - SOMENAME: SomeClass
3568
+ - SOMEOTHERNAME: SomeOtherClass
3569
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3570
+ Uploaded test-name (TIMINGS)
2698
3571
  Published test-name (TIMINGS)
2699
3572
  test-name.test-sub-domain.workers.dev",
2700
3573
  "warn": "",
@@ -2733,7 +3606,12 @@ export default{
2733
3606
  Object {
2734
3607
  "debug": "",
2735
3608
  "err": "",
2736
- "out": "Uploaded test-name (TIMINGS)
3609
+ "out": "Your worker has access to the following bindings:
3610
+ - Durable Objects:
3611
+ - SOMENAME: SomeClass
3612
+ - SOMEOTHERNAME: SomeOtherClass
3613
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3614
+ Uploaded test-name (TIMINGS)
2737
3615
  Published test-name (TIMINGS)
2738
3616
  test-name.test-sub-domain.workers.dev",
2739
3617
  "warn": "",
@@ -2774,7 +3652,12 @@ export default{
2774
3652
 
2775
3653
  await runWrangler("publish index.js --legacy-env false");
2776
3654
  expect(std.out).toMatchInlineSnapshot(`
2777
- "Uploaded test-name (TIMINGS)
3655
+ "Your worker has access to the following bindings:
3656
+ - Durable Objects:
3657
+ - SOMENAME: SomeClass
3658
+ - SOMEOTHERNAME: SomeOtherClass
3659
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3660
+ Uploaded test-name (TIMINGS)
2778
3661
  Published test-name (TIMINGS)
2779
3662
  test-name.test-sub-domain.workers.dev"
2780
3663
  `);
@@ -2832,7 +3715,12 @@ export default{
2832
3715
 
2833
3716
  await runWrangler("publish index.js --legacy-env false --env xyz");
2834
3717
  expect(std.out).toMatchInlineSnapshot(`
2835
- "Uploaded test-name (xyz) (TIMINGS)
3718
+ "Your worker has access to the following bindings:
3719
+ - Durable Objects:
3720
+ - SOMENAME: SomeClass
3721
+ - SOMEOTHERNAME: SomeOtherClass
3722
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3723
+ Uploaded test-name (xyz) (TIMINGS)
2836
3724
  Published test-name (xyz) (TIMINGS)
2837
3725
  xyz.test-name.test-sub-domain.workers.dev"
2838
3726
  `);
@@ -2886,7 +3774,12 @@ export default{
2886
3774
  Object {
2887
3775
  "debug": "",
2888
3776
  "err": "",
2889
- "out": "Uploaded test-name (TIMINGS)
3777
+ "out": "Your worker has access to the following bindings:
3778
+ - Durable Objects:
3779
+ - SOMENAME: SomeClass
3780
+ - SOMEOTHERNAME: SomeOtherClass
3781
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3782
+ Uploaded test-name (TIMINGS)
2890
3783
  Published test-name (TIMINGS)
2891
3784
  test-name.test-sub-domain.workers.dev",
2892
3785
  "warn": "▲ [WARNING] Processing wrangler.toml configuration:
@@ -2950,7 +3843,12 @@ export default{
2950
3843
  Object {
2951
3844
  "debug": "",
2952
3845
  "err": "",
2953
- "out": "Uploaded test-name (xyz) (TIMINGS)
3846
+ "out": "Your worker has access to the following bindings:
3847
+ - Durable Objects:
3848
+ - SOMENAME: SomeClass
3849
+ - SOMEOTHERNAME: SomeOtherClass
3850
+ Total Upload: 0xx KiB / gzip: 0xx KiB
3851
+ Uploaded test-name (xyz) (TIMINGS)
2954
3852
  Published test-name (xyz) (TIMINGS)
2955
3853
  xyz.test-name.test-sub-domain.workers.dev",
2956
3854
  "warn": "▲ [WARNING] Processing wrangler.toml configuration:
@@ -2985,6 +3883,7 @@ export default{
2985
3883
  name: "DURABLE_OBJECT_TWO",
2986
3884
  class_name: "AnotherDurableObject",
2987
3885
  script_name: "another-durable-object-worker",
3886
+ environment: "staging",
2988
3887
  },
2989
3888
  ],
2990
3889
  },
@@ -3043,6 +3942,12 @@ export default{
3043
3942
  mockUploadWorkerRequest({
3044
3943
  expectedType: "sw",
3045
3944
  expectedBindings: [
3945
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
3946
+ {
3947
+ name: "ENV_VAR_TWO",
3948
+ text: "Hello, I'm an environment variable",
3949
+ type: "plain_text",
3950
+ },
3046
3951
  {
3047
3952
  name: "KV_NAMESPACE_ONE",
3048
3953
  namespace_id: "kv-ns-one-id",
@@ -3061,6 +3966,7 @@ export default{
3061
3966
  },
3062
3967
  {
3063
3968
  class_name: "AnotherDurableObject",
3969
+ environment: "staging",
3064
3970
  name: "DURABLE_OBJECT_TWO",
3065
3971
  script_name: "another-durable-object-worker",
3066
3972
  type: "durable_object_namespace",
@@ -3075,12 +3981,6 @@ export default{
3075
3981
  name: "R2_BUCKET_TWO",
3076
3982
  type: "r2_bucket",
3077
3983
  },
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
3984
  {
3085
3985
  name: "WASM_MODULE_ONE",
3086
3986
  part: "WASM_MODULE_ONE",
@@ -3112,7 +4012,33 @@ export default{
3112
4012
 
3113
4013
  await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
3114
4014
  expect(std.out).toMatchInlineSnapshot(`
3115
- "Uploaded test-name (TIMINGS)
4015
+ "Your worker has access to the following bindings:
4016
+ - Data Blobs:
4017
+ - DATA_BLOB_ONE: some-data-blob.bin
4018
+ - DATA_BLOB_TWO: more-data-blob.bin
4019
+ - Durable Objects:
4020
+ - DURABLE_OBJECT_ONE: SomeDurableObject (defined in some-durable-object-worker)
4021
+ - DURABLE_OBJECT_TWO: AnotherDurableObject (defined in another-durable-object-worker) - staging
4022
+ - KV Namespaces:
4023
+ - KV_NAMESPACE_ONE: kv-ns-one-id
4024
+ - KV_NAMESPACE_TWO: kv-ns-two-id
4025
+ - R2 Buckets:
4026
+ - R2_BUCKET_ONE: r2-bucket-one-name
4027
+ - R2_BUCKET_TWO: r2-bucket-two-name
4028
+ - Text Blobs:
4029
+ - TEXT_BLOB_ONE: my-entire-app-depends-on-this.cfg
4030
+ - TEXT_BLOB_TWO: the-entirety-of-human-knowledge.txt
4031
+ - Unsafe:
4032
+ - some unsafe thing: UNSAFE_BINDING_ONE
4033
+ - another unsafe thing: UNSAFE_BINDING_TWO
4034
+ - Vars:
4035
+ - ENV_VAR_ONE: \\"123\\"
4036
+ - ENV_VAR_TWO: \\"Hello, I'm an environment variable\\"
4037
+ - Wasm Modules:
4038
+ - WASM_MODULE_ONE: some_wasm.wasm
4039
+ - WASM_MODULE_TWO: more_wasm.wasm
4040
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4041
+ Uploaded test-name (TIMINGS)
3116
4042
  Published test-name (TIMINGS)
3117
4043
  test-name.test-sub-domain.workers.dev"
3118
4044
  `);
@@ -3209,7 +4135,7 @@ export default{
3209
4135
  `);
3210
4136
  expect(std.out).toMatchInlineSnapshot(`
3211
4137
  "
3212
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4138
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3213
4139
  `);
3214
4140
  expect(std.err).toMatchInlineSnapshot(`
3215
4141
  "X [ERROR] Processing wrangler.toml configuration:
@@ -3308,7 +4234,7 @@ export default{
3308
4234
  `);
3309
4235
  expect(std.out).toMatchInlineSnapshot(`
3310
4236
  "
3311
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4237
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3312
4238
  `);
3313
4239
  expect(std.err).toMatchInlineSnapshot(`
3314
4240
  "X [ERROR] Processing wrangler.toml configuration:
@@ -3442,7 +4368,7 @@ export default{
3442
4368
  `);
3443
4369
  expect(std.out).toMatchInlineSnapshot(`
3444
4370
  "
3445
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4371
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3446
4372
  `);
3447
4373
  expect(std.err).toMatchInlineSnapshot(`
3448
4374
  "X [ERROR] Processing wrangler.toml configuration:
@@ -3488,10 +4414,14 @@ export default{
3488
4414
  mockSubDomainRequest();
3489
4415
  await runWrangler("publish index.js");
3490
4416
  expect(std.out).toMatchInlineSnapshot(`
3491
- "Uploaded test-name (TIMINGS)
3492
- Published test-name (TIMINGS)
3493
- test-name.test-sub-domain.workers.dev"
3494
- `);
4417
+ "Your worker has access to the following bindings:
4418
+ - Wasm Modules:
4419
+ - TESTWASMNAME: path/to/test.wasm
4420
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4421
+ Uploaded test-name (TIMINGS)
4422
+ Published test-name (TIMINGS)
4423
+ test-name.test-sub-domain.workers.dev"
4424
+ `);
3495
4425
  expect(std.err).toMatchInlineSnapshot(`""`);
3496
4426
  expect(std.warn).toMatchInlineSnapshot(`""`);
3497
4427
  });
@@ -3513,7 +4443,7 @@ export default{
3513
4443
  );
3514
4444
  expect(std.out).toMatchInlineSnapshot(`
3515
4445
  "
3516
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4446
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3517
4447
  `);
3518
4448
  expect(std.err).toMatchInlineSnapshot(`
3519
4449
  "X [ERROR] You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
@@ -3554,10 +4484,14 @@ export default{
3554
4484
  mockSubDomainRequest();
3555
4485
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3556
4486
  expect(std.out).toMatchInlineSnapshot(`
3557
- "Uploaded test-name (TIMINGS)
3558
- Published test-name (TIMINGS)
3559
- test-name.test-sub-domain.workers.dev"
3560
- `);
4487
+ "Your worker has access to the following bindings:
4488
+ - Wasm Modules:
4489
+ - TESTWASMNAME: path/to/and/the/path/to/test.wasm
4490
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4491
+ Uploaded test-name (TIMINGS)
4492
+ Published test-name (TIMINGS)
4493
+ test-name.test-sub-domain.workers.dev"
4494
+ `);
3561
4495
  expect(std.err).toMatchInlineSnapshot(`""`);
3562
4496
  expect(std.warn).toMatchInlineSnapshot(`""`);
3563
4497
  });
@@ -3586,10 +4520,11 @@ export default{
3586
4520
  mockSubDomainRequest();
3587
4521
  await runWrangler("publish index.js");
3588
4522
  expect(std.out).toMatchInlineSnapshot(`
3589
- "Uploaded test-name (TIMINGS)
3590
- Published test-name (TIMINGS)
3591
- test-name.test-sub-domain.workers.dev"
3592
- `);
4523
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
4524
+ Uploaded test-name (TIMINGS)
4525
+ Published test-name (TIMINGS)
4526
+ test-name.test-sub-domain.workers.dev"
4527
+ `);
3593
4528
  expect(std.err).toMatchInlineSnapshot(`""`);
3594
4529
  expect(std.warn).toMatchInlineSnapshot(`""`);
3595
4530
  });
@@ -3619,10 +4554,14 @@ export default{
3619
4554
  mockSubDomainRequest();
3620
4555
  await runWrangler("publish index.js");
3621
4556
  expect(std.out).toMatchInlineSnapshot(`
3622
- "Uploaded test-name (TIMINGS)
3623
- Published test-name (TIMINGS)
3624
- test-name.test-sub-domain.workers.dev"
3625
- `);
4557
+ "Your worker has access to the following bindings:
4558
+ - Text Blobs:
4559
+ - TESTTEXTBLOBNAME: path/to/text.file
4560
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4561
+ Uploaded test-name (TIMINGS)
4562
+ Published test-name (TIMINGS)
4563
+ test-name.test-sub-domain.workers.dev"
4564
+ `);
3626
4565
  expect(std.err).toMatchInlineSnapshot(`""`);
3627
4566
  expect(std.warn).toMatchInlineSnapshot(`""`);
3628
4567
  });
@@ -3644,7 +4583,7 @@ export default{
3644
4583
  );
3645
4584
  expect(std.out).toMatchInlineSnapshot(`
3646
4585
  "
3647
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4586
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3648
4587
  `);
3649
4588
  expect(std.err).toMatchInlineSnapshot(`
3650
4589
  "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
@@ -3689,10 +4628,14 @@ export default{
3689
4628
  mockSubDomainRequest();
3690
4629
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3691
4630
  expect(std.out).toMatchInlineSnapshot(`
3692
- "Uploaded test-name (TIMINGS)
3693
- Published test-name (TIMINGS)
3694
- test-name.test-sub-domain.workers.dev"
3695
- `);
4631
+ "Your worker has access to the following bindings:
4632
+ - Text Blobs:
4633
+ - TESTTEXTBLOBNAME: path/to/and/the/path/to/text.file
4634
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4635
+ Uploaded test-name (TIMINGS)
4636
+ Published test-name (TIMINGS)
4637
+ test-name.test-sub-domain.workers.dev"
4638
+ `);
3696
4639
  expect(std.err).toMatchInlineSnapshot(`""`);
3697
4640
  expect(std.warn).toMatchInlineSnapshot(`""`);
3698
4641
  });
@@ -3722,10 +4665,14 @@ export default{
3722
4665
  mockSubDomainRequest();
3723
4666
  await runWrangler("publish index.js");
3724
4667
  expect(std.out).toMatchInlineSnapshot(`
3725
- "Uploaded test-name (TIMINGS)
3726
- Published test-name (TIMINGS)
3727
- test-name.test-sub-domain.workers.dev"
3728
- `);
4668
+ "Your worker has access to the following bindings:
4669
+ - Data Blobs:
4670
+ - TESTDATABLOBNAME: path/to/data.bin
4671
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4672
+ Uploaded test-name (TIMINGS)
4673
+ Published test-name (TIMINGS)
4674
+ test-name.test-sub-domain.workers.dev"
4675
+ `);
3729
4676
  expect(std.err).toMatchInlineSnapshot(`""`);
3730
4677
  expect(std.warn).toMatchInlineSnapshot(`""`);
3731
4678
  });
@@ -3747,7 +4694,7 @@ export default{
3747
4694
  );
3748
4695
  expect(std.out).toMatchInlineSnapshot(`
3749
4696
  "
3750
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4697
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3751
4698
  `);
3752
4699
  expect(std.err).toMatchInlineSnapshot(`
3753
4700
  "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
@@ -3792,10 +4739,14 @@ export default{
3792
4739
  mockSubDomainRequest();
3793
4740
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3794
4741
  expect(std.out).toMatchInlineSnapshot(`
3795
- "Uploaded test-name (TIMINGS)
3796
- Published test-name (TIMINGS)
3797
- test-name.test-sub-domain.workers.dev"
3798
- `);
4742
+ "Your worker has access to the following bindings:
4743
+ - Data Blobs:
4744
+ - TESTDATABLOBNAME: path/to/and/the/path/to/data.bin
4745
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4746
+ Uploaded test-name (TIMINGS)
4747
+ Published test-name (TIMINGS)
4748
+ test-name.test-sub-domain.workers.dev"
4749
+ `);
3799
4750
  expect(std.err).toMatchInlineSnapshot(`""`);
3800
4751
  expect(std.warn).toMatchInlineSnapshot(`""`);
3801
4752
  });
@@ -3826,10 +4777,16 @@ export default{
3826
4777
 
3827
4778
  await runWrangler("publish index.js");
3828
4779
  expect(std.out).toMatchInlineSnapshot(`
3829
- "Uploaded test-name (TIMINGS)
3830
- Published test-name (TIMINGS)
3831
- test-name.test-sub-domain.workers.dev"
3832
- `);
4780
+ "Your worker has access to the following bindings:
4781
+ - Vars:
4782
+ - text: \\"plain ol' string\\"
4783
+ - count: \\"1\\"
4784
+ - complex: \\"[object Object]\\"
4785
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4786
+ Uploaded test-name (TIMINGS)
4787
+ Published test-name (TIMINGS)
4788
+ test-name.test-sub-domain.workers.dev"
4789
+ `);
3833
4790
  expect(std.err).toMatchInlineSnapshot(`""`);
3834
4791
  expect(std.warn).toMatchInlineSnapshot(`""`);
3835
4792
  });
@@ -3850,10 +4807,14 @@ export default{
3850
4807
 
3851
4808
  await runWrangler("publish index.js");
3852
4809
  expect(std.out).toMatchInlineSnapshot(`
3853
- "Uploaded test-name (TIMINGS)
3854
- Published test-name (TIMINGS)
3855
- test-name.test-sub-domain.workers.dev"
3856
- `);
4810
+ "Your worker has access to the following bindings:
4811
+ - R2 Buckets:
4812
+ - FOO: foo-bucket
4813
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4814
+ Uploaded test-name (TIMINGS)
4815
+ Published test-name (TIMINGS)
4816
+ test-name.test-sub-domain.workers.dev"
4817
+ `);
3857
4818
  expect(std.err).toMatchInlineSnapshot(`""`);
3858
4819
  expect(std.warn).toMatchInlineSnapshot(`""`);
3859
4820
  });
@@ -3892,10 +4853,14 @@ export default{
3892
4853
 
3893
4854
  await runWrangler("publish index.js");
3894
4855
  expect(std.out).toMatchInlineSnapshot(`
3895
- "Uploaded test-name (TIMINGS)
3896
- Published test-name (TIMINGS)
3897
- test-name.test-sub-domain.workers.dev"
3898
- `);
4856
+ "Your worker has access to the following bindings:
4857
+ - Durable Objects:
4858
+ - EXAMPLE_DO_BINDING: ExampleDurableObject
4859
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4860
+ Uploaded test-name (TIMINGS)
4861
+ Published test-name (TIMINGS)
4862
+ test-name.test-sub-domain.workers.dev"
4863
+ `);
3899
4864
  expect(std.err).toMatchInlineSnapshot(`""`);
3900
4865
  expect(std.warn).toMatchInlineSnapshot(`""`);
3901
4866
  });
@@ -3928,10 +4893,14 @@ export default{
3928
4893
 
3929
4894
  await runWrangler("publish index.js");
3930
4895
  expect(std.out).toMatchInlineSnapshot(`
3931
- "Uploaded test-name (TIMINGS)
3932
- Published test-name (TIMINGS)
3933
- test-name.test-sub-domain.workers.dev"
3934
- `);
4896
+ "Your worker has access to the following bindings:
4897
+ - Durable Objects:
4898
+ - EXAMPLE_DO_BINDING: ExampleDurableObject (defined in example-do-binding-worker)
4899
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4900
+ Uploaded test-name (TIMINGS)
4901
+ Published test-name (TIMINGS)
4902
+ test-name.test-sub-domain.workers.dev"
4903
+ `);
3935
4904
  expect(std.err).toMatchInlineSnapshot(`""`);
3936
4905
  expect(std.warn).toMatchInlineSnapshot(`""`);
3937
4906
  });
@@ -3969,10 +4938,14 @@ export default{
3969
4938
 
3970
4939
  await runWrangler("publish index.js");
3971
4940
  expect(std.out).toMatchInlineSnapshot(`
3972
- "Uploaded test-name (TIMINGS)
3973
- Published test-name (TIMINGS)
3974
- test-name.test-sub-domain.workers.dev"
3975
- `);
4941
+ "Your worker has access to the following bindings:
4942
+ - Durable Objects:
4943
+ - EXAMPLE_DO_BINDING: ExampleDurableObject
4944
+ Total Upload: 0xx KiB / gzip: 0xx KiB
4945
+ Uploaded test-name (TIMINGS)
4946
+ Published test-name (TIMINGS)
4947
+ test-name.test-sub-domain.workers.dev"
4948
+ `);
3976
4949
  expect(std.err).toMatchInlineSnapshot(`""`);
3977
4950
  expect(std.warn).toMatchInlineSnapshot(`""`);
3978
4951
  });
@@ -4002,6 +4975,51 @@ export default{
4002
4975
  });
4003
4976
  });
4004
4977
 
4978
+ describe("[services]", () => {
4979
+ it("should support service bindings", async () => {
4980
+ writeWranglerToml({
4981
+ services: [
4982
+ {
4983
+ binding: "FOO",
4984
+ service: "foo-service",
4985
+ environment: "production",
4986
+ },
4987
+ ],
4988
+ });
4989
+ writeWorkerSource();
4990
+ mockSubDomainRequest();
4991
+ mockUploadWorkerRequest({
4992
+ expectedBindings: [
4993
+ {
4994
+ type: "service",
4995
+ name: "FOO",
4996
+ service: "foo-service",
4997
+ environment: "production",
4998
+ },
4999
+ ],
5000
+ });
5001
+
5002
+ await runWrangler("publish index.js");
5003
+ expect(std.out).toMatchInlineSnapshot(`
5004
+ "Your worker has access to the following bindings:
5005
+ - Services:
5006
+ - FOO: foo-service - production
5007
+ Total Upload: 0xx KiB / gzip: 0xx KiB
5008
+ Uploaded test-name (TIMINGS)
5009
+ Published test-name (TIMINGS)
5010
+ test-name.test-sub-domain.workers.dev"
5011
+ `);
5012
+ expect(std.err).toMatchInlineSnapshot(`""`);
5013
+ expect(std.warn).toMatchInlineSnapshot(`
5014
+ "▲ [WARNING] Processing wrangler.toml configuration:
5015
+
5016
+ - \\"services\\" fields are experimental and may change or break at any time.
5017
+
5018
+ "
5019
+ `);
5020
+ });
5021
+ });
5022
+
4005
5023
  describe("[unsafe]", () => {
4006
5024
  it("should warn if using unsafe bindings", async () => {
4007
5025
  writeWranglerToml({
@@ -4029,10 +5047,14 @@ export default{
4029
5047
 
4030
5048
  await runWrangler("publish index.js");
4031
5049
  expect(std.out).toMatchInlineSnapshot(`
4032
- "Uploaded test-name (TIMINGS)
4033
- Published test-name (TIMINGS)
4034
- test-name.test-sub-domain.workers.dev"
4035
- `);
5050
+ "Your worker has access to the following bindings:
5051
+ - Unsafe:
5052
+ - binding-type: my-binding
5053
+ Total Upload: 0xx KiB / gzip: 0xx KiB
5054
+ Uploaded test-name (TIMINGS)
5055
+ Published test-name (TIMINGS)
5056
+ test-name.test-sub-domain.workers.dev"
5057
+ `);
4036
5058
  expect(std.err).toMatchInlineSnapshot(`""`);
4037
5059
  expect(std.warn).toMatchInlineSnapshot(`
4038
5060
  "▲ [WARNING] Processing wrangler.toml configuration:
@@ -4068,10 +5090,14 @@ export default{
4068
5090
 
4069
5091
  await runWrangler("publish index.js");
4070
5092
  expect(std.out).toMatchInlineSnapshot(`
4071
- "Uploaded test-name (TIMINGS)
4072
- Published test-name (TIMINGS)
4073
- test-name.test-sub-domain.workers.dev"
4074
- `);
5093
+ "Your worker has access to the following bindings:
5094
+ - Unsafe:
5095
+ - plain_text: my-binding
5096
+ Total Upload: 0xx KiB / gzip: 0xx KiB
5097
+ Uploaded test-name (TIMINGS)
5098
+ Published test-name (TIMINGS)
5099
+ test-name.test-sub-domain.workers.dev"
5100
+ `);
4075
5101
  expect(std.err).toMatchInlineSnapshot(`""`);
4076
5102
  expect(std.warn).toMatchInlineSnapshot(`
4077
5103
  "▲ [WARNING] Processing wrangler.toml configuration:
@@ -4113,7 +5139,8 @@ export default{
4113
5139
  });
4114
5140
  await runWrangler("publish index.js");
4115
5141
  expect(std.out).toMatchInlineSnapshot(`
4116
- "Uploaded test-name (TIMINGS)
5142
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
5143
+ Uploaded test-name (TIMINGS)
4117
5144
  Published test-name (TIMINGS)
4118
5145
  test-name.test-sub-domain.workers.dev"
4119
5146
  `);
@@ -4141,7 +5168,8 @@ export default{
4141
5168
  });
4142
5169
  await runWrangler("publish index.js");
4143
5170
  expect(std.out).toMatchInlineSnapshot(`
4144
- "Uploaded test-name (TIMINGS)
5171
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
5172
+ Uploaded test-name (TIMINGS)
4145
5173
  Published test-name (TIMINGS)
4146
5174
  test-name.test-sub-domain.workers.dev"
4147
5175
  `);
@@ -4173,7 +5201,8 @@ export default{
4173
5201
  });
4174
5202
  await runWrangler("publish index.js");
4175
5203
  expect(std.out).toMatchInlineSnapshot(`
4176
- "Uploaded test-name (TIMINGS)
5204
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
5205
+ Uploaded test-name (TIMINGS)
4177
5206
  Published test-name (TIMINGS)
4178
5207
  test-name.test-sub-domain.workers.dev"
4179
5208
  `);
@@ -4221,7 +5250,8 @@ export default{
4221
5250
  });
4222
5251
  await runWrangler("publish index.js");
4223
5252
  expect(std.out).toMatchInlineSnapshot(`
4224
- "Uploaded test-name (TIMINGS)
5253
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
5254
+ Uploaded test-name (TIMINGS)
4225
5255
  Published test-name (TIMINGS)
4226
5256
  test-name.test-sub-domain.workers.dev"
4227
5257
  `);
@@ -4317,7 +5347,8 @@ export default{
4317
5347
  });
4318
5348
  await runWrangler("publish index.js");
4319
5349
  expect(std.out).toMatchInlineSnapshot(`
4320
- "Uploaded test-name (TIMINGS)
5350
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
5351
+ Uploaded test-name (TIMINGS)
4321
5352
  Published test-name (TIMINGS)
4322
5353
  test-name.test-sub-domain.workers.dev"
4323
5354
  `);
@@ -4346,7 +5377,8 @@ export default{
4346
5377
  });
4347
5378
  await runWrangler("publish index.js");
4348
5379
  expect(std.out).toMatchInlineSnapshot(`
4349
- "Uploaded test-name (TIMINGS)
5380
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
5381
+ Uploaded test-name (TIMINGS)
4350
5382
  Published test-name (TIMINGS)
4351
5383
  test-name.test-sub-domain.workers.dev"
4352
5384
  `);
@@ -4374,7 +5406,8 @@ export default{
4374
5406
  });
4375
5407
  await runWrangler("publish index.js");
4376
5408
  expect(std.out).toMatchInlineSnapshot(`
4377
- "Uploaded test-name (TIMINGS)
5409
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
5410
+ Uploaded test-name (TIMINGS)
4378
5411
  Published test-name (TIMINGS)
4379
5412
  test-name.test-sub-domain.workers.dev"
4380
5413
  `);
@@ -4402,7 +5435,8 @@ export default{
4402
5435
  "publish index.js --compatibility-date 2022-03-17 --name test-name"
4403
5436
  );
4404
5437
  expect(std.out).toMatchInlineSnapshot(`
4405
- "Uploaded test-name (TIMINGS)
5438
+ "Total Upload: 0xx KiB / gzip: 0xx KiB
5439
+ Uploaded test-name (TIMINGS)
4406
5440
  Published test-name (TIMINGS)
4407
5441
  test-name.test-sub-domain.workers.dev"
4408
5442
  `);
@@ -4442,7 +5476,8 @@ export default{
4442
5476
  Object {
4443
5477
  "debug": "",
4444
5478
  "err": "",
4445
- "out": "Uploaded test-name (TIMINGS)
5479
+ "out": "Total Upload: 0xx KiB / gzip: 0xx KiB
5480
+ Uploaded test-name (TIMINGS)
4446
5481
  Published test-name (TIMINGS)
4447
5482
  test-name.test-sub-domain.workers.dev",
4448
5483
  "warn": "",
@@ -4471,7 +5506,8 @@ export default{
4471
5506
  Object {
4472
5507
  "debug": "",
4473
5508
  "err": "",
4474
- "out": "Uploaded test-name (TIMINGS)
5509
+ "out": "Total Upload: 0xx KiB / gzip: 0xx KiB
5510
+ Uploaded test-name (TIMINGS)
4475
5511
  Published test-name (TIMINGS)
4476
5512
  test-name.test-sub-domain.workers.dev",
4477
5513
  "warn": "",
@@ -4493,7 +5529,8 @@ export default{
4493
5529
  Object {
4494
5530
  "debug": "",
4495
5531
  "err": "",
4496
- "out": "Uploaded test-name (TIMINGS)
5532
+ "out": "Total Upload: 0xx KiB / gzip: 0xx KiB
5533
+ Uploaded test-name (TIMINGS)
4497
5534
  Published test-name (TIMINGS)
4498
5535
  test-name.test-sub-domain.workers.dev",
4499
5536
  "warn": "",
@@ -4504,14 +5541,26 @@ export default{
4504
5541
 
4505
5542
  describe("--dry-run", () => {
4506
5543
  it("should not publish the worker if --dry-run is specified", async () => {
4507
- writeWranglerToml();
5544
+ writeWranglerToml({
5545
+ // add a durable object with migrations
5546
+ // to make sure we _don't_ fetch migration status
5547
+ durable_objects: {
5548
+ bindings: [{ name: "NAME", class_name: "SomeClass" }],
5549
+ },
5550
+ migrations: [{ tag: "v1", new_classes: ["SomeClass"] }],
5551
+ });
4508
5552
  writeWorkerSource();
5553
+ process.env.CLOUDFLARE_ACCOUNT_ID = "";
4509
5554
  await runWrangler("publish index.js --dry-run");
4510
5555
  expect(std).toMatchInlineSnapshot(`
4511
5556
  Object {
4512
5557
  "debug": "",
4513
5558
  "err": "",
4514
- "out": "--dry-run: exiting now.",
5559
+ "out": "Your worker has access to the following bindings:
5560
+ - Durable Objects:
5561
+ - NAME: SomeClass
5562
+ Total Upload: 0xx KiB / gzip: 0xx KiB
5563
+ --dry-run: exiting now.",
4515
5564
  "warn": "",
4516
5565
  }
4517
5566
  `);
@@ -4527,14 +5576,36 @@ export default{
4527
5576
  Object {
4528
5577
  "debug": "",
4529
5578
  "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.
5579
+ "out": "Total Upload: 0xx KiB / gzip: 0xx KiB
5580
+ --dry-run: exiting now.",
5581
+ "warn": "▲ [WARNING] Enabling node.js compatibility mode for built-ins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details.
4532
5582
 
4533
5583
  ",
4534
5584
  }
4535
5585
  `);
4536
5586
  });
4537
5587
 
5588
+ it("should recommend node compatibility mode when using node builtins and node-compat isn't enabled", async () => {
5589
+ writeWranglerToml();
5590
+ fs.writeFileSync(
5591
+ "index.js",
5592
+ `
5593
+ import path from 'path';
5594
+ console.log(path.join("some/path/to", "a/file.txt"));
5595
+ export default {}
5596
+ `
5597
+ );
5598
+ let err: Error | undefined;
5599
+ try {
5600
+ await runWrangler("publish index.js --dry-run"); // expecting this to throw, as node compatibility isn't enabled
5601
+ } catch (e) {
5602
+ err = e as Error;
5603
+ }
5604
+ expect(err?.message).toMatch(
5605
+ `Detected a Node builtin module import while Node compatibility is disabled.\nAdd node_compat = true to your wrangler.toml file to enable Node compatibility.`
5606
+ );
5607
+ });
5608
+
4538
5609
  it("should polyfill node builtins when enabled", async () => {
4539
5610
  writeWranglerToml();
4540
5611
  fs.writeFileSync(
@@ -4550,21 +5621,78 @@ export default{
4550
5621
  Object {
4551
5622
  "debug": "",
4552
5623
  "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.
5624
+ "out": "Total Upload: 4xx KiB / gzip: 1xx KiB
5625
+ --dry-run: exiting now.",
5626
+ "warn": "▲ [WARNING] Enabling node.js compatibility mode for built-ins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details.
4555
5627
 
4556
5628
  ",
4557
5629
  }
4558
5630
  `);
4559
5631
  });
4560
5632
  });
5633
+
5634
+ describe("bundle reporter", () => {
5635
+ it("should print the bundle size", async () => {
5636
+ fs.writeFileSync(
5637
+ "./text.txt",
5638
+ `${new Array(100)
5639
+ .fill("Try not. Do or do not. There is no try.")
5640
+ .join("")}`
5641
+ );
5642
+
5643
+ fs.writeFileSync(
5644
+ "./hello.html",
5645
+ `<!DOCTYPE html>
5646
+ <html>
5647
+ <body>
5648
+ <h2>Hello World!</h2>
5649
+ </body>
5650
+ </html>
5651
+ `
5652
+ );
5653
+
5654
+ fs.writeFileSync(
5655
+ "index.js",
5656
+ `import hello from "./hello.html";
5657
+ import text from "./text.txt";
5658
+ export default {
5659
+ async fetch(request) {
5660
+ return new Response(json.stringify({ hello, text }));
5661
+ },
5662
+ };`
5663
+ );
5664
+ writeWranglerToml({
5665
+ main: "index.js",
5666
+ });
5667
+ mockSubDomainRequest();
5668
+ mockUploadWorkerRequest();
5669
+ await runWrangler("publish");
5670
+ expect(std).toMatchInlineSnapshot(`
5671
+ Object {
5672
+ "debug": "",
5673
+ "err": "",
5674
+ "out": "Total Upload: 4xx KiB / gzip: 0xx KiB
5675
+ Uploaded test-name (TIMINGS)
5676
+ Published test-name (TIMINGS)
5677
+ test-name.test-sub-domain.workers.dev",
5678
+ "warn": "",
5679
+ }
5680
+ `);
5681
+ });
5682
+ });
4561
5683
  });
4562
5684
 
4563
5685
  /** Write mock assets to the file system so they can be uploaded. */
4564
- function writeAssets(assets: { filePath: string; content: string }[]) {
5686
+ function writeAssets(
5687
+ assets: { filePath: string; content: string }[],
5688
+ destination = "assets"
5689
+ ) {
4565
5690
  for (const asset of assets) {
4566
- fs.mkdirSync(path.dirname(asset.filePath), { recursive: true });
4567
- fs.writeFileSync(asset.filePath, asset.content);
5691
+ const filePathDestination = path.join(destination, asset.filePath);
5692
+ fs.mkdirSync(path.dirname(filePathDestination), {
5693
+ recursive: true,
5694
+ });
5695
+ fs.writeFileSync(filePathDestination, asset.content);
4568
5696
  }
4569
5697
  }
4570
5698
 
@@ -4573,6 +5701,7 @@ function mockUploadWorkerRequest(
4573
5701
  options: {
4574
5702
  available_on_subdomain?: boolean;
4575
5703
  expectedEntry?: string;
5704
+ expectedMainModule?: string;
4576
5705
  expectedType?: "esm" | "sw";
4577
5706
  expectedBindings?: unknown;
4578
5707
  expectedModules?: Record<string, string>;
@@ -4586,6 +5715,7 @@ function mockUploadWorkerRequest(
4586
5715
  const {
4587
5716
  available_on_subdomain = true,
4588
5717
  expectedEntry,
5718
+ expectedMainModule = "index.js",
4589
5719
  expectedType = "esm",
4590
5720
  expectedBindings,
4591
5721
  expectedModules = {},
@@ -4609,6 +5739,7 @@ function mockUploadWorkerRequest(
4609
5739
  expect(envName).toEqual(env);
4610
5740
  }
4611
5741
  expect(queryParams.get("include_subdomain_availability")).toEqual("true");
5742
+ expect(queryParams.get("excludeScript")).toEqual("true");
4612
5743
  const formBody = body as FormData;
4613
5744
  if (expectedEntry !== undefined) {
4614
5745
  expect(await (formBody.get("index.js") as File).text()).toMatch(
@@ -4619,7 +5750,7 @@ function mockUploadWorkerRequest(
4619
5750
  formBody.get("metadata") as string
4620
5751
  ) as WorkerMetadata;
4621
5752
  if (expectedType === "esm") {
4622
- expect(metadata.main_module).toEqual("index.js");
5753
+ expect(metadata.main_module).toEqual(expectedMainModule);
4623
5754
  } else {
4624
5755
  expect(metadata.body_part).toEqual("index.js");
4625
5756
  }
@@ -4729,6 +5860,145 @@ function mockPublishRoutesRequest({
4729
5860
  );
4730
5861
  }
4731
5862
 
5863
+ function mockUnauthorizedPublishRoutesRequest({
5864
+ env = undefined,
5865
+ legacyEnv = false,
5866
+ }: {
5867
+ env?: string | undefined;
5868
+ legacyEnv?: boolean | undefined;
5869
+ } = {}) {
5870
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5871
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5872
+
5873
+ setMockRawResponse(
5874
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/routes`,
5875
+ "PUT",
5876
+ () =>
5877
+ createFetchResult(null, false, [
5878
+ { message: "Authentication error", code: 10000 },
5879
+ ])
5880
+ );
5881
+ }
5882
+
5883
+ function mockCollectKnownRoutesRequest(
5884
+ routes: { pattern: string; script: string }[]
5885
+ ) {
5886
+ setMockResponse(`/zones/:zoneId/workers/routes`, "GET", () => routes);
5887
+ }
5888
+
5889
+ function mockGetZoneFromHostRequest(host: string, zone: string) {
5890
+ setMockResponse("/zones", (_uri, _init, queryParams) => {
5891
+ expect(queryParams.get("name")).toEqual(host);
5892
+ return [{ id: zone }];
5893
+ });
5894
+ }
5895
+
5896
+ function mockPublishRoutesFallbackRequest(route: {
5897
+ pattern: string;
5898
+ script: string;
5899
+ }) {
5900
+ setMockResponse(`/zones/:zoneId/workers/routes`, "POST", (_url, { body }) => {
5901
+ expect(JSON.parse(body as string)).toEqual(route);
5902
+ return route.pattern;
5903
+ });
5904
+ }
5905
+
5906
+ function mockPublishCustomDomainsRequest({
5907
+ publishFlags,
5908
+ domains = [],
5909
+ env = undefined,
5910
+ legacyEnv = false,
5911
+ }: {
5912
+ publishFlags: {
5913
+ override_scope: boolean;
5914
+ override_existing_origin: boolean;
5915
+ override_existing_dns_record: boolean;
5916
+ };
5917
+ domains: Array<
5918
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5919
+ >;
5920
+ env?: string | undefined;
5921
+ legacyEnv?: boolean | undefined;
5922
+ }) {
5923
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5924
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5925
+
5926
+ setMockResponse(
5927
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5928
+ "PUT",
5929
+ ([_url, accountId, scriptName, envName], { body }) => {
5930
+ expect(accountId).toEqual("some-account-id");
5931
+ expect(scriptName).toEqual(
5932
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5933
+ );
5934
+ if (!legacyEnv) {
5935
+ expect(envName).toEqual(env);
5936
+ }
5937
+
5938
+ expect(JSON.parse(body as string)).toEqual({
5939
+ ...publishFlags,
5940
+ origins: domains,
5941
+ });
5942
+
5943
+ return null;
5944
+ }
5945
+ );
5946
+ }
5947
+
5948
+ function mockPublishCustomDomainsRequestConflictWithoutOverride({
5949
+ domains = [],
5950
+ originConflicts = false,
5951
+ dnsRecordConflicts = false,
5952
+ env = undefined,
5953
+ legacyEnv = false,
5954
+ }: {
5955
+ originConflicts?: boolean;
5956
+ dnsRecordConflicts?: boolean;
5957
+ domains: Array<
5958
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5959
+ >;
5960
+ env?: string | undefined;
5961
+ legacyEnv?: boolean | undefined;
5962
+ }) {
5963
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5964
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5965
+
5966
+ setMockRawResponse(
5967
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5968
+ "PUT",
5969
+ ([_url, accountId, scriptName, envName], { body }) => {
5970
+ expect(accountId).toEqual("some-account-id");
5971
+ expect(scriptName).toEqual(
5972
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5973
+ );
5974
+ if (!legacyEnv) {
5975
+ expect(envName).toEqual(env);
5976
+ }
5977
+
5978
+ const parsed = JSON.parse(body as string);
5979
+ expect(parsed.origins).toEqual(domains);
5980
+
5981
+ if (originConflicts && !parsed.override_existing_origin) {
5982
+ return createFetchResult(null, false, [
5983
+ {
5984
+ code: 100116,
5985
+ message: `Cannot create Custom Domain "${domains[0].hostname}": Custom Domain already exists and points to a different script; retry and use option "override_existing_origin" to override`,
5986
+ },
5987
+ ]);
5988
+ }
5989
+ if (dnsRecordConflicts && !parsed.override_existing_dns_record) {
5990
+ return createFetchResult(null, false, [
5991
+ {
5992
+ code: 100117,
5993
+ message: `Cannot create Custom Domain "${domains[0].hostname}": a DNS record already exists for this origin; retry and use option "override_existing_dns_record" to override`,
5994
+ },
5995
+ ]);
5996
+ }
5997
+ return createFetchResult(null, true);
5998
+ }
5999
+ );
6000
+ }
6001
+
4732
6002
  /** Create a mock handler for the request to get a list of all KV namespaces. */
4733
6003
  function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
4734
6004
  setMockResponse(
@@ -4741,16 +6011,28 @@ function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
4741
6011
  );
4742
6012
  }
4743
6013
 
6014
+ interface ExpectedAsset {
6015
+ filePath: string;
6016
+ content: string;
6017
+ expiration?: number;
6018
+ expiration_ttl?: number;
6019
+ }
6020
+ interface StaticAssetUpload {
6021
+ key: string;
6022
+ base64: boolean;
6023
+ value: string;
6024
+ expiration: number | undefined;
6025
+ expiration_ttl: number | undefined;
6026
+ }
6027
+
4744
6028
  /** Create a mock handler for the request that tries to do a bulk upload of assets to a KV namespace. */
4745
6029
  function mockUploadAssetsToKVRequest(
4746
6030
  expectedNamespaceId: string,
4747
- assets: {
4748
- filePath: string;
4749
- content: string;
4750
- expiration?: number;
4751
- expiration_ttl?: number;
4752
- }[]
6031
+ assets?: ExpectedAsset[]
4753
6032
  ) {
6033
+ const requests: {
6034
+ uploads: StaticAssetUpload[];
6035
+ }[] = [];
4754
6036
  setMockResponse(
4755
6037
  "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
4756
6038
  "PUT",
@@ -4758,32 +6040,31 @@ function mockUploadAssetsToKVRequest(
4758
6040
  expect(accountId).toEqual("some-account-id");
4759
6041
  expect(namespaceId).toEqual(expectedNamespaceId);
4760
6042
  const uploads = JSON.parse(body as string);
4761
- expect(assets.length).toEqual(uploads.length);
4762
- for (let i = 0; i < uploads.length; i++) {
4763
- const asset = assets[i];
4764
- const upload = uploads[i];
4765
- // The asset key consists of:
4766
- // - the basename of the filepath
4767
- // - some hash value
4768
- // - the extension
4769
- const keyMatcher = new RegExp(
4770
- "^" +
4771
- asset.filePath
4772
- .replace(/(\.[^.]+)$/, ".[a-z0-9]+$1")
4773
- .replace(/\./g, "\\.")
4774
- );
4775
- expect(upload.key).toMatch(keyMatcher);
4776
- // The asset value is base64 encoded.
4777
- expect(upload.base64).toBe(true);
4778
- expect(Buffer.from(upload.value, "base64").toString()).toEqual(
4779
- asset.content
4780
- );
4781
- expect(upload.expiration).toEqual(asset.expiration);
4782
- expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
6043
+ if (assets) {
6044
+ expect(assets.length).toEqual(uploads.length);
6045
+ for (let i = 0; i < uploads.length; i++) {
6046
+ checkAssetUpload(assets[i], uploads[i]);
6047
+ }
6048
+ } else {
6049
+ requests.push({ uploads });
4783
6050
  }
4784
- return null;
4785
6051
  }
4786
6052
  );
6053
+ return requests;
6054
+ }
6055
+
6056
+ function checkAssetUpload(asset: ExpectedAsset, upload: StaticAssetUpload) {
6057
+ // The asset key consists of: `<basename>.<hash>.<extension>`
6058
+ const keyMatcher = new RegExp(
6059
+ "^" +
6060
+ asset.filePath.replace(/(\.[^.]+)$/, ".[a-z0-9]+$1").replace(/\./g, "\\.")
6061
+ );
6062
+ expect(upload.key).toMatch(keyMatcher);
6063
+ // The asset value is base64 encoded.
6064
+ expect(upload.base64).toBe(true);
6065
+ expect(Buffer.from(upload.value, "base64").toString()).toEqual(asset.content);
6066
+ expect(upload.expiration).toEqual(asset.expiration);
6067
+ expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
4787
6068
  }
4788
6069
 
4789
6070
  /** Create a mock handler for thr request that does a bulk delete of unused assets */