wrangler 0.0.0-e6e1daba → 0.0.0-e7cf0caa

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 (101) hide show
  1. package/bin/wrangler.js +1 -1
  2. package/miniflare-dist/index.mjs +1 -1
  3. package/package.json +14 -9
  4. package/src/__tests__/api-devregistry.test.ts +121 -0
  5. package/src/__tests__/api.test.ts +27 -5
  6. package/src/__tests__/configuration.test.ts +294 -18
  7. package/src/__tests__/d1/execute.test.ts +3 -1
  8. package/src/__tests__/d1/migrate.test.ts +2 -0
  9. package/src/__tests__/delete.test.ts +6 -0
  10. package/src/__tests__/deployments.test.ts +335 -95
  11. package/src/__tests__/dev.test.tsx +87 -57
  12. package/src/__tests__/generate.test.ts +3 -4
  13. package/src/__tests__/helpers/mock-console.ts +6 -0
  14. package/src/__tests__/helpers/msw/handlers/deployments.ts +70 -3
  15. package/src/__tests__/helpers/msw/index.ts +4 -2
  16. package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
  17. package/src/__tests__/index.test.ts +10 -4
  18. package/src/__tests__/init.test.ts +136 -104
  19. package/src/__tests__/jest.setup.ts +4 -0
  20. package/src/__tests__/kv.test.ts +9 -9
  21. package/src/__tests__/logger.test.ts +68 -2
  22. package/src/__tests__/middleware.scheduled.test.ts +2 -2
  23. package/src/__tests__/middleware.test.ts +4 -3
  24. package/src/__tests__/mtls-certificates.test.ts +5 -2
  25. package/src/__tests__/pages/deployment-list.test.ts +2 -0
  26. package/src/__tests__/pages/functions-build.test.ts +91 -41
  27. package/src/__tests__/pages/project-list.test.ts +2 -0
  28. package/src/__tests__/pages/project-upload.test.ts +43 -24
  29. package/src/__tests__/pages/publish.test.ts +267 -148
  30. package/src/__tests__/publish.test.ts +420 -164
  31. package/src/__tests__/pubsub.test.ts +3 -0
  32. package/src/__tests__/queues.test.ts +5 -2
  33. package/src/__tests__/test-old-node-version.js +3 -3
  34. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  35. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  36. package/src/__tests__/type-generation.test.ts +1 -0
  37. package/src/__tests__/user.test.ts +1 -1
  38. package/src/__tests__/worker-namespace.test.ts +1 -0
  39. package/src/api/dev.ts +10 -22
  40. package/src/api/pages/create-worker-bundle-contents.ts +1 -0
  41. package/src/api/pages/publish.tsx +38 -51
  42. package/src/bundle.ts +44 -13
  43. package/src/config/environment.ts +36 -4
  44. package/src/config/index.ts +30 -2
  45. package/src/config/validation-helpers.ts +1 -1
  46. package/src/config/validation.ts +149 -5
  47. package/src/create-worker-upload-form.ts +28 -3
  48. package/src/d1/backups.tsx +15 -11
  49. package/src/d1/create.tsx +20 -16
  50. package/src/d1/execute.tsx +22 -19
  51. package/src/d1/list.tsx +2 -2
  52. package/src/d1/migrations/apply.tsx +35 -29
  53. package/src/d1/migrations/create.tsx +15 -12
  54. package/src/d1/migrations/list.tsx +10 -7
  55. package/src/deployments.ts +260 -8
  56. package/src/dev/dev.tsx +4 -4
  57. package/src/dev/local.tsx +14 -16
  58. package/src/dev/start-server.ts +12 -16
  59. package/src/dev/use-esbuild.ts +11 -13
  60. package/src/dev/validate-dev-props.ts +9 -0
  61. package/src/dev-registry.ts +2 -1
  62. package/src/dev.tsx +28 -13
  63. package/src/entry.ts +18 -8
  64. package/src/generate/index.ts +2 -2
  65. package/src/index.ts +76 -23
  66. package/src/init.ts +144 -134
  67. package/src/logger.ts +18 -3
  68. package/src/metrics/send-event.ts +2 -1
  69. package/src/miniflare-cli/index.ts +1 -1
  70. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  71. package/src/module-collection.ts +91 -25
  72. package/src/pages/build.ts +277 -99
  73. package/src/pages/buildFunctions.ts +20 -10
  74. package/src/pages/deployments.tsx +3 -5
  75. package/src/pages/dev.ts +21 -21
  76. package/src/pages/errors.ts +1 -0
  77. package/src/pages/functions/buildPlugin.ts +57 -34
  78. package/src/pages/functions/buildWorker.ts +34 -31
  79. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  80. package/src/pages/projects.tsx +2 -5
  81. package/src/pages/publish.tsx +1 -10
  82. package/src/pages/upload.tsx +29 -9
  83. package/src/paths.ts +1 -1
  84. package/src/publish/index.ts +1 -1
  85. package/src/publish/publish.ts +29 -34
  86. package/src/queues/cli/commands/consumer/add.ts +6 -0
  87. package/src/queues/client.ts +1 -0
  88. package/src/secret/index.ts +2 -1
  89. package/src/traverse-module-graph.ts +53 -0
  90. package/src/type-generation.ts +1 -1
  91. package/src/user/user.ts +1 -1
  92. package/src/utils/render.ts +93 -0
  93. package/src/worker.ts +18 -1
  94. package/templates/d1-beta-facade.js +5 -2
  95. package/templates/gitignore +1 -0
  96. package/templates/middleware/middleware-miniflare3-json-error.ts +17 -5
  97. package/templates/tsconfig.init.json +1 -2
  98. package/templates/tsconfig.tsbuildinfo +1 -1
  99. package/wrangler-dist/cli.d.ts +33 -13
  100. package/wrangler-dist/cli.js +20732 -19984
  101. package/src/__tests__/api-devregistry.test.js +0 -64
@@ -76,6 +76,7 @@ const bindingsConfigMock: Partial<Config> = {
76
76
  wasm_modules: { MODULE1: "module1.wasm", MODULE2: "module2.wasm" },
77
77
  unsafe: {
78
78
  bindings: [{ name: "testing_unsafe", type: "plain_text" }],
79
+ metadata: { some_key: "some_value" },
79
80
  },
80
81
  rules: [
81
82
  {
@@ -85,7 +85,7 @@ describe("User", () => {
85
85
  await expect(
86
86
  requireAuth({} as Config)
87
87
  ).rejects.toThrowErrorMatchingInlineSnapshot(
88
- `"In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/api/tokens/create/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN."`
88
+ `"In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/fundamentals/api/get-started/create-token/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN."`
89
89
  );
90
90
  });
91
91
 
@@ -27,6 +27,7 @@ describe("dispatch-namespace", () => {
27
27
  Object {
28
28
  "debug": "",
29
29
  "err": "",
30
+ "info": "",
30
31
  "out": "wrangler dispatch-namespace
31
32
 
32
33
  📦 Interact with a dispatch namespace
package/src/api/dev.ts CHANGED
@@ -18,7 +18,7 @@ export interface UnstableDevOptions {
18
18
  site?: string; // Root folder of static assets for Workers Sites
19
19
  siteInclude?: string[]; // Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.
20
20
  siteExclude?: string[]; // Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.
21
- nodeCompat?: boolean; // Enable node.js compatibility
21
+ nodeCompat?: boolean; // Enable Node.js compatibility
22
22
  compatibilityDate?: string; // Date to use for compatibility checks
23
23
  compatibilityFlags?: string[]; // Flags to use for compatibility checks
24
24
  persist?: boolean; // Enable persistence for local mode, using default path: .wrangler/state
@@ -43,7 +43,6 @@ export interface UnstableDevOptions {
43
43
  preview_bucket_name?: string;
44
44
  }[];
45
45
  logLevel?: "none" | "info" | "error" | "log" | "warn" | "debug"; // Specify logging level [choices: "debug", "info", "log", "warn", "error", "none"] [default: "log"]
46
- logPrefix?: string;
47
46
  inspect?: boolean;
48
47
  local?: boolean;
49
48
  accountId?: string;
@@ -144,7 +143,6 @@ export async function unstable_dev(
144
143
  enablePagesAssetsServiceBinding,
145
144
  liveReload,
146
145
  showInteractiveDevSession,
147
- forceLocal,
148
146
  onReady: (address, port) => {
149
147
  readyPort = port;
150
148
  readyAddress = address;
@@ -163,7 +161,7 @@ export async function unstable_dev(
163
161
  site: options?.site, // Root folder of static assets for Workers Sites
164
162
  siteInclude: options?.siteInclude, // Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.
165
163
  siteExclude: options?.siteExclude, // Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.
166
- nodeCompat: options?.nodeCompat, // Enable node.js compatibility
164
+ nodeCompat: options?.nodeCompat, // Enable Node.js compatibility
167
165
  persist: options?.persist, // Enable persistence for local mode, using default path: .wrangler/state
168
166
  persistTo: options?.persistTo, // Specify directory to use for local persistence (implies --persist)
169
167
  experimentalJsonConfig: undefined,
@@ -233,6 +231,7 @@ export async function unstable_dev(
233
231
  experimentalLocal: experimentalLocal ?? false,
234
232
  experimentalLocalRemoteKv: experimentalLocalRemoteKv ?? false,
235
233
  enablePagesAssetsServiceBinding,
234
+ forceLocal,
236
235
  liveReload,
237
236
  onReady: (address, port) => {
238
237
  readyPort = port;
@@ -252,7 +251,7 @@ export async function unstable_dev(
252
251
  site: options?.site, // Root folder of static assets for Workers Sites
253
252
  siteInclude: options?.siteInclude, // Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.
254
253
  siteExclude: options?.siteExclude, // Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded.
255
- nodeCompat: options?.nodeCompat, // Enable node.js compatibility
254
+ nodeCompat: options?.nodeCompat, // Enable Node.js compatibility
256
255
  persist: options?.persist, // Enable persistence for local mode, using default path: .wrangler/state
257
256
  persistTo: options?.persistTo, // Specify directory to use for local persistence (implies --persist)
258
257
  experimentalJsonConfig: undefined,
@@ -302,27 +301,16 @@ export async function unstable_dev(
302
301
  export function parseRequestInput(
303
302
  readyAddress: string,
304
303
  readyPort: number,
305
- input?: RequestInfo,
304
+ input: RequestInfo = "/",
306
305
  init?: RequestInit,
307
306
  protocol: "http" | "https" = "http"
308
307
  ): [RequestInfo, RequestInit | undefined] {
309
308
  if (input instanceof Request) {
310
309
  return [input, undefined];
311
- } else if (input instanceof URL) {
312
- input = `${protocol}://${readyAddress}:${readyPort}${input.pathname}`;
313
- } else if (typeof input === "string") {
314
- try {
315
- // Want to strip the URL to only get the pathname, but the user could pass in only the pathname
316
- // Will error if we try and pass "/something" into new URL("/something")
317
- input = `${protocol}://${readyAddress}:${readyPort}${
318
- new URL(input).pathname
319
- }`;
320
- } catch {
321
- input = `${protocol}://${readyAddress}:${readyPort}${input}`;
322
- }
323
- } else {
324
- input = `${protocol}://${readyAddress}:${readyPort}`;
325
310
  }
326
-
327
- return [input, init];
311
+ const url = new URL(`${input}`, `${protocol}://${readyAddress}:${readyPort}`);
312
+ url.protocol = protocol;
313
+ url.hostname = readyAddress;
314
+ url.port = readyPort.toString();
315
+ return [url, init];
328
316
  }
@@ -49,6 +49,7 @@ function createWorkerBundleFormData(workerBundle: BundleResult): FormData {
49
49
  bindings: {
50
50
  vars: undefined,
51
51
  kv_namespaces: undefined,
52
+ send_email: undefined,
52
53
  wasm_modules: undefined,
53
54
  text_blobs: undefined,
54
55
  data_blobs: undefined,
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
- import { dirname, join, resolve as resolvePath } from "node:path";
3
+ import { join, resolve as resolvePath } from "node:path";
4
4
  import { cwd } from "node:process";
5
5
  import { File, FormData } from "undici";
6
6
  import { fetchResult } from "../../cfetch";
@@ -69,14 +69,6 @@ interface PagesPublishOptions {
69
69
  */
70
70
  bundle?: boolean;
71
71
 
72
- /**
73
- * Whether to process non-JS module imports or not, such as
74
- * wasm/text/binary, when we run bundling on `functions` or
75
- * `_worker.js`
76
- * Default: false
77
- */
78
- experimentalWorkerBundle?: boolean;
79
-
80
72
  // TODO: Allow passing in the API key and plumb it through
81
73
  // to the API calls so that the publish function does not
82
74
  // rely on the `CLOUDFLARE_API_KEY` environment variable
@@ -98,7 +90,6 @@ export async function publish({
98
90
  commitDirty,
99
91
  functionsDirectory: customFunctionsDirectory,
100
92
  bundle,
101
- experimentalWorkerBundle,
102
93
  }: PagesPublishOptions) {
103
94
  let _headers: string | undefined,
104
95
  _redirects: string | undefined,
@@ -137,6 +128,11 @@ export async function publish({
137
128
  isProduction = project.production_branch === branch;
138
129
  }
139
130
 
131
+ const deploymentConfig =
132
+ project.deployment_configs[isProduction ? "production" : "preview"];
133
+ const nodejsCompat =
134
+ deploymentConfig.compatibility_flags?.includes("nodejs_compat");
135
+
140
136
  /**
141
137
  * Evaluate if this is an Advanced Mode or Pages Functions project. If Advanced Mode, we'll
142
138
  * go ahead and upload `_worker.js` as is, but if Pages Functions, we need to attempt to build
@@ -160,7 +156,6 @@ export async function publish({
160
156
  );
161
157
 
162
158
  if (!_workerJS && existsSync(functionsDirectory)) {
163
- const outfile = join(tmpdir(), `./functionsWorker-${Math.random()}.js`);
164
159
  const outputConfigPath = join(
165
160
  tmpdir(),
166
161
  `functions-filepath-routing-config-${Math.random()}.json`
@@ -168,18 +163,20 @@ export async function publish({
168
163
 
169
164
  try {
170
165
  workerBundle = await buildFunctions({
171
- outfile,
172
166
  outputConfigPath,
173
167
  functionsDirectory,
174
168
  onEnd: () => {},
175
- buildOutputDirectory: dirname(outfile),
169
+ buildOutputDirectory: directory,
176
170
  routesOutputPath,
177
171
  local: false,
178
172
  d1Databases,
179
- experimentalWorkerBundle,
173
+ nodejsCompat,
180
174
  });
181
175
 
182
- builtFunctions = readFileSync(outfile, "utf-8");
176
+ builtFunctions = readFileSync(
177
+ workerBundle.resolvedEntryPointPath,
178
+ "utf-8"
179
+ );
183
180
  filepathRoutingConfig = readFileSync(outputConfigPath, "utf-8");
184
181
  } catch (e) {
185
182
  if (e instanceof FunctionsNoRoutesError) {
@@ -247,10 +244,7 @@ export async function publish({
247
244
  * – this includes its routing and middleware characteristics.
248
245
  */
249
246
  if (_workerJS) {
250
- let workerFileContents = _workerJS;
251
- const enableBundling = bundle || experimentalWorkerBundle;
252
-
253
- if (enableBundling) {
247
+ if (bundle) {
254
248
  const outfile = join(tmpdir(), `./bundledWorker-${Math.random()}.mjs`);
255
249
  workerBundle = await buildRawWorker({
256
250
  workerScriptPath,
@@ -261,30 +255,29 @@ export async function publish({
261
255
  watch: false,
262
256
  onEnd: () => {},
263
257
  betaD1Shims: d1Databases,
264
- experimentalWorkerBundle,
258
+ nodejsCompat,
265
259
  });
266
- workerFileContents = readFileSync(outfile, "utf8");
267
260
  } else {
268
261
  await checkRawWorker(workerScriptPath, () => {});
262
+ // TODO: Replace this with the cool new no-bundle stuff when that lands: https://github.com/cloudflare/workers-sdk/pull/2769
263
+ workerBundle = {
264
+ modules: [],
265
+ dependencies: {},
266
+ stop: undefined,
267
+ resolvedEntryPointPath: workerScriptPath,
268
+ bundleType: "esm",
269
+ };
269
270
  }
270
271
 
271
- if (experimentalWorkerBundle) {
272
- const workerBundleContents = await createUploadWorkerBundleContents(
273
- workerBundle as BundleResult
274
- );
272
+ const workerBundleContents = await createUploadWorkerBundleContents(
273
+ workerBundle as BundleResult
274
+ );
275
275
 
276
- formData.append(
277
- "_worker.bundle",
278
- new File([workerBundleContents], "_worker.bundle")
279
- );
280
- logger.log(`✨ Uploading Worker bundle`);
281
- } else {
282
- formData.append(
283
- "_worker.js",
284
- new File([workerFileContents], "_worker.js")
285
- );
286
- logger.log(`✨ Uploading _worker.js`);
287
- }
276
+ formData.append(
277
+ "_worker.bundle",
278
+ new File([workerBundleContents], "_worker.bundle")
279
+ );
280
+ logger.log(`✨ Uploading Worker bundle`);
288
281
 
289
282
  if (_routesCustom) {
290
283
  // user provided a custom _routes.json file
@@ -310,21 +303,15 @@ export async function publish({
310
303
  * https://developers.cloudflare.com/pages/platform/functions/
311
304
  */
312
305
  if (builtFunctions && !_workerJS) {
313
- if (experimentalWorkerBundle) {
314
- const workerBundleContents = await createUploadWorkerBundleContents(
315
- workerBundle as BundleResult
316
- );
306
+ const workerBundleContents = await createUploadWorkerBundleContents(
307
+ workerBundle as BundleResult
308
+ );
317
309
 
318
- formData.append(
319
- "_worker.bundle",
320
- new File([workerBundleContents], "_worker.bundle")
321
- );
322
- logger.log(`✨ Uploading Functions bundle`);
323
- } else {
324
- // if Functions were build successfully, proceed to uploading the build file
325
- formData.append("_worker.js", new File([builtFunctions], "_worker.js"));
326
- logger.log(`✨ Uploading Functions`);
327
- }
310
+ formData.append(
311
+ "_worker.bundle",
312
+ new File([workerBundleContents], "_worker.bundle")
313
+ );
314
+ logger.log(`✨ Uploading Functions bundle`);
328
315
 
329
316
  if (_routesCustom) {
330
317
  // user provided a custom _routes.json file
package/src/bundle.ts CHANGED
@@ -13,6 +13,13 @@ import type { DurableObjectBindings } from "./config/environment";
13
13
  import type { WorkerRegistry } from "./dev-registry";
14
14
  import type { Entry } from "./entry";
15
15
  import type { CfModule } from "./worker";
16
+
17
+ export const COMMON_ESBUILD_OPTIONS = {
18
+ // Our workerd runtime uses the same V8 version as recent Chrome, which is highly ES2022 compliant: https://kangax.github.io/compat-table/es2016plus/
19
+ target: "es2022",
20
+ loader: { ".js": "jsx", ".mjs": "jsx", ".cjs": "jsx" },
21
+ } as const;
22
+
16
23
  export type BundleResult = {
17
24
  modules: CfModule[];
18
25
  dependencies: esbuild.Metafile["outputs"][string]["inputs"];
@@ -85,6 +92,24 @@ Add "node_compat = true" to your wrangler.toml file to enable Node compatibility
85
92
  }
86
93
  }
87
94
 
95
+ const nodejsCompatPlugin: esbuild.Plugin = {
96
+ name: "nodejs_compat Plugin",
97
+ setup(pluginBuild) {
98
+ pluginBuild.onResolve({ filter: /node:.*/ }, () => {
99
+ return { external: true };
100
+ });
101
+ },
102
+ };
103
+
104
+ const cloudflareJsPlugin: esbuild.Plugin = {
105
+ name: "cloudflare javascript Plugin",
106
+ setup(pluginBuild) {
107
+ pluginBuild.onResolve({ filter: /^cloudflare:.*/ }, () => {
108
+ return { external: true };
109
+ });
110
+ },
111
+ };
112
+
88
113
  /**
89
114
  * Generate a bundle for the worker identified by the arguments passed in.
90
115
  */
@@ -98,11 +123,13 @@ export async function bundleWorker(
98
123
  doBindings: DurableObjectBindings;
99
124
  jsxFactory?: string;
100
125
  jsxFragment?: string;
126
+ entryName?: string;
101
127
  rules: Config["rules"];
102
128
  watch?: esbuild.WatchMode | boolean;
103
129
  tsconfig?: string;
104
130
  minify?: boolean;
105
- nodeCompat?: boolean;
131
+ legacyNodeCompat?: boolean;
132
+ nodejsCompat?: boolean;
106
133
  define: Config["define"];
107
134
  checkFetch: boolean;
108
135
  services?: Config["services"];
@@ -127,11 +154,13 @@ export async function bundleWorker(
127
154
  doBindings,
128
155
  jsxFactory,
129
156
  jsxFragment,
157
+ entryName,
130
158
  rules,
131
159
  watch,
132
160
  tsconfig,
133
161
  minify,
134
- nodeCompat,
162
+ legacyNodeCompat,
163
+ nodejsCompat,
135
164
  checkFetch,
136
165
  local,
137
166
  assets,
@@ -277,7 +306,7 @@ export async function bundleWorker(
277
306
  currentEntry,
278
307
  tmpDir.path,
279
308
  betaD1Shims,
280
- local,
309
+ local && !experimentalLocal,
281
310
  doBindings
282
311
  );
283
312
  }),
@@ -324,17 +353,18 @@ export async function bundleWorker(
324
353
  bundle: true,
325
354
  absWorkingDir: entry.directory,
326
355
  outdir: destination,
356
+ entryNames: entryName || path.parse(entry.file).name,
327
357
  ...(isOutfile
328
358
  ? {
329
359
  outdir: undefined,
330
360
  outfile: destination,
361
+ entryNames: undefined,
331
362
  }
332
363
  : {}),
333
364
  inject,
334
365
  external: ["__STATIC_CONTENT_MANIFEST"],
335
366
  format: entry.format === "modules" ? "esm" : "iife",
336
- // Our workerd runtime uses the same V8 version as recent Chrome, which is highly ES2022 compliant: https://kangax.github.io/compat-table/es2016plus/
337
- target: "es2022",
367
+ target: COMMON_ESBUILD_OPTIONS.target,
338
368
  sourcemap: sourcemap ?? true, // this needs to use ?? to accept false
339
369
  // Include a reference to the output folder in the sourcemap.
340
370
  // This is omitted by default, but we need it to properly resolve source paths in error output.
@@ -347,22 +377,22 @@ export async function bundleWorker(
347
377
  // use process.env["NODE_ENV" + ""] so that esbuild doesn't replace it
348
378
  // when we do a build of wrangler. (re: https://github.com/cloudflare/workers-sdk/issues/1477)
349
379
  "process.env.NODE_ENV": `"${process.env["NODE_ENV" + ""]}"`,
350
- ...(nodeCompat ? { global: "globalThis" } : {}),
380
+ ...(legacyNodeCompat ? { global: "globalThis" } : {}),
351
381
  ...(checkFetch ? { fetch: "checkedFetch" } : {}),
352
382
  ...options.define,
353
383
  },
354
384
  }),
355
385
  loader: {
356
- ".js": "jsx",
357
- ".mjs": "jsx",
358
- ".cjs": "jsx",
386
+ ...COMMON_ESBUILD_OPTIONS.loader,
359
387
  ...(loader || {}),
360
388
  },
361
389
  plugins: [
362
390
  moduleCollector.plugin,
363
- ...(nodeCompat
391
+ ...(legacyNodeCompat
364
392
  ? [NodeGlobalsPolyfills({ buffer: true }), NodeModulesPolyfills()]
365
393
  : []),
394
+ ...(nodejsCompat ? [nodejsCompatPlugin] : []),
395
+ ...[cloudflareJsPlugin],
366
396
  ...(plugins || []),
367
397
  ],
368
398
  ...(jsxFactory && { jsxFactory }),
@@ -378,7 +408,8 @@ export async function bundleWorker(
378
408
  try {
379
409
  result = await esbuild.build(buildOptions);
380
410
  } catch (e) {
381
- if (!nodeCompat && isBuildFailure(e)) rewriteNodeCompatBuildFailure(e);
411
+ if (!legacyNodeCompat && isBuildFailure(e))
412
+ rewriteNodeCompatBuildFailure(e);
382
413
  throw e;
383
414
  }
384
415
 
@@ -803,7 +834,7 @@ async function applyD1BetaFacade(
803
834
  entry: Entry,
804
835
  tmpDirPath: string,
805
836
  betaD1Shims: string[],
806
- local: boolean,
837
+ miniflare2: boolean,
807
838
  doBindings: DurableObjectBindings
808
839
  ): Promise<Entry> {
809
840
  let entrypointPath = path.resolve(
@@ -854,7 +885,7 @@ async function applyD1BetaFacade(
854
885
  ],
855
886
  define: {
856
887
  __D1_IMPORTS__: JSON.stringify(betaD1Shims),
857
- __LOCAL_MODE__: JSON.stringify(local),
888
+ __LOCAL_MODE__: JSON.stringify(miniflare2),
858
889
  },
859
890
  outfile: targetPath,
860
891
  });
@@ -74,6 +74,12 @@ interface EnvironmentInheritable {
74
74
  */
75
75
  main: string | undefined;
76
76
 
77
+ /**
78
+ * The directory in which module rules should be evaluated in a `--no-bundle` worker
79
+ * This defaults to dirname(main) when left undefined
80
+ */
81
+ base_dir: string | undefined;
82
+
77
83
  /**
78
84
  * Whether we use <name>.<subdomain>.workers.dev to
79
85
  * test and deploy your worker.
@@ -339,6 +345,24 @@ interface EnvironmentNonInheritable {
339
345
  preview_id?: string;
340
346
  }[];
341
347
 
348
+ /**
349
+ * These specify bindings to send email from inside your Worker.
350
+ *
351
+ * NOTE: This field is not automatically inherited from the top level environment,
352
+ * and so must be specified in every named environment.
353
+ *
354
+ * @default `[]`
355
+ * @nonInheritable
356
+ */
357
+ send_email: {
358
+ /** The binding name used to refer to the this binding */
359
+ name: string;
360
+ /** If this binding should be restricted to a specific verified address */
361
+ destination_address?: string;
362
+ /** If this binding should be restricted to a set of verified addresses */
363
+ allowed_destination_addresses?: string[];
364
+ }[];
365
+
342
366
  /**
343
367
  * Specifies Queues that are bound to this Worker environment.
344
368
  *
@@ -374,6 +398,9 @@ interface EnvironmentNonInheritable {
374
398
 
375
399
  /** The queue to send messages that failed to be consumed. */
376
400
  dead_letter_queue?: string;
401
+
402
+ /** The maximum number of concurrent consumer Worker invocations. Leaving this unset will allow your consumer to scale to the maximum concurrency needed to keep up with the message backlog. */
403
+ max_concurrency?: number | null;
377
404
  }[];
378
405
  };
379
406
 
@@ -463,7 +490,6 @@ interface EnvironmentNonInheritable {
463
490
  * NOTE: This field is not automatically inherited from the top level environment,
464
491
  * and so must be specified in every named environment.
465
492
  *
466
- * @default `{ bindings: [] }`
467
493
  * @nonInheritable
468
494
  */
469
495
  unsafe: {
@@ -471,14 +497,20 @@ interface EnvironmentNonInheritable {
471
497
  * A set of bindings that should be put into a Worker's upload metadata without changes. These
472
498
  * can be used to implement bindings for features that haven't released and aren't supported
473
499
  * directly by wrangler or miniflare.
474
- *
475
- * @default []
476
500
  */
477
- bindings: {
501
+ bindings?: {
478
502
  name: string;
479
503
  type: string;
480
504
  [key: string]: unknown;
481
505
  }[];
506
+
507
+ /**
508
+ * Arbitrary key/value pairs that will be included in the uploaded metadata. Values specified
509
+ * here will always be applied to metadata last, so can add new or override existing fields.
510
+ */
511
+ metadata?: {
512
+ [key: string]: string;
513
+ };
482
514
  };
483
515
 
484
516
  mtls_certificates: {
@@ -97,6 +97,7 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
97
97
  data_blobs,
98
98
  durable_objects,
99
99
  kv_namespaces,
100
+ send_email,
100
101
  queues,
101
102
  d1_databases,
102
103
  r2_buckets,
@@ -155,6 +156,23 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
155
156
  });
156
157
  }
157
158
 
159
+ if (send_email !== undefined && send_email.length > 0) {
160
+ output.push({
161
+ type: "Send Email",
162
+ entries: send_email.map(
163
+ ({ name, destination_address, allowed_destination_addresses }) => {
164
+ return {
165
+ key: name,
166
+ value:
167
+ destination_address ||
168
+ allowed_destination_addresses?.join(", ") ||
169
+ "unrestricted",
170
+ };
171
+ }
172
+ ),
173
+ });
174
+ }
175
+
158
176
  if (queues !== undefined && queues.length > 0) {
159
177
  output.push({
160
178
  type: "Queues",
@@ -255,10 +273,10 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
255
273
  });
256
274
  }
257
275
 
258
- if (unsafe !== undefined && unsafe.length > 0) {
276
+ if (unsafe?.bindings !== undefined && unsafe.bindings.length > 0) {
259
277
  output.push({
260
278
  type: "Unsafe",
261
- entries: unsafe.map(({ name, type }) => ({
279
+ entries: unsafe.bindings.map(({ name, type }) => ({
262
280
  key: type,
263
281
  value: name,
264
282
  })),
@@ -319,6 +337,16 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
319
337
  });
320
338
  }
321
339
 
340
+ if (unsafe?.metadata !== undefined) {
341
+ output.push({
342
+ type: "Unsafe Metadata",
343
+ entries: Object.entries(unsafe.metadata).map(([key, value]) => ({
344
+ key,
345
+ value: `${value}`,
346
+ })),
347
+ });
348
+ }
349
+
322
350
  if (output.length === 0) {
323
351
  return;
324
352
  }
@@ -550,7 +550,7 @@ export const getBindingNames = (value: unknown): string[] => {
550
550
  } else if (isNamespaceList(value)) {
551
551
  return value.map(({ binding }) => binding);
552
552
  } else if (isRecord(value)) {
553
- return Object.keys(value);
553
+ return Object.keys(value).filter((k) => value[k] !== undefined);
554
554
  } else {
555
555
  return [];
556
556
  }