wrangler 2.4.4 → 2.6.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 (46) hide show
  1. package/bin/wrangler.js +20 -8
  2. package/miniflare-dist/index.mjs +90 -41
  3. package/package.json +3 -3
  4. package/src/__tests__/configuration.test.ts +211 -0
  5. package/src/__tests__/delete.test.ts +81 -48
  6. package/src/__tests__/dev.test.tsx +25 -8
  7. package/src/__tests__/helpers/mock-oauth-flow.ts +5 -1
  8. package/src/__tests__/helpers/msw/handlers/oauth.ts +13 -18
  9. package/src/__tests__/init.test.ts +18 -3
  10. package/src/__tests__/logout.test.ts +47 -0
  11. package/src/__tests__/metrics.test.ts +88 -43
  12. package/src/__tests__/pages-deployment-tail.test.ts +165 -101
  13. package/src/__tests__/publish.test.ts +94 -7
  14. package/src/__tests__/pubsub.test.ts +208 -88
  15. package/src/__tests__/queues.test.ts +155 -67
  16. package/src/__tests__/tail.test.ts +207 -108
  17. package/src/__tests__/type-generation.test.ts +7 -0
  18. package/src/__tests__/user.test.ts +43 -69
  19. package/src/config/environment.ts +16 -0
  20. package/src/config/index.ts +31 -8
  21. package/src/config/validation.ts +49 -0
  22. package/src/create-worker-upload-form.ts +9 -0
  23. package/src/d1/backups.tsx +7 -2
  24. package/src/d1/delete.tsx +4 -4
  25. package/src/d1/index.ts +2 -0
  26. package/src/d1/migrations/apply.tsx +6 -5
  27. package/src/d1/migrations/helpers.ts +4 -2
  28. package/src/d1/migrations/list.tsx +2 -2
  29. package/src/d1/migrations/options.ts +18 -0
  30. package/src/dev/dev.tsx +46 -22
  31. package/src/dev/local.tsx +63 -29
  32. package/src/dev/start-server.ts +18 -21
  33. package/src/dev.tsx +33 -13
  34. package/src/git-client.ts +15 -4
  35. package/src/index.tsx +1 -0
  36. package/src/init.ts +8 -0
  37. package/src/miniflare-cli/assets.ts +55 -28
  38. package/src/miniflare-cli/index.ts +2 -1
  39. package/src/pages/dev.tsx +7 -0
  40. package/src/proxy.ts +5 -0
  41. package/src/publish/publish.ts +1 -0
  42. package/src/secret/index.ts +1 -0
  43. package/src/type-generation.ts +10 -2
  44. package/src/worker.ts +6 -0
  45. package/wrangler-dist/cli.d.ts +15 -0
  46. package/wrangler-dist/cli.js +2045 -636
package/bin/wrangler.js CHANGED
@@ -62,15 +62,21 @@ Consider using a Node.js version manager such as https://volta.sh/ or https://gi
62
62
  ...process.argv.slice(2),
63
63
  ],
64
64
  {
65
- stdio: "inherit",
65
+ stdio: ["inherit", "inherit", "inherit", "ipc"],
66
66
  env: {
67
67
  ...process.env,
68
68
  NODE_EXTRA_CA_CERTS: pathToCACerts,
69
69
  },
70
70
  }
71
- ).on("exit", (code) =>
72
- process.exit(code === undefined || code === null ? 0 : code)
73
- );
71
+ )
72
+ .on("exit", (code) =>
73
+ process.exit(code === undefined || code === null ? 0 : code)
74
+ )
75
+ .on("message", (message) => {
76
+ if (process.send) {
77
+ process.send(message);
78
+ }
79
+ });
74
80
  }
75
81
 
76
82
  /**
@@ -95,11 +101,17 @@ function runDelegatedWrangler() {
95
101
  process.execPath,
96
102
  [resolvedBinaryPath, ...process.argv.slice(2)],
97
103
  {
98
- stdio: "inherit",
104
+ stdio: ["inherit", "inherit", "inherit", "ipc"],
99
105
  }
100
- ).on("exit", (code) =>
101
- process.exit(code === undefined || code === null ? 0 : code)
102
- );
106
+ )
107
+ .on("exit", (code) =>
108
+ process.exit(code === undefined || code === null ? 0 : code)
109
+ )
110
+ .on("message", (message) => {
111
+ if (process.send) {
112
+ process.send(message);
113
+ }
114
+ });
103
115
  }
104
116
 
105
117
  /**
@@ -128,16 +128,16 @@ var init_environment_polyfills = __esm({
128
128
  }
129
129
  });
130
130
 
131
- // ../pages-shared/environment-polyfills/miniflare.ts
132
- var miniflare_exports = {};
131
+ // ../pages-shared/environment-polyfills/miniflare-tre.ts
132
+ var miniflare_tre_exports = {};
133
133
  import {
134
134
  fetch as miniflareFetch,
135
135
  Headers as MiniflareHeaders,
136
136
  Request as MiniflareRequest,
137
137
  Response as MiniflareResponse
138
- } from "@miniflare/core";
139
- var init_miniflare = __esm({
140
- "../pages-shared/environment-polyfills/miniflare.ts"() {
138
+ } from "@miniflare/tre";
139
+ var init_miniflare_tre = __esm({
140
+ "../pages-shared/environment-polyfills/miniflare-tre.ts"() {
141
141
  init_environment_polyfills();
142
142
  polyfill({
143
143
  fetch: miniflareFetch,
@@ -148,6 +148,26 @@ var init_miniflare = __esm({
148
148
  }
149
149
  });
150
150
 
151
+ // ../pages-shared/environment-polyfills/miniflare.ts
152
+ var miniflare_exports = {};
153
+ import {
154
+ fetch as miniflareFetch2,
155
+ Headers as MiniflareHeaders2,
156
+ Request as MiniflareRequest2,
157
+ Response as MiniflareResponse2
158
+ } from "@miniflare/core";
159
+ var init_miniflare = __esm({
160
+ "../pages-shared/environment-polyfills/miniflare.ts"() {
161
+ init_environment_polyfills();
162
+ polyfill({
163
+ fetch: miniflareFetch2,
164
+ Headers: MiniflareHeaders2,
165
+ Request: MiniflareRequest2,
166
+ Response: MiniflareResponse2
167
+ });
168
+ }
169
+ });
170
+
151
171
  // ../pages-shared/asset-server/responses.ts
152
172
  function mergeHeaders(base, extra) {
153
173
  base = new Headers(base ?? {});
@@ -329,6 +349,15 @@ var init_rulesEngine = __esm({
329
349
  }
330
350
  });
331
351
 
352
+ // ../pages-shared/asset-server/url.ts
353
+ function stringifyURLToRootRelativePathname(url) {
354
+ return `${url.pathname}${url.search}${url.hash}`;
355
+ }
356
+ var init_url = __esm({
357
+ "../pages-shared/asset-server/url.ts"() {
358
+ }
359
+ });
360
+
332
361
  // ../pages-shared/asset-server/handler.ts
333
362
  var handler_exports = {};
334
363
  __export(handler_exports, {
@@ -339,6 +368,7 @@ __export(handler_exports, {
339
368
  HEADERS_VERSION_V1: () => HEADERS_VERSION_V1,
340
369
  REDIRECTS_VERSION: () => REDIRECTS_VERSION2,
341
370
  generateHandler: () => generateHandler,
371
+ getResponseFromMatch: () => getResponseFromMatch,
342
372
  normaliseHeaders: () => normaliseHeaders,
343
373
  parseQualityWeightedList: () => parseQualityWeightedList
344
374
  });
@@ -409,22 +439,7 @@ async function generateHandler({
409
439
  async function generateResponse() {
410
440
  const match = staticRedirectsMatcher() || generateRedirectsMatcher()({ request })[0];
411
441
  if (match) {
412
- const { status, to } = match;
413
- const destination = new URL(to, request.url);
414
- const location = destination.origin === new URL(request.url).origin ? `${destination.pathname}${destination.search || search}${destination.hash}` : `${destination.href}${destination.search ? "" : search}${destination.hash}`;
415
- switch (status) {
416
- case 301:
417
- return new MovedPermanentlyResponse(location);
418
- case 303:
419
- return new SeeOtherResponse(location);
420
- case 307:
421
- return new TemporaryRedirectResponse(location);
422
- case 308:
423
- return new PermanentRedirectResponse(location);
424
- case 302:
425
- default:
426
- return new FoundResponse(location);
427
- }
442
+ return getResponseFromMatch(match, url);
428
443
  }
429
444
  if (!request.method.match(/^(get|head)$/i)) {
430
445
  return new MethodNotAllowedResponse();
@@ -703,6 +718,27 @@ async function generateHandler({
703
718
  );
704
719
  }
705
720
  }
721
+ function getResponseFromMatch({
722
+ status,
723
+ to
724
+ }, requestUrl) {
725
+ const destination = new URL(to, requestUrl);
726
+ destination.search = destination.search || requestUrl.search;
727
+ const location = destination.origin === requestUrl.origin ? stringifyURLToRootRelativePathname(destination) : destination.toString();
728
+ switch (status) {
729
+ case 301:
730
+ return new MovedPermanentlyResponse(location);
731
+ case 303:
732
+ return new SeeOtherResponse(location);
733
+ case 307:
734
+ return new TemporaryRedirectResponse(location);
735
+ case 308:
736
+ return new PermanentRedirectResponse(location);
737
+ case 302:
738
+ default:
739
+ return new FoundResponse(location);
740
+ }
741
+ }
706
742
  function parseQualityWeightedList(list = "") {
707
743
  const items = {};
708
744
  list.replace(/\s/g, "").split(",").forEach((el) => {
@@ -728,6 +764,7 @@ var init_handler = __esm({
728
764
  "../pages-shared/asset-server/handler.ts"() {
729
765
  init_responses();
730
766
  init_rulesEngine();
767
+ init_url();
731
768
  ASSET_PRESERVATION_CACHE = "assetPreservationCache";
732
769
  CACHE_CONTROL_PRESERVATION = "public, s-maxage=604800";
733
770
  CACHE_CONTROL_BROWSER = "public, max-age=0, must-revalidate";
@@ -5632,7 +5669,11 @@ function constructRedirects({
5632
5669
  for (const rule of redirects.rules) {
5633
5670
  if (!rule.from.match(SPLAT_REGEX) && !rule.from.match(PLACEHOLDER_REGEX)) {
5634
5671
  if (canCreateStaticRule) {
5635
- staticRedirects[rule.from] = { status: rule.status, to: rule.to };
5672
+ staticRedirects[rule.from] = {
5673
+ status: rule.status,
5674
+ to: rule.to,
5675
+ lineNumber: rule.lineNumber
5676
+ };
5636
5677
  continue;
5637
5678
  } else {
5638
5679
  logger(
@@ -5974,11 +6015,6 @@ function parseRedirects(input) {
5974
6015
 
5975
6016
  // src/miniflare-cli/assets.ts
5976
6017
  var import_mime = __toESM(require_mime());
5977
- import { fetch as miniflareFetch2 } from "@miniflare/core";
5978
- import {
5979
- Response as MiniflareResponse2,
5980
- Request as MiniflareRequest2
5981
- } from "@miniflare/core";
5982
6018
  import { watch } from "chokidar";
5983
6019
 
5984
6020
  // src/pages/hash.tsx
@@ -5994,28 +6030,34 @@ var hashFile = (filepath) => {
5994
6030
 
5995
6031
  // src/miniflare-cli/assets.ts
5996
6032
  async function generateASSETSBinding(options) {
5997
- const assetsFetch = options.directory !== void 0 ? await generateAssetsFetch(options.directory, options.log) : invalidAssetsFetch;
6033
+ const assetsFetch = options.directory !== void 0 ? await generateAssetsFetch(options.directory, options.log, options.tre) : invalidAssetsFetch;
6034
+ const miniflare = options.tre ? await import("@miniflare/tre") : await import("@miniflare/core");
6035
+ const Request = miniflare.Request;
6036
+ const Response2 = miniflare.Response;
6037
+ const fetch2 = options.tre ? miniflare.fetch : (await import("@miniflare/web-sockets")).upgradingFetch;
5998
6038
  return async function(miniflareRequest) {
5999
6039
  if (options.proxyPort) {
6000
6040
  try {
6001
6041
  const url = new URL(miniflareRequest.url);
6002
6042
  url.host = `localhost:${options.proxyPort}`;
6003
- return await miniflareFetch2(url, miniflareRequest);
6043
+ const proxyRequest = new Request(url, miniflareRequest);
6044
+ if (proxyRequest.headers.get("Upgrade") === "websocket") {
6045
+ proxyRequest.headers.delete("Sec-WebSocket-Accept");
6046
+ proxyRequest.headers.delete("Sec-WebSocket-Key");
6047
+ }
6048
+ return await fetch2(proxyRequest);
6004
6049
  } catch (thrown) {
6005
6050
  options.log.error(new Error(`Could not proxy request: ${thrown}`));
6006
- return new MiniflareResponse2(
6007
- `[wrangler] Could not proxy request: ${thrown}`,
6008
- {
6009
- status: 502
6010
- }
6011
- );
6051
+ return new Response2(`[wrangler] Could not proxy request: ${thrown}`, {
6052
+ status: 502
6053
+ });
6012
6054
  }
6013
6055
  } else {
6014
6056
  try {
6015
6057
  return await assetsFetch(miniflareRequest);
6016
6058
  } catch (thrown) {
6017
6059
  options.log.error(new Error(`Could not serve static asset: ${thrown}`));
6018
- return new MiniflareResponse2(
6060
+ return new Response2(
6019
6061
  `[wrangler] Could not serve static asset: ${thrown}`,
6020
6062
  { status: 502 }
6021
6063
  );
@@ -6023,8 +6065,14 @@ async function generateASSETSBinding(options) {
6023
6065
  }
6024
6066
  };
6025
6067
  }
6026
- async function generateAssetsFetch(directory, log) {
6027
- await Promise.resolve().then(() => (init_miniflare(), miniflare_exports));
6068
+ async function generateAssetsFetch(directory, log, tre) {
6069
+ if (tre) {
6070
+ await Promise.resolve().then(() => (init_miniflare_tre(), miniflare_tre_exports));
6071
+ } else {
6072
+ await Promise.resolve().then(() => (init_miniflare(), miniflare_exports));
6073
+ }
6074
+ const miniflare = tre ? await import("@miniflare/tre") : await import("@miniflare/core");
6075
+ const Request = miniflare.Request;
6028
6076
  const { generateHandler: generateHandler2, parseQualityWeightedList: parseQualityWeightedList2 } = await Promise.resolve().then(() => (init_handler(), handler_exports));
6029
6077
  const headersFile = join(directory, "_headers");
6030
6078
  const redirectsFile = join(directory, "_redirects");
@@ -6118,7 +6166,7 @@ async function generateAssetsFetch(directory, log) {
6118
6166
  });
6119
6167
  };
6120
6168
  return async (input, init) => {
6121
- const request = new MiniflareRequest2(input, init);
6169
+ const request = new Request(input, init);
6122
6170
  return await generateResponse(request);
6123
6171
  };
6124
6172
  }
@@ -6224,7 +6272,8 @@ async function main() {
6224
6272
  const options = {
6225
6273
  log: config.log,
6226
6274
  proxyPort: opts.proxyPort,
6227
- directory: opts.directory
6275
+ directory: opts.directory,
6276
+ tre: false
6228
6277
  };
6229
6278
  config.serviceBindings = {
6230
6279
  ...config.serviceBindings,
@@ -6288,7 +6337,7 @@ async function main() {
6288
6337
  }
6289
6338
  process.send && process.send(
6290
6339
  JSON.stringify({
6291
- mfPort,
6340
+ port: mfPort,
6292
6341
  ready: true,
6293
6342
  durableObjectsPort: durableObjectsMfPort
6294
6343
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "2.4.4",
3
+ "version": "2.6.0",
4
4
  "description": "Command-line interface for all things Cloudflare Workers",
5
5
  "keywords": [
6
6
  "wrangler",
@@ -119,7 +119,7 @@
119
119
  "@databases/sql": "^3.2.0",
120
120
  "@iarna/toml": "^3.0.0",
121
121
  "@microsoft/api-extractor": "^7.28.3",
122
- "@miniflare/tre": "^3.0.0-next.7",
122
+ "@miniflare/tre": "^3.0.0-next.8",
123
123
  "@types/better-sqlite3": "^7.6.0",
124
124
  "@types/busboy": "^1.5.0",
125
125
  "@types/command-exists": "^1.2.0",
@@ -162,7 +162,7 @@
162
162
  "jest-websocket-mock": "^2.3.0",
163
163
  "mime": "^3.0.0",
164
164
  "minimatch": "^5.1.0",
165
- "msw": "^0.47.1",
165
+ "msw": "^0.49.1",
166
166
  "npx-import": "^1.1.3",
167
167
  "open": "^8.4.0",
168
168
  "p-queue": "^7.2.0",
@@ -55,6 +55,7 @@ describe("normalizeAndValidateConfig()", () => {
55
55
  },
56
56
  r2_buckets: [],
57
57
  services: [],
58
+ analytics_engine_datasets: [],
58
59
  route: undefined,
59
60
  routes: undefined,
60
61
  rules: [],
@@ -915,6 +916,15 @@ describe("normalizeAndValidateConfig()", () => {
915
916
  environment: "SERVICE_BINDING_ENVIRONMENT_1",
916
917
  },
917
918
  ],
919
+ analytics_engine_datasets: [
920
+ {
921
+ binding: "AE_BINDING_1",
922
+ dataset: "DATASET_1",
923
+ },
924
+ {
925
+ binding: "AE_BINDING_2",
926
+ },
927
+ ],
918
928
  unsafe: {
919
929
  bindings: [
920
930
  { name: "UNSAFE_BINDING_1", type: "UNSAFE_TYPE_1" },
@@ -2028,6 +2038,92 @@ describe("normalizeAndValidateConfig()", () => {
2028
2038
  });
2029
2039
  });
2030
2040
 
2041
+ describe("[analytics_engine_datasets]", () => {
2042
+ it("should error if analytics_engine_datasets is an object", () => {
2043
+ const { diagnostics } = normalizeAndValidateConfig(
2044
+ { analytics_engine_datasets: {} } as unknown as RawConfig,
2045
+ undefined,
2046
+ { env: undefined }
2047
+ );
2048
+
2049
+ expect(diagnostics.hasWarnings()).toBe(false);
2050
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2051
+ "Processing wrangler configuration:
2052
+ - The field \\"analytics_engine_datasets\\" should be an array but got {}."
2053
+ `);
2054
+ });
2055
+
2056
+ it("should error if analytics_engine_datasets is a string", () => {
2057
+ const { diagnostics } = normalizeAndValidateConfig(
2058
+ { analytics_engine_datasets: "BAD" } as unknown as RawConfig,
2059
+ undefined,
2060
+ { env: undefined }
2061
+ );
2062
+
2063
+ expect(diagnostics.hasWarnings()).toBe(false);
2064
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2065
+ "Processing wrangler configuration:
2066
+ - The field \\"analytics_engine_datasets\\" should be an array but got \\"BAD\\"."
2067
+ `);
2068
+ });
2069
+
2070
+ it("should error if analytics_engine_datasets is a number", () => {
2071
+ const { diagnostics } = normalizeAndValidateConfig(
2072
+ { analytics_engine_datasets: 999 } as unknown as RawConfig,
2073
+ undefined,
2074
+ { env: undefined }
2075
+ );
2076
+
2077
+ expect(diagnostics.hasWarnings()).toBe(false);
2078
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2079
+ "Processing wrangler configuration:
2080
+ - The field \\"analytics_engine_datasets\\" should be an array but got 999."
2081
+ `);
2082
+ });
2083
+
2084
+ it("should error if analytics_engine_datasets is null", () => {
2085
+ const { diagnostics } = normalizeAndValidateConfig(
2086
+ { analytics_engine_datasets: null } as unknown as RawConfig,
2087
+ undefined,
2088
+ { env: undefined }
2089
+ );
2090
+
2091
+ expect(diagnostics.hasWarnings()).toBe(false);
2092
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2093
+ "Processing wrangler configuration:
2094
+ - The field \\"analytics_engine_datasets\\" should be an array but got null."
2095
+ `);
2096
+ });
2097
+
2098
+ it("should error if analytics_engine_datasets.bindings are not valid", () => {
2099
+ const { diagnostics } = normalizeAndValidateConfig(
2100
+ {
2101
+ analytics_engine_datasets: [
2102
+ {},
2103
+ { binding: 2333, dataset: 2444 },
2104
+ {
2105
+ binding: "AE_BINDING_2",
2106
+ dataset: 2555,
2107
+ },
2108
+ { binding: "AE_BINDING_1", dataset: "" },
2109
+ ],
2110
+ } as unknown as RawConfig,
2111
+ undefined,
2112
+ { env: undefined }
2113
+ );
2114
+
2115
+ expect(diagnostics.hasWarnings()).toBe(false);
2116
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2117
+ "Processing wrangler configuration:
2118
+ - \\"analytics_engine_datasets[0]\\" bindings should have a string \\"binding\\" field but got {}.
2119
+ - \\"analytics_engine_datasets[1]\\" bindings should have a string \\"binding\\" field but got {\\"binding\\":2333,\\"dataset\\":2444}.
2120
+ - \\"analytics_engine_datasets[1]\\" bindings should, optionally, have a string \\"dataset\\" field but got {\\"binding\\":2333,\\"dataset\\":2444}.
2121
+ - \\"analytics_engine_datasets[2]\\" bindings should, optionally, have a string \\"dataset\\" field but got {\\"binding\\":\\"AE_BINDING_2\\",\\"dataset\\":2555}.
2122
+ - \\"analytics_engine_datasets[3]\\" bindings should, optionally, have a string \\"dataset\\" field but got {\\"binding\\":\\"AE_BINDING_1\\",\\"dataset\\":\\"\\"}."
2123
+ `);
2124
+ });
2125
+ });
2126
+
2031
2127
  describe("[dispatch_namespaces]", () => {
2032
2128
  it("should log an experimental warning when dispatch_namespaces is used", () => {
2033
2129
  const { diagnostics } = normalizeAndValidateConfig(
@@ -2697,6 +2793,8 @@ describe("normalizeAndValidateConfig()", () => {
2697
2793
  };
2698
2794
  const kv_namespaces: RawConfig["kv_namespaces"] = [];
2699
2795
  const r2_buckets: RawConfig["r2_buckets"] = [];
2796
+ const analytics_engine_datasets: RawConfig["analytics_engine_datasets"] =
2797
+ [];
2700
2798
  const unsafe: RawConfig["unsafe"] = { bindings: [] };
2701
2799
  const rawConfig: RawConfig = {
2702
2800
  define,
@@ -2704,6 +2802,7 @@ describe("normalizeAndValidateConfig()", () => {
2704
2802
  durable_objects,
2705
2803
  kv_namespaces,
2706
2804
  r2_buckets,
2805
+ analytics_engine_datasets,
2707
2806
  unsafe,
2708
2807
  env: {
2709
2808
  ENV1: {},
@@ -2723,6 +2822,7 @@ describe("normalizeAndValidateConfig()", () => {
2723
2822
  durable_objects,
2724
2823
  kv_namespaces,
2725
2824
  r2_buckets,
2825
+ analytics_engine_datasets,
2726
2826
  unsafe,
2727
2827
  })
2728
2828
  );
@@ -2746,6 +2846,9 @@ describe("normalizeAndValidateConfig()", () => {
2746
2846
  - \\"r2_buckets\\" exists at the top level, but not on \\"env.ENV1\\".
2747
2847
  This is not what you probably want, since \\"r2_buckets\\" is not inherited by environments.
2748
2848
  Please add \\"r2_buckets\\" to \\"env.ENV1\\".
2849
+ - \\"analytics_engine_datasets\\" exists at the top level, but not on \\"env.ENV1\\".
2850
+ This is not what you probably want, since \\"analytics_engine_datasets\\" is not inherited by environments.
2851
+ Please add \\"analytics_engine_datasets\\" to \\"env.ENV1\\".
2749
2852
  - \\"unsafe\\" exists at the top level, but not on \\"env.ENV1\\".
2750
2853
  This is not what you probably want, since \\"unsafe\\" is not inherited by environments.
2751
2854
  Please add \\"unsafe\\" to \\"env.ENV1\\"."
@@ -3447,6 +3550,114 @@ describe("normalizeAndValidateConfig()", () => {
3447
3550
  });
3448
3551
  });
3449
3552
 
3553
+ describe("[analytics_engine_datasets]", () => {
3554
+ it("should error if analytics_engine_datasets is an object", () => {
3555
+ const { diagnostics } = normalizeAndValidateConfig(
3556
+ {
3557
+ env: { ENV1: { analytics_engine_datasets: {} } },
3558
+ } as unknown as RawConfig,
3559
+ undefined,
3560
+ { env: "ENV1" }
3561
+ );
3562
+
3563
+ expect(diagnostics.hasWarnings()).toBe(false);
3564
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
3565
+ "Processing wrangler configuration:
3566
+
3567
+ - \\"env.ENV1\\" environment configuration
3568
+ - The field \\"env.ENV1.analytics_engine_datasets\\" should be an array but got {}."
3569
+ `);
3570
+ });
3571
+
3572
+ it("should error if analytics_engine_datasets is a string", () => {
3573
+ const { diagnostics } = normalizeAndValidateConfig(
3574
+ {
3575
+ env: { ENV1: { analytics_engine_datasets: "BAD" } },
3576
+ } as unknown as RawConfig,
3577
+ undefined,
3578
+ { env: "ENV1" }
3579
+ );
3580
+
3581
+ expect(diagnostics.hasWarnings()).toBe(false);
3582
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
3583
+ "Processing wrangler configuration:
3584
+
3585
+ - \\"env.ENV1\\" environment configuration
3586
+ - The field \\"env.ENV1.analytics_engine_datasets\\" should be an array but got \\"BAD\\"."
3587
+ `);
3588
+ });
3589
+
3590
+ it("should error if analytics_engine_datasets is a number", () => {
3591
+ const { diagnostics } = normalizeAndValidateConfig(
3592
+ {
3593
+ env: { ENV1: { analytics_engine_datasets: 999 } },
3594
+ } as unknown as RawConfig,
3595
+ undefined,
3596
+ { env: "ENV1" }
3597
+ );
3598
+
3599
+ expect(diagnostics.hasWarnings()).toBe(false);
3600
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
3601
+ "Processing wrangler configuration:
3602
+
3603
+ - \\"env.ENV1\\" environment configuration
3604
+ - The field \\"env.ENV1.analytics_engine_datasets\\" should be an array but got 999."
3605
+ `);
3606
+ });
3607
+
3608
+ it("should error if analytics_engine_datasets is null", () => {
3609
+ const { diagnostics } = normalizeAndValidateConfig(
3610
+ {
3611
+ env: { ENV1: { analytics_engine_datasets: null } },
3612
+ } as unknown as RawConfig,
3613
+ undefined,
3614
+ { env: "ENV1" }
3615
+ );
3616
+
3617
+ expect(diagnostics.hasWarnings()).toBe(false);
3618
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
3619
+ "Processing wrangler configuration:
3620
+
3621
+ - \\"env.ENV1\\" environment configuration
3622
+ - The field \\"env.ENV1.analytics_engine_datasets\\" should be an array but got null."
3623
+ `);
3624
+ });
3625
+
3626
+ it("should error if analytics_engine_datasets.bindings are not valid", () => {
3627
+ const { diagnostics } = normalizeAndValidateConfig(
3628
+ {
3629
+ env: {
3630
+ ENV1: {
3631
+ analytics_engine_datasets: [
3632
+ {},
3633
+ { binding: 2333, dataset: 2444 },
3634
+ {
3635
+ binding: "AE_BINDING_2",
3636
+ dataset: 2555,
3637
+ },
3638
+ { binding: "AE_BINDING_1", dataset: "" },
3639
+ ],
3640
+ },
3641
+ },
3642
+ } as unknown as RawConfig,
3643
+ undefined,
3644
+ { env: "ENV1" }
3645
+ );
3646
+
3647
+ expect(diagnostics.hasWarnings()).toBe(false);
3648
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
3649
+ "Processing wrangler configuration:
3650
+
3651
+ - \\"env.ENV1\\" environment configuration
3652
+ - \\"env.ENV1.analytics_engine_datasets[0]\\" bindings should have a string \\"binding\\" field but got {}.
3653
+ - \\"env.ENV1.analytics_engine_datasets[1]\\" bindings should have a string \\"binding\\" field but got {\\"binding\\":2333,\\"dataset\\":2444}.
3654
+ - \\"env.ENV1.analytics_engine_datasets[1]\\" bindings should, optionally, have a string \\"dataset\\" field but got {\\"binding\\":2333,\\"dataset\\":2444}.
3655
+ - \\"env.ENV1.analytics_engine_datasets[2]\\" bindings should, optionally, have a string \\"dataset\\" field but got {\\"binding\\":\\"AE_BINDING_2\\",\\"dataset\\":2555}.
3656
+ - \\"env.ENV1.analytics_engine_datasets[3]\\" bindings should, optionally, have a string \\"dataset\\" field but got {\\"binding\\":\\"AE_BINDING_1\\",\\"dataset\\":\\"\\"}."
3657
+ `);
3658
+ });
3659
+ });
3660
+
3450
3661
  describe("[unsafe.bindings]", () => {
3451
3662
  it("should error if unsafe is an array", () => {
3452
3663
  const { diagnostics } = normalizeAndValidateConfig(