wrangler 0.0.0-e043479 → 0.0.0-e0b9366

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 (51) hide show
  1. package/package.json +10 -4
  2. package/pages/functions/filepath-routing.test.ts +125 -25
  3. package/pages/functions/filepath-routing.ts +6 -3
  4. package/src/__tests__/configuration.test.ts +479 -114
  5. package/src/__tests__/dev.test.tsx +162 -8
  6. package/src/__tests__/dev2.test.tsx +152 -0
  7. package/src/__tests__/guess-worker-format.test.ts +9 -17
  8. package/src/__tests__/helpers/mock-account-id.ts +4 -0
  9. package/src/__tests__/helpers/mock-cfetch.ts +3 -3
  10. package/src/__tests__/helpers/mock-kv.ts +9 -16
  11. package/src/__tests__/helpers/run-in-tmp.ts +3 -0
  12. package/src/__tests__/https-options.test.ts +127 -0
  13. package/src/__tests__/index.test.ts +125 -0
  14. package/src/__tests__/jest.setup.ts +1 -1
  15. package/src/__tests__/kv.test.ts +27 -53
  16. package/src/__tests__/logout.test.ts +15 -13
  17. package/src/__tests__/pages.test.ts +44 -0
  18. package/src/__tests__/publish.test.ts +504 -32
  19. package/src/__tests__/route.test.ts +45 -0
  20. package/src/__tests__/whoami.test.tsx +21 -7
  21. package/src/bundle.ts +20 -11
  22. package/src/cfetch/internal.ts +11 -5
  23. package/src/config/config.ts +53 -44
  24. package/src/config/validation-helpers.ts +110 -12
  25. package/src/config/validation.ts +59 -41
  26. package/src/{api/preview.ts → create-worker-preview.ts} +23 -4
  27. package/src/{api/form_data.ts → create-worker-upload-form.ts} +1 -1
  28. package/src/dev/dev.tsx +357 -0
  29. package/src/dev/local.tsx +241 -0
  30. package/src/dev/remote.tsx +201 -0
  31. package/src/dev/use-esbuild.ts +100 -0
  32. package/src/entry.ts +111 -9
  33. package/src/https-options.ts +122 -0
  34. package/src/index.tsx +171 -109
  35. package/src/inspect.ts +9 -1
  36. package/src/{kv.tsx → kv.ts} +0 -0
  37. package/src/module-collection.ts +85 -2
  38. package/src/open-in-browser.ts +14 -2
  39. package/src/pages.tsx +1 -1
  40. package/src/proxy.ts +102 -40
  41. package/src/publish.ts +41 -50
  42. package/src/reporting.ts +25 -9
  43. package/src/selfsigned.d.ts +29 -0
  44. package/src/sites.tsx +51 -16
  45. package/src/user.tsx +132 -77
  46. package/src/{api/worker.ts → worker.ts} +0 -23
  47. package/wrangler-dist/cli.js +5012 -3107
  48. package/wrangler-dist/cli.js.map +3 -3
  49. package/src/__tests__/helpers/mock-user.ts +0 -27
  50. package/src/dev.tsx +0 -960
  51. package/src/guess-worker-format.ts +0 -68
@@ -65,8 +65,8 @@ describe("normalizeAndValidateConfig()", () => {
65
65
  dev: {
66
66
  ip: "255.255.255.255",
67
67
  port: 9999,
68
- local_protocol: "HTTPS",
69
- upstream_protocol: "HTTP",
68
+ local_protocol: "https",
69
+ upstream_protocol: "http",
70
70
  },
71
71
  build: {
72
72
  command: "COMMAND",
@@ -95,8 +95,8 @@ describe("normalizeAndValidateConfig()", () => {
95
95
  dev: {
96
96
  ip: 222,
97
97
  port: "FOO",
98
- local_protocol: 333,
99
- upstream_protocol: 444,
98
+ local_protocol: "wss",
99
+ upstream_protocol: "ws",
100
100
  },
101
101
  build: {
102
102
  command: 555,
@@ -115,20 +115,40 @@ describe("normalizeAndValidateConfig()", () => {
115
115
  );
116
116
  expect(diagnostics.hasWarnings()).toBe(false);
117
117
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
118
- "Processing wrangler configuration:
119
- - ERROR: \\"build.command\\" should be of type string but got 555.
120
- - ERROR: \\"build.cwd\\" should be of type string but got 666.
121
- - ERROR: \\"build.watch_dir\\" should be of type string but got 777.
122
- - ERROR: \\"legacy_env\\" should be of type boolean but got \\"FOO\\".
123
- - ERROR: \\"main\\" should be a string but got 111
124
- - ERROR: \\"dev.ip\\" should be of type string but got 222.
125
- - ERROR: \\"dev.port\\" should be of type number but got \\"FOO\\".
126
- - ERROR: \\"dev.local_protocol\\" should be of type string but got 333.
127
- - ERROR: \\"dev.upstream_protocol\\" should be of type string but got 444."
128
- `);
118
+ "Processing wrangler configuration:
119
+ - Expected \\"build.command\\" to be of type string but got 555.
120
+ - Expected \\"build.cwd\\" to be of type string but got 666.
121
+ - Expected \\"build.watch_dir\\" to be of type string but got 777.
122
+ - Expected \\"legacy_env\\" to be of type boolean but got \\"FOO\\".
123
+ - Expected \\"main\\" to be a string but got 111
124
+ - Expected \\"dev.ip\\" to be of type string but got 222.
125
+ - Expected \\"dev.port\\" to be of type number but got \\"FOO\\".
126
+ - Expected \\"dev.local_protocol\\" field to be one of [\\"http\\",\\"https\\"] but got \\"wss\\".
127
+ - Expected \\"dev.upstream_protocol\\" field to be one of [\\"http\\",\\"https\\"] but got \\"ws\\"."
128
+ `);
129
129
  });
130
130
 
131
131
  it("should warn on and remove unexpected top level fields", () => {
132
+ const expectedConfig = {
133
+ unexpected: {
134
+ subkey: "some-value",
135
+ },
136
+ };
137
+
138
+ const { config, diagnostics } = normalizeAndValidateConfig(
139
+ expectedConfig as unknown as RawConfig,
140
+ undefined
141
+ );
142
+
143
+ expect("unexpected" in config).toBe(false);
144
+ expect(diagnostics.hasErrors()).toBe(false);
145
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
146
+ "Processing wrangler configuration:
147
+ - Unexpected fields found in top-level field: \\"unexpected\\""
148
+ `);
149
+ });
150
+
151
+ it("should ignore `miniflare` top level fields", () => {
132
152
  const expectedConfig = {
133
153
  miniflare: {
134
154
  host: "127.0.0.1",
@@ -144,7 +164,7 @@ describe("normalizeAndValidateConfig()", () => {
144
164
  expect(diagnostics.hasErrors()).toBe(false);
145
165
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
146
166
  "Processing wrangler configuration:
147
- - Unexpected fields found in top-level field: \\"miniflare\\""
167
+ "
148
168
  `);
149
169
  });
150
170
 
@@ -244,84 +264,115 @@ describe("normalizeAndValidateConfig()", () => {
244
264
  expect(config).toEqual(expect.objectContaining(expectedConfig));
245
265
  expect(diagnostics.hasWarnings()).toBe(false);
246
266
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
247
- "Processing wrangler configuration:
248
- - ERROR: \\"migrations[0].tag\\" should be of type string but got 111.
249
- - ERROR: \\"migrations[0].new_classes.[0]\\" should be of type string but got 222.
250
- - ERROR: \\"migrations[0].new_classes.[1]\\" should be of type string but got 333.
251
- - \\"migrations[0].renamed_classes\\" should be an array of \\"{from: string, to: string}\\" objects but got [{\\"from\\":444,\\"to\\":555}].
252
- - ERROR: \\"migrations[0].deleted_classes.[0]\\" should be of type string but got 666.
253
- - ERROR: \\"migrations[0].deleted_classes.[1]\\" should be of type string but got 777."
254
- `);
267
+ "Processing wrangler configuration:
268
+ - Expected \\"migrations[0].tag\\" to be of type string but got 111.
269
+ - Expected \\"migrations[0].new_classes.[0]\\" to be of type string but got 222.
270
+ - Expected \\"migrations[0].new_classes.[1]\\" to be of type string but got 333.
271
+ - Expected \\"migrations[0].renamed_classes\\" to be an array of \\"{from: string, to: string}\\" objects but got [{\\"from\\":444,\\"to\\":555}].
272
+ - Expected \\"migrations[0].deleted_classes.[0]\\" to be of type string but got 666.
273
+ - Expected \\"migrations[0].deleted_classes.[1]\\" to be of type string but got 777."
274
+ `);
255
275
  });
256
276
 
257
- it("should override `site` config defaults with provided values", () => {
258
- const expectedConfig: RawConfig = {
259
- site: {
260
- bucket: "BUCKET",
261
- "entry-point": "ENTRY_POINT",
262
- include: ["INCLUDE_1", "INCLUDE_2"],
263
- exclude: ["EXCLUDE_1", "EXCLUDE_2"],
264
- },
265
- };
277
+ describe("site", () => {
278
+ it("should override `site` config defaults with provided values", () => {
279
+ const expectedConfig: RawConfig = {
280
+ site: {
281
+ bucket: "BUCKET",
282
+ include: ["INCLUDE_1", "INCLUDE_2"],
283
+ exclude: ["EXCLUDE_1", "EXCLUDE_2"],
284
+ },
285
+ };
266
286
 
267
- const { config, diagnostics } = normalizeAndValidateConfig(
268
- expectedConfig,
269
- undefined
270
- );
287
+ const { config, diagnostics } = normalizeAndValidateConfig(
288
+ expectedConfig,
289
+ undefined
290
+ );
271
291
 
272
- expect(config).toEqual(expect.objectContaining(expectedConfig));
273
- expect(diagnostics.hasErrors()).toBe(false);
274
- expect(diagnostics.hasWarnings()).toBe(false);
275
- });
292
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
293
+ expect(diagnostics.hasErrors()).toBe(false);
294
+ expect(diagnostics.hasWarnings()).toBe(false);
295
+ });
276
296
 
277
- it("should error if `site` config is missing `bucket`", () => {
278
- const expectedConfig: RawConfig = {
279
- site: {
280
- "entry-point": "ENTRY_POINT",
281
- include: ["INCLUDE_1", "INCLUDE_2"],
282
- exclude: ["EXCLUDE_1", "EXCLUDE_2"],
283
- },
284
- } as RawConfig;
297
+ it("should error if `site` config is missing `bucket`", () => {
298
+ const expectedConfig: RawConfig = {
299
+ // @ts-expect-error we're intentionally passing an invalid configuration here
300
+ site: {
301
+ include: ["INCLUDE_1", "INCLUDE_2"],
302
+ exclude: ["EXCLUDE_1", "EXCLUDE_2"],
303
+ },
304
+ };
285
305
 
286
- const { config, diagnostics } = normalizeAndValidateConfig(
287
- expectedConfig,
288
- undefined
289
- );
306
+ const { config, diagnostics } = normalizeAndValidateConfig(
307
+ expectedConfig,
308
+ undefined
309
+ );
290
310
 
291
- expect(config).toEqual(expect.objectContaining(expectedConfig));
292
- expect(diagnostics.hasErrors()).toBe(true);
293
- expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
294
- "Processing wrangler configuration:
295
- - ERROR: \\"site.bucket\\" is a required field."
296
- `);
297
- expect(diagnostics.hasWarnings()).toBe(false);
298
- });
311
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
312
+ expect(diagnostics.hasErrors()).toBe(true);
313
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
314
+ "Processing wrangler configuration:
315
+ - \\"site.bucket\\" is a required field."
316
+ `);
317
+ expect(diagnostics.hasWarnings()).toBe(false);
318
+ });
299
319
 
300
- it("should error on invalid `site` values", () => {
301
- const expectedConfig = {
302
- site: {
303
- bucket: "BUCKET",
304
- "entry-point": 111,
305
- include: [222, 333],
306
- exclude: [444, 555],
307
- },
308
- };
320
+ it("should error on invalid `site` values", () => {
321
+ const expectedConfig = {
322
+ site: {
323
+ bucket: "BUCKET",
324
+ include: [222, 333],
325
+ exclude: [444, 555],
326
+ },
327
+ };
309
328
 
310
- const { config, diagnostics } = normalizeAndValidateConfig(
311
- expectedConfig as unknown as RawConfig,
312
- undefined
313
- );
329
+ const { config, diagnostics } = normalizeAndValidateConfig(
330
+ expectedConfig as unknown as RawConfig,
331
+ undefined
332
+ );
314
333
 
315
- expect(config).toEqual(expect.objectContaining(expectedConfig));
316
- expect(diagnostics.hasWarnings()).toBe(false);
317
- expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
334
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
335
+ expect(diagnostics.hasWarnings()).toBe(false);
336
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
337
+ "Processing wrangler configuration:
338
+ - Expected \\"sites.include.[0]\\" to be of type string but got 222.
339
+ - Expected \\"sites.include.[1]\\" to be of type string but got 333.
340
+ - Expected \\"sites.exclude.[0]\\" to be of type string but got 444.
341
+ - Expected \\"sites.exclude.[1]\\" to be of type string but got 555."
342
+ `);
343
+ });
344
+
345
+ it("should error with a deprecation warning if entry-point is defined", async () => {
346
+ const { config, diagnostics } = normalizeAndValidateConfig(
347
+ {
348
+ site: {
349
+ bucket: "some/path",
350
+ "entry-point": "some/other/script.js",
351
+ },
352
+ } as unknown as RawConfig,
353
+ undefined
354
+ );
355
+
356
+ expect(config.site).toMatchInlineSnapshot(`
357
+ Object {
358
+ "bucket": "some/path",
359
+ "exclude": Array [],
360
+ "include": Array [],
361
+ }
362
+ `);
363
+ expect(diagnostics.hasWarnings()).toBe(true);
364
+ expect(diagnostics.hasErrors()).toBe(true);
365
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
318
366
  "Processing wrangler configuration:
319
- - ERROR: \\"site.entry_point\\" should be of type string but got 111.
320
- - ERROR: \\"sites.include.[0]\\" should be of type string but got 222.
321
- - ERROR: \\"sites.include.[1]\\" should be of type string but got 333.
322
- - ERROR: \\"sites.exclude.[0]\\" should be of type string but got 444.
323
- - ERROR: \\"sites.exclude.[1]\\" should be of type string but got 555."
367
+ - Unexpected fields found in site field: \\"entry-point\\""
324
368
  `);
369
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
370
+ "Processing wrangler configuration:
371
+ - DEPRECATION: \\"site.entry-point\\":
372
+ The \`site.entry-point\` config field is no longer used.
373
+ The entry-point should be specified via the command line or the \`main\` config field."
374
+ `);
375
+ });
325
376
  });
326
377
 
327
378
  it("should map `wasm_module` paths from relative to the config path to relative to the cwd", () => {
@@ -467,7 +518,6 @@ describe("normalizeAndValidateConfig()", () => {
467
518
  compatibility_flags: ["FLAG1", "FLAG2"],
468
519
  workers_dev: false,
469
520
  routes: ["ROUTE_1", "ROUTE_2"],
470
- route: "ROUTE_3",
471
521
  jsx_factory: "JSX_FACTORY",
472
522
  jsx_fragment: "JSX_FRAGMENT",
473
523
  triggers: { crons: ["CRON_1", "CRON_2"] },
@@ -553,6 +603,7 @@ describe("normalizeAndValidateConfig()", () => {
553
603
  "Processing wrangler configuration:
554
604
  - Expected \\"route\\" field to be a string but got 888.
555
605
  - Expected \\"routes\\" field to be an array of strings but got [666,777].
606
+ - Expected exactly one of [\\"routes\\",\\"route\\"].
556
607
  - Expected \\"workers_dev\\" field to be a boolean but got \\"BAD\\".
557
608
  - Expected \\"account_id\\" field to be a string but got 222.
558
609
  - Expected \\"compatibility_date\\" field to be a string but got 333.
@@ -560,7 +611,7 @@ describe("normalizeAndValidateConfig()", () => {
560
611
  - Expected \\"jsx_factory\\" field to be a string but got 999.
561
612
  - Expected \\"jsx_fragment\\" field to be a string but got 1000.
562
613
  - Expected \\"name\\" field to be a string but got 111.
563
- - Expected \\"usage_model\\" field to be on of bundled,unbound but got \\"INVALID\\"."
614
+ - Expected \\"usage_model\\" field to be one of [\\"bundled\\",\\"unbound\\"] but got \\"INVALID\\"."
564
615
  `);
565
616
  });
566
617
 
@@ -746,20 +797,20 @@ describe("normalizeAndValidateConfig()", () => {
746
797
  "Processing wrangler configuration:
747
798
 
748
799
  - \\"durable_objects.bindings[0]\\": {}
749
- - ERROR: bindings should have a string \\"name\\" field.
750
- - ERROR: should have a string \\"class_name\\" field.
800
+ - binding should have a string \\"name\\" field.
801
+ - binding should have a string \\"class_name\\" field.
751
802
 
752
803
  - \\"durable_objects.bindings[1]\\": {\\"name\\":\\"VALID\\"}
753
- - ERROR: should have a string \\"class_name\\" field.
804
+ - binding should have a string \\"class_name\\" field.
754
805
 
755
806
  - \\"durable_objects.bindings[2]\\": {\\"name\\":1555,\\"class_name\\":1666}
756
- - ERROR: bindings should have a string \\"name\\" field.
757
- - ERROR: should have a string \\"class_name\\" field.
807
+ - binding should have a string \\"name\\" field.
808
+ - binding should have a string \\"class_name\\" field.
758
809
 
759
810
  - \\"durable_objects.bindings[3]\\": {\\"name\\":1777,\\"class_name\\":1888,\\"script_name\\":1999}
760
- - ERROR: bindings should have a string \\"name\\" field.
761
- - ERROR: should have a string \\"class_name\\" field.
762
- - ERROR: should, optionally, have a string \\"script_name\\" field."
811
+ - binding should have a string \\"name\\" field.
812
+ - binding should have a string \\"class_name\\" field.
813
+ - binding should, optionally, have a string \\"script_name\\" field."
763
814
  `);
764
815
  });
765
816
  });
@@ -1176,15 +1227,15 @@ describe("normalizeAndValidateConfig()", () => {
1176
1227
  "Processing wrangler configuration:
1177
1228
 
1178
1229
  - \\"unsafe.bindings[0]\\": {}
1179
- - ERROR: should have a string \\"name\\" field.
1180
- - ERROR: should have a string \\"type\\" field.
1230
+ - binding should have a string \\"name\\" field.
1231
+ - binding should have a string \\"type\\" field.
1181
1232
 
1182
1233
  - \\"unsafe.bindings[1]\\": {\\"name\\":\\"UNSAFE_BINDING_1\\"}
1183
- - ERROR: should have a string \\"type\\" field.
1234
+ - binding should have a string \\"type\\" field.
1184
1235
 
1185
1236
  - \\"unsafe.bindings[2]\\": {\\"name\\":2666,\\"type\\":2777}
1186
- - ERROR: should have a string \\"name\\" field.
1187
- - ERROR: should have a string \\"type\\" field."
1237
+ - binding should have a string \\"name\\" field.
1238
+ - binding should have a string \\"type\\" field."
1188
1239
  `);
1189
1240
  });
1190
1241
  });
@@ -1228,6 +1279,25 @@ describe("normalizeAndValidateConfig()", () => {
1228
1279
  `);
1229
1280
  });
1230
1281
  });
1282
+
1283
+ describe("route & routes fields", () => {
1284
+ it("should error if both route and routes are specified", () => {
1285
+ const rawConfig: RawConfig = {
1286
+ route: "route1",
1287
+ routes: ["route2", "route3"],
1288
+ };
1289
+
1290
+ const { diagnostics } = normalizeAndValidateConfig(
1291
+ rawConfig,
1292
+ undefined
1293
+ );
1294
+
1295
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1296
+ "Processing wrangler configuration:
1297
+ - Expected exactly one of [\\"routes\\",\\"route\\"]."
1298
+ `);
1299
+ });
1300
+ });
1231
1301
  });
1232
1302
 
1233
1303
  describe("named environments", () => {
@@ -1239,7 +1309,6 @@ describe("normalizeAndValidateConfig()", () => {
1239
1309
  compatibility_flags: ["FLAG1", "FLAG2"],
1240
1310
  workers_dev: false,
1241
1311
  routes: ["ROUTE_1", "ROUTE_2"],
1242
- route: "ROUTE_3",
1243
1312
  jsx_factory: "JSX_FACTORY",
1244
1313
  jsx_fragment: "JSX_FRAGMENT",
1245
1314
  triggers: { crons: ["CRON_1", "CRON_2"] },
@@ -1264,7 +1333,6 @@ describe("normalizeAndValidateConfig()", () => {
1264
1333
  compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
1265
1334
  workers_dev: true,
1266
1335
  routes: ["ENV_ROUTE_1", "ENV_ROUTE_2"],
1267
- route: "ENV_ROUTE_3",
1268
1336
  jsx_factory: "ENV_JSX_FACTORY",
1269
1337
  jsx_fragment: "ENV_JSX_FRAGMENT",
1270
1338
  triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
@@ -1277,7 +1345,6 @@ describe("normalizeAndValidateConfig()", () => {
1277
1345
  compatibility_flags: ["FLAG1", "FLAG2"],
1278
1346
  workers_dev: false,
1279
1347
  routes: ["ROUTE_1", "ROUTE_2"],
1280
- route: "ROUTE_3",
1281
1348
  jsx_factory: "JSX_FACTORY",
1282
1349
  jsx_fragment: "JSX_FRAGMENT",
1283
1350
  triggers: { crons: ["CRON_1", "CRON_2"] },
@@ -1297,6 +1364,78 @@ describe("normalizeAndValidateConfig()", () => {
1297
1364
  expect(diagnostics.hasWarnings()).toBe(false);
1298
1365
  });
1299
1366
 
1367
+ describe("non-legacy", () => {
1368
+ it("should use top-level `name` field", () => {
1369
+ const rawConfig: RawConfig = {
1370
+ name: "NAME",
1371
+ legacy_env: false,
1372
+ env: { DEV: {} },
1373
+ };
1374
+
1375
+ const { config, diagnostics } = normalizeAndValidateConfig(
1376
+ rawConfig,
1377
+ undefined
1378
+ );
1379
+
1380
+ expect(config.env.DEV.name).toEqual("NAME");
1381
+ expect(diagnostics.hasErrors()).toBe(false);
1382
+ expect(diagnostics.hasWarnings()).toBe(false);
1383
+ });
1384
+
1385
+ it("should error if named environment contains a `name` field, even if there is no top-level name", () => {
1386
+ const rawConfig: RawConfig = {
1387
+ legacy_env: false,
1388
+ env: {
1389
+ DEV: {
1390
+ name: "ENV_NAME",
1391
+ },
1392
+ },
1393
+ };
1394
+
1395
+ const { config, diagnostics } = normalizeAndValidateConfig(
1396
+ rawConfig,
1397
+ undefined
1398
+ );
1399
+
1400
+ expect(config.env.DEV.name).toBeUndefined();
1401
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1402
+ "Processing wrangler configuration:
1403
+
1404
+ - \\"env.DEV\\" environment configuration
1405
+ - The \\"name\\" field is not allowed in named service environments.
1406
+ Please remove the field from this environment."
1407
+ `);
1408
+ expect(diagnostics.hasWarnings()).toBe(false);
1409
+ });
1410
+
1411
+ it("should error if top-level config and a named environment both contain a `name` field", () => {
1412
+ const rawConfig: RawConfig = {
1413
+ name: "NAME",
1414
+ legacy_env: false,
1415
+ env: {
1416
+ DEV: {
1417
+ name: "ENV_NAME",
1418
+ },
1419
+ },
1420
+ };
1421
+
1422
+ const { config, diagnostics } = normalizeAndValidateConfig(
1423
+ rawConfig,
1424
+ undefined
1425
+ );
1426
+
1427
+ expect(config.env.DEV.name).toEqual("NAME");
1428
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1429
+ "Processing wrangler configuration:
1430
+
1431
+ - \\"env.DEV\\" environment configuration
1432
+ - The \\"name\\" field is not allowed in named service environments.
1433
+ Please remove the field from this environment."
1434
+ `);
1435
+ expect(diagnostics.hasWarnings()).toBe(false);
1436
+ });
1437
+ });
1438
+
1300
1439
  it("should warn for non-inherited fields that are missing in environments", () => {
1301
1440
  const vars: RawConfig["vars"] = {
1302
1441
  FOO: "foo",
@@ -1383,6 +1522,7 @@ describe("normalizeAndValidateConfig()", () => {
1383
1522
  - \\"env.ENV1\\" environment configuration
1384
1523
  - Expected \\"route\\" field to be a string but got 888.
1385
1524
  - Expected \\"routes\\" field to be an array of strings but got [666,777].
1525
+ - Expected exactly one of [\\"routes\\",\\"route\\"].
1386
1526
  - Expected \\"workers_dev\\" field to be a boolean but got \\"BAD\\".
1387
1527
  - Expected \\"account_id\\" field to be a string but got 222.
1388
1528
  - Expected \\"compatibility_date\\" field to be a string but got 333.
@@ -1390,7 +1530,7 @@ describe("normalizeAndValidateConfig()", () => {
1390
1530
  - Expected \\"jsx_factory\\" field to be a string but got 999.
1391
1531
  - Expected \\"jsx_fragment\\" field to be a string but got 1000.
1392
1532
  - Expected \\"name\\" field to be a string but got 111.
1393
- - Expected \\"usage_model\\" field to be on of bundled,unbound but got \\"INVALID\\"."
1533
+ - Expected \\"usage_model\\" field to be one of [\\"bundled\\",\\"unbound\\"] but got \\"INVALID\\"."
1394
1534
  `);
1395
1535
  });
1396
1536
 
@@ -1608,20 +1748,20 @@ describe("normalizeAndValidateConfig()", () => {
1608
1748
  - \\"env.ENV1\\" environment configuration
1609
1749
 
1610
1750
  - \\"env.ENV1.durable_objects.bindings[0]\\": {}
1611
- - ERROR: bindings should have a string \\"name\\" field.
1612
- - ERROR: should have a string \\"class_name\\" field.
1751
+ - binding should have a string \\"name\\" field.
1752
+ - binding should have a string \\"class_name\\" field.
1613
1753
 
1614
1754
  - \\"env.ENV1.durable_objects.bindings[1]\\": {\\"name\\":\\"VALID\\"}
1615
- - ERROR: should have a string \\"class_name\\" field.
1755
+ - binding should have a string \\"class_name\\" field.
1616
1756
 
1617
1757
  - \\"env.ENV1.durable_objects.bindings[2]\\": {\\"name\\":1555,\\"class_name\\":1666}
1618
- - ERROR: bindings should have a string \\"name\\" field.
1619
- - ERROR: should have a string \\"class_name\\" field.
1758
+ - binding should have a string \\"name\\" field.
1759
+ - binding should have a string \\"class_name\\" field.
1620
1760
 
1621
1761
  - \\"env.ENV1.durable_objects.bindings[3]\\": {\\"name\\":1777,\\"class_name\\":1888,\\"script_name\\":1999}
1622
- - ERROR: bindings should have a string \\"name\\" field.
1623
- - ERROR: should have a string \\"class_name\\" field.
1624
- - ERROR: should, optionally, have a string \\"script_name\\" field."
1762
+ - binding should have a string \\"name\\" field.
1763
+ - binding should have a string \\"class_name\\" field.
1764
+ - binding should, optionally, have a string \\"script_name\\" field."
1625
1765
  `);
1626
1766
  });
1627
1767
  });
@@ -2118,15 +2258,15 @@ describe("normalizeAndValidateConfig()", () => {
2118
2258
  - \\"env.ENV1\\" environment configuration
2119
2259
 
2120
2260
  - \\"env.ENV1.unsafe.bindings[0]\\": {}
2121
- - ERROR: should have a string \\"name\\" field.
2122
- - ERROR: should have a string \\"type\\" field.
2261
+ - binding should have a string \\"name\\" field.
2262
+ - binding should have a string \\"type\\" field.
2123
2263
 
2124
2264
  - \\"env.ENV1.unsafe.bindings[1]\\": {\\"name\\":\\"UNSAFE_BINDING_1\\"}
2125
- - ERROR: should have a string \\"type\\" field.
2265
+ - binding should have a string \\"type\\" field.
2126
2266
 
2127
2267
  - \\"env.ENV1.unsafe.bindings[2]\\": {\\"name\\":2666,\\"type\\":2777}
2128
- - ERROR: should have a string \\"name\\" field.
2129
- - ERROR: should have a string \\"type\\" field."
2268
+ - binding should have a string \\"name\\" field.
2269
+ - binding should have a string \\"type\\" field."
2130
2270
  `);
2131
2271
  });
2132
2272
  });
@@ -2176,6 +2316,231 @@ describe("normalizeAndValidateConfig()", () => {
2176
2316
  `);
2177
2317
  });
2178
2318
  });
2319
+
2320
+ describe("route & routes fields", () => {
2321
+ it("should error if both route and routes are specified in the same environment", () => {
2322
+ const environment: RawEnvironment = {
2323
+ name: "ENV_NAME",
2324
+ account_id: "ENV_ACCOUNT_ID",
2325
+ compatibility_date: "2022-02-02",
2326
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
2327
+ workers_dev: true,
2328
+ route: "ENV_ROUTE_1",
2329
+ routes: ["ENV_ROUTE_2", "ENV_ROUTE_3"],
2330
+ jsx_factory: "ENV_JSX_FACTORY",
2331
+ jsx_fragment: "ENV_JSX_FRAGMENT",
2332
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
2333
+ usage_model: "unbound",
2334
+ };
2335
+ const expectedConfig: RawConfig = {
2336
+ name: "NAME",
2337
+ account_id: "ACCOUNT_ID",
2338
+ compatibility_date: "2022-01-01",
2339
+ compatibility_flags: ["FLAG1", "FLAG2"],
2340
+ workers_dev: false,
2341
+ routes: ["ROUTE_1", "ROUTE_2"],
2342
+ jsx_factory: "JSX_FACTORY",
2343
+ jsx_fragment: "JSX_FRAGMENT",
2344
+ triggers: { crons: ["CRON_1", "CRON_2"] },
2345
+ usage_model: "bundled",
2346
+ env: {
2347
+ ENV1: environment,
2348
+ },
2349
+ };
2350
+
2351
+ const { config, diagnostics } = normalizeAndValidateConfig(
2352
+ expectedConfig,
2353
+ undefined
2354
+ );
2355
+
2356
+ expect(config.env.ENV1).toEqual(expect.objectContaining(environment));
2357
+ expect(diagnostics.hasErrors()).toBe(true);
2358
+ expect(diagnostics.hasWarnings()).toBe(false);
2359
+
2360
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2361
+ "Processing wrangler configuration:
2362
+
2363
+ - \\"env.ENV1\\" environment configuration
2364
+ - Expected exactly one of [\\"routes\\",\\"route\\"]."
2365
+ `);
2366
+ });
2367
+
2368
+ it("should error if both route and routes are specified in the top-level environment", () => {
2369
+ const environment: RawEnvironment = {
2370
+ name: "ENV_NAME",
2371
+ account_id: "ENV_ACCOUNT_ID",
2372
+ compatibility_date: "2022-02-02",
2373
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
2374
+ workers_dev: true,
2375
+ routes: ["ENV_ROUTE_1", "ENV_ROUTE_2"],
2376
+ jsx_factory: "ENV_JSX_FACTORY",
2377
+ jsx_fragment: "ENV_JSX_FRAGMENT",
2378
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
2379
+ usage_model: "unbound",
2380
+ };
2381
+ const expectedConfig: RawConfig = {
2382
+ name: "NAME",
2383
+ account_id: "ACCOUNT_ID",
2384
+ compatibility_date: "2022-01-01",
2385
+ compatibility_flags: ["FLAG1", "FLAG2"],
2386
+ workers_dev: false,
2387
+ route: "ROUTE_1",
2388
+ routes: ["ROUTE_2", "ROUTE_3"],
2389
+ jsx_factory: "JSX_FACTORY",
2390
+ jsx_fragment: "JSX_FRAGMENT",
2391
+ triggers: { crons: ["CRON_1", "CRON_2"] },
2392
+ usage_model: "bundled",
2393
+ env: {
2394
+ ENV1: environment,
2395
+ },
2396
+ };
2397
+
2398
+ const { config, diagnostics } = normalizeAndValidateConfig(
2399
+ expectedConfig,
2400
+ undefined
2401
+ );
2402
+
2403
+ expect(config.env.ENV1).toEqual(expect.objectContaining(environment));
2404
+ expect(diagnostics.hasErrors()).toBe(true);
2405
+ expect(diagnostics.hasWarnings()).toBe(false);
2406
+
2407
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2408
+ "Processing wrangler configuration:
2409
+ - Expected exactly one of [\\"routes\\",\\"route\\"]."
2410
+ `);
2411
+ });
2412
+
2413
+ it("should not error if <env>.route and <top-level>.routes are specified", () => {
2414
+ const environment: RawEnvironment = {
2415
+ name: "ENV_NAME",
2416
+ account_id: "ENV_ACCOUNT_ID",
2417
+ compatibility_date: "2022-02-02",
2418
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
2419
+ workers_dev: true,
2420
+ route: "ENV_ROUTE_1",
2421
+ jsx_factory: "ENV_JSX_FACTORY",
2422
+ jsx_fragment: "ENV_JSX_FRAGMENT",
2423
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
2424
+ usage_model: "unbound",
2425
+ };
2426
+ const expectedConfig: RawConfig = {
2427
+ name: "NAME",
2428
+ account_id: "ACCOUNT_ID",
2429
+ compatibility_date: "2022-01-01",
2430
+ compatibility_flags: ["FLAG1", "FLAG2"],
2431
+ workers_dev: false,
2432
+ routes: ["ROUTE_1", "ROUTE_2"],
2433
+ jsx_factory: "JSX_FACTORY",
2434
+ jsx_fragment: "JSX_FRAGMENT",
2435
+ triggers: { crons: ["CRON_1", "CRON_2"] },
2436
+ usage_model: "bundled",
2437
+ env: {
2438
+ ENV1: environment,
2439
+ },
2440
+ };
2441
+
2442
+ const { config, diagnostics } = normalizeAndValidateConfig(
2443
+ expectedConfig,
2444
+ undefined
2445
+ );
2446
+
2447
+ expect(config.env.ENV1).toEqual(expect.objectContaining(environment));
2448
+ expect(diagnostics.hasErrors()).toBe(false);
2449
+ expect(diagnostics.hasWarnings()).toBe(false);
2450
+ });
2451
+
2452
+ it("should not error if <env>.routes and <top-level>.route are specified", () => {
2453
+ const environment: RawEnvironment = {
2454
+ name: "ENV_NAME",
2455
+ account_id: "ENV_ACCOUNT_ID",
2456
+ compatibility_date: "2022-02-02",
2457
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
2458
+ workers_dev: true,
2459
+ routes: ["ENV_ROUTE_1", "ENV_ROUTE_2"],
2460
+ jsx_factory: "ENV_JSX_FACTORY",
2461
+ jsx_fragment: "ENV_JSX_FRAGMENT",
2462
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
2463
+ usage_model: "unbound",
2464
+ };
2465
+ const expectedConfig: RawConfig = {
2466
+ name: "NAME",
2467
+ account_id: "ACCOUNT_ID",
2468
+ compatibility_date: "2022-01-01",
2469
+ compatibility_flags: ["FLAG1", "FLAG2"],
2470
+ workers_dev: false,
2471
+ route: "ROUTE_1",
2472
+ jsx_factory: "JSX_FACTORY",
2473
+ jsx_fragment: "JSX_FRAGMENT",
2474
+ triggers: { crons: ["CRON_1", "CRON_2"] },
2475
+ usage_model: "bundled",
2476
+ env: {
2477
+ ENV1: environment,
2478
+ },
2479
+ };
2480
+
2481
+ const { config, diagnostics } = normalizeAndValidateConfig(
2482
+ expectedConfig,
2483
+ undefined
2484
+ );
2485
+
2486
+ expect(config.env.ENV1).toEqual(expect.objectContaining(environment));
2487
+ expect(diagnostics.hasErrors()).toBe(false);
2488
+ expect(diagnostics.hasWarnings()).toBe(false);
2489
+ });
2490
+
2491
+ it("should not error if <env1>.route and <env2>.routes are specified", () => {
2492
+ const environment1: RawEnvironment = {
2493
+ name: "ENV_NAME",
2494
+ account_id: "ENV_ACCOUNT_ID",
2495
+ compatibility_date: "2022-02-02",
2496
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
2497
+ workers_dev: true,
2498
+ routes: ["ENV1_ROUTE_1", "ENV2_ROUTE_2"],
2499
+ jsx_factory: "ENV_JSX_FACTORY",
2500
+ jsx_fragment: "ENV_JSX_FRAGMENT",
2501
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
2502
+ usage_model: "unbound",
2503
+ };
2504
+ const environment2: RawEnvironment = {
2505
+ name: "ENV_NAME",
2506
+ account_id: "ENV_ACCOUNT_ID",
2507
+ compatibility_date: "2022-02-02",
2508
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
2509
+ workers_dev: true,
2510
+ route: "ENV2_ROUTE_1",
2511
+ jsx_factory: "ENV_JSX_FACTORY",
2512
+ jsx_fragment: "ENV_JSX_FRAGMENT",
2513
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
2514
+ usage_model: "unbound",
2515
+ };
2516
+ const expectedConfig: RawConfig = {
2517
+ name: "NAME",
2518
+ account_id: "ACCOUNT_ID",
2519
+ compatibility_date: "2022-01-01",
2520
+ compatibility_flags: ["FLAG1", "FLAG2"],
2521
+ workers_dev: false,
2522
+ route: "ROUTE_1",
2523
+ jsx_factory: "JSX_FACTORY",
2524
+ jsx_fragment: "JSX_FRAGMENT",
2525
+ triggers: { crons: ["CRON_1", "CRON_2"] },
2526
+ usage_model: "bundled",
2527
+ env: {
2528
+ ENV1: environment1,
2529
+ ENV2: environment2,
2530
+ },
2531
+ };
2532
+
2533
+ const { config, diagnostics } = normalizeAndValidateConfig(
2534
+ expectedConfig,
2535
+ undefined
2536
+ );
2537
+
2538
+ expect(config.env.ENV1).toEqual(expect.objectContaining(environment1));
2539
+ expect(config.env.ENV2).toEqual(expect.objectContaining(environment2));
2540
+ expect(diagnostics.hasErrors()).toBe(false);
2541
+ expect(diagnostics.hasWarnings()).toBe(false);
2542
+ });
2543
+ });
2179
2544
  });
2180
2545
  });
2181
2546