wrangler 0.0.0-e33294b0 → 0.0.0-e351afcf

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 (127) hide show
  1. package/bin/wrangler.js +1 -1
  2. package/miniflare-dist/index.mjs +183 -92
  3. package/package.json +15 -10
  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__/constellation.test.ts +371 -0
  8. package/src/__tests__/d1/execute.test.ts +3 -1
  9. package/src/__tests__/d1/migrate.test.ts +102 -0
  10. package/src/__tests__/delete.test.ts +6 -0
  11. package/src/__tests__/deployments.test.ts +335 -95
  12. package/src/__tests__/dev.test.tsx +87 -57
  13. package/src/__tests__/generate.test.ts +3 -4
  14. package/src/__tests__/guess-worker-format.test.ts +35 -0
  15. package/src/__tests__/helpers/mock-console.ts +6 -0
  16. package/src/__tests__/helpers/msw/handlers/deployments.ts +70 -3
  17. package/src/__tests__/helpers/msw/index.ts +4 -2
  18. package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
  19. package/src/__tests__/index.test.ts +14 -6
  20. package/src/__tests__/init.test.ts +136 -104
  21. package/src/__tests__/jest.setup.ts +4 -0
  22. package/src/__tests__/kv.test.ts +9 -9
  23. package/src/__tests__/logger.test.ts +68 -2
  24. package/src/__tests__/middleware.scheduled.test.ts +2 -2
  25. package/src/__tests__/middleware.test.ts +4 -3
  26. package/src/__tests__/mtls-certificates.test.ts +7 -3
  27. package/src/__tests__/pages/deployment-list.test.ts +2 -0
  28. package/src/__tests__/pages/functions-build.test.ts +159 -39
  29. package/src/__tests__/pages/project-list.test.ts +2 -0
  30. package/src/__tests__/pages/project-upload.test.ts +43 -24
  31. package/src/__tests__/pages/publish.test.ts +267 -148
  32. package/src/__tests__/publish.test.ts +1040 -339
  33. package/src/__tests__/pubsub.test.ts +3 -0
  34. package/src/__tests__/queues.test.ts +5 -2
  35. package/src/__tests__/test-old-node-version.js +3 -3
  36. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  37. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  38. package/src/__tests__/type-generation.test.ts +1 -0
  39. package/src/__tests__/user.test.ts +2 -2
  40. package/src/__tests__/worker-namespace.test.ts +1 -0
  41. package/src/api/dev.ts +15 -22
  42. package/src/api/pages/create-worker-bundle-contents.ts +1 -0
  43. package/src/api/pages/publish.tsx +64 -61
  44. package/src/bundle.ts +51 -16
  45. package/src/config/environment.ts +36 -4
  46. package/src/config/index.ts +30 -2
  47. package/src/config/validation-helpers.ts +1 -1
  48. package/src/config/validation.ts +149 -5
  49. package/src/constellation/createProject.tsx +51 -0
  50. package/src/constellation/deleteProject.ts +51 -0
  51. package/src/constellation/deleteProjectModel.ts +68 -0
  52. package/src/constellation/index.ts +75 -0
  53. package/src/constellation/listCatalog.tsx +35 -0
  54. package/src/constellation/listModel.tsx +41 -0
  55. package/src/constellation/listProject.tsx +28 -0
  56. package/src/constellation/listRuntime.tsx +28 -0
  57. package/src/constellation/options.ts +17 -0
  58. package/src/constellation/types.ts +17 -0
  59. package/src/constellation/uploadModel.tsx +64 -0
  60. package/src/constellation/utils.ts +90 -0
  61. package/src/create-worker-preview.ts +19 -8
  62. package/src/create-worker-upload-form.ts +28 -3
  63. package/src/d1/backups.tsx +19 -15
  64. package/src/d1/create.tsx +45 -39
  65. package/src/d1/delete.ts +1 -1
  66. package/src/d1/execute.tsx +23 -20
  67. package/src/d1/list.tsx +14 -12
  68. package/src/d1/migrations/apply.tsx +36 -30
  69. package/src/d1/migrations/create.tsx +15 -12
  70. package/src/d1/migrations/helpers.ts +5 -8
  71. package/src/d1/migrations/list.tsx +10 -7
  72. package/src/deployments.ts +260 -8
  73. package/src/dev/dev.tsx +6 -4
  74. package/src/dev/local.tsx +65 -40
  75. package/src/dev/start-server.ts +57 -52
  76. package/src/dev/use-esbuild.ts +59 -52
  77. package/src/dev/validate-dev-props.ts +9 -0
  78. package/src/dev-registry.ts +2 -1
  79. package/src/dev.tsx +38 -18
  80. package/src/docs/helpers.ts +50 -0
  81. package/src/docs/index.ts +25 -68
  82. package/src/entry.ts +19 -9
  83. package/src/environment-variables/factory.ts +2 -1
  84. package/src/generate/index.ts +2 -2
  85. package/src/index.ts +87 -24
  86. package/src/init.ts +144 -134
  87. package/src/inspect.ts +16 -1
  88. package/src/kv/helpers.ts +7 -4
  89. package/src/logger.ts +23 -4
  90. package/src/metrics/send-event.ts +2 -1
  91. package/src/miniflare-cli/assets.ts +8 -7
  92. package/src/miniflare-cli/index.ts +3 -3
  93. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  94. package/src/module-collection.ts +92 -26
  95. package/src/pages/build.ts +290 -100
  96. package/src/pages/buildFunctions.ts +20 -10
  97. package/src/pages/deployments.tsx +3 -5
  98. package/src/pages/dev.ts +44 -26
  99. package/src/pages/errors.ts +1 -0
  100. package/src/pages/functions/buildPlugin.ts +57 -34
  101. package/src/pages/functions/buildWorker.ts +91 -31
  102. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  103. package/src/pages/projects.tsx +2 -5
  104. package/src/pages/publish.tsx +1 -10
  105. package/src/pages/upload.tsx +29 -9
  106. package/src/paths.ts +1 -1
  107. package/src/publish/index.ts +1 -1
  108. package/src/publish/publish.ts +29 -34
  109. package/src/queues/cli/commands/consumer/add.ts +6 -0
  110. package/src/queues/client.ts +1 -0
  111. package/src/r2/helpers.ts +1 -0
  112. package/src/secret/index.ts +2 -1
  113. package/src/sites.ts +164 -52
  114. package/src/traverse-module-graph.ts +53 -0
  115. package/src/type-generation.ts +1 -1
  116. package/src/user/user.ts +2 -1
  117. package/src/utils/render.ts +93 -0
  118. package/src/worker.ts +18 -1
  119. package/templates/d1-beta-facade.js +5 -2
  120. package/templates/gitignore +1 -0
  121. package/templates/middleware/middleware-miniflare3-json-error.ts +17 -5
  122. package/templates/pages-template-plugin.ts +7 -3
  123. package/templates/tsconfig.init.json +1 -2
  124. package/templates/tsconfig.tsbuildinfo +1 -1
  125. package/wrangler-dist/cli.d.ts +552 -16
  126. package/wrangler-dist/cli.js +32141 -24052
  127. 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
  {
@@ -60,7 +60,7 @@ describe("User", () => {
60
60
  expect(counter).toBe(1);
61
61
  expect(std.out).toMatchInlineSnapshot(`
62
62
  "Attempting to login via OAuth...
63
- Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
63
+ Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20constellation%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
64
64
  Successfully logged in."
65
65
  `);
66
66
  expect(readAuthConfigFile()).toEqual<UserAuthConfig>({
@@ -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
@@ -3,6 +3,7 @@ import { startApiDev, startDev } from "../dev";
3
3
  import { logger } from "../logger";
4
4
 
5
5
  import type { Environment } from "../config";
6
+ import type { Rule } from "../config/environment";
6
7
  import type { EnablePagesAssetsServiceBindingOptions } from "../miniflare-cli/types";
7
8
  import type { RequestInit, Response, RequestInfo } from "undici";
8
9
 
@@ -18,7 +19,7 @@ export interface UnstableDevOptions {
18
19
  site?: string; // Root folder of static assets for Workers Sites
19
20
  siteInclude?: string[]; // Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded.
20
21
  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
22
+ nodeCompat?: boolean; // Enable Node.js compatibility
22
23
  compatibilityDate?: string; // Date to use for compatibility checks
23
24
  compatibilityFlags?: string[]; // Flags to use for compatibility checks
24
25
  persist?: boolean; // Enable persistence for local mode, using default path: .wrangler/state
@@ -42,8 +43,10 @@ export interface UnstableDevOptions {
42
43
  bucket_name: string;
43
44
  preview_bucket_name?: string;
44
45
  }[];
46
+ processEntrypoint?: boolean;
47
+ moduleRoot?: string;
48
+ rules?: Rule[];
45
49
  logLevel?: "none" | "info" | "error" | "log" | "warn" | "debug"; // Specify logging level [choices: "debug", "info", "log", "warn", "error", "none"] [default: "log"]
46
- logPrefix?: string;
47
50
  inspect?: boolean;
48
51
  local?: boolean;
49
52
  accountId?: string;
@@ -144,7 +147,6 @@ export async function unstable_dev(
144
147
  enablePagesAssetsServiceBinding,
145
148
  liveReload,
146
149
  showInteractiveDevSession,
147
- forceLocal,
148
150
  onReady: (address, port) => {
149
151
  readyPort = port;
150
152
  readyAddress = address;
@@ -152,6 +154,7 @@ export async function unstable_dev(
152
154
  },
153
155
  config: options?.config,
154
156
  env: options?.env,
157
+ processEntrypoint: !!options?.processEntrypoint,
155
158
  bundle: options?.bundle,
156
159
  compatibilityDate: options?.compatibilityDate,
157
160
  compatibilityFlags: options?.compatibilityFlags,
@@ -163,7 +166,7 @@ export async function unstable_dev(
163
166
  site: options?.site, // Root folder of static assets for Workers Sites
164
167
  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
168
  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
169
+ nodeCompat: options?.nodeCompat, // Enable Node.js compatibility
167
170
  persist: options?.persist, // Enable persistence for local mode, using default path: .wrangler/state
168
171
  persistTo: options?.persistTo, // Specify directory to use for local persistence (implies --persist)
169
172
  experimentalJsonConfig: undefined,
@@ -233,6 +236,7 @@ export async function unstable_dev(
233
236
  experimentalLocal: experimentalLocal ?? false,
234
237
  experimentalLocalRemoteKv: experimentalLocalRemoteKv ?? false,
235
238
  enablePagesAssetsServiceBinding,
239
+ forceLocal,
236
240
  liveReload,
237
241
  onReady: (address, port) => {
238
242
  readyPort = port;
@@ -252,7 +256,7 @@ export async function unstable_dev(
252
256
  site: options?.site, // Root folder of static assets for Workers Sites
253
257
  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
258
  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
259
+ nodeCompat: options?.nodeCompat, // Enable Node.js compatibility
256
260
  persist: options?.persist, // Enable persistence for local mode, using default path: .wrangler/state
257
261
  persistTo: options?.persistTo, // Specify directory to use for local persistence (implies --persist)
258
262
  experimentalJsonConfig: undefined,
@@ -302,27 +306,16 @@ export async function unstable_dev(
302
306
  export function parseRequestInput(
303
307
  readyAddress: string,
304
308
  readyPort: number,
305
- input?: RequestInfo,
309
+ input: RequestInfo = "/",
306
310
  init?: RequestInit,
307
311
  protocol: "http" | "https" = "http"
308
312
  ): [RequestInfo, RequestInit | undefined] {
309
313
  if (input instanceof Request) {
310
314
  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
315
  }
326
-
327
- return [input, init];
316
+ const url = new URL(`${input}`, `${protocol}://${readyAddress}:${readyPort}`);
317
+ url.protocol = protocol;
318
+ url.hostname = readyAddress;
319
+ url.port = readyPort.toString();
320
+ return [url, init];
328
321
  }
@@ -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
- import { existsSync, readFileSync } from "node:fs";
1
+ import { existsSync, lstatSync, 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";
@@ -14,6 +14,7 @@ import {
14
14
  import {
15
15
  buildRawWorker,
16
16
  checkRawWorker,
17
+ traverseAndBuildWorkerJSDirectory,
17
18
  } from "../../pages/functions/buildWorker";
18
19
  import { validateRoutes } from "../../pages/functions/routes-validation";
19
20
  import { upload } from "../../pages/upload";
@@ -65,18 +66,10 @@ interface PagesPublishOptions {
65
66
 
66
67
  /**
67
68
  * Whether to run bundling on `_worker.js` before deploying.
68
- * Default: false
69
+ * Default: true
69
70
  */
70
71
  bundle?: boolean;
71
72
 
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
73
  // TODO: Allow passing in the API key and plumb it through
81
74
  // to the API calls so that the publish function does not
82
75
  // rely on the `CLOUDFLARE_API_KEY` environment variable
@@ -98,15 +91,17 @@ export async function publish({
98
91
  commitDirty,
99
92
  functionsDirectory: customFunctionsDirectory,
100
93
  bundle,
101
- experimentalWorkerBundle,
102
94
  }: PagesPublishOptions) {
103
95
  let _headers: string | undefined,
104
96
  _redirects: string | undefined,
105
97
  _routesGenerated: string | undefined,
106
98
  _routesCustom: string | undefined,
99
+ _workerJSIsDirectory = false,
107
100
  _workerJS: string | undefined;
108
101
 
109
- const workerScriptPath = resolvePath(directory, "_worker.js");
102
+ bundle = bundle ?? true;
103
+
104
+ const _workerPath = resolvePath(directory, "_worker.js");
110
105
 
111
106
  try {
112
107
  _headers = readFileSync(join(directory, "_headers"), "utf-8");
@@ -125,7 +120,10 @@ export async function publish({
125
120
  } catch {}
126
121
 
127
122
  try {
128
- _workerJS = readFileSync(workerScriptPath, "utf-8");
123
+ _workerJSIsDirectory = lstatSync(_workerPath).isDirectory();
124
+ if (!_workerJSIsDirectory) {
125
+ _workerJS = readFileSync(_workerPath, "utf-8");
126
+ }
129
127
  } catch {}
130
128
 
131
129
  // Grab the bindings from the API, we need these for shims and other such hacky inserts
@@ -137,6 +135,11 @@ export async function publish({
137
135
  isProduction = project.production_branch === branch;
138
136
  }
139
137
 
138
+ const deploymentConfig =
139
+ project.deployment_configs[isProduction ? "production" : "preview"];
140
+ const nodejsCompat =
141
+ deploymentConfig.compatibility_flags?.includes("nodejs_compat");
142
+
140
143
  /**
141
144
  * Evaluate if this is an Advanced Mode or Pages Functions project. If Advanced Mode, we'll
142
145
  * go ahead and upload `_worker.js` as is, but if Pages Functions, we need to attempt to build
@@ -160,7 +163,6 @@ export async function publish({
160
163
  );
161
164
 
162
165
  if (!_workerJS && existsSync(functionsDirectory)) {
163
- const outfile = join(tmpdir(), `./functionsWorker-${Math.random()}.js`);
164
166
  const outputConfigPath = join(
165
167
  tmpdir(),
166
168
  `functions-filepath-routing-config-${Math.random()}.json`
@@ -168,18 +170,20 @@ export async function publish({
168
170
 
169
171
  try {
170
172
  workerBundle = await buildFunctions({
171
- outfile,
172
173
  outputConfigPath,
173
174
  functionsDirectory,
174
175
  onEnd: () => {},
175
- buildOutputDirectory: dirname(outfile),
176
+ buildOutputDirectory: directory,
176
177
  routesOutputPath,
177
178
  local: false,
178
179
  d1Databases,
179
- experimentalWorkerBundle,
180
+ nodejsCompat,
180
181
  });
181
182
 
182
- builtFunctions = readFileSync(outfile, "utf-8");
183
+ builtFunctions = readFileSync(
184
+ workerBundle.resolvedEntryPointPath,
185
+ "utf-8"
186
+ );
183
187
  filepathRoutingConfig = readFileSync(outputConfigPath, "utf-8");
184
188
  } catch (e) {
185
189
  if (e instanceof FunctionsNoRoutesError) {
@@ -243,48 +247,53 @@ export async function publish({
243
247
  * Advanced Mode
244
248
  * https://developers.cloudflare.com/pages/platform/functions/#advanced-mode
245
249
  *
246
- * When using a _worker.js file, the entire /functions directory is ignored
250
+ * When using a _worker.js file or _worker.js/ directory, the entire /functions directory is ignored
247
251
  * – this includes its routing and middleware characteristics.
248
252
  */
249
- if (_workerJS) {
250
- let workerFileContents = _workerJS;
251
- const enableBundling = bundle || experimentalWorkerBundle;
252
-
253
- if (enableBundling) {
253
+ if (_workerJSIsDirectory) {
254
+ workerBundle = await traverseAndBuildWorkerJSDirectory({
255
+ workerJSDirectory: _workerPath,
256
+ buildOutputDirectory: directory,
257
+ d1Databases,
258
+ nodejsCompat,
259
+ });
260
+ } else if (_workerJS) {
261
+ if (bundle) {
254
262
  const outfile = join(tmpdir(), `./bundledWorker-${Math.random()}.mjs`);
255
263
  workerBundle = await buildRawWorker({
256
- workerScriptPath,
264
+ workerScriptPath: _workerPath,
257
265
  outfile,
258
- directory: directory ?? ".",
266
+ directory,
259
267
  local: false,
260
268
  sourcemap: true,
261
269
  watch: false,
262
270
  onEnd: () => {},
263
271
  betaD1Shims: d1Databases,
264
- experimentalWorkerBundle,
272
+ nodejsCompat,
265
273
  });
266
- workerFileContents = readFileSync(outfile, "utf8");
267
274
  } else {
268
- await checkRawWorker(workerScriptPath, () => {});
275
+ await checkRawWorker(_workerPath, () => {});
276
+ // TODO: Let users configure this in the future.
277
+ workerBundle = {
278
+ modules: [],
279
+ dependencies: {},
280
+ stop: undefined,
281
+ resolvedEntryPointPath: _workerPath,
282
+ bundleType: "esm",
283
+ };
269
284
  }
285
+ }
270
286
 
271
- if (experimentalWorkerBundle) {
272
- const workerBundleContents = await createUploadWorkerBundleContents(
273
- workerBundle as BundleResult
274
- );
287
+ if (_workerJS || _workerJSIsDirectory) {
288
+ const workerBundleContents = await createUploadWorkerBundleContents(
289
+ workerBundle as BundleResult
290
+ );
275
291
 
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
- }
292
+ formData.append(
293
+ "_worker.bundle",
294
+ new File([workerBundleContents], "_worker.bundle")
295
+ );
296
+ logger.log(`✨ Uploading Worker bundle`);
288
297
 
289
298
  if (_routesCustom) {
290
299
  // user provided a custom _routes.json file
@@ -309,22 +318,16 @@ export async function publish({
309
318
  * Pages Functions
310
319
  * https://developers.cloudflare.com/pages/platform/functions/
311
320
  */
312
- if (builtFunctions && !_workerJS) {
313
- if (experimentalWorkerBundle) {
314
- const workerBundleContents = await createUploadWorkerBundleContents(
315
- workerBundle as BundleResult
316
- );
321
+ if (builtFunctions && !_workerJS && !_workerJSIsDirectory) {
322
+ const workerBundleContents = await createUploadWorkerBundleContents(
323
+ workerBundle as BundleResult
324
+ );
317
325
 
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
- }
326
+ formData.append(
327
+ "_worker.bundle",
328
+ new File([workerBundleContents], "_worker.bundle")
329
+ );
330
+ logger.log(`✨ Uploading Functions bundle`);
328
331
 
329
332
  if (_routesCustom) {
330
333
  // user provided a custom _routes.json file
package/src/bundle.ts CHANGED
@@ -7,12 +7,19 @@ import NodeModulesPolyfills from "@esbuild-plugins/node-modules-polyfill";
7
7
  import * as esbuild from "esbuild";
8
8
  import tmp from "tmp-promise";
9
9
  import createModuleCollector from "./module-collection";
10
- import { getBasePath, toUrlPath } from "./paths";
10
+ import { getBasePath } from "./paths";
11
11
  import type { Config } from "./config";
12
12
  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
  */
@@ -92,17 +117,21 @@ export async function bundleWorker(
92
117
  entry: Entry,
93
118
  destination: string,
94
119
  options: {
120
+ // When `bundle` is set to false, we apply shims to the Worker, but won't pull in any imports
121
+ bundle?: boolean;
95
122
  serveAssetsFromWorker: boolean;
96
123
  assets?: StaticAssetsConfig;
97
124
  betaD1Shims?: string[];
98
125
  doBindings: DurableObjectBindings;
99
126
  jsxFactory?: string;
100
127
  jsxFragment?: string;
128
+ entryName?: string;
101
129
  rules: Config["rules"];
102
130
  watch?: esbuild.WatchMode | boolean;
103
131
  tsconfig?: string;
104
132
  minify?: boolean;
105
- nodeCompat?: boolean;
133
+ legacyNodeCompat?: boolean;
134
+ nodejsCompat?: boolean;
106
135
  define: Config["define"];
107
136
  checkFetch: boolean;
108
137
  services?: Config["services"];
@@ -122,16 +151,19 @@ export async function bundleWorker(
122
151
  }
123
152
  ): Promise<BundleResult> {
124
153
  const {
154
+ bundle = true,
125
155
  serveAssetsFromWorker,
126
156
  betaD1Shims,
127
157
  doBindings,
128
158
  jsxFactory,
129
159
  jsxFragment,
160
+ entryName,
130
161
  rules,
131
162
  watch,
132
163
  tsconfig,
133
164
  minify,
134
- nodeCompat,
165
+ legacyNodeCompat,
166
+ nodejsCompat,
135
167
  checkFetch,
136
168
  local,
137
169
  assets,
@@ -277,7 +309,7 @@ export async function bundleWorker(
277
309
  currentEntry,
278
310
  tmpDir.path,
279
311
  betaD1Shims,
280
- local,
312
+ local && !experimentalLocal,
281
313
  doBindings
282
314
  );
283
315
  }),
@@ -321,19 +353,21 @@ export async function bundleWorker(
321
353
 
322
354
  const buildOptions: esbuild.BuildOptions & { metafile: true } = {
323
355
  entryPoints: [inputEntry.file],
324
- bundle: true,
356
+ bundle,
325
357
  absWorkingDir: entry.directory,
326
358
  outdir: destination,
359
+ entryNames: entryName || path.parse(entry.file).name,
327
360
  ...(isOutfile
328
361
  ? {
329
362
  outdir: undefined,
330
363
  outfile: destination,
364
+ entryNames: undefined,
331
365
  }
332
366
  : {}),
333
367
  inject,
334
- external: ["__STATIC_CONTENT_MANIFEST"],
368
+ external: bundle ? ["__STATIC_CONTENT_MANIFEST"] : undefined,
335
369
  format: entry.format === "modules" ? "esm" : "iife",
336
- target: "es2020",
370
+ target: COMMON_ESBUILD_OPTIONS.target,
337
371
  sourcemap: sourcemap ?? true, // this needs to use ?? to accept false
338
372
  // Include a reference to the output folder in the sourcemap.
339
373
  // This is omitted by default, but we need it to properly resolve source paths in error output.
@@ -346,22 +380,22 @@ export async function bundleWorker(
346
380
  // use process.env["NODE_ENV" + ""] so that esbuild doesn't replace it
347
381
  // when we do a build of wrangler. (re: https://github.com/cloudflare/workers-sdk/issues/1477)
348
382
  "process.env.NODE_ENV": `"${process.env["NODE_ENV" + ""]}"`,
349
- ...(nodeCompat ? { global: "globalThis" } : {}),
383
+ ...(legacyNodeCompat ? { global: "globalThis" } : {}),
350
384
  ...(checkFetch ? { fetch: "checkedFetch" } : {}),
351
385
  ...options.define,
352
386
  },
353
387
  }),
354
388
  loader: {
355
- ".js": "jsx",
356
- ".mjs": "jsx",
357
- ".cjs": "jsx",
389
+ ...COMMON_ESBUILD_OPTIONS.loader,
358
390
  ...(loader || {}),
359
391
  },
360
392
  plugins: [
361
393
  moduleCollector.plugin,
362
- ...(nodeCompat
394
+ ...(legacyNodeCompat
363
395
  ? [NodeGlobalsPolyfills({ buffer: true }), NodeModulesPolyfills()]
364
396
  : []),
397
+ ...(nodejsCompat ? [nodejsCompatPlugin] : []),
398
+ ...[cloudflareJsPlugin],
365
399
  ...(plugins || []),
366
400
  ],
367
401
  ...(jsxFactory && { jsxFactory }),
@@ -377,7 +411,8 @@ export async function bundleWorker(
377
411
  try {
378
412
  result = await esbuild.build(buildOptions);
379
413
  } catch (e) {
380
- if (!nodeCompat && isBuildFailure(e)) rewriteNodeCompatBuildFailure(e);
414
+ if (!legacyNodeCompat && isBuildFailure(e))
415
+ rewriteNodeCompatBuildFailure(e);
381
416
  throw e;
382
417
  }
383
418
 
@@ -567,7 +602,7 @@ async function applyMiddlewareLoaderFacade(
567
602
  ...Object.fromEntries(
568
603
  middleware.map((val, index) => [
569
604
  middlewareIdentifiers[index],
570
- toUrlPath(path.resolve(getBasePath(), val.path)),
605
+ path.resolve(getBasePath(), val.path),
571
606
  ])
572
607
  ),
573
608
  }),
@@ -802,7 +837,7 @@ async function applyD1BetaFacade(
802
837
  entry: Entry,
803
838
  tmpDirPath: string,
804
839
  betaD1Shims: string[],
805
- local: boolean,
840
+ miniflare2: boolean,
806
841
  doBindings: DurableObjectBindings
807
842
  ): Promise<Entry> {
808
843
  let entrypointPath = path.resolve(
@@ -853,7 +888,7 @@ async function applyD1BetaFacade(
853
888
  ],
854
889
  define: {
855
890
  __D1_IMPORTS__: JSON.stringify(betaD1Shims),
856
- __LOCAL_MODE__: JSON.stringify(local),
891
+ __LOCAL_MODE__: JSON.stringify(miniflare2),
857
892
  },
858
893
  outfile: targetPath,
859
894
  });
@@ -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: {