wrangler 2.9.0 → 2.10.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 (82) hide show
  1. package/README.md +3 -3
  2. package/miniflare-dist/index.mjs +2 -15
  3. package/package.json +9 -9
  4. package/src/__tests__/configuration.test.ts +70 -0
  5. package/src/__tests__/d1/d1.test.ts +3 -6
  6. package/src/__tests__/d1/execute.test.ts +64 -0
  7. package/src/__tests__/d1/migrate.test.ts +107 -0
  8. package/src/__tests__/deployments.test.ts +40 -16
  9. package/src/__tests__/dev.test.tsx +3 -3
  10. package/src/__tests__/generate.test.ts +1 -1
  11. package/src/__tests__/helpers/end-event-loop.ts +6 -0
  12. package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
  13. package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
  14. package/src/__tests__/helpers/msw/handlers/deployments.ts +40 -16
  15. package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
  16. package/src/__tests__/index.test.ts +3 -4
  17. package/src/__tests__/init.test.ts +1 -1
  18. package/src/__tests__/kv.test.ts +8 -8
  19. package/src/__tests__/middleware.test.ts +65 -0
  20. package/src/__tests__/mtls-certificates.test.ts +585 -0
  21. package/src/__tests__/pages/deployment-list.test.ts +78 -0
  22. package/src/__tests__/pages/functions-build.test.ts +402 -0
  23. package/src/__tests__/pages/pages.test.ts +81 -0
  24. package/src/__tests__/pages/project-create.test.ts +63 -0
  25. package/src/__tests__/pages/project-list.test.ts +108 -0
  26. package/src/__tests__/pages/project-upload.test.ts +481 -0
  27. package/src/__tests__/pages/publish.test.ts +2745 -0
  28. package/src/__tests__/publish.test.ts +58 -27
  29. package/src/__tests__/queues.test.ts +2 -2
  30. package/src/__tests__/secret.test.ts +4 -4
  31. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  32. package/src/__tests__/user.test.ts +1 -1
  33. package/src/__tests__/whoami.test.tsx +1 -1
  34. package/src/__tests__/worker-namespace.test.ts +1 -1
  35. package/src/api/index.ts +8 -0
  36. package/src/api/mtls-certificate.ts +148 -0
  37. package/src/api/pages/create-worker-bundle-contents.ts +75 -0
  38. package/src/api/pages/publish.tsx +52 -8
  39. package/src/bundle.ts +6 -5
  40. package/src/config/config.ts +7 -7
  41. package/src/config/environment.ts +9 -2
  42. package/src/config/index.ts +13 -0
  43. package/src/config/validation.ts +50 -3
  44. package/src/create-worker-upload-form.ts +9 -0
  45. package/src/d1/execute.tsx +124 -91
  46. package/src/d1/migrations/apply.tsx +36 -29
  47. package/src/d1/migrations/create.tsx +10 -8
  48. package/src/d1/migrations/helpers.ts +63 -38
  49. package/src/d1/migrations/list.tsx +31 -20
  50. package/src/d1/migrations/options.ts +6 -1
  51. package/src/d1/types.ts +1 -0
  52. package/src/d1/utils.ts +2 -1
  53. package/src/deployments.ts +62 -39
  54. package/src/dev/dev.tsx +1 -15
  55. package/src/dev/remote.tsx +2 -2
  56. package/src/dev.tsx +9 -6
  57. package/src/generate/index.ts +1 -1
  58. package/src/index.ts +15 -5
  59. package/src/miniflare-cli/assets.ts +1 -1
  60. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  61. package/src/mtls-certificate/cli.ts +155 -0
  62. package/src/pages/build.ts +103 -23
  63. package/src/pages/buildFunctions.ts +32 -31
  64. package/src/pages/dev.ts +4 -2
  65. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  66. package/src/pages/publish.tsx +12 -1
  67. package/src/pages/utils.ts +1 -1
  68. package/src/publish/publish.ts +3 -2
  69. package/src/secret/index.ts +1 -0
  70. package/src/sites.ts +1 -1
  71. package/src/tail/filters.ts +1 -1
  72. package/src/user/user.ts +4 -3
  73. package/src/worker.ts +6 -0
  74. package/templates/format-dev-errors.ts +1 -0
  75. package/templates/new-worker.ts +3 -0
  76. package/templates/serve-static-assets.ts +1 -0
  77. package/templates/service-bindings-module-facade.js +1 -0
  78. package/templates/tsconfig.init.json +1 -1
  79. package/templates/tsconfig.tsbuildinfo +1 -1
  80. package/wrangler-dist/cli.d.ts +82 -2
  81. package/wrangler-dist/cli.js +1726 -1616
  82. package/src/__tests__/pages.test.ts +0 -2905
@@ -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%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%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>({
@@ -160,7 +160,7 @@ describe("getUserInfo()", () => {
160
160
  await getUserInfo();
161
161
 
162
162
  expect(std.warn).toMatchInlineSnapshot(`
163
- "▲ [WARNING] It looks like you have used Wrangler 1's \`config\` command to login with an API token.
163
+ "▲ [WARNING] It looks like you have used Wrangler v1's \`config\` command to login with an API token.
164
164
 
165
165
  This is no longer supported in the current version of Wrangler.
166
166
  If you wish to authenticate via an API token then please set the \`CLOUDFLARE_API_TOKEN\`
@@ -17,7 +17,7 @@ describe("dispatch-namespace", () => {
17
17
  mockAccountId();
18
18
  mockApiToken();
19
19
 
20
- it("should should display a list of available subcommands, for dispatch-namespace with no subcommand", async () => {
20
+ it("should display a list of available subcommands, for dispatch-namespace with no subcommand", async () => {
21
21
  await runWrangler("dispatch-namespace");
22
22
 
23
23
  // wait a tick for the help menu to be printed
package/src/api/index.ts CHANGED
@@ -1,3 +1,11 @@
1
1
  export { unstable_dev } from "./dev";
2
2
  export type { UnstableDevWorker, UnstableDevOptions } from "./dev";
3
3
  export { unstable_pages } from "./pages";
4
+ export {
5
+ uploadMTlsCertificate,
6
+ uploadMTlsCertificateFromFs,
7
+ listMTlsCertificates,
8
+ getMTlsCertificate,
9
+ getMTlsCertificateByName,
10
+ deleteMTlsCertificate,
11
+ } from "./mtls-certificate";
@@ -0,0 +1,148 @@
1
+ import { fetchResult } from "../cfetch";
2
+ import { readFileSync } from "../parse";
3
+
4
+ /**
5
+ * the representation of an mTLS certificate in the account certificate store
6
+ */
7
+ export interface MTlsCertificateResponse {
8
+ id: string;
9
+ name?: string;
10
+ ca: boolean;
11
+ certificates: string;
12
+ expires_on: string;
13
+ issuer: string;
14
+ serial_number: string;
15
+ signature: string;
16
+ uploaded_on: string;
17
+ }
18
+
19
+ /**
20
+ * details for uploading an mTLS certificate from disk
21
+ */
22
+ export interface MTlsCertificateUploadDetails {
23
+ certificateChainFilename: string;
24
+ privateKeyFilename: string;
25
+ name?: string;
26
+ }
27
+
28
+ /**
29
+ * details for uploading an mTLS certificate via the ssl api
30
+ */
31
+ export interface MTlsCertificateBody {
32
+ certificateChain: string;
33
+ privateKey: string;
34
+ name?: string;
35
+ }
36
+
37
+ /**
38
+ * supported filters for listing mTLS certificates via the ssl api
39
+ */
40
+ export interface MTlsCertificateListFilter {
41
+ name?: string;
42
+ }
43
+
44
+ /**
45
+ * indicates that looking up a certificate by name failed due to zero matching results
46
+ */
47
+ export class ErrorMTlsCertificateNameNotFound extends Error {}
48
+
49
+ /**
50
+ * indicates that looking up a certificate by name failed due to more than one matching results
51
+ */
52
+ export class ErrorMTlsCertificateManyNamesMatch extends Error {}
53
+
54
+ /**
55
+ * reads an mTLS certificate and private key pair from disk and uploads it to the account mTLS certificate store
56
+ */
57
+ export async function uploadMTlsCertificateFromFs(
58
+ accountId: string,
59
+ details: MTlsCertificateUploadDetails
60
+ ): Promise<MTlsCertificateResponse> {
61
+ return await uploadMTlsCertificate(accountId, {
62
+ certificateChain: readFileSync(details.certificateChainFilename),
63
+ privateKey: readFileSync(details.privateKeyFilename),
64
+ name: details.name,
65
+ });
66
+ }
67
+
68
+ /**
69
+ * uploads an mTLS certificate and private key pair to the account mTLS certificate store
70
+ */
71
+ export async function uploadMTlsCertificate(
72
+ accountId: string,
73
+ body: MTlsCertificateBody
74
+ ): Promise<MTlsCertificateResponse> {
75
+ return await fetchResult(`/accounts/${accountId}/mtls_certificates`, {
76
+ method: "POST",
77
+ body: JSON.stringify({
78
+ name: body.name,
79
+ certificates: body.certificateChain,
80
+ private_key: body.privateKey,
81
+ ca: false,
82
+ }),
83
+ });
84
+ }
85
+
86
+ /**
87
+ * fetches an mTLS certificate from the account mTLS certificate store by ID
88
+ */
89
+ export async function getMTlsCertificate(
90
+ accountId: string,
91
+ id: string
92
+ ): Promise<MTlsCertificateResponse> {
93
+ return await fetchResult(
94
+ `/accounts/${accountId}/mtls_certificates/${id}`,
95
+ {}
96
+ );
97
+ }
98
+
99
+ /**
100
+ * lists mTLS certificates for an account. filtering by name is supported
101
+ */
102
+ export async function listMTlsCertificates(
103
+ accountId: string,
104
+ filter: MTlsCertificateListFilter
105
+ ): Promise<MTlsCertificateResponse[]> {
106
+ const params = new URLSearchParams();
107
+ params.append("ca", "false");
108
+ if (filter.name) {
109
+ params.append("name", filter.name);
110
+ }
111
+ return await fetchResult(
112
+ `/accounts/${accountId}/mtls_certificates`,
113
+ {},
114
+ params
115
+ );
116
+ }
117
+
118
+ /**
119
+ * fetches an mTLS certificate from the account mTLS certificate store by name. will throw an error if no certificates are found, or multiple are found with that name
120
+ */
121
+ export async function getMTlsCertificateByName(
122
+ accountId: string,
123
+ name: string
124
+ ): Promise<MTlsCertificateResponse> {
125
+ const certificates = await listMTlsCertificates(accountId, { name });
126
+ if (certificates.length === 0) {
127
+ throw new ErrorMTlsCertificateNameNotFound(
128
+ `certificate not found with name "${name}"`
129
+ );
130
+ }
131
+ if (certificates.length > 1) {
132
+ throw new ErrorMTlsCertificateManyNamesMatch(
133
+ `multiple certificates found with name "${name}"`
134
+ );
135
+ }
136
+ const certificate = certificates[0];
137
+ return certificate;
138
+ }
139
+
140
+ export async function deleteMTlsCertificate(
141
+ accountId: string,
142
+ certificateId: string
143
+ ) {
144
+ return await fetchResult(
145
+ `/accounts/${accountId}/mtls_certificates/${certificateId}`,
146
+ { method: "DELETE" }
147
+ );
148
+ }
@@ -0,0 +1,75 @@
1
+ import { readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { Response } from "undici";
4
+ import { createWorkerUploadForm } from "../../create-worker-upload-form";
5
+ import type { BundleResult } from "../../bundle";
6
+ import type { CfWorkerInit } from "../../worker";
7
+ import type { Blob } from "node:buffer";
8
+ import type { FormData } from "undici";
9
+
10
+ /**
11
+ * Takes a Worker bundle - `BundleResult` - and generates the _worker.bundle
12
+ * contents
13
+ */
14
+ export async function createUploadWorkerBundleContents(
15
+ workerBundle: BundleResult
16
+ ): Promise<Blob> {
17
+ const workerBundleFormData = createWorkerBundleFormData(workerBundle);
18
+ const metadata = JSON.parse(workerBundleFormData.get("metadata") as string);
19
+
20
+ /**
21
+ * Pages doesn't need the metadata bindings returned by
22
+ * `createWorkerBundleFormData`. Let's strip them out and return only
23
+ * the contents we need
24
+ */
25
+ workerBundleFormData.set(
26
+ "metadata",
27
+ JSON.stringify({ main_module: metadata.main_module })
28
+ );
29
+
30
+ return await new Response(workerBundleFormData).blob();
31
+ }
32
+
33
+ /**
34
+ * Creates a `FormData` upload from a `BundleResult`
35
+ */
36
+ function createWorkerBundleFormData(workerBundle: BundleResult): FormData {
37
+ const mainModule = {
38
+ name: path.basename(workerBundle.resolvedEntryPointPath),
39
+ content: readFileSync(workerBundle.resolvedEntryPointPath, {
40
+ encoding: "utf-8",
41
+ }),
42
+ type: workerBundle.bundleType || "esm",
43
+ };
44
+
45
+ const worker: CfWorkerInit = {
46
+ name: mainModule.name,
47
+ main: mainModule,
48
+ modules: workerBundle.modules,
49
+ bindings: {
50
+ vars: undefined,
51
+ kv_namespaces: undefined,
52
+ wasm_modules: undefined,
53
+ text_blobs: undefined,
54
+ data_blobs: undefined,
55
+ durable_objects: undefined,
56
+ queues: undefined,
57
+ r2_buckets: undefined,
58
+ d1_databases: undefined,
59
+ services: undefined,
60
+ analytics_engine_datasets: undefined,
61
+ dispatch_namespaces: undefined,
62
+ mtls_certificates: undefined,
63
+ logfwdr: undefined,
64
+ unsafe: undefined,
65
+ },
66
+ migrations: undefined,
67
+ compatibility_date: undefined,
68
+ compatibility_flags: undefined,
69
+ usage_model: undefined,
70
+ keepVars: undefined,
71
+ logpush: undefined,
72
+ };
73
+
74
+ return createWorkerUploadForm(worker);
75
+ }
@@ -17,6 +17,8 @@ import {
17
17
  } from "../../pages/functions/buildWorker";
18
18
  import { validateRoutes } from "../../pages/functions/routes-validation";
19
19
  import { upload } from "../../pages/upload";
20
+ import { createUploadWorkerBundleContents } from "./create-worker-bundle-contents";
21
+ import type { BundleResult } from "../../bundle";
20
22
  import type { Project, Deployment } from "@cloudflare/types";
21
23
 
22
24
  interface PagesPublishOptions {
@@ -67,6 +69,14 @@ interface PagesPublishOptions {
67
69
  */
68
70
  bundle?: boolean;
69
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
+
70
80
  // TODO: Allow passing in the API key and plumb it through
71
81
  // to the API calls so that the publish function does not
72
82
  // rely on the `CLOUDFLARE_API_KEY` environment variable
@@ -88,6 +98,7 @@ export async function publish({
88
98
  commitDirty,
89
99
  functionsDirectory: customFunctionsDirectory,
90
100
  bundle,
101
+ experimentalWorkerBundle,
91
102
  }: PagesPublishOptions) {
92
103
  let _headers: string | undefined,
93
104
  _redirects: string | undefined,
@@ -132,6 +143,8 @@ export async function publish({
132
143
  * Functions first and exit if it failed
133
144
  */
134
145
  let builtFunctions: string | undefined = undefined;
146
+ let workerBundle: BundleResult | undefined = undefined;
147
+
135
148
  const functionsDirectory =
136
149
  customFunctionsDirectory || join(cwd(), "functions");
137
150
  const routesOutputPath = !existsSync(join(directory, "_routes.json"))
@@ -154,7 +167,7 @@ export async function publish({
154
167
  );
155
168
 
156
169
  try {
157
- await buildFunctions({
170
+ workerBundle = await buildFunctions({
158
171
  outfile,
159
172
  outputConfigPath,
160
173
  functionsDirectory,
@@ -163,6 +176,7 @@ export async function publish({
163
176
  routesOutputPath,
164
177
  local: false,
165
178
  d1Databases,
179
+ experimentalWorkerBundle,
166
180
  });
167
181
 
168
182
  builtFunctions = readFileSync(outfile, "utf-8");
@@ -234,9 +248,11 @@ export async function publish({
234
248
  */
235
249
  if (_workerJS) {
236
250
  let workerFileContents = _workerJS;
237
- if (bundle) {
251
+ const enableBundling = bundle || experimentalWorkerBundle;
252
+
253
+ if (enableBundling) {
238
254
  const outfile = join(tmpdir(), `./bundledWorker-${Math.random()}.mjs`);
239
- await buildRawWorker({
255
+ workerBundle = await buildRawWorker({
240
256
  workerScriptPath,
241
257
  outfile,
242
258
  directory: directory ?? ".",
@@ -245,14 +261,30 @@ export async function publish({
245
261
  watch: false,
246
262
  onEnd: () => {},
247
263
  betaD1Shims: d1Databases,
264
+ experimentalWorkerBundle,
248
265
  });
249
266
  workerFileContents = readFileSync(outfile, "utf8");
250
267
  } else {
251
268
  await checkRawWorker(workerScriptPath, () => {});
252
269
  }
253
270
 
254
- formData.append("_worker.js", new File([workerFileContents], "_worker.js"));
255
- logger.log(`✨ Uploading _worker.js`);
271
+ if (experimentalWorkerBundle) {
272
+ const workerBundleContents = await createUploadWorkerBundleContents(
273
+ workerBundle as BundleResult
274
+ );
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
+ }
256
288
 
257
289
  if (_routesCustom) {
258
290
  // user provided a custom _routes.json file
@@ -278,9 +310,21 @@ export async function publish({
278
310
  * https://developers.cloudflare.com/pages/platform/functions/
279
311
  */
280
312
  if (builtFunctions && !_workerJS) {
281
- // if Functions were build successfully, proceed to uploading the build file
282
- formData.append("_worker.js", new File([builtFunctions], "_worker.js"));
283
- logger.log(`✨ Uploading Functions`);
313
+ if (experimentalWorkerBundle) {
314
+ const workerBundleContents = await createUploadWorkerBundleContents(
315
+ workerBundle as BundleResult
316
+ );
317
+
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
+ }
284
328
 
285
329
  if (_routesCustom) {
286
330
  // user provided a custom _routes.json file
package/src/bundle.ts CHANGED
@@ -116,7 +116,7 @@ export async function bundleWorker(
116
116
  loader?: Record<string, string>;
117
117
  sourcemap?: esbuild.CommonOptions["sourcemap"];
118
118
  plugins?: esbuild.Plugin[];
119
- // TODO: Rip these out https://github.com/cloudflare/wrangler2/issues/2153
119
+ // TODO: Rip these out https://github.com/cloudflare/workers-sdk/issues/2153
120
120
  disableModuleCollection?: boolean;
121
121
  isOutfile?: boolean;
122
122
  }
@@ -344,7 +344,7 @@ export async function bundleWorker(
344
344
  ...(process.env.NODE_ENV && {
345
345
  define: {
346
346
  // use process.env["NODE_ENV" + ""] so that esbuild doesn't replace it
347
- // when we do a build of wrangler. (re: https://github.com/cloudflare/wrangler2/issues/1477)
347
+ // when we do a build of wrangler. (re: https://github.com/cloudflare/workers-sdk/issues/1477)
348
348
  "process.env.NODE_ENV": `"${process.env["NODE_ENV" + ""]}"`,
349
349
  ...(nodeCompat ? { global: "globalThis" } : {}),
350
350
  ...(checkFetch ? { fetch: "checkedFetch" } : {}),
@@ -574,9 +574,10 @@ async function applyMiddlewareLoaderFacade(
574
574
  ],
575
575
  outfile: targetPathInsertion,
576
576
  });
577
-
578
- let targetPathLoader = path.join(tmpDirPath, path.basename(entry.file));
579
- if (path.extname(entry.file) === "") targetPathLoader += ".js";
577
+ const targetPathLoader = path.join(
578
+ tmpDirPath,
579
+ "middleware-loader.entry.js"
580
+ );
580
581
  const loaderPath = path.resolve(
581
582
  getBasePath(),
582
583
  "templates/middleware/loader-modules.ts"
@@ -18,7 +18,7 @@ import type { CamelCaseKey } from "yargs";
18
18
  *
19
19
  * Legend for the annotations:
20
20
  *
21
- * - `@breaking`: the deprecation/optionality is a breaking change from wrangler 1.
21
+ * - `@breaking`: the deprecation/optionality is a breaking change from Wrangler v1.
22
22
  * - `@todo`: there's more work to be done (with details attached).
23
23
  */
24
24
  export type Config = ConfigFields<DevConfig> & Environment;
@@ -32,7 +32,7 @@ export interface ConfigFields<Dev extends RawDevConfig> {
32
32
  configPath: string | undefined;
33
33
 
34
34
  /**
35
- * A boolean to enable "legacy" style wrangler environments (from wrangler 1).
35
+ * A boolean to enable "legacy" style wrangler environments (from Wrangler v1).
36
36
  * These have been superseded by Services, but there may be projects that won't
37
37
  * (or can't) use them. If you're using a legacy environment, you can set this
38
38
  * to `true` to enable it.
@@ -96,7 +96,7 @@ export interface ConfigFields<Dev extends RawDevConfig> {
96
96
  /**
97
97
  * The location of your Worker script.
98
98
  *
99
- * @deprecated DO NOT use this (it's a holdover from wrangler 1.x). Either use the top level `main` field, or pass the path to your entry file as a command line argument.
99
+ * @deprecated DO NOT use this (it's a holdover from Wrangler v1.x). Either use the top level `main` field, or pass the path to your entry file as a command line argument.
100
100
  * @breaking
101
101
  */
102
102
  "entry-point"?: string;
@@ -216,10 +216,10 @@ export interface DevConfig {
216
216
  * Protocol that wrangler dev forwards requests on
217
217
  *
218
218
  * Setting this to `http` is not currently implemented.
219
- * See https://github.com/cloudflare/wrangler2/issues/583
219
+ * See https://github.com/cloudflare/workers-sdk/issues/583
220
220
  *
221
221
  * @default `https`
222
- * @todo this needs to be implemented https://github.com/cloudflare/wrangler2/issues/583
222
+ * @todo this needs to be implemented https://github.com/cloudflare/workers-sdk/issues/583
223
223
  */
224
224
  upstream_protocol: "https" | "http";
225
225
 
@@ -233,7 +233,7 @@ export type RawDevConfig = Partial<DevConfig>;
233
233
 
234
234
  export interface DeprecatedConfigFields {
235
235
  /**
236
- * The project "type". A holdover from wrangler 1.x.
236
+ * The project "type". A holdover from Wrangler v1.x.
237
237
  * Valid values were "webpack", "javascript", and "rust".
238
238
  *
239
239
  * @deprecated DO NOT USE THIS. Most common features now work out of the box with wrangler, including modules, jsx, typescript, etc. If you need anything more, use a custom build.
@@ -243,7 +243,7 @@ export interface DeprecatedConfigFields {
243
243
 
244
244
  /**
245
245
  * Path to the webpack config to use when building your worker.
246
- * A holdover from wrangler 1.x, used with `type: "webpack"`.
246
+ * A holdover from Wrangler v1.x, used with `type: "webpack"`.
247
247
  *
248
248
  * @deprecated DO NOT USE THIS. Most common features now work out of the box with wrangler, including modules, jsx, typescript, etc. If you need anything more, use a custom build.
249
249
  * @breaking
@@ -78,7 +78,7 @@ interface EnvironmentInheritable {
78
78
  * Whether we use <name>.<subdomain>.workers.dev to
79
79
  * test and deploy your worker.
80
80
  *
81
- * @default `true` (This is a breaking change from wrangler 1)
81
+ * @default `true` (This is a breaking change from Wrangler v1)
82
82
  * @breaking
83
83
  * @inheritable
84
84
  */
@@ -480,6 +480,13 @@ interface EnvironmentNonInheritable {
480
480
  [key: string]: unknown;
481
481
  }[];
482
482
  };
483
+
484
+ mtls_certificates: {
485
+ /** The binding name used to refer to the certificate in the worker */
486
+ binding: string;
487
+ /** The uuid of the uploaded mTLS certificate */
488
+ certificate_id: string;
489
+ }[];
483
490
  }
484
491
 
485
492
  /**
@@ -497,7 +504,7 @@ interface EnvironmentDeprecated {
497
504
  /**
498
505
  * Legacy way of defining KVNamespaces that is no longer supported.
499
506
  *
500
- * @deprecated DO NOT USE. This was a legacy bug from wrangler 1, that we do not want to support.
507
+ * @deprecated DO NOT USE. This was a legacy bug from Wrangler v1, that we do not want to support.
501
508
  */
502
509
  "kv-namespaces"?: string;
503
510
 
@@ -108,6 +108,7 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
108
108
  vars,
109
109
  wasm_modules,
110
110
  dispatch_namespaces,
111
+ mtls_certificates,
111
112
  } = bindings;
112
113
 
113
114
  if (data_blobs !== undefined && Object.keys(data_blobs).length > 0) {
@@ -306,6 +307,18 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
306
307
  });
307
308
  }
308
309
 
310
+ if (mtls_certificates !== undefined && mtls_certificates.length > 0) {
311
+ output.push({
312
+ type: "mTLS Certificates",
313
+ entries: mtls_certificates.map(({ binding, certificate_id }) => {
314
+ return {
315
+ key: binding,
316
+ value: certificate_id,
317
+ };
318
+ }),
319
+ });
320
+ }
321
+
309
322
  if (output.length === 0) {
310
323
  return;
311
324
  }
@@ -741,7 +741,7 @@ function isValidRouteValue(item: unknown): boolean {
741
741
 
742
742
  /**
743
743
  * If account_id has been passed as an empty string, normalise it to undefined.
744
- * This is to workaround older wrangler1-era templates that have account_id = '',
744
+ * This is to workaround older Wrangler v1-era templates that have account_id = '',
745
745
  * which isn't a valid value anyway
746
746
  */
747
747
  function mutateEmptyStringAccountIDValue(
@@ -760,7 +760,7 @@ function mutateEmptyStringAccountIDValue(
760
760
 
761
761
  /**
762
762
  * Normalize empty string to `undefined` by mutating rawEnv.route value.
763
- * As part of backward compatibility with Wrangler1 converting empty string to `undefined`
763
+ * As part of backward compatibility with Wrangler v1 converting empty string to `undefined`
764
764
  */
765
765
  function mutateEmptyStringRouteValue(
766
766
  diagnostics: Diagnostics,
@@ -1134,6 +1134,16 @@ function normalizeAndValidateEnvironment(
1134
1134
  validateBindingArray(envName, validateWorkerNamespaceBinding),
1135
1135
  []
1136
1136
  ),
1137
+ mtls_certificates: notInheritable(
1138
+ diagnostics,
1139
+ topLevelEnv,
1140
+ rawConfig,
1141
+ rawEnv,
1142
+ envName,
1143
+ "mtls_certificates",
1144
+ validateBindingArray(envName, validateMTlsCertificateBinding),
1145
+ []
1146
+ ),
1137
1147
  logfwdr: inheritable(
1138
1148
  diagnostics,
1139
1149
  topLevelEnv,
@@ -1590,6 +1600,7 @@ const validateUnsafeBinding: ValidatorFn = (diagnostics, field, value) => {
1590
1600
  "r2_bucket",
1591
1601
  "service",
1592
1602
  "logfwdr",
1603
+ "mtls_certificate",
1593
1604
  ];
1594
1605
 
1595
1606
  if (safeBindings.includes(value.type)) {
@@ -1823,7 +1834,7 @@ const validateD1Binding: ValidatorFn = (diagnostics, field, value) => {
1823
1834
  }
1824
1835
  if (isValid && !process.env.NO_D1_WARNING) {
1825
1836
  diagnostics.warnings.push(
1826
- "D1 Bindings are currently in alpha to allow the API to evolve before general availability.\nPlease report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose\nNote: Run this command with the environment variable NO_D1_WARNING=true to hide this message\n\nFor example: `export NO_D1_WARNING=true && wrangler <YOUR COMMAND HERE>`"
1837
+ "D1 Bindings are currently in alpha to allow the API to evolve before general availability.\nPlease report any issues to https://github.com/cloudflare/workers-sdk/issues/new/choose\nNote: Run this command with the environment variable NO_D1_WARNING=true to hide this message\n\nFor example: `export NO_D1_WARNING=true && wrangler <YOUR COMMAND HERE>`"
1827
1838
  );
1828
1839
  }
1829
1840
  return isValid;
@@ -2036,6 +2047,42 @@ const validateWorkerNamespaceBinding: ValidatorFn = (
2036
2047
  return isValid;
2037
2048
  };
2038
2049
 
2050
+ const validateMTlsCertificateBinding: ValidatorFn = (
2051
+ diagnostics,
2052
+ field,
2053
+ value
2054
+ ) => {
2055
+ if (typeof value !== "object" || value === null) {
2056
+ diagnostics.errors.push(
2057
+ `"mtls_certificates" bindings should be objects, but got ${JSON.stringify(
2058
+ value
2059
+ )}`
2060
+ );
2061
+ return false;
2062
+ }
2063
+ let isValid = true;
2064
+ if (!isRequiredProperty(value, "binding", "string")) {
2065
+ diagnostics.errors.push(
2066
+ `"${field}" bindings should have a string "binding" field but got ${JSON.stringify(
2067
+ value
2068
+ )}.`
2069
+ );
2070
+ isValid = false;
2071
+ }
2072
+ if (
2073
+ !isRequiredProperty(value, "certificate_id", "string") ||
2074
+ (value as { certificate_id: string }).certificate_id.length === 0
2075
+ ) {
2076
+ diagnostics.errors.push(
2077
+ `"${field}" bindings should have a string "certificate_id" field but got ${JSON.stringify(
2078
+ value
2079
+ )}.`
2080
+ );
2081
+ isValid = false;
2082
+ }
2083
+ return isValid;
2084
+ };
2085
+
2039
2086
  function validateQueues(envName: string): ValidatorFn {
2040
2087
  return (diagnostics, field, value, config) => {
2041
2088
  const fieldPath =
@@ -45,6 +45,7 @@ type WorkerMetadataBinding =
45
45
  | { type: "service"; name: string; service: string; environment?: string }
46
46
  | { type: "analytics_engine"; name: string; dataset?: string }
47
47
  | { type: "dispatch_namespace"; name: string; namespace: string }
48
+ | { type: "mtls_certificate"; name: string; certificate_id: string }
48
49
  | {
49
50
  type: "logfwdr";
50
51
  name: string;
@@ -166,6 +167,14 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
166
167
  });
167
168
  });
168
169
 
170
+ bindings.mtls_certificates?.forEach(({ binding, certificate_id }) => {
171
+ metadataBindings.push({
172
+ name: binding,
173
+ type: "mtls_certificate",
174
+ certificate_id,
175
+ });
176
+ });
177
+
169
178
  bindings.logfwdr?.bindings.forEach(({ name, destination }) => {
170
179
  metadataBindings.push({
171
180
  name: name,