wrangler 2.0.21 → 2.0.24

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 (65) hide show
  1. package/README.md +20 -2
  2. package/bin/wrangler.js +1 -1
  3. package/miniflare-dist/index.mjs +527 -5
  4. package/package.json +18 -5
  5. package/src/__tests__/configuration.test.ts +88 -16
  6. package/src/__tests__/dev.test.tsx +95 -4
  7. package/src/__tests__/generate.test.ts +93 -0
  8. package/src/__tests__/helpers/mock-cfetch.ts +54 -2
  9. package/src/__tests__/index.test.ts +10 -27
  10. package/src/__tests__/jest.setup.ts +31 -1
  11. package/src/__tests__/kv.test.ts +82 -61
  12. package/src/__tests__/metrics.test.ts +35 -0
  13. package/src/__tests__/publish.test.ts +573 -254
  14. package/src/__tests__/r2.test.ts +155 -71
  15. package/src/__tests__/user.test.ts +1 -0
  16. package/src/__tests__/validate-dev-props.test.ts +56 -0
  17. package/src/__tests__/version.test.ts +35 -0
  18. package/src/__tests__/whoami.test.tsx +60 -1
  19. package/src/api/dev.ts +43 -9
  20. package/src/bundle.ts +297 -37
  21. package/src/cfetch/internal.ts +34 -2
  22. package/src/config/config.ts +14 -2
  23. package/src/config/environment.ts +40 -8
  24. package/src/config/index.ts +13 -0
  25. package/src/config/validation.ts +110 -8
  26. package/src/create-worker-preview.ts +3 -1
  27. package/src/create-worker-upload-form.ts +25 -0
  28. package/src/dev/dev.tsx +135 -31
  29. package/src/dev/local.tsx +48 -20
  30. package/src/dev/remote.tsx +39 -12
  31. package/src/dev/use-esbuild.ts +25 -0
  32. package/src/dev/validate-dev-props.ts +31 -0
  33. package/src/dev-registry.tsx +157 -0
  34. package/src/dev.tsx +137 -65
  35. package/src/generate.ts +112 -14
  36. package/src/index.tsx +222 -7
  37. package/src/inspect.ts +93 -5
  38. package/src/metrics/index.ts +1 -0
  39. package/src/metrics/is-ci.ts +14 -0
  40. package/src/metrics/metrics-config.ts +19 -2
  41. package/src/metrics/metrics-dispatcher.ts +1 -0
  42. package/src/metrics/metrics-usage-headers.ts +24 -0
  43. package/src/metrics/send-event.ts +2 -2
  44. package/src/miniflare-cli/assets.ts +543 -0
  45. package/src/miniflare-cli/index.ts +36 -4
  46. package/src/module-collection.ts +3 -3
  47. package/src/pages/constants.ts +1 -0
  48. package/src/pages/deployments.tsx +1 -1
  49. package/src/pages/dev.tsx +85 -639
  50. package/src/pages/publish.tsx +1 -1
  51. package/src/pages/upload.tsx +32 -13
  52. package/src/publish.ts +139 -112
  53. package/src/r2.ts +68 -0
  54. package/src/user/choose-account.tsx +20 -11
  55. package/src/user/user.tsx +20 -2
  56. package/src/whoami.tsx +79 -1
  57. package/src/worker.ts +12 -0
  58. package/templates/first-party-worker-module-facade.ts +18 -0
  59. package/templates/format-dev-errors.ts +32 -0
  60. package/templates/pages-shim.ts +9 -0
  61. package/templates/{static-asset-facade.js → serve-static-assets.ts} +21 -7
  62. package/templates/service-bindings-module-facade.js +51 -0
  63. package/templates/service-bindings-sw-facade.js +39 -0
  64. package/wrangler-dist/cli.d.ts +32 -3
  65. package/wrangler-dist/cli.js +45257 -25209
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "2.0.21",
3
+ "version": "2.0.24",
4
4
  "description": "Command-line interface for all things Cloudflare Workers",
5
5
  "keywords": [
6
6
  "wrangler",
@@ -53,14 +53,21 @@
53
53
  "bundle": "node -r esbuild-register scripts/bundle.ts",
54
54
  "check:type": "tsc",
55
55
  "clean": "rm -rf wrangler-dist miniflare-dist emitted-types",
56
- "dev": "npm run clean && concurrently -c black,blue 'npm run bundle -- --watch' 'npm run check:type -- --watch --preserveWatchOutput'",
56
+ "dev": "npm run clean && concurrently -c black,blue --kill-others-on-fail false 'npm run bundle -- --watch' 'npm run check:type -- --watch --preserveWatchOutput'",
57
57
  "emit-types": "tsc -p tsconfig.emit.json && node -r esbuild-register scripts/emit-types.ts",
58
58
  "prepublishOnly": "SOURCEMAPS=false npm run build",
59
59
  "start": "npm run bundle && NODE_OPTIONS=--enable-source-maps ./bin/wrangler.js",
60
60
  "test": "jest --silent=false --verbose=true",
61
- "test-watch": "npm run test -- --runInBand --testTimeout=50000 --watch"
61
+ "test-watch": "npm run test -- --runInBand --testTimeout=50000 --watch",
62
+ "test:ci": "npm run test -- --verbose=true --coverage"
62
63
  },
63
64
  "jest": {
65
+ "coverageReporters": [
66
+ "json",
67
+ "html",
68
+ "text",
69
+ "cobertura"
70
+ ],
64
71
  "moduleNameMapper": {
65
72
  "clipboardy": "<rootDir>/src/__tests__/helpers/clipboardy-mock.js",
66
73
  "miniflare/cli": "<rootDir>/../../node_modules/miniflare/dist/src/cli.js"
@@ -88,17 +95,20 @@
88
95
  "@esbuild-plugins/node-globals-polyfill": "^0.1.1",
89
96
  "@esbuild-plugins/node-modules-polyfill": "^0.1.4",
90
97
  "blake3-wasm": "^2.1.5",
91
- "esbuild": "0.14.47",
98
+ "chokidar": "^3.5.3",
99
+ "esbuild": "0.14.51",
92
100
  "miniflare": "^2.6.0",
93
101
  "nanoid": "^3.3.3",
94
102
  "path-to-regexp": "^6.2.0",
95
103
  "selfsigned": "^2.0.1",
104
+ "source-map": "^0.7.4",
96
105
  "xxhash-wasm": "^1.0.1"
97
106
  },
98
107
  "devDependencies": {
99
108
  "@iarna/toml": "^3.0.0",
100
109
  "@microsoft/api-extractor": "^7.28.3",
101
110
  "@types/command-exists": "^1.2.0",
111
+ "@types/express": "^4.17.13",
102
112
  "@types/glob-to-regexp": "0.4.1",
103
113
  "@types/mime": "^2.0.3",
104
114
  "@types/prompts": "^2.0.14",
@@ -109,14 +119,16 @@
109
119
  "@types/ws": "^8.5.3",
110
120
  "@types/yargs": "^17.0.10",
111
121
  "@webcontainer/env": "^1.0.1",
112
- "chokidar": "^3.5.3",
122
+ "body-parser": "^1.20.0",
113
123
  "clipboardy": "^3.0.0",
114
124
  "cmd-shim": "^4.1.0",
115
125
  "command-exists": "^1.2.9",
116
126
  "concurrently": "^7.2.2",
127
+ "create-cloudflare": "^1.0.0",
117
128
  "devtools-protocol": "^0.0.955664",
118
129
  "dotenv": "^16.0.0",
119
130
  "execa": "^6.1.0",
131
+ "express": "^4.18.1",
120
132
  "faye-websocket": "^0.11.4",
121
133
  "finalhandler": "^1.2.0",
122
134
  "find-up": "^6.3.0",
@@ -130,6 +142,7 @@
130
142
  "ink-table": "^3.0.0",
131
143
  "ink-testing-library": "^2.1.0",
132
144
  "ink-text-input": "^4.0.3",
145
+ "is-ci": "^3.0.1",
133
146
  "jest-fetch-mock": "^3.0.3",
134
147
  "jest-websocket-mock": "^2.3.0",
135
148
  "mime": "^3.0.0",
@@ -40,6 +40,10 @@ describe("normalizeAndValidateConfig()", () => {
40
40
  tsconfig: undefined,
41
41
  kv_namespaces: [],
42
42
  legacy_env: true,
43
+ logfwdr: {
44
+ bindings: [],
45
+ schema: undefined,
46
+ },
43
47
  send_metrics: undefined,
44
48
  main: undefined,
45
49
  migrations: [],
@@ -68,6 +72,7 @@ describe("normalizeAndValidateConfig()", () => {
68
72
  no_bundle: undefined,
69
73
  minify: undefined,
70
74
  node_compat: undefined,
75
+ first_party_worker: undefined,
71
76
  });
72
77
  expect(diagnostics.hasErrors()).toBe(false);
73
78
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -463,6 +468,56 @@ describe("normalizeAndValidateConfig()", () => {
463
468
  });
464
469
 
465
470
  describe("[assets]", () => {
471
+ it("normalizes a string input to an object", () => {
472
+ const { config, diagnostics } = normalizeAndValidateConfig(
473
+ {
474
+ assets: "path/to/assets",
475
+ } as unknown as RawConfig,
476
+ undefined,
477
+ { env: undefined }
478
+ );
479
+
480
+ expect(config.assets).toMatchInlineSnapshot(`
481
+ Object {
482
+ "browser_TTL": undefined,
483
+ "bucket": "path/to/assets",
484
+ "exclude": Array [],
485
+ "include": Array [],
486
+ "serve_single_page_app": false,
487
+ }
488
+ `);
489
+ expect(diagnostics.hasWarnings()).toBe(true);
490
+ expect(diagnostics.hasErrors()).toBe(false);
491
+
492
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
493
+ "Processing wrangler configuration:
494
+ - \\"assets\\" fields are experimental and may change or break at any time."
495
+ `);
496
+ });
497
+
498
+ it("errors when input is not a string or object", () => {
499
+ const { config, diagnostics } = normalizeAndValidateConfig(
500
+ {
501
+ assets: 123,
502
+ } as unknown as RawConfig,
503
+ undefined,
504
+ { env: undefined }
505
+ );
506
+
507
+ expect(config.assets).toBeUndefined();
508
+ expect(diagnostics.hasWarnings()).toBe(true);
509
+ expect(diagnostics.hasErrors()).toBe(true);
510
+
511
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
512
+ "Processing wrangler configuration:
513
+ - \\"assets\\" fields are experimental and may change or break at any time."
514
+ `);
515
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
516
+ "Processing wrangler configuration:
517
+ - Expected the \`assets\` field to be a string or an object, but got number."
518
+ `);
519
+ });
520
+
466
521
  it("should error if `assets` config is missing `bucket`", () => {
467
522
  const expectedConfig: RawConfig = {
468
523
  // @ts-expect-error we're intentionally passing an invalid configuration here
@@ -478,7 +533,9 @@ describe("normalizeAndValidateConfig()", () => {
478
533
  { env: undefined }
479
534
  );
480
535
 
481
- expect(config).toEqual(expect.objectContaining(expectedConfig));
536
+ expect(config.assets).toEqual(
537
+ expect.objectContaining(expectedConfig.assets)
538
+ );
482
539
  expect(diagnostics.hasWarnings()).toBe(true);
483
540
  expect(diagnostics.hasErrors()).toBe(true);
484
541
 
@@ -498,6 +555,8 @@ describe("normalizeAndValidateConfig()", () => {
498
555
  bucket: "BUCKET",
499
556
  include: [222, 333],
500
557
  exclude: [444, 555],
558
+ browser_TTL: "not valid",
559
+ serve_single_page_app: "INVALID",
501
560
  },
502
561
  };
503
562
 
@@ -514,12 +573,14 @@ describe("normalizeAndValidateConfig()", () => {
514
573
  - \\"assets\\" fields are experimental and may change or break at any time."
515
574
  `);
516
575
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
517
- "Processing wrangler configuration:
518
- - Expected \\"assets.include.[0]\\" to be of type string but got 222.
519
- - Expected \\"assets.include.[1]\\" to be of type string but got 333.
520
- - Expected \\"assets.exclude.[0]\\" to be of type string but got 444.
521
- - Expected \\"assets.exclude.[1]\\" to be of type string but got 555."
522
- `);
576
+ "Processing wrangler configuration:
577
+ - Expected \\"assets.include.[0]\\" to be of type string but got 222.
578
+ - Expected \\"assets.include.[1]\\" to be of type string but got 333.
579
+ - Expected \\"assets.exclude.[0]\\" to be of type string but got 444.
580
+ - Expected \\"assets.exclude.[1]\\" to be of type string but got 555.
581
+ - Expected \\"assets.browser_TTL\\" to be of type number but got \\"not valid\\".
582
+ - Expected \\"assets.serve_single_page_app\\" to be of type boolean but got \\"INVALID\\"."
583
+ `);
523
584
  });
524
585
  });
525
586
 
@@ -858,6 +919,7 @@ describe("normalizeAndValidateConfig()", () => {
858
919
  no_bundle: true,
859
920
  minify: true,
860
921
  node_compat: true,
922
+ first_party_worker: true,
861
923
  };
862
924
 
863
925
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -931,6 +993,7 @@ describe("normalizeAndValidateConfig()", () => {
931
993
  no_bundle: "INVALID",
932
994
  minify: "INVALID",
933
995
  node_compat: "INVALID",
996
+ first_party_worker: "INVALID",
934
997
  } as unknown as RawEnvironment;
935
998
 
936
999
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -997,7 +1060,8 @@ describe("normalizeAndValidateConfig()", () => {
997
1060
  - The field \\"define.DEF1\\" should be a string but got 1777.
998
1061
  - Expected \\"no_bundle\\" to be of type boolean but got \\"INVALID\\".
999
1062
  - Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
1000
- - Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\"."
1063
+ - Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\".
1064
+ - Expected \\"first_party_worker\\" to be of type boolean but got \\"INVALID\\"."
1001
1065
  `);
1002
1066
  });
1003
1067
 
@@ -2311,6 +2375,7 @@ describe("normalizeAndValidateConfig()", () => {
2311
2375
  no_bundle: true,
2312
2376
  minify: true,
2313
2377
  node_compat: true,
2378
+ first_party_worker: true,
2314
2379
  };
2315
2380
 
2316
2381
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -2354,6 +2419,7 @@ describe("normalizeAndValidateConfig()", () => {
2354
2419
  no_bundle: false,
2355
2420
  minify: false,
2356
2421
  node_compat: false,
2422
+ first_party_worker: false,
2357
2423
  };
2358
2424
  const rawConfig: RawConfig = {
2359
2425
  name: "mock-name",
@@ -2376,6 +2442,7 @@ describe("normalizeAndValidateConfig()", () => {
2376
2442
  no_bundle: true,
2377
2443
  minify: true,
2378
2444
  node_compat: true,
2445
+ first_party_worker: true,
2379
2446
  env: {
2380
2447
  ENV1: rawEnv,
2381
2448
  },
@@ -2637,6 +2704,7 @@ describe("normalizeAndValidateConfig()", () => {
2637
2704
  no_bundle: "INVALID",
2638
2705
  minify: "INVALID",
2639
2706
  node_compat: "INVALID",
2707
+ first_party_worker: "INVALID",
2640
2708
  } as unknown as RawEnvironment;
2641
2709
 
2642
2710
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -2672,7 +2740,8 @@ describe("normalizeAndValidateConfig()", () => {
2672
2740
  - Expected \\"usage_model\\" field to be one of [\\"bundled\\",\\"unbound\\"] but got \\"INVALID\\".
2673
2741
  - Expected \\"no_bundle\\" to be of type boolean but got \\"INVALID\\".
2674
2742
  - Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
2675
- - Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\"."
2743
+ - Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\".
2744
+ - Expected \\"first_party_worker\\" to be of type boolean but got \\"INVALID\\"."
2676
2745
  `);
2677
2746
  });
2678
2747
 
@@ -3670,6 +3739,7 @@ describe("normalizeAndValidateConfig()", () => {
3670
3739
  it("should remove and warn about deprecated properties", () => {
3671
3740
  const environment: RawEnvironment = {
3672
3741
  zone_id: "ZONE_ID",
3742
+ "kv-namespaces": "BAD_KV_NAMESPACE",
3673
3743
  experimental_services: [
3674
3744
  {
3675
3745
  name: "mock-name",
@@ -3695,14 +3765,16 @@ describe("normalizeAndValidateConfig()", () => {
3695
3765
  expect(diagnostics.hasErrors()).toBe(false);
3696
3766
  expect(diagnostics.hasWarnings()).toBe(true);
3697
3767
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
3698
- "Processing wrangler configuration:
3768
+ "Processing wrangler configuration:
3699
3769
 
3700
- - \\"env.ENV1\\" environment configuration
3701
- - Deprecation: \\"zone_id\\":
3702
- This is unnecessary since we can deduce this from routes directly.
3703
- - Deprecation: \\"experimental_services\\":
3704
- The \\"experimental_services\\" field is no longer supported. Simply rename the [experimental_services] field to [services]."
3705
- `);
3770
+ - \\"env.ENV1\\" environment configuration
3771
+ - Deprecation: \\"kv-namespaces\\":
3772
+ The \\"kv-namespaces\\" field is no longer supported, please rename to \\"kv_namespaces\\"
3773
+ - Deprecation: \\"zone_id\\":
3774
+ This is unnecessary since we can deduce this from routes directly.
3775
+ - Deprecation: \\"experimental_services\\":
3776
+ The \\"experimental_services\\" field is no longer supported. Simply rename the [experimental_services] field to [services]."
3777
+ `);
3706
3778
  });
3707
3779
  });
3708
3780
 
@@ -525,9 +525,9 @@ describe("wrangler dev", () => {
525
525
 
526
526
  await expect(runWrangler("dev")).rejects
527
527
  .toThrowErrorMatchingInlineSnapshot(`
528
- "The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
529
- The \`main\` property in wrangler.toml should point to the file generated by the custom build."
530
- `);
528
+ "The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
529
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build."
530
+ `);
531
531
  expect(std.out).toMatchInlineSnapshot(`
532
532
  "Running custom build: node -e \\"console.log('custom build');\\"
533
533
 
@@ -673,6 +673,78 @@ describe("wrangler dev", () => {
673
673
  });
674
674
  });
675
675
 
676
+ describe("inspector port", () => {
677
+ it("should use 9229 as the default port", async () => {
678
+ writeWranglerToml({
679
+ main: "index.js",
680
+ });
681
+ fs.writeFileSync("index.js", `export default {};`);
682
+ await runWrangler("dev");
683
+ expect((Dev as jest.Mock).mock.calls[0][0].inspectorPort).toEqual(9229);
684
+ expect(std).toMatchInlineSnapshot(`
685
+ Object {
686
+ "debug": "",
687
+ "err": "",
688
+ "out": "",
689
+ "warn": "",
690
+ }
691
+ `);
692
+ });
693
+
694
+ it("should read --inspector-port", async () => {
695
+ writeWranglerToml({
696
+ main: "index.js",
697
+ });
698
+ fs.writeFileSync("index.js", `export default {};`);
699
+ await runWrangler("dev --inspector-port=9999");
700
+ expect((Dev as jest.Mock).mock.calls[0][0].inspectorPort).toEqual(9999);
701
+ expect(std).toMatchInlineSnapshot(`
702
+ Object {
703
+ "debug": "",
704
+ "err": "",
705
+ "out": "",
706
+ "warn": "",
707
+ }
708
+ `);
709
+ });
710
+
711
+ it("should read dev.inspector_port from wrangler.toml", async () => {
712
+ writeWranglerToml({
713
+ main: "index.js",
714
+ dev: {
715
+ inspector_port: 9999,
716
+ },
717
+ });
718
+ fs.writeFileSync("index.js", `export default {};`);
719
+ await runWrangler("dev");
720
+ expect((Dev as jest.Mock).mock.calls[0][0].inspectorPort).toEqual(9999);
721
+ expect(std).toMatchInlineSnapshot(`
722
+ Object {
723
+ "debug": "",
724
+ "err": "",
725
+ "out": "",
726
+ "warn": "",
727
+ }
728
+ `);
729
+ });
730
+
731
+ it("should error if a bad dev.inspector_port config is provided", async () => {
732
+ writeWranglerToml({
733
+ main: "index.js",
734
+ dev: {
735
+ // @ts-expect-error intentionally bad port
736
+ inspector_port: "some string",
737
+ },
738
+ });
739
+ fs.writeFileSync("index.js", `export default {};`);
740
+ await expect(runWrangler("dev")).rejects
741
+ .toThrowErrorMatchingInlineSnapshot(`
742
+ "Processing wrangler.toml configuration:
743
+ - Expected \\"dev.inspector_port\\" to be of type number but got \\"some string\\"."
744
+ `);
745
+ });
746
+ });
747
+
676
748
  describe("port", () => {
677
749
  it("should default port to 8787 if it is not in use", async () => {
678
750
  writeWranglerToml({
@@ -686,7 +758,7 @@ describe("wrangler dev", () => {
686
758
  expect(std.err).toMatchInlineSnapshot(`""`);
687
759
  });
688
760
 
689
- it("should use to `port` from `wrangler.toml`, if available", async () => {
761
+ it("should use `port` from `wrangler.toml`, if available", async () => {
690
762
  writeWranglerToml({
691
763
  main: "index.js",
692
764
  dev: {
@@ -704,6 +776,22 @@ describe("wrangler dev", () => {
704
776
  expect(std.err).toMatchInlineSnapshot(`""`);
705
777
  });
706
778
 
779
+ it("should error if a bad dev.port config is provided", async () => {
780
+ writeWranglerToml({
781
+ main: "index.js",
782
+ dev: {
783
+ // @ts-expect-error intentionally bad port
784
+ port: "some string",
785
+ },
786
+ });
787
+ fs.writeFileSync("index.js", `export default {};`);
788
+ await expect(runWrangler("dev")).rejects
789
+ .toThrowErrorMatchingInlineSnapshot(`
790
+ "Processing wrangler.toml configuration:
791
+ - Expected \\"dev.port\\" to be of type number but got \\"some string\\"."
792
+ `);
793
+ });
794
+
707
795
  it("should use --port command line arg, if provided", async () => {
708
796
  writeWranglerToml({
709
797
  main: "index.js",
@@ -950,6 +1038,7 @@ describe("wrangler dev", () => {
950
1038
  it("should error if config.assets and --site are used together", async () => {
951
1039
  writeWranglerToml({
952
1040
  main: "./index.js",
1041
+ // @ts-expect-error we allow string inputs here
953
1042
  assets: "abc",
954
1043
  });
955
1044
  fs.writeFileSync("index.js", `export default {};`);
@@ -963,6 +1052,7 @@ describe("wrangler dev", () => {
963
1052
  it("should error if config.assets and config.site are used together", async () => {
964
1053
  writeWranglerToml({
965
1054
  main: "./index.js",
1055
+ // @ts-expect-error we allow string inputs here
966
1056
  assets: "abc",
967
1057
  site: {
968
1058
  bucket: "xyz",
@@ -1014,6 +1104,7 @@ describe("wrangler dev", () => {
1014
1104
  it("should warn if config.assets is used", async () => {
1015
1105
  writeWranglerToml({
1016
1106
  main: "./index.js",
1107
+ // @ts-expect-error we allow string inputs here
1017
1108
  assets: "./assets",
1018
1109
  });
1019
1110
  fs.writeFileSync("index.js", `export default {};`);
@@ -0,0 +1,93 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import process from "node:process";
4
+ import { setup } from "create-cloudflare";
5
+ import { mockConsoleMethods } from "./helpers/mock-console";
6
+ import { mockConfirm, clearConfirmMocks } from "./helpers/mock-dialogs";
7
+ import { runInTempDir } from "./helpers/run-in-tmp";
8
+ import { runWrangler } from "./helpers/run-wrangler";
9
+
10
+ const createCloudflareMock = setup as jest.Mock;
11
+
12
+ describe("generate", () => {
13
+ runInTempDir();
14
+ const std = mockConsoleMethods();
15
+
16
+ afterEach(() => {
17
+ clearConfirmMocks();
18
+ });
19
+
20
+ it("defers to `wrangler init` when no template is given", async () => {
21
+ mockConfirm(
22
+ {
23
+ text: "Would you like to use git to manage this Worker?",
24
+ result: false,
25
+ },
26
+ {
27
+ text: "No package.json found. Would you like to create one?",
28
+ result: false,
29
+ }
30
+ );
31
+ await runWrangler("generate no-template");
32
+ expect(std.out).toMatchInlineSnapshot(
33
+ `"✨ Created no-template/wrangler.toml"`
34
+ );
35
+ });
36
+
37
+ it("runs `create-cloudflare` when a template is given", async () => {
38
+ await expect(
39
+ runWrangler("generate my-worker some-template")
40
+ ).resolves.toBeUndefined();
41
+
42
+ expect(createCloudflareMock).toBeCalled();
43
+ });
44
+
45
+ it("complains when given the --type argument", async () => {
46
+ await expect(
47
+ runWrangler("generate worker-name worker-template --type rust")
48
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
49
+ `"The --type option is no longer supported."`
50
+ );
51
+ });
52
+
53
+ it("complains when given the --site argument", async () => {
54
+ await expect(runWrangler("generate worker-name worker-template --site"))
55
+ .rejects.toThrowErrorMatchingInlineSnapshot(`
56
+ "The --site option is no longer supported.
57
+ If you wish to create a brand new Worker Sites project then clone the \`worker-sites-template\` starter repository:
58
+
59
+ \`\`\`
60
+ git clone --depth=1 --branch=wrangler2 https://github.com/cloudflare/worker-sites-template worker-name
61
+ cd worker-name
62
+ \`\`\`
63
+
64
+ Find out more about how to create and maintain Sites projects at https://developers.cloudflare.com/workers/platform/sites.
65
+ Have you considered using Cloudflare Pages instead? See https://pages.cloudflare.com/."
66
+ `);
67
+ });
68
+
69
+ it("auto-increments the worker directory name", async () => {
70
+ fs.mkdirSync("my-worker");
71
+ await expect(
72
+ runWrangler("generate my-worker some-template")
73
+ ).resolves.toBeUndefined();
74
+
75
+ expect(createCloudflareMock).lastCalledWith(
76
+ path.resolve(process.cwd(), "my-worker-1"),
77
+ "some-template",
78
+ { debug: false, force: false, init: true }
79
+ );
80
+
81
+ fs.mkdirSync("my-worker-1");
82
+
83
+ await expect(
84
+ runWrangler("generate my-worker some-template")
85
+ ).resolves.toBeUndefined();
86
+
87
+ expect(createCloudflareMock).lastCalledWith(
88
+ path.resolve(process.cwd(), "my-worker-2"),
89
+ "some-template",
90
+ { debug: false, force: false, init: true }
91
+ );
92
+ });
93
+ });
@@ -1,8 +1,10 @@
1
+ import { Readable } from "node:stream";
1
2
  import { URL, URLSearchParams } from "node:url";
2
3
  import { pathToRegexp } from "path-to-regexp";
4
+ import { Response } from "undici";
3
5
  import { getCloudflareApiBaseUrl } from "../../cfetch";
4
6
  import type { FetchResult, FetchError } from "../../cfetch";
5
- import type { RequestInit } from "undici";
7
+ import type { RequestInit, BodyInit, HeadersInit } from "undici";
6
8
 
7
9
  /**
8
10
  * The signature of the function that will handle a mock request.
@@ -180,6 +182,7 @@ export function unsetAllMocks() {
180
182
  */
181
183
 
182
184
  const kvGetMocks = new Map<string, string | Buffer>();
185
+ const r2GetMocks = new Map<string, string | undefined>();
183
186
 
184
187
  /**
185
188
  * @mocked typeof fetchKVGetValue
@@ -206,6 +209,55 @@ export function setMockFetchKVGetValue(
206
209
  kvGetMocks.set(`${accountId}/${namespaceId}/${key}`, value);
207
210
  }
208
211
 
209
- export function unsetMockFetchKVGetValues() {
212
+ /**
213
+ * @mocked typeof fetchR2Objects
214
+ */
215
+ export async function mockFetchR2Objects(
216
+ resource: string,
217
+ bodyInit: {
218
+ body: BodyInit | Readable;
219
+ headers: HeadersInit | undefined;
220
+ method: "PUT" | "GET";
221
+ }
222
+ ): Promise<Response> {
223
+ /**
224
+ * Here we destroy & removeListeners to "drain" the stream, for testing purposes
225
+ * mimicking the fetch request taking in the stream and draining it.
226
+ */
227
+ if (bodyInit.body instanceof Readable) {
228
+ bodyInit.body.destroy();
229
+ bodyInit.body.removeAllListeners();
230
+ }
231
+
232
+ if (r2GetMocks.has(resource)) {
233
+ const value = r2GetMocks.get(resource);
234
+
235
+ return new Response(value);
236
+ }
237
+ throw new Error(`no expected mock found for \`r2 object get\` - ${resource}`);
238
+ }
239
+
240
+ /**
241
+ * Mock setter for usage within test blocks, companion helper to `mockFetchR2Objects`
242
+ */
243
+ export function setMockFetchR2Objects({
244
+ accountId,
245
+ bucketName,
246
+ objectName,
247
+ mockResponse,
248
+ }: {
249
+ accountId: string;
250
+ bucketName: string;
251
+ objectName: string;
252
+ mockResponse?: string;
253
+ }) {
254
+ r2GetMocks.set(
255
+ `/accounts/${accountId}/r2/buckets/${bucketName}/objects/${objectName}`,
256
+ mockResponse
257
+ );
258
+ }
259
+
260
+ export function unsetSpecialMockFns() {
210
261
  kvGetMocks.clear();
262
+ r2GetMocks.clear();
211
263
  }
@@ -203,36 +203,19 @@ describe("wrangler", () => {
203
203
  await runWrangler("r2");
204
204
  await endEventLoop();
205
205
  expect(std.out).toMatchInlineSnapshot(`
206
- "wrangler r2
206
+ "wrangler r2
207
207
 
208
- 📦 Interact with an R2 store
208
+ 📦 Interact with an R2 store
209
209
 
210
- Commands:
211
- wrangler r2 bucket Manage R2 buckets
212
-
213
- Flags:
214
- -c, --config Path to .toml configuration file [string]
215
- -h, --help Show help [boolean]
216
- -v, --version Show version number [boolean]"
217
- `);
218
- });
219
- });
210
+ Commands:
211
+ wrangler r2 object Manage R2 objects
212
+ wrangler r2 bucket Manage R2 buckets
220
213
 
221
- describe("Deprecated commands", () => {
222
- it("should print a deprecation message for 'generate'", async () => {
223
- await runWrangler("generate").catch((err) => {
224
- expect(err.message).toMatchInlineSnapshot(`
225
- "Deprecation:
226
- \`wrangler generate\` has been deprecated.
227
- Try running \`wrangler init\` to generate a basic Worker, or cloning the template repository instead:
228
-
229
- \`\`\`
230
- git clone https://github.com/cloudflare/worker-template
231
- \`\`\`
232
-
233
- Please refer to https://developers.cloudflare.com/workers/wrangler/deprecations/#generate for more information."
234
- `);
235
- });
214
+ Flags:
215
+ -c, --config Path to .toml configuration file [string]
216
+ -h, --help Show help [boolean]
217
+ -v, --version Show version number [boolean]"
218
+ `);
236
219
  });
237
220
  });
238
221