wrangler 0.0.0-e2f9bb2 → 0.0.0-e3278fa

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 (90) hide show
  1. package/Cloudflare_CA.pem +18 -0
  2. package/README.md +3 -1
  3. package/bin/wrangler.js +36 -4
  4. package/package.json +12 -7
  5. package/pages/functions/buildPlugin.ts +13 -0
  6. package/pages/functions/buildWorker.ts +14 -1
  7. package/pages/functions/template-plugin.ts +3 -2
  8. package/src/__tests__/configuration.test.ts +370 -87
  9. package/src/__tests__/dev.test.tsx +298 -77
  10. package/src/__tests__/helpers/mock-dialogs.ts +43 -2
  11. package/src/__tests__/index.test.ts +79 -72
  12. package/src/__tests__/init.test.ts +718 -123
  13. package/src/__tests__/jest.setup.ts +8 -0
  14. package/src/__tests__/kv.test.ts +173 -146
  15. package/src/__tests__/package-manager.test.ts +154 -7
  16. package/src/__tests__/pages.test.ts +478 -53
  17. package/src/__tests__/parse.test.ts +8 -0
  18. package/src/__tests__/publish.test.ts +1094 -215
  19. package/src/__tests__/r2.test.ts +55 -36
  20. package/src/__tests__/secret.test.ts +39 -4
  21. package/src/__tests__/whoami.test.tsx +34 -0
  22. package/src/abort.d.ts +3 -0
  23. package/src/bundle.ts +34 -6
  24. package/src/cfetch/index.ts +21 -4
  25. package/src/cfetch/internal.ts +23 -18
  26. package/src/config/config.ts +2 -2
  27. package/src/config/environment.ts +40 -14
  28. package/src/config/index.ts +162 -0
  29. package/src/config/validation-helpers.ts +10 -1
  30. package/src/config/validation.ts +180 -65
  31. package/src/create-worker-preview.ts +32 -22
  32. package/src/create-worker-upload-form.ts +22 -8
  33. package/src/dev/dev.tsx +12 -18
  34. package/src/dev/local.tsx +10 -0
  35. package/src/dev/remote.tsx +40 -16
  36. package/src/dialogs.tsx +48 -0
  37. package/src/durable.ts +102 -0
  38. package/src/entry.ts +64 -9
  39. package/src/index.tsx +548 -317
  40. package/src/inspect.ts +39 -0
  41. package/src/kv.ts +114 -25
  42. package/src/open-in-browser.ts +5 -12
  43. package/src/package-manager.ts +50 -3
  44. package/src/pages.tsx +434 -207
  45. package/src/parse.ts +23 -4
  46. package/src/proxy.ts +59 -35
  47. package/src/publish.ts +374 -127
  48. package/src/sites.tsx +61 -28
  49. package/src/user.tsx +23 -2
  50. package/src/whoami.tsx +3 -2
  51. package/src/worker.ts +10 -1
  52. package/src/zones.ts +73 -0
  53. package/templates/new-worker-scheduled.js +17 -0
  54. package/templates/new-worker-scheduled.ts +32 -0
  55. package/templates/new-worker.ts +16 -1
  56. package/templates/static-asset-facade.js +0 -4
  57. package/wrangler-dist/cli.js +96965 -83414
  58. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  59. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  60. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  61. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  62. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  63. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  64. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  65. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  66. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  67. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  68. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  69. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  70. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  71. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  72. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  73. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  74. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  75. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  76. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  77. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  78. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  79. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  80. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  81. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  82. package/vendor/wrangler-mime/LICENSE +0 -21
  83. package/vendor/wrangler-mime/Mime.js +0 -97
  84. package/vendor/wrangler-mime/README.md +0 -187
  85. package/vendor/wrangler-mime/cli.js +0 -46
  86. package/vendor/wrangler-mime/index.js +0 -4
  87. package/vendor/wrangler-mime/lite.js +0 -4
  88. package/vendor/wrangler-mime/package.json +0 -52
  89. package/vendor/wrangler-mime/types/other.js +0 -1
  90. 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";
@@ -469,7 +471,10 @@ describe("publish", () => {
469
471
  mockSubDomainRequest();
470
472
  await runWrangler("publish ./some-path/worker/index.js");
471
473
  expect(std.out).toMatchInlineSnapshot(`
472
- "Uploaded test-name (TIMINGS)
474
+ "Your worker has access to the following bindings:
475
+ - Vars:
476
+ - xyz: \\"123\\"
477
+ Uploaded test-name (TIMINGS)
473
478
  Published test-name (TIMINGS)
474
479
  test-name.test-sub-domain.workers.dev"
475
480
  `);
@@ -644,6 +649,213 @@ describe("publish", () => {
644
649
  await runWrangler("publish ./index --env dev --legacy-env false");
645
650
  });
646
651
 
652
+ it("should fallback to the Wrangler 1 zone-based API if the bulk-routes API fails", async () => {
653
+ writeWranglerToml({
654
+ routes: ["example.com/some-route/*"],
655
+ });
656
+ writeWorkerSource();
657
+ mockUpdateWorkerRequest({ enabled: false });
658
+ mockUploadWorkerRequest({ expectedType: "esm" });
659
+ // Simulate the bulk-routes API failing with a not authorized error.
660
+ mockUnauthorizedPublishRoutesRequest();
661
+ // Simulate that the worker has already been deployed to another route in this zone.
662
+ mockCollectKnownRoutesRequest([
663
+ {
664
+ pattern: "foo.example.com/other-route",
665
+ script: "test-name",
666
+ },
667
+ ]);
668
+ mockGetZoneFromHostRequest("example.com", "some-zone-id");
669
+ mockPublishRoutesFallbackRequest({
670
+ pattern: "example.com/some-route/*",
671
+ script: "test-name",
672
+ });
673
+ await runWrangler("publish ./index");
674
+
675
+ expect(std.err).toMatchInlineSnapshot(`""`);
676
+ expect(std.warn).toMatchInlineSnapshot(`
677
+ "▲ [WARNING] The current authentication token does not have 'All Zones' permissions.
678
+
679
+ Falling back to using the zone-based API endpoint to update each route individually.
680
+ Note that there is no access to routes associated with zones that the API token does not have
681
+ permission for.
682
+ Existing routes for this Worker in such zones will not be deleted.
683
+
684
+
685
+ ▲ [WARNING] Previously deployed routes:
686
+
687
+ The following routes were already associated with this worker, and have not been deleted:
688
+ - \\"foo.example.com/other-route\\"
689
+ If these routes are not wanted then you can remove them in the dashboard.
690
+
691
+ "
692
+ `);
693
+ expect(std.out).toMatchInlineSnapshot(`
694
+ "Uploaded test-name (TIMINGS)
695
+ Published test-name (TIMINGS)
696
+ example.com/some-route/*"
697
+ `);
698
+ });
699
+
700
+ it("should error if the bulk-routes API fails and trying to push to a non-production environment", async () => {
701
+ writeWranglerToml({
702
+ routes: ["example.com/some-route/*"],
703
+ legacy_env: false,
704
+ });
705
+ writeWorkerSource();
706
+ mockUpdateWorkerRequest({ env: "staging", enabled: false });
707
+ mockUploadWorkerRequest({ env: "staging", expectedType: "esm" });
708
+ // Simulate the bulk-routes API failing with a not authorized error.
709
+ mockUnauthorizedPublishRoutesRequest({ env: "staging" });
710
+ // Simulate that the worker has already been deployed to another route in this zone.
711
+ mockCollectKnownRoutesRequest([
712
+ {
713
+ pattern: "foo.example.com/other-route",
714
+ script: "test-name",
715
+ },
716
+ ]);
717
+ mockGetZoneFromHostRequest("example.com", "some-zone-id");
718
+ mockPublishRoutesFallbackRequest({
719
+ pattern: "example.com/some-route/*",
720
+ script: "test-name",
721
+ });
722
+ await expect(runWrangler("publish ./index --env=staging")).rejects
723
+ .toThrowErrorMatchingInlineSnapshot(`
724
+ "Service environments combined with an API token that doesn't have 'All Zones' permissions is not supported.
725
+ Either turn off service environments by setting \`legacy_env = true\`, creating an API token with 'All Zones' permissions, or logging in via OAuth"
726
+ `);
727
+ });
728
+
729
+ describe("custom domains", () => {
730
+ it("should publish routes marked with 'custom_domain' as separate custom domains", async () => {
731
+ writeWranglerToml({
732
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
733
+ });
734
+ writeWorkerSource();
735
+ mockUpdateWorkerRequest({ enabled: false });
736
+ mockUploadWorkerRequest({ expectedType: "esm" });
737
+ mockPublishCustomDomainsRequest({
738
+ publishFlags: {
739
+ override_scope: true,
740
+ override_existing_origin: false,
741
+ override_existing_dns_record: false,
742
+ },
743
+ domains: [{ hostname: "api.example.com" }],
744
+ });
745
+ await runWrangler("publish ./index");
746
+ expect(std.out).toContain("api.example.com (custom domain)");
747
+ });
748
+
749
+ it("should allow retrying if publish fails with a conflicting custom domain error", async () => {
750
+ writeWranglerToml({
751
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
752
+ });
753
+ writeWorkerSource();
754
+ mockUpdateWorkerRequest({ enabled: false });
755
+ mockUploadWorkerRequest({ expectedType: "esm" });
756
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
757
+ originConflicts: true,
758
+ domains: [{ hostname: "api.example.com" }],
759
+ });
760
+ mockConfirm({
761
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
762
+ result: true,
763
+ });
764
+ await runWrangler("publish ./index");
765
+ expect(std.out).toContain("api.example.com (custom domain)");
766
+ });
767
+
768
+ it("should allow retrying if publish fails with a conflicting DNS record error", async () => {
769
+ writeWranglerToml({
770
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
771
+ });
772
+ writeWorkerSource();
773
+ mockUpdateWorkerRequest({ enabled: false });
774
+ mockUploadWorkerRequest({ expectedType: "esm" });
775
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
776
+ dnsRecordConflicts: true,
777
+ domains: [{ hostname: "api.example.com" }],
778
+ });
779
+ mockConfirm({
780
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
781
+ result: true,
782
+ });
783
+ await runWrangler("publish ./index");
784
+ expect(std.out).toContain("api.example.com (custom domain)");
785
+ });
786
+
787
+ it("should allow retrying for conflicting custom domains and then again for conflicting dns", async () => {
788
+ writeWranglerToml({
789
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
790
+ });
791
+ writeWorkerSource();
792
+ mockUpdateWorkerRequest({ enabled: false });
793
+ mockUploadWorkerRequest({ expectedType: "esm" });
794
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
795
+ originConflicts: true,
796
+ dnsRecordConflicts: true,
797
+ domains: [{ hostname: "api.example.com" }],
798
+ });
799
+ mockConfirm(
800
+ {
801
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
802
+ result: true,
803
+ },
804
+ {
805
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
806
+ result: true,
807
+ }
808
+ );
809
+ await runWrangler("publish ./index");
810
+ expect(std.out).toContain("api.example.com (custom domain)");
811
+ });
812
+
813
+ it("should throw if an invalid custom domain is requested", async () => {
814
+ writeWranglerToml({
815
+ routes: [{ pattern: "*.example.com", custom_domain: true }],
816
+ });
817
+ writeWorkerSource();
818
+ await expect(
819
+ runWrangler("publish ./index")
820
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
821
+ `"Cannot use \\"*.example.com\\" as a Custom Domain; wildcard operators (*) are not allowed"`
822
+ );
823
+
824
+ writeWranglerToml({
825
+ routes: [
826
+ { pattern: "api.example.com/at/a/path", custom_domain: true },
827
+ ],
828
+ });
829
+ writeWorkerSource();
830
+ await expect(
831
+ runWrangler("publish ./index")
832
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
833
+ `"Cannot use \\"api.example.com/at/a/path\\" as a Custom Domain; paths are not allowed"`
834
+ );
835
+ });
836
+
837
+ it("should not retry publish on error if user does not confirm", async () => {
838
+ writeWranglerToml({
839
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
840
+ });
841
+ writeWorkerSource();
842
+ mockUpdateWorkerRequest({ enabled: false });
843
+ mockUploadWorkerRequest({ expectedType: "esm" });
844
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
845
+ dnsRecordConflicts: true,
846
+ domains: [{ hostname: "api.example.com" }],
847
+ });
848
+ mockConfirm({
849
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
850
+ result: false,
851
+ });
852
+ await runWrangler("publish ./index");
853
+ expect(std.out).toContain(
854
+ 'Publishing to Custom Domain "api.example.com" was skipped, fix conflict and try again'
855
+ );
856
+ });
857
+ });
858
+
647
859
  it.todo("should error if it's a workers.dev route");
648
860
  });
649
861
 
@@ -878,6 +1090,78 @@ export default{
878
1090
  expect(std.err).toMatchInlineSnapshot(`""`);
879
1091
  });
880
1092
 
1093
+ it("should preserve exports on a module format worker", async () => {
1094
+ writeWranglerToml();
1095
+ fs.writeFileSync(
1096
+ "index.js",
1097
+ `
1098
+ export const abc = 123;
1099
+ export const def = "show me the money";
1100
+ export default {};`
1101
+ );
1102
+
1103
+ await runWrangler("publish index.js --dry-run --outdir out");
1104
+
1105
+ expect(
1106
+ (
1107
+ await esbuild.build({
1108
+ entryPoints: [path.resolve("./out/index.js")],
1109
+ metafile: true,
1110
+ write: false,
1111
+ })
1112
+ ).metafile?.outputs["index.js"].exports
1113
+ ).toMatchInlineSnapshot(`
1114
+ Array [
1115
+ "abc",
1116
+ "def",
1117
+ "default",
1118
+ ]
1119
+ `);
1120
+
1121
+ expect(std).toMatchInlineSnapshot(`
1122
+ Object {
1123
+ "debug": "",
1124
+ "err": "",
1125
+ "out": "--dry-run: exiting now.",
1126
+ "warn": "",
1127
+ }
1128
+ `);
1129
+ });
1130
+
1131
+ it("should not preserve exports on a service-worker format worker", async () => {
1132
+ writeWranglerToml();
1133
+ fs.writeFileSync(
1134
+ "index.js",
1135
+ `
1136
+ export const abc = 123;
1137
+ export const def = "show me the money";
1138
+ addEventListener('fetch', event => {});`
1139
+ );
1140
+
1141
+ await runWrangler("publish index.js --dry-run --outdir out");
1142
+
1143
+ expect(
1144
+ (
1145
+ await esbuild.build({
1146
+ entryPoints: [path.resolve("./out/index.js")],
1147
+ metafile: true,
1148
+ write: false,
1149
+ })
1150
+ ).metafile?.outputs["index.js"].exports
1151
+ ).toMatchInlineSnapshot(`Array []`);
1152
+
1153
+ expect(std).toMatchInlineSnapshot(`
1154
+ Object {
1155
+ "debug": "",
1156
+ "err": "",
1157
+ "out": "--dry-run: exiting now.",
1158
+ "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...
1159
+
1160
+ ",
1161
+ }
1162
+ `);
1163
+ });
1164
+
881
1165
  it("should be able to transpile entry-points in sub-directories (sw)", async () => {
882
1166
  writeWranglerToml();
883
1167
  writeWorkerSource({ basePath: "./src", type: "sw" });
@@ -914,7 +1198,7 @@ export default{
914
1198
 
915
1199
  expect(std.out).toMatchInlineSnapshot(`
916
1200
  "
917
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1201
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
918
1202
  `);
919
1203
  expect(std.err).toMatchInlineSnapshot(`
920
1204
  "X [ERROR] Processing wrangler.toml configuration:
@@ -939,8 +1223,8 @@ export default{
939
1223
 
940
1224
  it("should warn if there is a `site.entry-point` configuration", async () => {
941
1225
  const assets = [
942
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
943
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1226
+ { filePath: "file-1.txt", content: "Content of file-1" },
1227
+ { filePath: "file-2.txt", content: "Content of file-2" },
944
1228
  ];
945
1229
  const kvNamespace = {
946
1230
  title: "__test-name-workers_sites_assets",
@@ -966,10 +1250,10 @@ export default{
966
1250
  Object {
967
1251
  "debug": "",
968
1252
  "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...
1253
+ "out": "Reading file-1.txt...
1254
+ Uploading as file-1.2ca234f380.txt...
1255
+ Reading file-2.txt...
1256
+ Uploading as file-2.5938485188.txt...
973
1257
  ↗️ Done syncing assets
974
1258
  Uploaded test-name (TIMINGS)
975
1259
  Published test-name (TIMINGS)
@@ -990,8 +1274,8 @@ export default{
990
1274
 
991
1275
  it("should resolve site.entry-point relative to wrangler.toml", async () => {
992
1276
  const assets = [
993
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
994
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1277
+ { filePath: "file-1.txt", content: "Content of file-1" },
1278
+ { filePath: "file-2.txt", content: "Content of file-2" },
995
1279
  ];
996
1280
  const kvNamespace = {
997
1281
  title: "__test-name-workers_sites_assets",
@@ -1017,10 +1301,10 @@ export default{
1017
1301
  await runWrangler("publish --config ./my-site/wrangler.toml");
1018
1302
 
1019
1303
  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...
1304
+ "Reading file-1.txt...
1305
+ Uploading as file-1.2ca234f380.txt...
1306
+ Reading file-2.txt...
1307
+ Uploading as file-2.5938485188.txt...
1024
1308
  ↗️ Done syncing assets
1025
1309
  Uploaded test-name (TIMINGS)
1026
1310
  Published test-name (TIMINGS)
@@ -1072,7 +1356,7 @@ export default{
1072
1356
 
1073
1357
  expect(std.out).toMatchInlineSnapshot(`
1074
1358
  "
1075
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
1359
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1076
1360
  `);
1077
1361
  expect(std.err).toMatchInlineSnapshot(`
1078
1362
  "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.
@@ -1085,8 +1369,8 @@ export default{
1085
1369
  describe("asset upload", () => {
1086
1370
  it("should upload all the files in the directory specified by `config.site.bucket`", async () => {
1087
1371
  const assets = [
1088
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1089
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1372
+ { filePath: "file-1.txt", content: "Content of file-1" },
1373
+ { filePath: "file-2.txt", content: "Content of file-2" },
1090
1374
  ];
1091
1375
  const kvNamespace = {
1092
1376
  title: "__test-name-workers_sites_assets",
@@ -1108,10 +1392,60 @@ export default{
1108
1392
  await runWrangler("publish");
1109
1393
 
1110
1394
  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...
1395
+ "Reading file-1.txt...
1396
+ Uploading as file-1.2ca234f380.txt...
1397
+ Reading file-2.txt...
1398
+ Uploading as file-2.5938485188.txt...
1399
+ ↗️ Done syncing assets
1400
+ Uploaded test-name (TIMINGS)
1401
+ Published test-name (TIMINGS)
1402
+ test-name.test-sub-domain.workers.dev"
1403
+ `);
1404
+ expect(std.err).toMatchInlineSnapshot(`""`);
1405
+ });
1406
+
1407
+ it("should not contain backslash for assets with nested directories", async () => {
1408
+ const assets = [
1409
+ { filePath: "subdir/file-1.txt", content: "Content of file-1" },
1410
+ { filePath: "subdir/file-2.txt", content: "Content of file-2" },
1411
+ ];
1412
+ const kvNamespace = {
1413
+ title: "__test-name-workers_sites_assets",
1414
+ id: "__test-name-workers_sites_assets-id",
1415
+ };
1416
+ writeWranglerToml({
1417
+ main: "./index.js",
1418
+ site: {
1419
+ bucket: "assets",
1420
+ },
1421
+ });
1422
+ writeWorkerSource();
1423
+ writeAssets(assets);
1424
+ mockUploadWorkerRequest({
1425
+ expectedBindings: [
1426
+ {
1427
+ name: "__STATIC_CONTENT",
1428
+ namespace_id: "__test-name-workers_sites_assets-id",
1429
+ type: "kv_namespace",
1430
+ },
1431
+ ],
1432
+ expectedModules: {
1433
+ __STATIC_CONTENT_MANIFEST:
1434
+ '{"subdir/file-1.txt":"subdir/file-1.2ca234f380.txt","subdir/file-2.txt":"subdir/file-2.5938485188.txt"}',
1435
+ },
1436
+ });
1437
+ mockSubDomainRequest();
1438
+ mockListKVNamespacesRequest(kvNamespace);
1439
+ mockKeyListRequest(kvNamespace.id, []);
1440
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1441
+
1442
+ await runWrangler("publish");
1443
+
1444
+ expect(std.out).toMatchInlineSnapshot(`
1445
+ "Reading subdir/file-1.txt...
1446
+ Uploading as subdir/file-1.2ca234f380.txt...
1447
+ Reading subdir/file-2.txt...
1448
+ Uploading as subdir/file-2.5938485188.txt...
1115
1449
  ↗️ Done syncing assets
1116
1450
  Uploaded test-name (TIMINGS)
1117
1451
  Published test-name (TIMINGS)
@@ -1122,8 +1456,8 @@ export default{
1122
1456
 
1123
1457
  it("when using a service-worker type, it should add an asset manifest as a text_blob, and bind to a namespace", async () => {
1124
1458
  const assets = [
1125
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1126
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1459
+ { filePath: "file-1.txt", content: "Content of file-1" },
1460
+ { filePath: "file-2.txt", content: "Content of file-2" },
1127
1461
  ];
1128
1462
  const kvNamespace = {
1129
1463
  title: "__test-name-workers_sites_assets",
@@ -1141,7 +1475,7 @@ export default{
1141
1475
  expectedType: "sw",
1142
1476
  expectedModules: {
1143
1477
  __STATIC_CONTENT_MANIFEST:
1144
- '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
1478
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
1145
1479
  },
1146
1480
  expectedBindings: [
1147
1481
  {
@@ -1164,10 +1498,10 @@ export default{
1164
1498
  await runWrangler("publish");
1165
1499
 
1166
1500
  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...
1501
+ "Reading file-1.txt...
1502
+ Uploading as file-1.2ca234f380.txt...
1503
+ Reading file-2.txt...
1504
+ Uploading as file-2.5938485188.txt...
1171
1505
  ↗️ Done syncing assets
1172
1506
  Uploaded test-name (TIMINGS)
1173
1507
  Published test-name (TIMINGS)
@@ -1178,8 +1512,8 @@ export default{
1178
1512
 
1179
1513
  it("when using a module worker type, it should add an asset manifest module, and bind to a namespace", async () => {
1180
1514
  const assets = [
1181
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1182
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1515
+ { filePath: "file-1.txt", content: "Content of file-1" },
1516
+ { filePath: "file-2.txt", content: "Content of file-2" },
1183
1517
  ];
1184
1518
  const kvNamespace = {
1185
1519
  title: "__test-name-workers_sites_assets",
@@ -1203,7 +1537,7 @@ export default{
1203
1537
  ],
1204
1538
  expectedModules: {
1205
1539
  __STATIC_CONTENT_MANIFEST:
1206
- '{"file-1.txt":"assets/file-1.2ca234f380.txt","file-2.txt":"assets/file-2.5938485188.txt"}',
1540
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
1207
1541
  },
1208
1542
  });
1209
1543
  mockSubDomainRequest();
@@ -1214,10 +1548,10 @@ export default{
1214
1548
  await runWrangler("publish");
1215
1549
 
1216
1550
  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...
1551
+ "Reading file-1.txt...
1552
+ Uploading as file-1.2ca234f380.txt...
1553
+ Reading file-2.txt...
1554
+ Uploading as file-2.5938485188.txt...
1221
1555
  ↗️ Done syncing assets
1222
1556
  Uploaded test-name (TIMINGS)
1223
1557
  Published test-name (TIMINGS)
@@ -1229,8 +1563,8 @@ export default{
1229
1563
  it("should make environment specific kv namespace for assets, even for service envs", async () => {
1230
1564
  // This is the same test as the one before this, but with an env arg
1231
1565
  const assets = [
1232
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1233
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1566
+ { filePath: "file-1.txt", content: "Content of file-1" },
1567
+ { filePath: "file-2.txt", content: "Content of file-2" },
1234
1568
  ];
1235
1569
  const kvNamespace = {
1236
1570
  title: "__test-name-some-env-workers_sites_assets",
@@ -1262,10 +1596,10 @@ export default{
1262
1596
  await runWrangler("publish --env some-env --legacy-env false");
1263
1597
 
1264
1598
  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...
1599
+ "Reading file-1.txt...
1600
+ Uploading as file-1.2ca234f380.txt...
1601
+ Reading file-2.txt...
1602
+ Uploading as file-2.5938485188.txt...
1269
1603
  ↗️ Done syncing assets
1270
1604
  Uploaded test-name (some-env) (TIMINGS)
1271
1605
  Published test-name (some-env) (TIMINGS)
@@ -1277,8 +1611,8 @@ export default{
1277
1611
  it("should make environment specific kv namespace for assets, even for legacy envs", async () => {
1278
1612
  // And this is the same test as the one before this, but with legacyEnv:true
1279
1613
  const assets = [
1280
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1281
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1614
+ { filePath: "file-1.txt", content: "Content of file-1" },
1615
+ { filePath: "file-2.txt", content: "Content of file-2" },
1282
1616
  ];
1283
1617
  const kvNamespace = {
1284
1618
  title: "__test-name-some-env-workers_sites_assets",
@@ -1311,10 +1645,10 @@ export default{
1311
1645
  await runWrangler("publish --env some-env --legacy-env true");
1312
1646
 
1313
1647
  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...
1648
+ "Reading file-1.txt...
1649
+ Uploading as file-1.2ca234f380.txt...
1650
+ Reading file-2.txt...
1651
+ Uploading as file-2.5938485188.txt...
1318
1652
  ↗️ Done syncing assets
1319
1653
  Uploaded test-name-some-env (TIMINGS)
1320
1654
  Published test-name-some-env (TIMINGS)
@@ -1325,8 +1659,8 @@ export default{
1325
1659
 
1326
1660
  it("should only upload files that are not already in the KV namespace", async () => {
1327
1661
  const assets = [
1328
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1329
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1662
+ { filePath: "file-1.txt", content: "Content of file-1" },
1663
+ { filePath: "file-2.txt", content: "Content of file-2" },
1330
1664
  ];
1331
1665
  const kvNamespace = {
1332
1666
  title: "__test-name-workers_sites_assets",
@@ -1344,21 +1678,19 @@ export default{
1344
1678
  mockSubDomainRequest();
1345
1679
  mockListKVNamespacesRequest(kvNamespace);
1346
1680
  // Put file-1 in the KV namespace
1347
- mockKeyListRequest(kvNamespace.id, [
1348
- { name: "assets/file-1.2ca234f380.txt" },
1349
- ]);
1681
+ mockKeyListRequest(kvNamespace.id, [{ name: "file-1.2ca234f380.txt" }]);
1350
1682
  // Check we do not upload file-1
1351
1683
  mockUploadAssetsToKVRequest(
1352
1684
  kvNamespace.id,
1353
- assets.filter((a) => a.filePath !== "assets/file-1.txt")
1685
+ assets.filter((a) => a.filePath !== "file-1.txt")
1354
1686
  );
1355
1687
  await runWrangler("publish");
1356
1688
 
1357
1689
  expect(std.out).toMatchInlineSnapshot(`
1358
- "Reading assets/file-1.txt...
1690
+ "Reading file-1.txt...
1359
1691
  Skipping - already uploaded.
1360
- Reading assets/file-2.txt...
1361
- Uploading as assets/file-2.5938485188.txt...
1692
+ Reading file-2.txt...
1693
+ Uploading as file-2.5938485188.txt...
1362
1694
  ↗️ Done syncing assets
1363
1695
  Uploaded test-name (TIMINGS)
1364
1696
  Published test-name (TIMINGS)
@@ -1369,8 +1701,8 @@ export default{
1369
1701
 
1370
1702
  it("should only upload files that match the `site-include` arg", async () => {
1371
1703
  const assets = [
1372
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1373
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1704
+ { filePath: "file-1.txt", content: "Content of file-1" },
1705
+ { filePath: "file-2.txt", content: "Content of file-2" },
1374
1706
  ];
1375
1707
  const kvNamespace = {
1376
1708
  title: "__test-name-workers_sites_assets",
@@ -1391,13 +1723,13 @@ export default{
1391
1723
  // Check we only upload file-1
1392
1724
  mockUploadAssetsToKVRequest(
1393
1725
  kvNamespace.id,
1394
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1726
+ assets.filter((a) => a.filePath === "file-1.txt")
1395
1727
  );
1396
1728
  await runWrangler("publish --site-include file-1.txt");
1397
1729
 
1398
1730
  expect(std.out).toMatchInlineSnapshot(`
1399
- "Reading assets/file-1.txt...
1400
- Uploading as assets/file-1.2ca234f380.txt...
1731
+ "Reading file-1.txt...
1732
+ Uploading as file-1.2ca234f380.txt...
1401
1733
  ↗️ Done syncing assets
1402
1734
  Uploaded test-name (TIMINGS)
1403
1735
  Published test-name (TIMINGS)
@@ -1408,8 +1740,8 @@ export default{
1408
1740
 
1409
1741
  it("should not upload files that match the `site-exclude` arg", async () => {
1410
1742
  const assets = [
1411
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1412
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1743
+ { filePath: "file-1.txt", content: "Content of file-1" },
1744
+ { filePath: "file-2.txt", content: "Content of file-2" },
1413
1745
  ];
1414
1746
  const kvNamespace = {
1415
1747
  title: "__test-name-workers_sites_assets",
@@ -1430,13 +1762,13 @@ export default{
1430
1762
  // Check we only upload file-1
1431
1763
  mockUploadAssetsToKVRequest(
1432
1764
  kvNamespace.id,
1433
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1765
+ assets.filter((a) => a.filePath === "file-1.txt")
1434
1766
  );
1435
1767
  await runWrangler("publish --site-exclude file-2.txt");
1436
1768
 
1437
1769
  expect(std.out).toMatchInlineSnapshot(`
1438
- "Reading assets/file-1.txt...
1439
- Uploading as assets/file-1.2ca234f380.txt...
1770
+ "Reading file-1.txt...
1771
+ Uploading as file-1.2ca234f380.txt...
1440
1772
  ↗️ Done syncing assets
1441
1773
  Uploaded test-name (TIMINGS)
1442
1774
  Published test-name (TIMINGS)
@@ -1447,8 +1779,8 @@ export default{
1447
1779
 
1448
1780
  it("should only upload files that match the `site.include` config", async () => {
1449
1781
  const assets = [
1450
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1451
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1782
+ { filePath: "file-1.txt", content: "Content of file-1" },
1783
+ { filePath: "file-2.txt", content: "Content of file-2" },
1452
1784
  ];
1453
1785
  const kvNamespace = {
1454
1786
  title: "__test-name-workers_sites_assets",
@@ -1470,13 +1802,13 @@ export default{
1470
1802
  // Check we only upload file-1
1471
1803
  mockUploadAssetsToKVRequest(
1472
1804
  kvNamespace.id,
1473
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1805
+ assets.filter((a) => a.filePath === "file-1.txt")
1474
1806
  );
1475
1807
  await runWrangler("publish");
1476
1808
 
1477
1809
  expect(std.out).toMatchInlineSnapshot(`
1478
- "Reading assets/file-1.txt...
1479
- Uploading as assets/file-1.2ca234f380.txt...
1810
+ "Reading file-1.txt...
1811
+ Uploading as file-1.2ca234f380.txt...
1480
1812
  ↗️ Done syncing assets
1481
1813
  Uploaded test-name (TIMINGS)
1482
1814
  Published test-name (TIMINGS)
@@ -1487,8 +1819,8 @@ export default{
1487
1819
 
1488
1820
  it("should not upload files that match the `site.exclude` config", async () => {
1489
1821
  const assets = [
1490
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1491
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1822
+ { filePath: "file-1.txt", content: "Content of file-1" },
1823
+ { filePath: "file-2.txt", content: "Content of file-2" },
1492
1824
  ];
1493
1825
  const kvNamespace = {
1494
1826
  title: "__test-name-workers_sites_assets",
@@ -1510,13 +1842,13 @@ export default{
1510
1842
  // Check we only upload file-1
1511
1843
  mockUploadAssetsToKVRequest(
1512
1844
  kvNamespace.id,
1513
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1845
+ assets.filter((a) => a.filePath === "file-1.txt")
1514
1846
  );
1515
1847
  await runWrangler("publish");
1516
1848
 
1517
1849
  expect(std.out).toMatchInlineSnapshot(`
1518
- "Reading assets/file-1.txt...
1519
- Uploading as assets/file-1.2ca234f380.txt...
1850
+ "Reading file-1.txt...
1851
+ Uploading as file-1.2ca234f380.txt...
1520
1852
  ↗️ Done syncing assets
1521
1853
  Uploaded test-name (TIMINGS)
1522
1854
  Published test-name (TIMINGS)
@@ -1527,8 +1859,8 @@ export default{
1527
1859
 
1528
1860
  it("should use `site-include` arg over `site.include` config", async () => {
1529
1861
  const assets = [
1530
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1531
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1862
+ { filePath: "file-1.txt", content: "Content of file-1" },
1863
+ { filePath: "file-2.txt", content: "Content of file-2" },
1532
1864
  ];
1533
1865
  const kvNamespace = {
1534
1866
  title: "__test-name-workers_sites_assets",
@@ -1550,13 +1882,13 @@ export default{
1550
1882
  // Check we only upload file-1
1551
1883
  mockUploadAssetsToKVRequest(
1552
1884
  kvNamespace.id,
1553
- assets.filter((a) => a.filePath === "assets/file-1.txt")
1885
+ assets.filter((a) => a.filePath === "file-1.txt")
1554
1886
  );
1555
1887
  await runWrangler("publish --site-include file-1.txt");
1556
1888
 
1557
1889
  expect(std.out).toMatchInlineSnapshot(`
1558
- "Reading assets/file-1.txt...
1559
- Uploading as assets/file-1.2ca234f380.txt...
1890
+ "Reading file-1.txt...
1891
+ Uploading as file-1.2ca234f380.txt...
1560
1892
  ↗️ Done syncing assets
1561
1893
  Uploaded test-name (TIMINGS)
1562
1894
  Published test-name (TIMINGS)
@@ -1567,8 +1899,8 @@ export default{
1567
1899
 
1568
1900
  it("should use `site-exclude` arg over `site.exclude` config", async () => {
1569
1901
  const assets = [
1570
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1571
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
1902
+ { filePath: "file-1.txt", content: "Content of file-1" },
1903
+ { filePath: "file-2.txt", content: "Content of file-2" },
1572
1904
  ];
1573
1905
  const kvNamespace = {
1574
1906
  title: "__test-name-workers_sites_assets",
@@ -1578,7 +1910,7 @@ export default{
1578
1910
  main: "./index.js",
1579
1911
  site: {
1580
1912
  bucket: "assets",
1581
- exclude: ["assets/file-1.txt"],
1913
+ exclude: ["file-1.txt"],
1582
1914
  },
1583
1915
  });
1584
1916
  writeWorkerSource();
@@ -1590,13 +1922,13 @@ export default{
1590
1922
  // Check we only upload file-1
1591
1923
  mockUploadAssetsToKVRequest(
1592
1924
  kvNamespace.id,
1593
- assets.filter((a) => a.filePath.endsWith("assets/file-1.txt"))
1925
+ assets.filter((a) => a.filePath.endsWith("file-1.txt"))
1594
1926
  );
1595
1927
  await runWrangler("publish --site-exclude file-2.txt");
1596
1928
 
1597
1929
  expect(std.out).toMatchInlineSnapshot(`
1598
- "Reading assets/file-1.txt...
1599
- Uploading as assets/file-1.2ca234f380.txt...
1930
+ "Reading file-1.txt...
1931
+ Uploading as file-1.2ca234f380.txt...
1600
1932
  ↗️ Done syncing assets
1601
1933
  Uploaded test-name (TIMINGS)
1602
1934
  Published test-name (TIMINGS)
@@ -1608,11 +1940,11 @@ export default{
1608
1940
  it("should walk directories except node_modules", async () => {
1609
1941
  const assets = [
1610
1942
  {
1611
- filePath: "assets/directory-1/file-1.txt",
1943
+ filePath: "directory-1/file-1.txt",
1612
1944
  content: "Content of file-1",
1613
1945
  },
1614
1946
  {
1615
- filePath: "assets/node_modules/file-2.txt",
1947
+ filePath: "node_modules/file-2.txt",
1616
1948
  content: "Content of file-2",
1617
1949
  },
1618
1950
  ];
@@ -1637,8 +1969,8 @@ export default{
1637
1969
  await runWrangler("publish");
1638
1970
 
1639
1971
  expect(std.out).toMatchInlineSnapshot(`
1640
- "Reading assets/directory-1/file-1.txt...
1641
- Uploading as assets/directory-1/file-1.2ca234f380.txt...
1972
+ "Reading directory-1/file-1.txt...
1973
+ Uploading as directory-1/file-1.2ca234f380.txt...
1642
1974
  ↗️ Done syncing assets
1643
1975
  Uploaded test-name (TIMINGS)
1644
1976
  Published test-name (TIMINGS)
@@ -1650,15 +1982,15 @@ export default{
1650
1982
  it("should skip hidden files and directories except `.well-known`", async () => {
1651
1983
  const assets = [
1652
1984
  {
1653
- filePath: "assets/.hidden-file.txt",
1985
+ filePath: ".hidden-file.txt",
1654
1986
  content: "Content of hidden-file",
1655
1987
  },
1656
1988
  {
1657
- filePath: "assets/.hidden/file-1.txt",
1989
+ filePath: ".hidden/file-1.txt",
1658
1990
  content: "Content of file-1",
1659
1991
  },
1660
1992
  {
1661
- filePath: "assets/.well-known/file-2.txt",
1993
+ filePath: ".well-known/file-2.txt",
1662
1994
  content: "Content of file-2",
1663
1995
  },
1664
1996
  ];
@@ -1683,8 +2015,8 @@ export default{
1683
2015
  await runWrangler("publish");
1684
2016
 
1685
2017
  expect(std.out).toMatchInlineSnapshot(`
1686
- "Reading assets/.well-known/file-2.txt...
1687
- Uploading as assets/.well-known/file-2.5938485188.txt...
2018
+ "Reading .well-known/file-2.txt...
2019
+ Uploading as .well-known/file-2.5938485188.txt...
1688
2020
  ↗️ Done syncing assets
1689
2021
  Uploaded test-name (TIMINGS)
1690
2022
  Published test-name (TIMINGS)
@@ -1696,12 +2028,12 @@ export default{
1696
2028
  it("should error if the asset is over 25Mb", async () => {
1697
2029
  const assets = [
1698
2030
  {
1699
- filePath: "assets/large-file.txt",
2031
+ filePath: "large-file.txt",
1700
2032
  // This file is greater than 25MiB when base64 encoded but small enough to be uploaded.
1701
2033
  content: "X".repeat(25 * 1024 * 1024 * 0.8 + 1),
1702
2034
  },
1703
2035
  {
1704
- filePath: "assets/too-large-file.txt",
2036
+ filePath: "too-large-file.txt",
1705
2037
  content: "X".repeat(25 * 1024 * 1024 + 1),
1706
2038
  },
1707
2039
  ];
@@ -1713,7 +2045,7 @@ export default{
1713
2045
  main: "./index.js",
1714
2046
  site: {
1715
2047
  bucket: "assets",
1716
- exclude: ["assets/file-1.txt"],
2048
+ exclude: ["file-1.txt"],
1717
2049
  },
1718
2050
  });
1719
2051
  writeWorkerSource();
@@ -1726,25 +2058,131 @@ export default{
1726
2058
  await expect(
1727
2059
  runWrangler("publish")
1728
2060
  ).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"`
2061
+ `"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
2062
  );
1731
2063
 
1732
2064
  expect(std.out).toMatchInlineSnapshot(`
1733
- "Reading assets/large-file.txt...
1734
- Uploading as assets/large-file.0ea0637a45.txt...
2065
+ "Reading large-file.txt...
2066
+ Uploading as large-file.0ea0637a45.txt...
2067
+ Reading too-large-file.txt...
1735
2068
 
1736
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2069
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1737
2070
  `);
1738
2071
  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
2072
+ "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
2073
 
1741
2074
  "
1742
2075
  `);
1743
2076
  });
1744
2077
 
2078
+ it("should batch assets in groups <100 mb", async () => {
2079
+ // Let's have 20 files, from size 1 - 20 mb
2080
+ const assets = Array.from({ length: 20 }, (_, index) => ({
2081
+ filePath: `file-${`${index}`.padStart(2, "0")}.txt`,
2082
+ content: "X".repeat(1024 * 1024 * (index + 1)),
2083
+ }));
2084
+
2085
+ const kvNamespace = {
2086
+ title: "__test-name-workers_sites_assets",
2087
+ id: "__test-name-workers_sites_assets-id",
2088
+ };
2089
+ writeWranglerToml({
2090
+ main: "./index.js",
2091
+ site: {
2092
+ bucket: "assets",
2093
+ },
2094
+ });
2095
+ writeWorkerSource();
2096
+ writeAssets(assets);
2097
+ mockUploadWorkerRequest();
2098
+ mockSubDomainRequest();
2099
+ mockListKVNamespacesRequest(kvNamespace);
2100
+ mockKeyListRequest(kvNamespace.id, []);
2101
+
2102
+ // We expect this to be uploaded in 3 batches
2103
+ // The first batch has 11 files (88mb)
2104
+ // The next batch has 5 files (93mb)
2105
+ // And the last one has 4 files (98mb)
2106
+
2107
+ // Since the bulk upload api endpoint stays the same
2108
+ // We're going to have to clear the mock as soon as it's resolved
2109
+ // And immediately add a mock for another one
2110
+ // Welcome to a callback pyramid in 2022
2111
+
2112
+ const removeFirstBulkUploadMockFn = mockUploadAssetsToKVRequest(
2113
+ kvNamespace.id,
2114
+ assets.slice(0, 11),
2115
+ () => {
2116
+ removeFirstBulkUploadMockFn();
2117
+ const removeSecondBulkUploadMockFn = mockUploadAssetsToKVRequest(
2118
+ kvNamespace.id,
2119
+ assets.slice(11, 16),
2120
+ () => {
2121
+ removeSecondBulkUploadMockFn();
2122
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets.slice(16, 20));
2123
+ }
2124
+ );
2125
+ }
2126
+ );
2127
+
2128
+ await runWrangler("publish");
2129
+
2130
+ expect(std).toMatchInlineSnapshot(`
2131
+ Object {
2132
+ "debug": "",
2133
+ "err": "",
2134
+ "out": "Reading file-00.txt...
2135
+ Uploading as file-00.be5be5dd26.txt...
2136
+ Reading file-01.txt...
2137
+ Uploading as file-01.4842d35994.txt...
2138
+ Reading file-02.txt...
2139
+ Uploading as file-02.990572ec63.txt...
2140
+ Reading file-03.txt...
2141
+ Uploading as file-03.9d7dda9045.txt...
2142
+ Reading file-04.txt...
2143
+ Uploading as file-04.2b6fac6382.txt...
2144
+ Reading file-05.txt...
2145
+ Uploading as file-05.55762dc758.txt...
2146
+ Reading file-06.txt...
2147
+ Uploading as file-06.f408a6b020.txt...
2148
+ Reading file-07.txt...
2149
+ Uploading as file-07.64c051715b.txt...
2150
+ Reading file-08.txt...
2151
+ Uploading as file-08.d286789adb.txt...
2152
+ Reading file-09.txt...
2153
+ Uploading as file-09.6838c183a8.txt...
2154
+ Reading file-10.txt...
2155
+ Uploading as file-10.6e03221d2a.txt...
2156
+ Reading file-11.txt...
2157
+ Uploading as file-11.37d3fb2eff.txt...
2158
+ Reading file-12.txt...
2159
+ Uploading as file-12.b3556942f8.txt...
2160
+ Reading file-13.txt...
2161
+ Uploading as file-13.680caf51b1.txt...
2162
+ Reading file-14.txt...
2163
+ Uploading as file-14.51e88468f0.txt...
2164
+ Reading file-15.txt...
2165
+ Uploading as file-15.8e3fedb394.txt...
2166
+ Reading file-16.txt...
2167
+ Uploading as file-16.c81c5e426f.txt...
2168
+ Reading file-17.txt...
2169
+ Uploading as file-17.4b2ae3c47b.txt...
2170
+ Reading file-18.txt...
2171
+ Uploading as file-18.07f245e02b.txt...
2172
+ Reading file-19.txt...
2173
+ Uploading as file-19.f0d69f705d.txt...
2174
+ ↗️ Done syncing assets
2175
+ Uploaded test-name (TIMINGS)
2176
+ Published test-name (TIMINGS)
2177
+ test-name.test-sub-domain.workers.dev",
2178
+ "warn": "",
2179
+ }
2180
+ `);
2181
+ });
2182
+
1745
2183
  it("should error if the asset key is over 512 characters", async () => {
1746
2184
  const longFilePathAsset = {
1747
- filePath: "assets/" + "folder/".repeat(100) + "file.txt",
2185
+ filePath: "folder/".repeat(100) + "file.txt",
1748
2186
  content: "content of file",
1749
2187
  };
1750
2188
  const kvNamespace = {
@@ -1767,16 +2205,16 @@ export default{
1767
2205
  await expect(
1768
2206
  runWrangler("publish")
1769
2207
  ).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\\","`
2208
+ `"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
2209
  );
1772
2210
 
1773
2211
  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...
2212
+ "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
2213
 
1776
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2214
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
1777
2215
  `);
1778
2216
  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\\",
2217
+ "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
2218
 
1781
2219
  "
1782
2220
  `);
@@ -1784,8 +2222,8 @@ export default{
1784
2222
 
1785
2223
  it("should delete uploaded assets that aren't included anymore", async () => {
1786
2224
  const assets = [
1787
- { filePath: "assets/file-1.txt", content: "Content of file-1" },
1788
- { filePath: "assets/file-2.txt", content: "Content of file-2" },
2225
+ { filePath: "file-1.txt", content: "Content of file-1" },
2226
+ { filePath: "file-2.txt", content: "Content of file-2" },
1789
2227
  ];
1790
2228
  const kvNamespace = {
1791
2229
  title: "__test-name-workers_sites_assets",
@@ -1804,32 +2242,86 @@ export default{
1804
2242
  mockListKVNamespacesRequest(kvNamespace);
1805
2243
  mockKeyListRequest(kvNamespace.id, [
1806
2244
  // Put file-1 in the KV namespace
1807
- { name: "assets/file-1.2ca234f380.txt" },
2245
+ { name: "file-1.2ca234f380.txt" },
1808
2246
  // As well as a couple from a previous upload
1809
- { name: "assets/file-3.somehash.txt" },
1810
- { name: "assets/file-4.anotherhash.txt" },
2247
+ { name: "file-3.somehash.txt" },
2248
+ { name: "file-4.anotherhash.txt" },
1811
2249
  ]);
1812
2250
 
1813
2251
  // we upload only file-1.txt
1814
- mockUploadAssetsToKVRequest(kvNamespace.id, [
1815
- ...assets.filter((a) => a.filePath !== "assets/file-1.txt"),
1816
- ]);
2252
+ mockUploadAssetsToKVRequest(
2253
+ kvNamespace.id,
2254
+ assets.filter((a) => a.filePath !== "file-1.txt")
2255
+ );
1817
2256
 
1818
2257
  // and mark file-3 and file-4 for deletion
1819
2258
  mockDeleteUnusedAssetsRequest(kvNamespace.id, [
1820
- "assets/file-3.somehash.txt",
1821
- "assets/file-4.anotherhash.txt",
2259
+ "file-3.somehash.txt",
2260
+ "file-4.anotherhash.txt",
1822
2261
  ]);
1823
2262
 
1824
2263
  await runWrangler("publish");
1825
2264
 
1826
2265
  expect(std.out).toMatchInlineSnapshot(`
1827
- "Reading assets/file-1.txt...
2266
+ "Reading file-1.txt...
1828
2267
  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...
2268
+ Reading file-2.txt...
2269
+ Uploading as file-2.5938485188.txt...
2270
+ Deleting file-3.somehash.txt from the asset store...
2271
+ Deleting file-4.anotherhash.txt from the asset store...
2272
+ ↗️ Done syncing assets
2273
+ Uploaded test-name (TIMINGS)
2274
+ Published test-name (TIMINGS)
2275
+ test-name.test-sub-domain.workers.dev"
2276
+ `);
2277
+ expect(std.err).toMatchInlineSnapshot(`""`);
2278
+ });
2279
+
2280
+ it("should generate an asset manifest with keys relative to site.bucket", async () => {
2281
+ const assets = [
2282
+ { filePath: "file-1.txt", content: "Content of file-1" },
2283
+ { filePath: "file-2.txt", content: "Content of file-2" },
2284
+ ];
2285
+ const kvNamespace = {
2286
+ title: "__test-name-workers_sites_assets",
2287
+ id: "__test-name-workers_sites_assets-id",
2288
+ };
2289
+
2290
+ writeWranglerToml({
2291
+ main: "./src/index.js",
2292
+ site: {
2293
+ bucket: "assets",
2294
+ },
2295
+ });
2296
+ writeWorkerSource({ basePath: "src", type: "esm" });
2297
+ writeAssets(assets);
2298
+ mockUploadWorkerRequest({
2299
+ expectedBindings: [
2300
+ {
2301
+ name: "__STATIC_CONTENT",
2302
+ namespace_id: "__test-name-workers_sites_assets-id",
2303
+ type: "kv_namespace",
2304
+ },
2305
+ ],
2306
+ expectedModules: {
2307
+ __STATIC_CONTENT_MANIFEST:
2308
+ '{"file-1.txt":"file-1.2ca234f380.txt","file-2.txt":"file-2.5938485188.txt"}',
2309
+ },
2310
+ });
2311
+ mockSubDomainRequest();
2312
+ mockListKVNamespacesRequest(kvNamespace);
2313
+ mockKeyListRequest(kvNamespace.id, []);
2314
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
2315
+
2316
+ process.chdir("./src");
2317
+ await runWrangler("publish");
2318
+ process.chdir("../");
2319
+
2320
+ expect(std.out).toMatchInlineSnapshot(`
2321
+ "Reading file-1.txt...
2322
+ Uploading as file-1.2ca234f380.txt...
2323
+ Reading file-2.txt...
2324
+ Uploading as file-2.5938485188.txt...
1833
2325
  ↗️ Done syncing assets
1834
2326
  Uploaded test-name (TIMINGS)
1835
2327
  Published test-name (TIMINGS)
@@ -2476,18 +2968,66 @@ export default{
2476
2968
  },
2477
2969
  });
2478
2970
 
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
- );
2971
+ await expect(runWrangler("publish index.js")).rejects
2972
+ .toThrowErrorMatchingInlineSnapshot(`
2973
+ "The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2974
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build."
2975
+ `);
2976
+ expect(std.out).toMatchInlineSnapshot(`
2977
+ "Running custom build: node -e \\"console.log('custom build');\\"
2978
+
2979
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
2980
+ `);
2981
+ expect(std.err).toMatchInlineSnapshot(`
2982
+ "X [ERROR] The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2983
+
2984
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
2985
+
2986
+ "
2987
+ `);
2988
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2989
+ });
2990
+
2991
+ it("should throw an error if the entry is a directory after the build finishes", async () => {
2992
+ writeWranglerToml({
2993
+ main: "./",
2994
+ build: {
2995
+ command: `node -e "console.log('custom build');"`,
2996
+ },
2997
+ });
2998
+
2999
+ fs.writeFileSync("./worker.js", "some content", "utf-8");
3000
+ fs.mkdirSync("./dist");
3001
+ fs.writeFileSync("./dist/index.ts", "some content", "utf-8");
3002
+
3003
+ await expect(runWrangler("publish")).rejects
3004
+ .toThrowErrorMatchingInlineSnapshot(`
3005
+ "The expected output file at \\".\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
3006
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
3007
+ The provided entry-point path, \\".\\", points to a directory, rather than a file.
3008
+
3009
+ Did you mean to set the main field to one of:
3010
+ \`\`\`
3011
+ main = \\"./worker.js\\"
3012
+ main = \\"./dist/index.ts\\"
3013
+ \`\`\`"
3014
+ `);
2484
3015
  expect(std.out).toMatchInlineSnapshot(`
2485
3016
  "Running custom build: node -e \\"console.log('custom build');\\"
2486
3017
 
2487
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3018
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
2488
3019
  `);
2489
3020
  expect(std.err).toMatchInlineSnapshot(`
2490
- "X [ERROR] Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
3021
+ "X [ERROR] The expected output file at \\".\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
3022
+
3023
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
3024
+ The provided entry-point path, \\".\\", points to a directory, rather than a file.
3025
+
3026
+ Did you mean to set the main field to one of:
3027
+ \`\`\`
3028
+ main = \\"./worker.js\\"
3029
+ main = \\"./dist/index.ts\\"
3030
+ \`\`\`
2491
3031
 
2492
3032
  "
2493
3033
  `);
@@ -2577,13 +3117,30 @@ export default{
2577
3117
  mockUploadWorkerRequest();
2578
3118
  await runWrangler("publish index.js");
2579
3119
  expect(std.out).toMatchInlineSnapshot(`
2580
- "Uploaded test-name (TIMINGS)
3120
+ "Your worker has access to the following bindings:
3121
+ - Durable Objects:
3122
+ - SOMENAME: SomeClass
3123
+ Uploaded test-name (TIMINGS)
2581
3124
  Published test-name (TIMINGS)
2582
3125
  test-name.test-sub-domain.workers.dev"
2583
3126
  `);
2584
3127
  expect(std.err).toMatchInlineSnapshot(`""`);
2585
3128
  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.
3129
+ "▲ [WARNING] Processing wrangler.toml configuration:
3130
+
3131
+ - In wrangler.toml, you have configured [durable_objects] exported by this Worker (SomeClass),
3132
+ but no [migrations] for them. This may not work as expected until you add a [migrations] section
3133
+ to your wrangler.toml. Add this configuration to your wrangler.toml:
3134
+
3135
+ \`\`\`
3136
+ [[migrations]]
3137
+ tag = \\"v1\\" # Should be unique for each entry
3138
+ new_classes = [\\"SomeClass\\"]
3139
+ \`\`\`
3140
+
3141
+ Refer to
3142
+ https://developers.cloudflare.com/workers/learning/using-durable-objects/#durable-object-migrations-in-wranglertoml
3143
+ for more details.
2587
3144
 
2588
3145
  "
2589
3146
  `);
@@ -2609,7 +3166,10 @@ export default{
2609
3166
  mockUploadWorkerRequest();
2610
3167
  await runWrangler("publish index.js");
2611
3168
  expect(std.out).toMatchInlineSnapshot(`
2612
- "Uploaded test-name (TIMINGS)
3169
+ "Your worker has access to the following bindings:
3170
+ - Durable Objects:
3171
+ - SOMENAME: SomeClass (defined in some-script)
3172
+ Uploaded test-name (TIMINGS)
2613
3173
  Published test-name (TIMINGS)
2614
3174
  test-name.test-sub-domain.workers.dev"
2615
3175
  `);
@@ -2648,7 +3208,11 @@ export default{
2648
3208
 
2649
3209
  await runWrangler("publish index.js");
2650
3210
  expect(std.out).toMatchInlineSnapshot(`
2651
- "Uploaded test-name (TIMINGS)
3211
+ "Your worker has access to the following bindings:
3212
+ - Durable Objects:
3213
+ - SOMENAME: SomeClass
3214
+ - SOMEOTHERNAME: SomeOtherClass
3215
+ Uploaded test-name (TIMINGS)
2652
3216
  Published test-name (TIMINGS)
2653
3217
  test-name.test-sub-domain.workers.dev"
2654
3218
  `);
@@ -2694,7 +3258,11 @@ export default{
2694
3258
  Object {
2695
3259
  "debug": "",
2696
3260
  "err": "",
2697
- "out": "Uploaded test-name (TIMINGS)
3261
+ "out": "Your worker has access to the following bindings:
3262
+ - Durable Objects:
3263
+ - SOMENAME: SomeClass
3264
+ - SOMEOTHERNAME: SomeOtherClass
3265
+ Uploaded test-name (TIMINGS)
2698
3266
  Published test-name (TIMINGS)
2699
3267
  test-name.test-sub-domain.workers.dev",
2700
3268
  "warn": "",
@@ -2733,7 +3301,11 @@ export default{
2733
3301
  Object {
2734
3302
  "debug": "",
2735
3303
  "err": "",
2736
- "out": "Uploaded test-name (TIMINGS)
3304
+ "out": "Your worker has access to the following bindings:
3305
+ - Durable Objects:
3306
+ - SOMENAME: SomeClass
3307
+ - SOMEOTHERNAME: SomeOtherClass
3308
+ Uploaded test-name (TIMINGS)
2737
3309
  Published test-name (TIMINGS)
2738
3310
  test-name.test-sub-domain.workers.dev",
2739
3311
  "warn": "",
@@ -2774,7 +3346,11 @@ export default{
2774
3346
 
2775
3347
  await runWrangler("publish index.js --legacy-env false");
2776
3348
  expect(std.out).toMatchInlineSnapshot(`
2777
- "Uploaded test-name (TIMINGS)
3349
+ "Your worker has access to the following bindings:
3350
+ - Durable Objects:
3351
+ - SOMENAME: SomeClass
3352
+ - SOMEOTHERNAME: SomeOtherClass
3353
+ Uploaded test-name (TIMINGS)
2778
3354
  Published test-name (TIMINGS)
2779
3355
  test-name.test-sub-domain.workers.dev"
2780
3356
  `);
@@ -2832,7 +3408,11 @@ export default{
2832
3408
 
2833
3409
  await runWrangler("publish index.js --legacy-env false --env xyz");
2834
3410
  expect(std.out).toMatchInlineSnapshot(`
2835
- "Uploaded test-name (xyz) (TIMINGS)
3411
+ "Your worker has access to the following bindings:
3412
+ - Durable Objects:
3413
+ - SOMENAME: SomeClass
3414
+ - SOMEOTHERNAME: SomeOtherClass
3415
+ Uploaded test-name (xyz) (TIMINGS)
2836
3416
  Published test-name (xyz) (TIMINGS)
2837
3417
  xyz.test-name.test-sub-domain.workers.dev"
2838
3418
  `);
@@ -2886,7 +3466,11 @@ export default{
2886
3466
  Object {
2887
3467
  "debug": "",
2888
3468
  "err": "",
2889
- "out": "Uploaded test-name (TIMINGS)
3469
+ "out": "Your worker has access to the following bindings:
3470
+ - Durable Objects:
3471
+ - SOMENAME: SomeClass
3472
+ - SOMEOTHERNAME: SomeOtherClass
3473
+ Uploaded test-name (TIMINGS)
2890
3474
  Published test-name (TIMINGS)
2891
3475
  test-name.test-sub-domain.workers.dev",
2892
3476
  "warn": "▲ [WARNING] Processing wrangler.toml configuration:
@@ -2950,7 +3534,11 @@ export default{
2950
3534
  Object {
2951
3535
  "debug": "",
2952
3536
  "err": "",
2953
- "out": "Uploaded test-name (xyz) (TIMINGS)
3537
+ "out": "Your worker has access to the following bindings:
3538
+ - Durable Objects:
3539
+ - SOMENAME: SomeClass
3540
+ - SOMEOTHERNAME: SomeOtherClass
3541
+ Uploaded test-name (xyz) (TIMINGS)
2954
3542
  Published test-name (xyz) (TIMINGS)
2955
3543
  xyz.test-name.test-sub-domain.workers.dev",
2956
3544
  "warn": "▲ [WARNING] Processing wrangler.toml configuration:
@@ -2985,6 +3573,7 @@ export default{
2985
3573
  name: "DURABLE_OBJECT_TWO",
2986
3574
  class_name: "AnotherDurableObject",
2987
3575
  script_name: "another-durable-object-worker",
3576
+ environment: "staging",
2988
3577
  },
2989
3578
  ],
2990
3579
  },
@@ -3043,6 +3632,12 @@ export default{
3043
3632
  mockUploadWorkerRequest({
3044
3633
  expectedType: "sw",
3045
3634
  expectedBindings: [
3635
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
3636
+ {
3637
+ name: "ENV_VAR_TWO",
3638
+ text: "Hello, I'm an environment variable",
3639
+ type: "plain_text",
3640
+ },
3046
3641
  {
3047
3642
  name: "KV_NAMESPACE_ONE",
3048
3643
  namespace_id: "kv-ns-one-id",
@@ -3061,6 +3656,7 @@ export default{
3061
3656
  },
3062
3657
  {
3063
3658
  class_name: "AnotherDurableObject",
3659
+ environment: "staging",
3064
3660
  name: "DURABLE_OBJECT_TWO",
3065
3661
  script_name: "another-durable-object-worker",
3066
3662
  type: "durable_object_namespace",
@@ -3075,12 +3671,6 @@ export default{
3075
3671
  name: "R2_BUCKET_TWO",
3076
3672
  type: "r2_bucket",
3077
3673
  },
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
3674
  {
3085
3675
  name: "WASM_MODULE_ONE",
3086
3676
  part: "WASM_MODULE_ONE",
@@ -3112,7 +3702,32 @@ export default{
3112
3702
 
3113
3703
  await expect(runWrangler("publish index.js")).resolves.toBeUndefined();
3114
3704
  expect(std.out).toMatchInlineSnapshot(`
3115
- "Uploaded test-name (TIMINGS)
3705
+ "Your worker has access to the following bindings:
3706
+ - Data Blobs:
3707
+ - DATA_BLOB_ONE: some-data-blob.bin
3708
+ - DATA_BLOB_TWO: more-data-blob.bin
3709
+ - Durable Objects:
3710
+ - DURABLE_OBJECT_ONE: SomeDurableObject (defined in some-durable-object-worker)
3711
+ - DURABLE_OBJECT_TWO: AnotherDurableObject (defined in another-durable-object-worker) - staging
3712
+ - KV Namespaces:
3713
+ - KV_NAMESPACE_ONE: kv-ns-one-id
3714
+ - KV_NAMESPACE_TWO: kv-ns-two-id
3715
+ - R2 Buckets:
3716
+ - R2_BUCKET_ONE: r2-bucket-one-name
3717
+ - R2_BUCKET_TWO: r2-bucket-two-name
3718
+ - Text Blobs:
3719
+ - TEXT_BLOB_ONE: my-entire-app-depends-on-this.cfg
3720
+ - TEXT_BLOB_TWO: the-entirety-of-human-knowledge.txt
3721
+ - Unsafe:
3722
+ - some unsafe thing: UNSAFE_BINDING_ONE
3723
+ - another unsafe thing: UNSAFE_BINDING_TWO
3724
+ - Vars:
3725
+ - ENV_VAR_ONE: \\"123\\"
3726
+ - ENV_VAR_TWO: \\"Hello, I'm an environment variable\\"
3727
+ - Wasm Modules:
3728
+ - WASM_MODULE_ONE: some_wasm.wasm
3729
+ - WASM_MODULE_TWO: more_wasm.wasm
3730
+ Uploaded test-name (TIMINGS)
3116
3731
  Published test-name (TIMINGS)
3117
3732
  test-name.test-sub-domain.workers.dev"
3118
3733
  `);
@@ -3209,7 +3824,7 @@ export default{
3209
3824
  `);
3210
3825
  expect(std.out).toMatchInlineSnapshot(`
3211
3826
  "
3212
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3827
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3213
3828
  `);
3214
3829
  expect(std.err).toMatchInlineSnapshot(`
3215
3830
  "X [ERROR] Processing wrangler.toml configuration:
@@ -3308,7 +3923,7 @@ export default{
3308
3923
  `);
3309
3924
  expect(std.out).toMatchInlineSnapshot(`
3310
3925
  "
3311
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
3926
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3312
3927
  `);
3313
3928
  expect(std.err).toMatchInlineSnapshot(`
3314
3929
  "X [ERROR] Processing wrangler.toml configuration:
@@ -3442,7 +4057,7 @@ export default{
3442
4057
  `);
3443
4058
  expect(std.out).toMatchInlineSnapshot(`
3444
4059
  "
3445
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4060
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3446
4061
  `);
3447
4062
  expect(std.err).toMatchInlineSnapshot(`
3448
4063
  "X [ERROR] Processing wrangler.toml configuration:
@@ -3488,10 +4103,13 @@ export default{
3488
4103
  mockSubDomainRequest();
3489
4104
  await runWrangler("publish index.js");
3490
4105
  expect(std.out).toMatchInlineSnapshot(`
3491
- "Uploaded test-name (TIMINGS)
3492
- Published test-name (TIMINGS)
3493
- test-name.test-sub-domain.workers.dev"
3494
- `);
4106
+ "Your worker has access to the following bindings:
4107
+ - Wasm Modules:
4108
+ - TESTWASMNAME: path/to/test.wasm
4109
+ Uploaded test-name (TIMINGS)
4110
+ Published test-name (TIMINGS)
4111
+ test-name.test-sub-domain.workers.dev"
4112
+ `);
3495
4113
  expect(std.err).toMatchInlineSnapshot(`""`);
3496
4114
  expect(std.warn).toMatchInlineSnapshot(`""`);
3497
4115
  });
@@ -3513,7 +4131,7 @@ export default{
3513
4131
  );
3514
4132
  expect(std.out).toMatchInlineSnapshot(`
3515
4133
  "
3516
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4134
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3517
4135
  `);
3518
4136
  expect(std.err).toMatchInlineSnapshot(`
3519
4137
  "X [ERROR] You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code
@@ -3554,10 +4172,13 @@ export default{
3554
4172
  mockSubDomainRequest();
3555
4173
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3556
4174
  expect(std.out).toMatchInlineSnapshot(`
3557
- "Uploaded test-name (TIMINGS)
3558
- Published test-name (TIMINGS)
3559
- test-name.test-sub-domain.workers.dev"
3560
- `);
4175
+ "Your worker has access to the following bindings:
4176
+ - Wasm Modules:
4177
+ - TESTWASMNAME: path/to/and/the/path/to/test.wasm
4178
+ Uploaded test-name (TIMINGS)
4179
+ Published test-name (TIMINGS)
4180
+ test-name.test-sub-domain.workers.dev"
4181
+ `);
3561
4182
  expect(std.err).toMatchInlineSnapshot(`""`);
3562
4183
  expect(std.warn).toMatchInlineSnapshot(`""`);
3563
4184
  });
@@ -3619,10 +4240,13 @@ export default{
3619
4240
  mockSubDomainRequest();
3620
4241
  await runWrangler("publish index.js");
3621
4242
  expect(std.out).toMatchInlineSnapshot(`
3622
- "Uploaded test-name (TIMINGS)
3623
- Published test-name (TIMINGS)
3624
- test-name.test-sub-domain.workers.dev"
3625
- `);
4243
+ "Your worker has access to the following bindings:
4244
+ - Text Blobs:
4245
+ - TESTTEXTBLOBNAME: path/to/text.file
4246
+ Uploaded test-name (TIMINGS)
4247
+ Published test-name (TIMINGS)
4248
+ test-name.test-sub-domain.workers.dev"
4249
+ `);
3626
4250
  expect(std.err).toMatchInlineSnapshot(`""`);
3627
4251
  expect(std.warn).toMatchInlineSnapshot(`""`);
3628
4252
  });
@@ -3644,7 +4268,7 @@ export default{
3644
4268
  );
3645
4269
  expect(std.out).toMatchInlineSnapshot(`
3646
4270
  "
3647
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4271
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3648
4272
  `);
3649
4273
  expect(std.err).toMatchInlineSnapshot(`
3650
4274
  "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 +4313,13 @@ export default{
3689
4313
  mockSubDomainRequest();
3690
4314
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3691
4315
  expect(std.out).toMatchInlineSnapshot(`
3692
- "Uploaded test-name (TIMINGS)
3693
- Published test-name (TIMINGS)
3694
- test-name.test-sub-domain.workers.dev"
3695
- `);
4316
+ "Your worker has access to the following bindings:
4317
+ - Text Blobs:
4318
+ - TESTTEXTBLOBNAME: path/to/and/the/path/to/text.file
4319
+ Uploaded test-name (TIMINGS)
4320
+ Published test-name (TIMINGS)
4321
+ test-name.test-sub-domain.workers.dev"
4322
+ `);
3696
4323
  expect(std.err).toMatchInlineSnapshot(`""`);
3697
4324
  expect(std.warn).toMatchInlineSnapshot(`""`);
3698
4325
  });
@@ -3722,10 +4349,13 @@ export default{
3722
4349
  mockSubDomainRequest();
3723
4350
  await runWrangler("publish index.js");
3724
4351
  expect(std.out).toMatchInlineSnapshot(`
3725
- "Uploaded test-name (TIMINGS)
3726
- Published test-name (TIMINGS)
3727
- test-name.test-sub-domain.workers.dev"
3728
- `);
4352
+ "Your worker has access to the following bindings:
4353
+ - Data Blobs:
4354
+ - TESTDATABLOBNAME: path/to/data.bin
4355
+ Uploaded test-name (TIMINGS)
4356
+ Published test-name (TIMINGS)
4357
+ test-name.test-sub-domain.workers.dev"
4358
+ `);
3729
4359
  expect(std.err).toMatchInlineSnapshot(`""`);
3730
4360
  expect(std.warn).toMatchInlineSnapshot(`""`);
3731
4361
  });
@@ -3747,7 +4377,7 @@ export default{
3747
4377
  );
3748
4378
  expect(std.out).toMatchInlineSnapshot(`
3749
4379
  "
3750
- If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
4380
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
3751
4381
  `);
3752
4382
  expect(std.err).toMatchInlineSnapshot(`
3753
4383
  "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 +4422,13 @@ export default{
3792
4422
  mockSubDomainRequest();
3793
4423
  await runWrangler("publish index.js --config ./path/to/wrangler.toml");
3794
4424
  expect(std.out).toMatchInlineSnapshot(`
3795
- "Uploaded test-name (TIMINGS)
3796
- Published test-name (TIMINGS)
3797
- test-name.test-sub-domain.workers.dev"
3798
- `);
4425
+ "Your worker has access to the following bindings:
4426
+ - Data Blobs:
4427
+ - TESTDATABLOBNAME: path/to/and/the/path/to/data.bin
4428
+ Uploaded test-name (TIMINGS)
4429
+ Published test-name (TIMINGS)
4430
+ test-name.test-sub-domain.workers.dev"
4431
+ `);
3799
4432
  expect(std.err).toMatchInlineSnapshot(`""`);
3800
4433
  expect(std.warn).toMatchInlineSnapshot(`""`);
3801
4434
  });
@@ -3826,10 +4459,15 @@ export default{
3826
4459
 
3827
4460
  await runWrangler("publish index.js");
3828
4461
  expect(std.out).toMatchInlineSnapshot(`
3829
- "Uploaded test-name (TIMINGS)
3830
- Published test-name (TIMINGS)
3831
- test-name.test-sub-domain.workers.dev"
3832
- `);
4462
+ "Your worker has access to the following bindings:
4463
+ - Vars:
4464
+ - text: \\"plain ol' string\\"
4465
+ - count: \\"1\\"
4466
+ - complex: \\"[object Object]\\"
4467
+ Uploaded test-name (TIMINGS)
4468
+ Published test-name (TIMINGS)
4469
+ test-name.test-sub-domain.workers.dev"
4470
+ `);
3833
4471
  expect(std.err).toMatchInlineSnapshot(`""`);
3834
4472
  expect(std.warn).toMatchInlineSnapshot(`""`);
3835
4473
  });
@@ -3850,10 +4488,13 @@ export default{
3850
4488
 
3851
4489
  await runWrangler("publish index.js");
3852
4490
  expect(std.out).toMatchInlineSnapshot(`
3853
- "Uploaded test-name (TIMINGS)
3854
- Published test-name (TIMINGS)
3855
- test-name.test-sub-domain.workers.dev"
3856
- `);
4491
+ "Your worker has access to the following bindings:
4492
+ - R2 Buckets:
4493
+ - FOO: foo-bucket
4494
+ Uploaded test-name (TIMINGS)
4495
+ Published test-name (TIMINGS)
4496
+ test-name.test-sub-domain.workers.dev"
4497
+ `);
3857
4498
  expect(std.err).toMatchInlineSnapshot(`""`);
3858
4499
  expect(std.warn).toMatchInlineSnapshot(`""`);
3859
4500
  });
@@ -3892,10 +4533,13 @@ export default{
3892
4533
 
3893
4534
  await runWrangler("publish index.js");
3894
4535
  expect(std.out).toMatchInlineSnapshot(`
3895
- "Uploaded test-name (TIMINGS)
3896
- Published test-name (TIMINGS)
3897
- test-name.test-sub-domain.workers.dev"
3898
- `);
4536
+ "Your worker has access to the following bindings:
4537
+ - Durable Objects:
4538
+ - EXAMPLE_DO_BINDING: ExampleDurableObject
4539
+ Uploaded test-name (TIMINGS)
4540
+ Published test-name (TIMINGS)
4541
+ test-name.test-sub-domain.workers.dev"
4542
+ `);
3899
4543
  expect(std.err).toMatchInlineSnapshot(`""`);
3900
4544
  expect(std.warn).toMatchInlineSnapshot(`""`);
3901
4545
  });
@@ -3928,10 +4572,13 @@ export default{
3928
4572
 
3929
4573
  await runWrangler("publish index.js");
3930
4574
  expect(std.out).toMatchInlineSnapshot(`
3931
- "Uploaded test-name (TIMINGS)
3932
- Published test-name (TIMINGS)
3933
- test-name.test-sub-domain.workers.dev"
3934
- `);
4575
+ "Your worker has access to the following bindings:
4576
+ - Durable Objects:
4577
+ - EXAMPLE_DO_BINDING: ExampleDurableObject (defined in example-do-binding-worker)
4578
+ Uploaded test-name (TIMINGS)
4579
+ Published test-name (TIMINGS)
4580
+ test-name.test-sub-domain.workers.dev"
4581
+ `);
3935
4582
  expect(std.err).toMatchInlineSnapshot(`""`);
3936
4583
  expect(std.warn).toMatchInlineSnapshot(`""`);
3937
4584
  });
@@ -3969,10 +4616,13 @@ export default{
3969
4616
 
3970
4617
  await runWrangler("publish index.js");
3971
4618
  expect(std.out).toMatchInlineSnapshot(`
3972
- "Uploaded test-name (TIMINGS)
3973
- Published test-name (TIMINGS)
3974
- test-name.test-sub-domain.workers.dev"
3975
- `);
4619
+ "Your worker has access to the following bindings:
4620
+ - Durable Objects:
4621
+ - EXAMPLE_DO_BINDING: ExampleDurableObject
4622
+ Uploaded test-name (TIMINGS)
4623
+ Published test-name (TIMINGS)
4624
+ test-name.test-sub-domain.workers.dev"
4625
+ `);
3976
4626
  expect(std.err).toMatchInlineSnapshot(`""`);
3977
4627
  expect(std.warn).toMatchInlineSnapshot(`""`);
3978
4628
  });
@@ -4002,6 +4652,50 @@ export default{
4002
4652
  });
4003
4653
  });
4004
4654
 
4655
+ describe("[services]", () => {
4656
+ it("should support service bindings", async () => {
4657
+ writeWranglerToml({
4658
+ services: [
4659
+ {
4660
+ binding: "FOO",
4661
+ service: "foo-service",
4662
+ environment: "production",
4663
+ },
4664
+ ],
4665
+ });
4666
+ writeWorkerSource();
4667
+ mockSubDomainRequest();
4668
+ mockUploadWorkerRequest({
4669
+ expectedBindings: [
4670
+ {
4671
+ type: "service",
4672
+ name: "FOO",
4673
+ service: "foo-service",
4674
+ environment: "production",
4675
+ },
4676
+ ],
4677
+ });
4678
+
4679
+ await runWrangler("publish index.js");
4680
+ expect(std.out).toMatchInlineSnapshot(`
4681
+ "Your worker has access to the following bindings:
4682
+ - Services:
4683
+ - FOO: foo-service - production
4684
+ Uploaded test-name (TIMINGS)
4685
+ Published test-name (TIMINGS)
4686
+ test-name.test-sub-domain.workers.dev"
4687
+ `);
4688
+ expect(std.err).toMatchInlineSnapshot(`""`);
4689
+ expect(std.warn).toMatchInlineSnapshot(`
4690
+ "▲ [WARNING] Processing wrangler.toml configuration:
4691
+
4692
+ - \\"services\\" fields are experimental and may change or break at any time.
4693
+
4694
+ "
4695
+ `);
4696
+ });
4697
+ });
4698
+
4005
4699
  describe("[unsafe]", () => {
4006
4700
  it("should warn if using unsafe bindings", async () => {
4007
4701
  writeWranglerToml({
@@ -4029,10 +4723,13 @@ export default{
4029
4723
 
4030
4724
  await runWrangler("publish index.js");
4031
4725
  expect(std.out).toMatchInlineSnapshot(`
4032
- "Uploaded test-name (TIMINGS)
4033
- Published test-name (TIMINGS)
4034
- test-name.test-sub-domain.workers.dev"
4035
- `);
4726
+ "Your worker has access to the following bindings:
4727
+ - Unsafe:
4728
+ - binding-type: my-binding
4729
+ Uploaded test-name (TIMINGS)
4730
+ Published test-name (TIMINGS)
4731
+ test-name.test-sub-domain.workers.dev"
4732
+ `);
4036
4733
  expect(std.err).toMatchInlineSnapshot(`""`);
4037
4734
  expect(std.warn).toMatchInlineSnapshot(`
4038
4735
  "▲ [WARNING] Processing wrangler.toml configuration:
@@ -4068,10 +4765,13 @@ export default{
4068
4765
 
4069
4766
  await runWrangler("publish index.js");
4070
4767
  expect(std.out).toMatchInlineSnapshot(`
4071
- "Uploaded test-name (TIMINGS)
4072
- Published test-name (TIMINGS)
4073
- test-name.test-sub-domain.workers.dev"
4074
- `);
4768
+ "Your worker has access to the following bindings:
4769
+ - Unsafe:
4770
+ - plain_text: my-binding
4771
+ Uploaded test-name (TIMINGS)
4772
+ Published test-name (TIMINGS)
4773
+ test-name.test-sub-domain.workers.dev"
4774
+ `);
4075
4775
  expect(std.err).toMatchInlineSnapshot(`""`);
4076
4776
  expect(std.warn).toMatchInlineSnapshot(`
4077
4777
  "▲ [WARNING] Processing wrangler.toml configuration:
@@ -4504,14 +5204,25 @@ export default{
4504
5204
 
4505
5205
  describe("--dry-run", () => {
4506
5206
  it("should not publish the worker if --dry-run is specified", async () => {
4507
- writeWranglerToml();
5207
+ writeWranglerToml({
5208
+ // add a durable object with migrations
5209
+ // to make sure we _don't_ fetch migration status
5210
+ durable_objects: {
5211
+ bindings: [{ name: "NAME", class_name: "SomeClass" }],
5212
+ },
5213
+ migrations: [{ tag: "v1", new_classes: ["SomeClass"] }],
5214
+ });
4508
5215
  writeWorkerSource();
5216
+ process.env.CLOUDFLARE_ACCOUNT_ID = "";
4509
5217
  await runWrangler("publish index.js --dry-run");
4510
5218
  expect(std).toMatchInlineSnapshot(`
4511
5219
  Object {
4512
5220
  "debug": "",
4513
5221
  "err": "",
4514
- "out": "--dry-run: exiting now.",
5222
+ "out": "Your worker has access to the following bindings:
5223
+ - Durable Objects:
5224
+ - NAME: SomeClass
5225
+ --dry-run: exiting now.",
4515
5226
  "warn": "",
4516
5227
  }
4517
5228
  `);
@@ -4528,13 +5239,34 @@ export default{
4528
5239
  "debug": "",
4529
5240
  "err": "",
4530
5241
  "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.
5242
+ "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
5243
 
4533
5244
  ",
4534
5245
  }
4535
5246
  `);
4536
5247
  });
4537
5248
 
5249
+ it("should recommend node compatibility mode when using node builtins and node-compat isn't enabled", async () => {
5250
+ writeWranglerToml();
5251
+ fs.writeFileSync(
5252
+ "index.js",
5253
+ `
5254
+ import path from 'path';
5255
+ console.log(path.join("some/path/to", "a/file.txt"));
5256
+ export default {}
5257
+ `
5258
+ );
5259
+ let err: Error | undefined;
5260
+ try {
5261
+ await runWrangler("publish index.js --dry-run"); // expecting this to throw, as node compatibility isn't enabled
5262
+ } catch (e) {
5263
+ err = e as Error;
5264
+ }
5265
+ expect(err?.message).toMatch(
5266
+ `Detected a Node builtin module import while Node compatibility is disabled.\nAdd node_compat = true to your wrangler.toml file to enable Node compatibility.`
5267
+ );
5268
+ });
5269
+
4538
5270
  it("should polyfill node builtins when enabled", async () => {
4539
5271
  writeWranglerToml();
4540
5272
  fs.writeFileSync(
@@ -4551,7 +5283,7 @@ export default{
4551
5283
  "debug": "",
4552
5284
  "err": "",
4553
5285
  "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.
5286
+ "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
5287
 
4556
5288
  ",
4557
5289
  }
@@ -4561,10 +5293,16 @@ export default{
4561
5293
  });
4562
5294
 
4563
5295
  /** Write mock assets to the file system so they can be uploaded. */
4564
- function writeAssets(assets: { filePath: string; content: string }[]) {
5296
+ function writeAssets(
5297
+ assets: { filePath: string; content: string }[],
5298
+ destination = "assets"
5299
+ ) {
4565
5300
  for (const asset of assets) {
4566
- fs.mkdirSync(path.dirname(asset.filePath), { recursive: true });
4567
- fs.writeFileSync(asset.filePath, asset.content);
5301
+ const filePathDestination = path.join(destination, asset.filePath);
5302
+ fs.mkdirSync(path.dirname(filePathDestination), {
5303
+ recursive: true,
5304
+ });
5305
+ fs.writeFileSync(filePathDestination, asset.content);
4568
5306
  }
4569
5307
  }
4570
5308
 
@@ -4729,6 +5467,145 @@ function mockPublishRoutesRequest({
4729
5467
  );
4730
5468
  }
4731
5469
 
5470
+ function mockUnauthorizedPublishRoutesRequest({
5471
+ env = undefined,
5472
+ legacyEnv = false,
5473
+ }: {
5474
+ env?: string | undefined;
5475
+ legacyEnv?: boolean | undefined;
5476
+ } = {}) {
5477
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5478
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5479
+
5480
+ setMockRawResponse(
5481
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/routes`,
5482
+ "PUT",
5483
+ () =>
5484
+ createFetchResult(null, false, [
5485
+ { message: "Authentication error", code: 10000 },
5486
+ ])
5487
+ );
5488
+ }
5489
+
5490
+ function mockCollectKnownRoutesRequest(
5491
+ routes: { pattern: string; script: string }[]
5492
+ ) {
5493
+ setMockResponse(`/zones/:zoneId/workers/routes`, "GET", () => routes);
5494
+ }
5495
+
5496
+ function mockGetZoneFromHostRequest(host: string, zone: string) {
5497
+ setMockResponse("/zones", (_uri, _init, queryParams) => {
5498
+ expect(queryParams.get("name")).toEqual(host);
5499
+ return [{ id: zone }];
5500
+ });
5501
+ }
5502
+
5503
+ function mockPublishRoutesFallbackRequest(route: {
5504
+ pattern: string;
5505
+ script: string;
5506
+ }) {
5507
+ setMockResponse(`/zones/:zoneId/workers/routes`, "POST", (_url, { body }) => {
5508
+ expect(JSON.parse(body as string)).toEqual(route);
5509
+ return route.pattern;
5510
+ });
5511
+ }
5512
+
5513
+ function mockPublishCustomDomainsRequest({
5514
+ publishFlags,
5515
+ domains = [],
5516
+ env = undefined,
5517
+ legacyEnv = false,
5518
+ }: {
5519
+ publishFlags: {
5520
+ override_scope: boolean;
5521
+ override_existing_origin: boolean;
5522
+ override_existing_dns_record: boolean;
5523
+ };
5524
+ domains: Array<
5525
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5526
+ >;
5527
+ env?: string | undefined;
5528
+ legacyEnv?: boolean | undefined;
5529
+ }) {
5530
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5531
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5532
+
5533
+ setMockResponse(
5534
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5535
+ "PUT",
5536
+ ([_url, accountId, scriptName, envName], { body }) => {
5537
+ expect(accountId).toEqual("some-account-id");
5538
+ expect(scriptName).toEqual(
5539
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5540
+ );
5541
+ if (!legacyEnv) {
5542
+ expect(envName).toEqual(env);
5543
+ }
5544
+
5545
+ expect(JSON.parse(body as string)).toEqual({
5546
+ ...publishFlags,
5547
+ origins: domains,
5548
+ });
5549
+
5550
+ return null;
5551
+ }
5552
+ );
5553
+ }
5554
+
5555
+ function mockPublishCustomDomainsRequestConflictWithoutOverride({
5556
+ domains = [],
5557
+ originConflicts = false,
5558
+ dnsRecordConflicts = false,
5559
+ env = undefined,
5560
+ legacyEnv = false,
5561
+ }: {
5562
+ originConflicts?: boolean;
5563
+ dnsRecordConflicts?: boolean;
5564
+ domains: Array<
5565
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5566
+ >;
5567
+ env?: string | undefined;
5568
+ legacyEnv?: boolean | undefined;
5569
+ }) {
5570
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5571
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5572
+
5573
+ setMockRawResponse(
5574
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5575
+ "PUT",
5576
+ ([_url, accountId, scriptName, envName], { body }) => {
5577
+ expect(accountId).toEqual("some-account-id");
5578
+ expect(scriptName).toEqual(
5579
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5580
+ );
5581
+ if (!legacyEnv) {
5582
+ expect(envName).toEqual(env);
5583
+ }
5584
+
5585
+ const parsed = JSON.parse(body as string);
5586
+ expect(parsed.origins).toEqual(domains);
5587
+
5588
+ if (originConflicts && !parsed.override_existing_origin) {
5589
+ return createFetchResult(null, false, [
5590
+ {
5591
+ code: 100116,
5592
+ 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`,
5593
+ },
5594
+ ]);
5595
+ }
5596
+ if (dnsRecordConflicts && !parsed.override_existing_dns_record) {
5597
+ return createFetchResult(null, false, [
5598
+ {
5599
+ code: 100117,
5600
+ 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`,
5601
+ },
5602
+ ]);
5603
+ }
5604
+ return createFetchResult(null, true);
5605
+ }
5606
+ );
5607
+ }
5608
+
4732
5609
  /** Create a mock handler for the request to get a list of all KV namespaces. */
4733
5610
  function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
4734
5611
  setMockResponse(
@@ -4749,9 +5626,10 @@ function mockUploadAssetsToKVRequest(
4749
5626
  content: string;
4750
5627
  expiration?: number;
4751
5628
  expiration_ttl?: number;
4752
- }[]
5629
+ }[],
5630
+ onUpload?: () => void
4753
5631
  ) {
4754
- setMockResponse(
5632
+ return setMockResponse(
4755
5633
  "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
4756
5634
  "PUT",
4757
5635
  ([_url, accountId, namespaceId], { body }) => {
@@ -4781,6 +5659,7 @@ function mockUploadAssetsToKVRequest(
4781
5659
  expect(upload.expiration).toEqual(asset.expiration);
4782
5660
  expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
4783
5661
  }
5662
+ onUpload?.();
4784
5663
  return null;
4785
5664
  }
4786
5665
  );