wrangler 2.1.15 → 2.2.0

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 (71) hide show
  1. package/miniflare-dist/index.mjs +3 -1
  2. package/package.json +1 -1
  3. package/src/__tests__/access.test.ts +25 -0
  4. package/src/__tests__/api-dev.test.ts +1 -1
  5. package/src/__tests__/api-devregistry.test.js +2 -2
  6. package/src/__tests__/configuration.test.ts +119 -2
  7. package/src/__tests__/d1.test.ts +2 -0
  8. package/src/__tests__/deployments.test.ts +22 -22
  9. package/src/__tests__/dev.test.tsx +167 -15
  10. package/src/__tests__/helpers/msw/handlers/access.ts +13 -0
  11. package/src/__tests__/helpers/msw/handlers/deployments.ts +22 -43
  12. package/src/__tests__/helpers/msw/handlers/zones.ts +22 -0
  13. package/src/__tests__/helpers/msw/index.ts +4 -0
  14. package/src/__tests__/index.test.ts +42 -33
  15. package/src/__tests__/init.test.ts +88 -4
  16. package/src/__tests__/jest.setup.ts +11 -0
  17. package/src/__tests__/kv.test.ts +400 -400
  18. package/src/__tests__/pages.test.ts +30 -28
  19. package/src/__tests__/publish.test.ts +1161 -647
  20. package/src/__tests__/pubsub.test.ts +3 -0
  21. package/src/__tests__/queues.test.ts +371 -0
  22. package/src/__tests__/r2.test.ts +57 -52
  23. package/src/__tests__/worker-namespace.test.ts +15 -10
  24. package/src/bundle-reporter.tsx +41 -2
  25. package/src/bundle.ts +59 -30
  26. package/src/cli.ts +0 -1
  27. package/src/config/environment.ts +50 -0
  28. package/src/config/index.ts +41 -0
  29. package/src/config/validation.ts +173 -0
  30. package/src/create-worker-preview.ts +10 -3
  31. package/src/create-worker-upload-form.ts +12 -0
  32. package/src/d1/backups.tsx +11 -5
  33. package/src/d1/execute.tsx +52 -47
  34. package/src/d1/index.ts +2 -1
  35. package/src/delete.ts +7 -10
  36. package/src/deployments.ts +73 -0
  37. package/src/deprecated/index.ts +9 -24
  38. package/src/dev/dev-vars.ts +11 -8
  39. package/src/dev/dev.tsx +12 -0
  40. package/src/dev/local.tsx +26 -0
  41. package/src/dev/remote.tsx +2 -0
  42. package/src/dev/start-server.ts +7 -0
  43. package/src/dev/use-esbuild.ts +12 -5
  44. package/src/dev.tsx +12 -9
  45. package/src/dispatch-namespace.ts +4 -3
  46. package/src/index.tsx +61 -45
  47. package/src/init.ts +4 -4
  48. package/src/inspect.ts +21 -1
  49. package/src/kv/index.ts +5 -54
  50. package/src/logger.ts +12 -0
  51. package/src/pages/upload.tsx +19 -2
  52. package/src/proxy.ts +38 -6
  53. package/src/publish/index.ts +11 -8
  54. package/src/publish/publish.ts +151 -30
  55. package/src/pubsub/pubsub-commands.tsx +3 -2
  56. package/src/queues/cli/commands/consumer/add.ts +71 -0
  57. package/src/queues/cli/commands/consumer/index.ts +22 -0
  58. package/src/queues/cli/commands/consumer/remove.ts +38 -0
  59. package/src/queues/cli/commands/create.ts +25 -0
  60. package/src/queues/cli/commands/delete.ts +26 -0
  61. package/src/queues/cli/commands/index.ts +33 -0
  62. package/src/queues/cli/commands/list.ts +25 -0
  63. package/src/queues/client.ts +135 -0
  64. package/src/secret/index.ts +14 -39
  65. package/src/tail/index.ts +5 -8
  66. package/src/user/access.ts +69 -0
  67. package/src/worker.ts +7 -0
  68. package/src/yargs-types.ts +15 -2
  69. package/src/zones.ts +31 -5
  70. package/wrangler-dist/cli.d.ts +42 -0
  71. package/wrangler-dist/cli.js +3858 -3244
@@ -5592,6 +5592,7 @@ function createMetadataObject({
5592
5592
  headers,
5593
5593
  webAnalyticsToken,
5594
5594
  deploymentId,
5595
+ failOpen,
5595
5596
  logger = (_message) => {
5596
5597
  }
5597
5598
  }) {
@@ -5599,7 +5600,8 @@ function createMetadataObject({
5599
5600
  ...constructRedirects({ redirects, logger }),
5600
5601
  ...constructHeaders({ headers, logger }),
5601
5602
  ...constructWebAnalytics({ webAnalyticsToken, logger }),
5602
- deploymentId
5603
+ deploymentId,
5604
+ failOpen
5603
5605
  };
5604
5606
  }
5605
5607
  function constructRedirects({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "2.1.15",
3
+ "version": "2.2.0",
4
4
  "description": "Command-line interface for all things Cloudflare Workers",
5
5
  "keywords": [
6
6
  "wrangler",
@@ -0,0 +1,25 @@
1
+ import { domainUsesAccess, getAccessToken } from "../user/access";
2
+ import { msw, mswAccessHandlers } from "./helpers/msw";
3
+
4
+ describe("access", () => {
5
+ beforeEach(() => {
6
+ msw.use(...mswAccessHandlers);
7
+ });
8
+
9
+ describe("basic", () => {
10
+ it("should correctly detect an access protected domain", async () => {
11
+ expect(await domainUsesAccess("access-protected.com")).toBeTruthy();
12
+ expect(await domainUsesAccess("not-access-protected.com")).toBeFalsy();
13
+ });
14
+ it("should not fail without cloudflared installed", async () => {
15
+ expect(await getAccessToken("not-access-protected.com")).toBeFalsy();
16
+ });
17
+ it("should error without cloudflared installed on an access protected domain", async () => {
18
+ await expect(getAccessToken("access-protected.com")).rejects.toEqual(
19
+ new Error(
20
+ "To use Wrangler with Cloudflare Access, please install `cloudflared` from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation"
21
+ )
22
+ );
23
+ });
24
+ });
25
+ });
@@ -5,7 +5,7 @@ import { runInTempDir } from "./helpers/run-in-tmp";
5
5
 
6
6
  jest.unmock("undici");
7
7
 
8
- describe("unstable_dev", () => {
8
+ describe.skip("unstable_dev", () => {
9
9
  it("should return Hello World", async () => {
10
10
  const worker = await unstable_dev(
11
11
  "src/__tests__/helpers/worker-scripts/hello-world-worker.js",
@@ -1,13 +1,13 @@
1
1
  import { unstable_dev } from "../api";
2
2
  import { fetch } from "undici";
3
3
 
4
- jest.unmock("undici");
4
+ // jest.unmock("undici");
5
5
 
6
6
  /**
7
7
  * a huge caveat to how testing multi-worker scripts works:
8
8
  * you can't shutdown the first worker you spun up, or it'll kill the devRegistry
9
9
  */
10
- describe("multi-worker testing", () => {
10
+ describe.skip("multi-worker testing", () => {
11
11
  let childWorker;
12
12
  let parentWorker;
13
13
 
@@ -49,6 +49,10 @@ describe("normalizeAndValidateConfig()", () => {
49
49
  main: undefined,
50
50
  migrations: [],
51
51
  name: undefined,
52
+ queues: {
53
+ consumers: [],
54
+ producers: [],
55
+ },
52
56
  r2_buckets: [],
53
57
  services: [],
54
58
  route: undefined,
@@ -75,6 +79,7 @@ describe("normalizeAndValidateConfig()", () => {
75
79
  node_compat: undefined,
76
80
  first_party_worker: undefined,
77
81
  keep_vars: undefined,
82
+ logpush: undefined,
78
83
  });
79
84
  expect(diagnostics.hasErrors()).toBe(false);
80
85
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -924,6 +929,7 @@ describe("normalizeAndValidateConfig()", () => {
924
929
  minify: true,
925
930
  node_compat: true,
926
931
  first_party_worker: true,
932
+ logpush: true,
927
933
  };
928
934
 
929
935
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -998,6 +1004,7 @@ describe("normalizeAndValidateConfig()", () => {
998
1004
  minify: "INVALID",
999
1005
  node_compat: "INVALID",
1000
1006
  first_party_worker: "INVALID",
1007
+ logpush: "INVALID",
1001
1008
  } as unknown as RawEnvironment;
1002
1009
 
1003
1010
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -1065,7 +1072,8 @@ describe("normalizeAndValidateConfig()", () => {
1065
1072
  - Expected \\"no_bundle\\" to be of type boolean but got \\"INVALID\\".
1066
1073
  - Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
1067
1074
  - Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\".
1068
- - Expected \\"first_party_worker\\" to be of type boolean but got \\"INVALID\\"."
1075
+ - Expected \\"first_party_worker\\" to be of type boolean but got \\"INVALID\\".
1076
+ - Expected \\"logpush\\" to be of type boolean but got \\"INVALID\\"."
1069
1077
  `);
1070
1078
  });
1071
1079
 
@@ -1698,6 +1706,110 @@ describe("normalizeAndValidateConfig()", () => {
1698
1706
  });
1699
1707
  });
1700
1708
 
1709
+ describe("[queues]", () => {
1710
+ it("should error if queues is not an object", () => {
1711
+ const { config, diagnostics } = normalizeAndValidateConfig(
1712
+ { queues: [] } as unknown as RawConfig,
1713
+ undefined,
1714
+ { env: undefined }
1715
+ );
1716
+
1717
+ expect(config).toEqual(
1718
+ expect.not.objectContaining({ queues: expect.anything })
1719
+ );
1720
+ expect(diagnostics.hasWarnings()).toBe(false);
1721
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1722
+ "Processing wrangler configuration:
1723
+ - The field \\"queues\\" should be an object but got []."
1724
+ `);
1725
+ });
1726
+
1727
+ it("should error if queues producer bindings are not valid", () => {
1728
+ const { config, diagnostics } = normalizeAndValidateConfig(
1729
+ {
1730
+ queues: {
1731
+ invalidField: "madeupValue",
1732
+ producers: [
1733
+ {},
1734
+ { binding: "QUEUE_BINDING_1" },
1735
+ { binding: 2333, queue: 2444 },
1736
+ { binding: "QUEUE_BINDING_3", queue: "" },
1737
+ ],
1738
+ },
1739
+ } as unknown as RawConfig,
1740
+ undefined,
1741
+ { env: undefined }
1742
+ );
1743
+
1744
+ expect(config).toEqual(
1745
+ expect.not.objectContaining({
1746
+ queues: { producers: expect.anything },
1747
+ })
1748
+ );
1749
+ expect(diagnostics.hasWarnings()).toBe(true);
1750
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
1751
+ "Processing wrangler configuration:
1752
+ - Unexpected fields found in queues field: \\"invalidField\\""
1753
+ `);
1754
+
1755
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1756
+ "Processing wrangler configuration:
1757
+ - \\"queues.producers[0]\\" bindings should have a string \\"binding\\" field but got {}.
1758
+ - \\"queues.producers[0]\\" bindings should have a string \\"queue\\" field but got {}.
1759
+ - \\"queues.producers[1]\\" bindings should have a string \\"queue\\" field but got {\\"binding\\":\\"QUEUE_BINDING_1\\"}.
1760
+ - \\"queues.producers[2]\\" bindings should have a string \\"binding\\" field but got {\\"binding\\":2333,\\"queue\\":2444}.
1761
+ - \\"queues.producers[2]\\" bindings should have a string \\"queue\\" field but got {\\"binding\\":2333,\\"queue\\":2444}.
1762
+ - \\"queues.producers[3]\\" bindings should have a string \\"queue\\" field but got {\\"binding\\":\\"QUEUE_BINDING_3\\",\\"queue\\":\\"\\"}."
1763
+ `);
1764
+ });
1765
+
1766
+ it("should error if queues consumers are not valid", () => {
1767
+ const { config, diagnostics } = normalizeAndValidateConfig(
1768
+ {
1769
+ queues: {
1770
+ invalidField: "madeupValue",
1771
+ consumers: [
1772
+ {},
1773
+ { queue: 22 },
1774
+ { queue: "myQueue", invalidField: "madeupValue" },
1775
+ {
1776
+ queue: "myQueue",
1777
+ max_batch_size: "3",
1778
+ max_batch_timeout: null,
1779
+ max_retries: "hello",
1780
+ dead_letter_queue: 5,
1781
+ },
1782
+ ],
1783
+ },
1784
+ } as unknown as RawConfig,
1785
+ undefined,
1786
+ { env: undefined }
1787
+ );
1788
+
1789
+ expect(config).toEqual(
1790
+ expect.not.objectContaining({
1791
+ queues: { producers: expect.anything },
1792
+ })
1793
+ );
1794
+ expect(diagnostics.hasWarnings()).toBe(true);
1795
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
1796
+ "Processing wrangler configuration:
1797
+ - Unexpected fields found in queues field: \\"invalidField\\"
1798
+ - Unexpected fields found in queues.consumers[2] field: \\"invalidField\\""
1799
+ `);
1800
+
1801
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1802
+ "Processing wrangler configuration:
1803
+ - \\"queues.consumers[0]\\" should have a string \\"queue\\" field but got {}.
1804
+ - \\"queues.consumers[1]\\" should have a string \\"queue\\" field but got {\\"queue\\":22}.
1805
+ - \\"queues.consumers[3]\\" should, optionally, have a number \\"max_batch_size\\" field but got {\\"queue\\":\\"myQueue\\",\\"max_batch_size\\":\\"3\\",\\"max_batch_timeout\\":null,\\"max_retries\\":\\"hello\\",\\"dead_letter_queue\\":5}.
1806
+ - \\"queues.consumers[3]\\" should, optionally, have a number \\"max_batch_timeout\\" field but got {\\"queue\\":\\"myQueue\\",\\"max_batch_size\\":\\"3\\",\\"max_batch_timeout\\":null,\\"max_retries\\":\\"hello\\",\\"dead_letter_queue\\":5}.
1807
+ - \\"queues.consumers[3]\\" should, optionally, have a number \\"max_retries\\" field but got {\\"queue\\":\\"myQueue\\",\\"max_batch_size\\":\\"3\\",\\"max_batch_timeout\\":null,\\"max_retries\\":\\"hello\\",\\"dead_letter_queue\\":5}.
1808
+ - \\"queues.consumers[3]\\" should, optionally, have a string \\"dead_letter_queue\\" field but got {\\"queue\\":\\"myQueue\\",\\"max_batch_size\\":\\"3\\",\\"max_batch_timeout\\":null,\\"max_retries\\":\\"hello\\",\\"dead_letter_queue\\":5}."
1809
+ `);
1810
+ });
1811
+ });
1812
+
1701
1813
  describe("[r2_buckets]", () => {
1702
1814
  it("should error if r2_buckets is an object", () => {
1703
1815
  const { diagnostics } = normalizeAndValidateConfig(
@@ -2332,6 +2444,7 @@ describe("normalizeAndValidateConfig()", () => {
2332
2444
  minify: true,
2333
2445
  node_compat: true,
2334
2446
  first_party_worker: true,
2447
+ logpush: true,
2335
2448
  };
2336
2449
 
2337
2450
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -2376,6 +2489,7 @@ describe("normalizeAndValidateConfig()", () => {
2376
2489
  minify: false,
2377
2490
  node_compat: false,
2378
2491
  first_party_worker: false,
2492
+ logpush: false,
2379
2493
  };
2380
2494
  const rawConfig: RawConfig = {
2381
2495
  name: "mock-name",
@@ -2399,6 +2513,7 @@ describe("normalizeAndValidateConfig()", () => {
2399
2513
  minify: true,
2400
2514
  node_compat: true,
2401
2515
  first_party_worker: true,
2516
+ logpush: true,
2402
2517
  env: {
2403
2518
  ENV1: rawEnv,
2404
2519
  },
@@ -2661,6 +2776,7 @@ describe("normalizeAndValidateConfig()", () => {
2661
2776
  minify: "INVALID",
2662
2777
  node_compat: "INVALID",
2663
2778
  first_party_worker: "INVALID",
2779
+ logpush: "INVALID",
2664
2780
  } as unknown as RawEnvironment;
2665
2781
 
2666
2782
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -2697,7 +2813,8 @@ describe("normalizeAndValidateConfig()", () => {
2697
2813
  - Expected \\"no_bundle\\" to be of type boolean but got \\"INVALID\\".
2698
2814
  - Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
2699
2815
  - Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\".
2700
- - Expected \\"first_party_worker\\" to be of type boolean but got \\"INVALID\\"."
2816
+ - Expected \\"first_party_worker\\" to be of type boolean but got \\"INVALID\\".
2817
+ - Expected \\"logpush\\" to be of type boolean but got \\"INVALID\\"."
2701
2818
  `);
2702
2819
  });
2703
2820
 
@@ -29,6 +29,7 @@ describe("d1", () => {
29
29
 
30
30
  Flags:
31
31
  -c, --config Path to .toml configuration file [string]
32
+ -e, --env Environment to use for operations and .env files [string]
32
33
  -h, --help Show help [boolean]
33
34
  -v, --version Show version number [boolean]
34
35
 
@@ -61,6 +62,7 @@ describe("d1", () => {
61
62
 
62
63
  Flags:
63
64
  -c, --config Path to .toml configuration file [string]
65
+ -e, --env Environment to use for operations and .env files [string]
64
66
  -h, --help Show help [boolean]
65
67
  -v, --version Show version number [boolean]
66
68
 
@@ -54,38 +54,38 @@ describe("deployments", () => {
54
54
  it("should log deployments", async () => {
55
55
  await runWrangler("deployments");
56
56
  expect(std.out).toMatchInlineSnapshot(`
57
- "
58
- Version ID: Galaxy-Class
59
- Version number: 1701-E
60
- Created on: 2021-01-01T00:00:00.000000Z
61
- Author email: Jean-Luc-Picard@federation.org
62
- Latest deploy: true
57
+ "🚧\`wrangler deployments\` is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
58
+
63
59
 
64
- Version ID: Intrepid-Class
65
- Version number: NCC-74656
60
+ Deployment ID: Intrepid-Class
66
61
  Created on: 2021-02-02T00:00:00.000000Z
67
- Author email: Kathryn-Janeway@federation.org
68
- Latest deploy: false
69
- "
62
+ Author: Kathryn-Janeway@federation.org
63
+ Source: Wrangler
64
+
65
+ Deployment ID: Galaxy-Class
66
+ Created on: 2021-01-01T00:00:00.000000Z
67
+ Author: Jean-Luc-Picard@federation.org
68
+ Source: Wrangler
69
+ 🟩Active"
70
70
  `);
71
71
  });
72
72
 
73
73
  it("should log deployments for script with passed in name option", async () => {
74
74
  await runWrangler("deployments --name somethingElse");
75
75
  expect(std.out).toMatchInlineSnapshot(`
76
- "
77
- Version ID: Galaxy-Class
78
- Version number: 1701-E
79
- Created on: 2021-01-01T00:00:00.000000Z
80
- Author email: Jean-Luc-Picard@federation.org
81
- Latest deploy: true
76
+ "🚧\`wrangler deployments\` is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
77
+
82
78
 
83
- Version ID: Intrepid-Class
84
- Version number: NCC-74656
79
+ Deployment ID: Intrepid-Class
85
80
  Created on: 2021-02-02T00:00:00.000000Z
86
- Author email: Kathryn-Janeway@federation.org
87
- Latest deploy: false
88
- "
81
+ Author: Kathryn-Janeway@federation.org
82
+ Source: Wrangler
83
+
84
+ Deployment ID: Galaxy-Class
85
+ Created on: 2021-01-01T00:00:00.000000Z
86
+ Author: Jean-Luc-Picard@federation.org
87
+ Source: Wrangler
88
+ 🟩Active"
89
89
  `);
90
90
  });
91
91
  });
@@ -3,14 +3,31 @@ import getPort from "get-port";
3
3
  import patchConsole from "patch-console";
4
4
  import dedent from "ts-dedent";
5
5
  import Dev from "../dev/dev";
6
+ import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
6
7
  import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
7
8
  import { mockConsoleMethods } from "./helpers/mock-console";
9
+ import {
10
+ msw,
11
+ mswSuccessOauthHandlers,
12
+ mswSuccessUserHandlers,
13
+ mswZoneHandlers,
14
+ } from "./helpers/msw";
8
15
  import { runInTempDir } from "./helpers/run-in-tmp";
9
16
  import { runWrangler } from "./helpers/run-wrangler";
10
17
  import writeWranglerToml from "./helpers/write-wrangler-toml";
11
18
 
12
19
  describe("wrangler dev", () => {
20
+ beforeEach(() => {
21
+ msw.use(
22
+ ...mswZoneHandlers,
23
+ ...mswSuccessOauthHandlers,
24
+ ...mswSuccessUserHandlers
25
+ );
26
+ });
27
+
13
28
  runInTempDir();
29
+ mockAccountId();
30
+ mockApiToken();
14
31
  const std = mockConsoleMethods();
15
32
  afterEach(() => {
16
33
  (Dev as jest.Mock).mockClear();
@@ -319,6 +336,87 @@ describe("wrangler dev", () => {
319
336
  );
320
337
  });
321
338
 
339
+ it("should find the host from the given pattern, not zone_name", async () => {
340
+ writeWranglerToml({
341
+ main: "index.js",
342
+ routes: [
343
+ {
344
+ pattern: "https://subdomain.exists.com/*",
345
+ zone_name: "does-not-exist.com",
346
+ },
347
+ ],
348
+ });
349
+ await fs.promises.writeFile("index.js", `export default {};`);
350
+ await runWrangler("dev");
351
+ expect(std.out).toMatchInlineSnapshot(`""`);
352
+ expect(std.err).toMatchInlineSnapshot(`""`);
353
+ });
354
+
355
+ it("should fail for non-existing zones", async () => {
356
+ writeWranglerToml({
357
+ main: "index.js",
358
+ routes: [
359
+ {
360
+ pattern: "https://subdomain.does-not-exist.com/*",
361
+ zone_name: "exists.com",
362
+ },
363
+ ],
364
+ });
365
+ await fs.promises.writeFile("index.js", `export default {};`);
366
+ await expect(runWrangler("dev")).rejects.toEqual(
367
+ new Error("Could not find zone for subdomain.does-not-exist.com")
368
+ );
369
+ });
370
+
371
+ it("should fail for non-existing zones, when falling back from */*", async () => {
372
+ writeWranglerToml({
373
+ main: "index.js",
374
+ routes: [
375
+ {
376
+ pattern: "*/*",
377
+ zone_name: "does-not-exist.com",
378
+ },
379
+ ],
380
+ });
381
+ await fs.promises.writeFile("index.js", `export default {};`);
382
+ await expect(runWrangler("dev")).rejects.toEqual(
383
+ new Error("Could not find zone for does-not-exist.com")
384
+ );
385
+ });
386
+
387
+ it("should fallback to zone_name when given the pattern */*", async () => {
388
+ writeWranglerToml({
389
+ main: "index.js",
390
+ routes: [
391
+ {
392
+ pattern: "*/*",
393
+ zone_name: "exists.com",
394
+ },
395
+ ],
396
+ });
397
+ await fs.promises.writeFile("index.js", `export default {};`);
398
+ await runWrangler("dev");
399
+ expect(std.out).toMatchInlineSnapshot(`""`);
400
+ expect(std.err).toMatchInlineSnapshot(`""`);
401
+ });
402
+ it("fails when given the pattern */* and no zone_name", async () => {
403
+ writeWranglerToml({
404
+ main: "index.js",
405
+ routes: [
406
+ {
407
+ pattern: "*/*",
408
+ zone_id: "exists-com",
409
+ },
410
+ ],
411
+ });
412
+ await fs.promises.writeFile("index.js", `export default {};`);
413
+ const err = new TypeError() as unknown as { code: string; input: string };
414
+ err.code = "ERR_INVALID_URL";
415
+ err.input = "http:///";
416
+
417
+ await expect(runWrangler("dev")).rejects.toEqual(err);
418
+ });
419
+
322
420
  it("given a long host, it should use the longest subdomain that resolves to a zone", async () => {
323
421
  writeWranglerToml({
324
422
  main: "index.js",
@@ -566,6 +664,40 @@ describe("wrangler dev", () => {
566
664
  `);
567
665
  expect(std.warn).toMatchInlineSnapshot(`""`);
568
666
  });
667
+
668
+ describe(".env", () => {
669
+ beforeEach(() => {
670
+ fs.writeFileSync(".env", "CUSTOM_BUILD_VAR=default");
671
+ fs.writeFileSync(".env.custom", "CUSTOM_BUILD_VAR=custom");
672
+ fs.writeFileSync("index.js", `export default {};`);
673
+ writeWranglerToml({
674
+ main: "index.js",
675
+ env: { custom: {} },
676
+ build: {
677
+ // Ideally, we'd just log the var here and match it in `std.out`,
678
+ // but stdout from custom builds is piped directly to
679
+ // `process.stdout` which we don't capture.
680
+ command: `node -e "require('fs').writeFileSync('var.txt', process.env.CUSTOM_BUILD_VAR)"`,
681
+ },
682
+ });
683
+
684
+ // We won't overwrite existing process.env keys with .env values (to
685
+ // allow .env overrides to specified on then shell), so make sure this
686
+ // key definitely doesn't exist.
687
+ delete process.env.CUSTOM_BUILD_VAR;
688
+ });
689
+
690
+ it("should load environment variables from `.env`", async () => {
691
+ await runWrangler("dev");
692
+ const output = fs.readFileSync("var.txt", "utf8");
693
+ expect(output).toMatch("default");
694
+ });
695
+ it("should prefer to load environment variables from `.env.<environment>` if `--env <environment>` is set", async () => {
696
+ await runWrangler("dev --env custom");
697
+ const output = fs.readFileSync("var.txt", "utf8");
698
+ expect(output).toMatch("custom");
699
+ });
700
+ });
569
701
  });
570
702
 
571
703
  describe("upstream-protocol", () => {
@@ -970,6 +1102,27 @@ describe("wrangler dev", () => {
970
1102
  expect(std.warn).toMatchInlineSnapshot(`""`);
971
1103
  expect(std.err).toMatchInlineSnapshot(`""`);
972
1104
  });
1105
+
1106
+ it("should prefer `.dev.vars.<environment>` if `--env <environment> set`", async () => {
1107
+ fs.writeFileSync("index.js", `export default {};`);
1108
+ fs.writeFileSync(".dev.vars", "DEFAULT_VAR=default");
1109
+ fs.writeFileSync(".dev.vars.custom", "CUSTOM_VAR=custom");
1110
+
1111
+ writeWranglerToml({ main: "index.js", env: { custom: {} } });
1112
+ await runWrangler("dev --env custom");
1113
+ const varBindings: Record<string, unknown> = (Dev as jest.Mock).mock
1114
+ .calls[0][0].bindings.vars;
1115
+
1116
+ expect(varBindings).toEqual({ CUSTOM_VAR: "custom" });
1117
+ expect(std.out).toMatchInlineSnapshot(`
1118
+ "Using vars defined in .dev.vars.custom
1119
+ Your worker has access to the following bindings:
1120
+ - Vars:
1121
+ - CUSTOM_VAR: \\"(hidden)\\""
1122
+ `);
1123
+ expect(std.warn).toMatchInlineSnapshot(`""`);
1124
+ expect(std.err).toMatchInlineSnapshot(`""`);
1125
+ });
973
1126
  });
974
1127
 
975
1128
  describe("serve static assets", () => {
@@ -996,13 +1149,13 @@ describe("wrangler dev", () => {
996
1149
 
997
1150
  Flags:
998
1151
  -c, --config Path to .toml configuration file [string]
1152
+ -e, --env Environment to use for operations and .env files [string]
999
1153
  -h, --help Show help [boolean]
1000
1154
  -v, --version Show version number [boolean]
1001
1155
 
1002
1156
  Options:
1003
1157
  --name Name of the worker [string]
1004
1158
  --no-bundle Skip internal build steps and directly publish script [boolean] [default: false]
1005
- -e, --env Perform on a specific environment [string]
1006
1159
  --compatibility-date Date to use for compatibility checks [string]
1007
1160
  --compatibility-flags, --compatibility-flag Flags to use for compatibility checks [array]
1008
1161
  --latest Use the latest version of the worker runtime [boolean] [default: true]
@@ -1259,24 +1412,23 @@ describe("wrangler dev", () => {
1259
1412
  });
1260
1413
  fs.writeFileSync("index.js", `export default {};`);
1261
1414
  await runWrangler("dev index.js");
1262
- expect(std).toMatchInlineSnapshot(`
1263
- Object {
1264
- "debug": "",
1265
- "err": "",
1266
- "out": "Your worker has access to the following bindings:
1267
- - Services:
1268
- - WorkerA: A
1269
- - WorkerB: B - staging",
1270
- "warn": "▲ [WARNING] Processing wrangler.toml configuration:
1415
+ expect(std.out).toMatchInlineSnapshot(`
1416
+ "Your worker has access to the following bindings:
1417
+ - Services:
1418
+ - WorkerA: A
1419
+ - WorkerB: B - staging"
1420
+ `);
1421
+ expect(std.warn).toMatchInlineSnapshot(`
1422
+ "▲ [WARNING] Processing wrangler.toml configuration:
1271
1423
 
1272
- - \\"services\\" fields are experimental and may change or break at any time.
1424
+ - \\"services\\" fields are experimental and may change or break at any time.
1273
1425
 
1274
1426
 
1275
- ▲ [WARNING] This worker is bound to live services: WorkerA (A), WorkerB (B@staging)
1427
+ ▲ [WARNING] This worker is bound to live services: WorkerA (A), WorkerB (B@staging)
1276
1428
 
1277
- ",
1278
- }
1279
- `);
1429
+ "
1430
+ `);
1431
+ expect(std.err).toMatchInlineSnapshot(`""`);
1280
1432
  });
1281
1433
  });
1282
1434
 
@@ -0,0 +1,13 @@
1
+ import { rest } from "msw";
2
+
3
+ export default [
4
+ rest.get("*access-protected.com*", (_, response, cxt) => {
5
+ return response.once(
6
+ cxt.status(302),
7
+ cxt.set("location", "access-protected-com.cloudflareaccess.com")
8
+ );
9
+ }),
10
+ rest.get("*not-access-protected.com*", (_, response, cxt) => {
11
+ return response.once(cxt.status(200), cxt.body("OK"));
12
+ }),
13
+ ];