wrangler 2.0.23 → 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 (55) hide show
  1. package/README.md +20 -2
  2. package/bin/wrangler.js +1 -1
  3. package/miniflare-dist/index.mjs +96 -34
  4. package/package.json +9 -4
  5. package/src/__tests__/configuration.test.ts +88 -16
  6. package/src/__tests__/dev.test.tsx +3 -0
  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 +2 -2
  12. package/src/__tests__/metrics.test.ts +5 -0
  13. package/src/__tests__/publish.test.ts +497 -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__/whoami.test.tsx +60 -1
  18. package/src/bundle.ts +278 -44
  19. package/src/cfetch/internal.ts +34 -2
  20. package/src/config/config.ts +7 -2
  21. package/src/config/environment.ts +40 -8
  22. package/src/config/index.ts +13 -0
  23. package/src/config/validation.ts +101 -7
  24. package/src/create-worker-upload-form.ts +25 -0
  25. package/src/dev/dev.tsx +107 -28
  26. package/src/dev/local.tsx +20 -10
  27. package/src/dev/remote.tsx +39 -8
  28. package/src/dev/use-esbuild.ts +25 -0
  29. package/src/dev/validate-dev-props.ts +31 -0
  30. package/src/dev-registry.tsx +157 -0
  31. package/src/dev.tsx +93 -75
  32. package/src/generate.ts +112 -14
  33. package/src/index.tsx +182 -4
  34. package/src/inspect.ts +93 -5
  35. package/src/metrics/index.ts +1 -0
  36. package/src/metrics/metrics-dispatcher.ts +1 -0
  37. package/src/metrics/metrics-usage-headers.ts +24 -0
  38. package/src/metrics/send-event.ts +2 -2
  39. package/src/module-collection.ts +3 -3
  40. package/src/pages/constants.ts +1 -0
  41. package/src/pages/deployments.tsx +1 -1
  42. package/src/pages/dev.tsx +6 -1
  43. package/src/pages/publish.tsx +1 -1
  44. package/src/pages/upload.tsx +32 -13
  45. package/src/publish.ts +126 -112
  46. package/src/r2.ts +68 -0
  47. package/src/user/user.tsx +20 -2
  48. package/src/whoami.tsx +79 -1
  49. package/src/worker.ts +12 -0
  50. package/templates/first-party-worker-module-facade.ts +18 -0
  51. package/templates/format-dev-errors.ts +32 -0
  52. package/templates/{static-asset-facade.js → serve-static-assets.ts} +21 -7
  53. package/templates/service-bindings-module-facade.js +51 -0
  54. package/templates/service-bindings-sw-facade.js +39 -0
  55. package/wrangler-dist/cli.js +40192 -15265
package/README.md CHANGED
@@ -39,11 +39,25 @@ npm run deploy
39
39
  $ npm install wrangler --save-dev
40
40
  ```
41
41
 
42
+ ## Configuration:
43
+
44
+ Wrangler is configured via a `wrangler.toml` file in the project root. When utilizing the `wrangler init` command, a `wrangler.toml` file will be created for you.
45
+
46
+ example:
47
+
48
+ ```toml
49
+ main = "./src/index.ts" # init w/ TypeScript
50
+ name = "my-worker"
51
+ compatibility_date = "YYY-MM-DD"
52
+ ```
53
+
54
+ for more detailed information about configuration, see the [documentation](https://developers.cloudflare.com/workers/cli-wrangler/configuration)
55
+
42
56
  ## Commands
43
57
 
44
58
  ### `wrangler init [name]`
45
59
 
46
- Creates a Worker project. For details on configuration keys and values, refer to the [documentation](https://developers.cloudflare.com/workers/cli-wrangler/configuration).
60
+ Creates a Worker project. For details on configuration keys and values, refer to the [documentation](https://developers.cloudflare.com/workers/wrangler/commands/#init).
47
61
 
48
62
  ### `wrangler dev`
49
63
 
@@ -67,4 +81,8 @@ For more commands and options, refer to the [documentation](https://developers.c
67
81
 
68
82
  ## Documentation
69
83
 
70
- For the latest Wrangler documentation, [click here](https://6b05b6e1.cloudflare-docs-7ou.pages.dev/workers/wrangler/).
84
+ For the latest Wrangler documentation, [click here](https://developers.cloudflare.com/workers/wrangler/).
85
+
86
+ ```
87
+
88
+ ```
package/bin/wrangler.js CHANGED
@@ -35,7 +35,7 @@ Consider using a Node.js version manager such as https://volta.sh/ or https://gi
35
35
  // - maybe we can generate a certificate that concatenates with ours?
36
36
  //
37
37
  // I do think it'll be rare that someone wants to add a cert AND
38
- // use cloudflare WARP, but let's wait till the situation actually
38
+ // use Cloudflare WARP, but let's wait till the situation actually
39
39
  // arises before we do anything about it
40
40
  } else {
41
41
  const osTempDir = os.tmpdir();
@@ -22,7 +22,10 @@ var __copyProps = (to, from, except, desc) => {
22
22
  }
23
23
  return to;
24
24
  };
25
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
26
29
 
27
30
  // ../../node_modules/mime/Mime.js
28
31
  var require_Mime = __commonJS({
@@ -50,7 +53,9 @@ var require_Mime = __commonJS({
50
53
  continue;
51
54
  }
52
55
  if (!force && ext in this._types) {
53
- throw new Error('Attempt to change mapping for "' + ext + '" extension from "' + this._types[ext] + '" to "' + type + '". Pass `force=true` to allow this, otherwise remove "' + ext + '" from the list of extensions for "' + type + '".');
56
+ throw new Error(
57
+ 'Attempt to change mapping for "' + ext + '" extension from "' + this._types[ext] + '" to "' + type + '". Pass `force=true` to allow this, otherwise remove "' + ext + '" from the list of extensions for "' + type + '".'
58
+ );
54
59
  }
55
60
  this._types[ext] = type;
56
61
  }
@@ -4935,7 +4940,10 @@ async function generateASSETSBinding(options) {
4935
4940
  return await assetsFetch(request);
4936
4941
  } catch (thrown) {
4937
4942
  options.log.error(new Error(`Could not serve static asset: ${thrown}`));
4938
- return new Response(`[wrangler] Could not serve static asset: ${thrown}`, { status: 502 });
4943
+ return new Response(
4944
+ `[wrangler] Could not serve static asset: ${thrown}`,
4945
+ { status: 502 }
4946
+ );
4939
4947
  }
4940
4948
  }
4941
4949
  };
@@ -4955,7 +4963,9 @@ function generateRulesMatcher(rules, replacerFn = (match) => match) {
4955
4963
  const compiledRules = Object.entries(rules).map(([rule, match]) => {
4956
4964
  const crossHost = rule.startsWith("https://");
4957
4965
  rule = rule.split("*").map(escapeRegex).join("(?<splat>.*)");
4958
- const host_matches = rule.matchAll(/(?<=^https:\\\/\\\/[^/]*?):([^\\]+)(?=\\)/g);
4966
+ const host_matches = rule.matchAll(
4967
+ /(?<=^https:\\\/\\\/[^/]*?):([^\\]+)(?=\\)/g
4968
+ );
4959
4969
  for (const hostMatch of host_matches) {
4960
4970
  rule = rule.split(hostMatch[0]).join(`(?<${hostMatch[1]}>[^/.]+)`);
4961
4971
  }
@@ -5016,10 +5026,15 @@ function generateHeadersMatcher(headersFile) {
5016
5026
  if (rule && Object.keys(rule.headers).length > 0) {
5017
5027
  rules[rule.path] = rule.headers;
5018
5028
  }
5019
- const rulesMatcher = generateRulesMatcher(rules, (match, replacements) => Object.fromEntries(Object.entries(match).map(([name, value]) => [
5020
- name,
5021
- replacer(value, replacements)
5022
- ])));
5029
+ const rulesMatcher = generateRulesMatcher(
5030
+ rules,
5031
+ (match, replacements) => Object.fromEntries(
5032
+ Object.entries(match).map(([name, value]) => [
5033
+ name,
5034
+ replacer(value, replacements)
5035
+ ])
5036
+ )
5037
+ );
5023
5038
  return (request) => {
5024
5039
  const matches = rulesMatcher({
5025
5040
  request
@@ -5035,17 +5050,22 @@ function generateRedirectsMatcher(redirectsFile) {
5035
5050
  if (existsSync(redirectsFile)) {
5036
5051
  const contents = readFileSync4(redirectsFile).toString();
5037
5052
  const lines = contents.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("#") && line !== "");
5038
- const rules = Object.fromEntries(lines.map((line) => line.split(" ")).filter((tokens) => tokens.length === 2 || tokens.length === 3).map((tokens) => {
5039
- const from = validateURL(tokens[0], true, false, false);
5040
- const to = validateURL(tokens[1], false, true, true);
5041
- let status = parseInt(tokens[2]) || 302;
5042
- status = [301, 302, 303, 307, 308].includes(status) ? status : void 0;
5043
- return from && to && status ? [from, { to, status }] : void 0;
5044
- }).filter((rule) => rule !== void 0));
5045
- const rulesMatcher = generateRulesMatcher(rules, ({ status, to }, replacements) => ({
5046
- status,
5047
- to: replacer(to, replacements)
5048
- }));
5053
+ const rules = Object.fromEntries(
5054
+ lines.map((line) => line.split(" ")).filter((tokens) => tokens.length === 2 || tokens.length === 3).map((tokens) => {
5055
+ const from = validateURL(tokens[0], true, false, false);
5056
+ const to = validateURL(tokens[1], false, true, true);
5057
+ let status = parseInt(tokens[2]) || 302;
5058
+ status = [301, 302, 303, 307, 308].includes(status) ? status : void 0;
5059
+ return from && to && status ? [from, { to, status }] : void 0;
5060
+ }).filter((rule) => rule !== void 0)
5061
+ );
5062
+ const rulesMatcher = generateRulesMatcher(
5063
+ rules,
5064
+ ({ status, to }, replacements) => ({
5065
+ status,
5066
+ to: replacer(to, replacements)
5067
+ })
5068
+ );
5049
5069
  return (request) => {
5050
5070
  const match = rulesMatcher({
5051
5071
  request
@@ -5068,7 +5088,11 @@ function validateURL(token, onlyRelative = false, includeSearch = false, include
5068
5088
  if (host && host.groups && host.groups.host) {
5069
5089
  if (onlyRelative)
5070
5090
  return;
5071
- return `https://${host.groups.host}${extractPathname(host.groups.path, includeSearch, includeHash)}`;
5091
+ return `https://${host.groups.host}${extractPathname(
5092
+ host.groups.path,
5093
+ includeSearch,
5094
+ includeHash
5095
+ )}`;
5072
5096
  } else {
5073
5097
  if (!token.startsWith("/") && onlyRelative)
5074
5098
  token = `/${token}`;
@@ -5158,13 +5182,19 @@ async function generateAssetsFetch(directory, log) {
5158
5182
  if (asset = getAsset(`${cwd}/404.html`)) {
5159
5183
  deconstructedResponse.status = 404;
5160
5184
  deconstructedResponse.body = serveAsset(asset);
5161
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5185
+ deconstructedResponse.headers.set(
5186
+ "Content-Type",
5187
+ (0, import_mime.getType)(asset) || "application/octet-stream"
5188
+ );
5162
5189
  return deconstructedResponse;
5163
5190
  }
5164
5191
  }
5165
5192
  if (asset = getAsset(`/index.html`)) {
5166
5193
  deconstructedResponse.body = serveAsset(asset);
5167
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5194
+ deconstructedResponse.headers.set(
5195
+ "Content-Type",
5196
+ (0, import_mime.getType)(asset) || "application/octet-stream"
5197
+ );
5168
5198
  return deconstructedResponse;
5169
5199
  }
5170
5200
  deconstructedResponse.status = 404;
@@ -5174,17 +5204,26 @@ async function generateAssetsFetch(directory, log) {
5174
5204
  if (url.pathname.endsWith("/")) {
5175
5205
  if (asset = getAsset(`${url.pathname}/index.html`)) {
5176
5206
  deconstructedResponse.body = serveAsset(asset);
5177
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5207
+ deconstructedResponse.headers.set(
5208
+ "Content-Type",
5209
+ (0, import_mime.getType)(asset) || "application/octet-stream"
5210
+ );
5178
5211
  return deconstructedResponse;
5179
5212
  } else if (asset = getAsset(`${url.pathname.replace(/\/$/, ".html")}`)) {
5180
5213
  deconstructedResponse.status = 301;
5181
- deconstructedResponse.headers.set("Location", `${url.pathname.slice(0, -1)}${url.search}`);
5214
+ deconstructedResponse.headers.set(
5215
+ "Location",
5216
+ `${url.pathname.slice(0, -1)}${url.search}`
5217
+ );
5182
5218
  return deconstructedResponse;
5183
5219
  }
5184
5220
  }
5185
5221
  if (url.pathname.endsWith("/index")) {
5186
5222
  deconstructedResponse.status = 301;
5187
- deconstructedResponse.headers.set("Location", `${url.pathname.slice(0, -"index".length)}${url.search}`);
5223
+ deconstructedResponse.headers.set(
5224
+ "Location",
5225
+ `${url.pathname.slice(0, -"index".length)}${url.search}`
5226
+ );
5188
5227
  return deconstructedResponse;
5189
5228
  }
5190
5229
  if (asset = getAsset(url.pathname)) {
@@ -5192,16 +5231,25 @@ async function generateAssetsFetch(directory, log) {
5192
5231
  const extensionlessPath = url.pathname.slice(0, -".html".length);
5193
5232
  if (getAsset(extensionlessPath) || extensionlessPath === "/") {
5194
5233
  deconstructedResponse.body = serveAsset(asset);
5195
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5234
+ deconstructedResponse.headers.set(
5235
+ "Content-Type",
5236
+ (0, import_mime.getType)(asset) || "application/octet-stream"
5237
+ );
5196
5238
  return deconstructedResponse;
5197
5239
  } else {
5198
5240
  deconstructedResponse.status = 301;
5199
- deconstructedResponse.headers.set("Location", `${extensionlessPath}${url.search}`);
5241
+ deconstructedResponse.headers.set(
5242
+ "Location",
5243
+ `${extensionlessPath}${url.search}`
5244
+ );
5200
5245
  return deconstructedResponse;
5201
5246
  }
5202
5247
  } else {
5203
5248
  deconstructedResponse.body = serveAsset(asset);
5204
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5249
+ deconstructedResponse.headers.set(
5250
+ "Content-Type",
5251
+ (0, import_mime.getType)(asset) || "application/octet-stream"
5252
+ );
5205
5253
  return deconstructedResponse;
5206
5254
  }
5207
5255
  } else if (hasFileExtension(url.pathname)) {
@@ -5210,12 +5258,18 @@ async function generateAssetsFetch(directory, log) {
5210
5258
  }
5211
5259
  if (asset = getAsset(`${url.pathname}.html`)) {
5212
5260
  deconstructedResponse.body = serveAsset(asset);
5213
- deconstructedResponse.headers.set("Content-Type", (0, import_mime.getType)(asset) || "application/octet-stream");
5261
+ deconstructedResponse.headers.set(
5262
+ "Content-Type",
5263
+ (0, import_mime.getType)(asset) || "application/octet-stream"
5264
+ );
5214
5265
  return deconstructedResponse;
5215
5266
  }
5216
5267
  if (asset = getAsset(`${url.pathname}/index.html`)) {
5217
5268
  deconstructedResponse.status = 301;
5218
- deconstructedResponse.headers.set("Location", `${url.pathname}/${url.search}`);
5269
+ deconstructedResponse.headers.set(
5270
+ "Location",
5271
+ `${url.pathname}/${url.search}`
5272
+ );
5219
5273
  return deconstructedResponse;
5220
5274
  } else {
5221
5275
  notFound();
@@ -5257,13 +5311,17 @@ async function generateAssetsFetch(directory, log) {
5257
5311
  };
5258
5312
  }
5259
5313
  var invalidAssetsFetch = () => {
5260
- throw new Error("Trying to fetch assets directly when there is no `directory` option specified.");
5314
+ throw new Error(
5315
+ "Trying to fetch assets directly when there is no `directory` option specified."
5316
+ );
5261
5317
  };
5262
5318
 
5263
5319
  // src/miniflare-cli/enum-keys.ts
5264
5320
  var enumObject = (e) => {
5265
5321
  const copy = { ...e };
5266
- Object.values(e).forEach((value) => typeof value === "number" && delete copy[value]);
5322
+ Object.values(e).forEach(
5323
+ (value) => typeof value === "number" && delete copy[value]
5324
+ );
5267
5325
  return copy;
5268
5326
  };
5269
5327
  var enumKeys = (e) => {
@@ -5314,9 +5372,13 @@ async function main() {
5314
5372
  let mf;
5315
5373
  try {
5316
5374
  if (args._[1]) {
5317
- const opts = JSON.parse(args._[1]);
5375
+ const opts = JSON.parse(
5376
+ args._[1]
5377
+ );
5318
5378
  if (isNaN(opts.proxyPort || NaN) && !opts.directory) {
5319
- throw new Error("MiniflareCLIOptions: built in service bindings set to true, but no port or directory provided");
5379
+ throw new Error(
5380
+ "MiniflareCLIOptions: built in service bindings set to true, but no port or directory provided"
5381
+ );
5320
5382
  }
5321
5383
  const options = {
5322
5384
  log: config.log,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "2.0.23",
3
+ "version": "2.0.24",
4
4
  "description": "Command-line interface for all things Cloudflare Workers",
5
5
  "keywords": [
6
6
  "wrangler",
@@ -58,10 +58,10 @@
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": {
64
- "collectCoverage": true,
65
65
  "coverageReporters": [
66
66
  "json",
67
67
  "html",
@@ -96,17 +96,19 @@
96
96
  "@esbuild-plugins/node-modules-polyfill": "^0.1.4",
97
97
  "blake3-wasm": "^2.1.5",
98
98
  "chokidar": "^3.5.3",
99
- "esbuild": "0.14.47",
99
+ "esbuild": "0.14.51",
100
100
  "miniflare": "^2.6.0",
101
101
  "nanoid": "^3.3.3",
102
102
  "path-to-regexp": "^6.2.0",
103
103
  "selfsigned": "^2.0.1",
104
+ "source-map": "^0.7.4",
104
105
  "xxhash-wasm": "^1.0.1"
105
106
  },
106
107
  "devDependencies": {
107
108
  "@iarna/toml": "^3.0.0",
108
109
  "@microsoft/api-extractor": "^7.28.3",
109
110
  "@types/command-exists": "^1.2.0",
111
+ "@types/express": "^4.17.13",
110
112
  "@types/glob-to-regexp": "0.4.1",
111
113
  "@types/mime": "^2.0.3",
112
114
  "@types/prompts": "^2.0.14",
@@ -117,13 +119,16 @@
117
119
  "@types/ws": "^8.5.3",
118
120
  "@types/yargs": "^17.0.10",
119
121
  "@webcontainer/env": "^1.0.1",
122
+ "body-parser": "^1.20.0",
120
123
  "clipboardy": "^3.0.0",
121
124
  "cmd-shim": "^4.1.0",
122
125
  "command-exists": "^1.2.9",
123
126
  "concurrently": "^7.2.2",
127
+ "create-cloudflare": "^1.0.0",
124
128
  "devtools-protocol": "^0.0.955664",
125
129
  "dotenv": "^16.0.0",
126
130
  "execa": "^6.1.0",
131
+ "express": "^4.18.1",
127
132
  "faye-websocket": "^0.11.4",
128
133
  "finalhandler": "^1.2.0",
129
134
  "find-up": "^6.3.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
 
@@ -1038,6 +1038,7 @@ describe("wrangler dev", () => {
1038
1038
  it("should error if config.assets and --site are used together", async () => {
1039
1039
  writeWranglerToml({
1040
1040
  main: "./index.js",
1041
+ // @ts-expect-error we allow string inputs here
1041
1042
  assets: "abc",
1042
1043
  });
1043
1044
  fs.writeFileSync("index.js", `export default {};`);
@@ -1051,6 +1052,7 @@ describe("wrangler dev", () => {
1051
1052
  it("should error if config.assets and config.site are used together", async () => {
1052
1053
  writeWranglerToml({
1053
1054
  main: "./index.js",
1055
+ // @ts-expect-error we allow string inputs here
1054
1056
  assets: "abc",
1055
1057
  site: {
1056
1058
  bucket: "xyz",
@@ -1102,6 +1104,7 @@ describe("wrangler dev", () => {
1102
1104
  it("should warn if config.assets is used", async () => {
1103
1105
  writeWranglerToml({
1104
1106
  main: "./index.js",
1107
+ // @ts-expect-error we allow string inputs here
1105
1108
  assets: "./assets",
1106
1109
  });
1107
1110
  fs.writeFileSync("index.js", `export default {};`);