Repository: cloudflare/workers-sdk
Pull request #8507: [vite-plugin] fix: make sure that internal variables are not exposed in the importable `env` object
Author: login: dario-piotrowicz
Labels: name: vite-plugin
description: Relating to the `@cloudflare/vite-plugin` package
Created: 2025-03-14T18:35:41Z | Merged: 2025-03-21T18:01:09Z

Fixes #8458

---

<!--
Please don't delete the checkboxes <3
The following selections do not need to be completed if this PR only contains changes to .md files
-->

- Tests
  - [ ] TODO (before merge)
  - [x] Tests included
  - [ ] Tests not necessary because:
- Wrangler E2E Tests CI Job required? (Use "e2e" label or ask maintainer to run separately)
  - [ ] I don't know
  - [ ] Required
  - [x] Not required because: change not related to wrangler
- Public documentation
  - [ ] TODO (before merge)
  - [ ] Cloudflare docs PR(s): <!--e.g. <https://github.com/cloudflare/cloudflare-docs/pull/>...-->
  - [x] Documentation not necessary because: bugfix
- Wrangler V3 Backport
  - [ ] TODO (before merge)
  - [ ] PR: <!--e.g. <https://github.com/cloudflare/workers-sdk/pull/>...-->
  - [x] Not necessary because: not a Wrangler change

<!--
Have you read our [Contributing guide](https://github.com/cloudflare/workers-sdk/blob/main/CONTRIBUTING.md)?
In particular, for non-trivial changes, please always engage on the issue or create a discussion or feature request issue first before writing your code.
-->


Linked issue #8458: [vite-plugin] Apply `stripInternalEnv` to importable env
We need to apply the `stripInternalEnv` logic: https://github.com/cloudflare/workers-sdk/blob/869ec7b916487ec43b958a27bdfea13588c5685f/packages/vite-plugin-cloudflare/src/runner-worker/env.ts#L13-L23
 to the importable env object (ref: https://github.com/cloudflare/workerd/pull/3610)

Note: we don't necessarily want to call `stripInternalEnv` on the process.env object since that should not include any value besides the ones set by the user (as per: https://github.com/cloudflare/workers-sdk/issues/8457)

___

Internal ref: DEVX-1744

Diff:
diff --git a/.changeset/smart-jars-guess.md b/.changeset/smart-jars-guess.md
new file mode 100644
index 0000000000..4b8c561d13
--- /dev/null
+++ b/.changeset/smart-jars-guess.md
@@ -0,0 +1,5 @@
+---
+"@cloudflare/vite-plugin": patch
+---
+
+fix: make sure that internal variables are not exposed in the importable `env` object
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/.dev.vars b/packages/vite-plugin-cloudflare/playground/importable-env/.dev.vars
new file mode 100644
index 0000000000..5f7237d40c
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/.dev.vars
@@ -0,0 +1 @@
+importable-env_SECRET = "my importable env secret"
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/.gitignore b/packages/vite-plugin-cloudflare/playground/importable-env/.gitignore
new file mode 100644
index 0000000000..c0529254e3
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/.gitignore
@@ -0,0 +1 @@
+!.dev.vars
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/__tests__/env-entries.spec.ts b/packages/vite-plugin-cloudflare/playground/importable-env/__tests__/env-entries.spec.ts
new file mode 100644
index 0000000000..78de388550
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/__tests__/env-entries.spec.ts
@@ -0,0 +1,41 @@
+import { expect, test } from "vitest";
+import { getJsonResponse, serverLogs } from "../../__test-utils__";
+
+test("the importable env is accessible from outside the request handler", async () => {
+	expect(serverLogs.info.join()).toMatch(
+		/outside of request handler: importedEnv\["importable-env_VAR"\] === "my importable env variable"/
+	);
+});
+
+test("the fetch handler env contains the correct entries", async () => {
+	const json = await getJsonResponse();
+	expect(json?.["entries of the fetch handler env"]).toEqual([
+		{
+			key: "importable-env_VAR",
+			value: "my importable env variable",
+		},
+		{
+			key: "importable-env_SECRET",
+			value: "my importable env secret",
+		},
+	]);
+});
+
+test("the imported env contains the correct entries", async () => {
+	const json = await getJsonResponse();
+	expect(json?.["entries of the imported env"]).toEqual([
+		{
+			key: "importable-env_VAR",
+			value: "my importable env variable",
+		},
+		{
+			key: "importable-env_SECRET",
+			value: "my importable env secret",
+		},
+	]);
+});
+
+test("the entries in the fetch handler env and the imported env are the same", async () => {
+	const json = await getJsonResponse();
+	expect(json?.["are the two set of entries the same?"]).toEqual(true);
+});
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/package.json b/packages/vite-plugin-cloudflare/playground/importable-env/package.json
new file mode 100644
index 0000000000..600e1d6c1b
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/package.json
@@ -0,0 +1,19 @@
+{
+	"name": "@playground/importable-env",
+	"private": true,
+	"type": "module",
+	"scripts": {
+		"build": "vite build --app",
+		"check:types": "tsc --build",
+		"dev": "vite dev",
+		"preview": "vite preview"
+	},
+	"devDependencies": {
+		"@cloudflare/vite-plugin": "workspace:*",
+		"@cloudflare/workers-tsconfig": "workspace:*",
+		"@cloudflare/workers-types": "^4.20250310.0",
+		"typescript": "catalog:default",
+		"vite": "catalog:vite-plugin",
+		"wrangler": "workspace:*"
+	}
+}
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/src/index.ts b/packages/vite-plugin-cloudflare/playground/importable-env/src/index.ts
new file mode 100644
index 0000000000..1f87e42d80
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/src/index.ts
@@ -0,0 +1,27 @@
+import { env as importedEnv } from "cloudflare:workers";
+
+type Env = Record<string, unknown>;
+
+const key = "importable-env_VAR";
+console.log(
+	`outside of request handler: importedEnv["${key}"] === "${(importedEnv as Env)[key]}"`
+);
+
+export default {
+	async fetch(_req, argEnv) {
+		const entriesOfArgEnv = getEntriesOf(argEnv);
+		const entriesOfImportedEnv = getEntriesOf(importedEnv);
+
+		return Response.json({
+			"entries of the fetch handler env": entriesOfArgEnv,
+			"entries of the imported env": entriesOfImportedEnv,
+			"are the two set of entries the same?":
+				JSON.stringify(entriesOfArgEnv) ===
+				JSON.stringify(entriesOfImportedEnv),
+		});
+	},
+} satisfies ExportedHandler<Env>;
+
+function getEntriesOf(obj: Object) {
+	return Object.entries(obj).map(([key, value]) => ({ key, value }));
+}
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.json b/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.json
new file mode 100644
index 0000000000..b52af703bd
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.json
@@ -0,0 +1,7 @@
+{
+	"files": [],
+	"references": [
+		{ "path": "./tsconfig.node.json" },
+		{ "path": "./tsconfig.worker.json" }
+	]
+}
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.node.json b/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.node.json
new file mode 100644
index 0000000000..773be9834a
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.node.json
@@ -0,0 +1,4 @@
+{
+	"extends": ["@cloudflare/workers-tsconfig/base.json"],
+	"include": ["vite.config.ts", "__tests__"]
+}
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.worker.json b/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.worker.json
new file mode 100644
index 0000000000..da43778b82
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/tsconfig.worker.json
@@ -0,0 +1,4 @@
+{
+	"extends": ["@cloudflare/workers-tsconfig/worker.json"],
+	"include": ["src"]
+}
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/turbo.json b/packages/vite-plugin-cloudflare/playground/importable-env/turbo.json
new file mode 100644
index 0000000000..6556dcf3e5
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/turbo.json
@@ -0,0 +1,9 @@
+{
+	"$schema": "http://turbo.build/schema.json",
+	"extends": ["//"],
+	"tasks": {
+		"build": {
+			"outputs": ["dist/**"]
+		}
+	}
+}
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/vite.config.ts b/packages/vite-plugin-cloudflare/playground/importable-env/vite.config.ts
new file mode 100644
index 0000000000..55c8276338
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/vite.config.ts
@@ -0,0 +1,6 @@
+import { cloudflare } from "@cloudflare/vite-plugin";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+	plugins: [cloudflare({ persistState: false })],
+});
diff --git a/packages/vite-plugin-cloudflare/playground/importable-env/wrangler.toml b/packages/vite-plugin-cloudflare/playground/importable-env/wrangler.toml
new file mode 100644
index 0000000000..35ddb787ec
--- /dev/null
+++ b/packages/vite-plugin-cloudflare/playground/importable-env/wrangler.toml
@@ -0,0 +1,6 @@
+name = "worker"
+main = "./src/index.ts"
+compatibility_date = "2024-12-30"
+
+[vars]
+importable-env_VAR = "my importable env variable"
diff --git a/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts b/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts
index 51ab84ff6f..39ba33f317 100644
--- a/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts
+++ b/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts
@@ -3,6 +3,7 @@ import {
 	ModuleRunner,
 } from "vite/module-runner";
 import { additionalModuleRE, UNKNOWN_HOST } from "../shared";
+import { stripInternalEnv } from "./env";
 import type { WrapperEnv } from "./env";
 
 let moduleRunner: ModuleRunner;
@@ -75,6 +76,18 @@ export async function createModuleRunner(
 				}
 			},
 			async runExternalModule(filepath) {
+				if (filepath === "cloudflare:workers") {
+					const originalCloudflareWorkersModule = await import(
+						"cloudflare:workers"
+					);
+					return Object.seal({
+						...originalCloudflareWorkersModule,
+						env: stripInternalEnv(
+							originalCloudflareWorkersModule.env as WrapperEnv
+						),
+					});
+				}
+
 				if (
 					!additionalModuleRE.test(filepath) &&
 					filepath.includes("/node_modules") &&
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 023b8eaba0..98b1ec86bb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2132,6 +2132,27 @@ importers:
         specifier: workspace:*
         version: link:../../../wrangler
 
+  packages/vite-plugin-cloudflare/playground/importable-env:
+    devDependencies:
+      '@cloudflare/vite-plugin':
+        specifier: workspace:*
+        version: link:../..
+      '@cloudflare/workers-tsconfig':
+        specifier: workspace:*
+        version: link:../../../workers-tsconfig
+      '@cloudflare/workers-types':
+        specifier: ^4.20250310.0
+        version: 4.20250320.0
+      typescript:
+        specifier: catalog:default
+        version: 5.7.3
+      vite:
+        specifier: catalog:vite-plugin
+        version: 6.1.0(@types/node@18.19.76)(jiti@2.4.2)
+      wrangler:
+        specifier: workspace:*
+        version: link:../../../wrangler
+
   packages/vite-plugin-cloudflare/playground/module-resolution:
     devDependencies:
       '@cloudflare-dev-module-resolution/imports':


Reviews:
user: login: threepointone
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T12:22:37Z
user: login: jamesopstad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T09:12:13Z
user: login: dario-piotrowicz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T09:48:41Z
user: login: jamesopstad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T10:39:43Z
user: login: dario-piotrowicz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T11:43:10Z
user: login: dario-piotrowicz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T11:48:17Z
user: login: jamesopstad
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T16:28:16Z
user: login: jamesopstad
body: I wouldn't worry about running the CI again for these typos so I don't mind if we merge and fix them later.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T16:30:06Z
user: login: dario-piotrowicz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T17:59:22Z

Review comments:
diff_hunk: @@ -77,6 +78,18 @@ export async function createModuleRunner(
 			async runExternalModule(filepath) {
 				const moduleRE = new RegExp(MODULE_PATTERN);
 
+				if (filepath === "cloudflare:workers") {
+					const originalCloudflareWorkersModule = await import(
+						"cloudflare:workers"
+					);
+					return {
+						...originalCloudflareWorkersModule,
+						env: stripInternalEnv(
+							originalCloudflareWorkersModule.env as WrapperEnv
+						),
+					};
+				}
path: packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts
user: login: jamesopstad
body: Do you think it matters that you're returning a normal object rather than a module namespace object here? Not sure if this could lead to behaviour differences.
created_at: 2025-03-20T09:12:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -77,6 +78,18 @@ export async function createModuleRunner(
 			async runExternalModule(filepath) {
 				const moduleRE = new RegExp(MODULE_PATTERN);
 
+				if (filepath === "cloudflare:workers") {
+					const originalCloudflareWorkersModule = await import(
+						"cloudflare:workers"
+					);
+					return {
+						...originalCloudflareWorkersModule,
+						env: stripInternalEnv(
+							originalCloudflareWorkersModule.env as WrapperEnv
+						),
+					};
+				}
path: packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts
user: login: dario-piotrowicz
body: no I don't think it matters, I can't really imagine how this could effect user's code 🤔 do you have something in mind? or a different way of implementing this?

Also even if there could be behavioural differences I can't imagine them being very broad in scope (i.e. I think this could at most introduce some minor bug that would only apply to dev when you access the module, which we could look into and solve when reported), so this feels to me pretty safe overall 🤔 
created_at: 2025-03-20T09:48:41Z
author_association: MEMBER
diff_hunk: @@ -77,6 +78,18 @@ export async function createModuleRunner(
 			async runExternalModule(filepath) {
 				const moduleRE = new RegExp(MODULE_PATTERN);
 
+				if (filepath === "cloudflare:workers") {
+					const originalCloudflareWorkersModule = await import(
+						"cloudflare:workers"
+					);
+					return {
+						...originalCloudflareWorkersModule,
+						env: stripInternalEnv(
+							originalCloudflareWorkersModule.env as WrapperEnv
+						),
+					};
+				}
path: packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts
user: login: jamesopstad
body: I'm happy with that. Alternative would be to use a virtual module but this is nicer because it keeps everything in the runner worker. How about using `Object.freeze()` so the object is still immutable?

```suggestion
					return Object.freeze({
						...originalCloudflareWorkersModule,
						env: stripInternalEnv(
							originalCloudflareWorkersModule.env as WrapperEnv
						),
					});
				}
```
created_at: 2025-03-20T10:39:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -77,6 +78,18 @@ export async function createModuleRunner(
 			async runExternalModule(filepath) {
 				const moduleRE = new RegExp(MODULE_PATTERN);
 
+				if (filepath === "cloudflare:workers") {
+					const originalCloudflareWorkersModule = await import(
+						"cloudflare:workers"
+					);
+					return {
+						...originalCloudflareWorkersModule,
+						env: stripInternalEnv(
+							originalCloudflareWorkersModule.env as WrapperEnv
+						),
+					};
+				}
path: packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts
user: login: dario-piotrowicz
body: > Alternative would be to use a virtual module

I tried that but that was pretty problematic, because we would essentially need to convert `cloudflare:workers` imports into virtual module ones, the problem is that in the virtual module for that you'd have to import the actual `cloudflare:workers` module, but that would also be treated as a virtual module import when run in the environment, so as far as I could tell there isn't a clean way to do this with virtual modules (unless I missed something)
created_at: 2025-03-20T11:43:10Z
author_association: MEMBER
diff_hunk: @@ -77,6 +78,18 @@ export async function createModuleRunner(
 			async runExternalModule(filepath) {
 				const moduleRE = new RegExp(MODULE_PATTERN);
 
+				if (filepath === "cloudflare:workers") {
+					const originalCloudflareWorkersModule = await import(
+						"cloudflare:workers"
+					);
+					return {
+						...originalCloudflareWorkersModule,
+						env: stripInternalEnv(
+							originalCloudflareWorkersModule.env as WrapperEnv
+						),
+					};
+				}
path: packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts
user: login: dario-piotrowicz
body: > How about using Object.freeze() so the object is still immutable?

Sure 👍, but what about doing `Object.seal()` instead?
[mdn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import#module_namespace_object) states that the module namespace objects are _sealed_ not _frozen_
created_at: 2025-03-20T11:48:17Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,41 @@
+import { expect, test } from "vitest";
+import { getJsonResponse, serverLogs } from "../../__test-utils__";
+
+test("the importable env is accessible from outside the request handler", async () => {
+	expect(serverLogs.info.join()).toMatch(
+		/outside of request handler: importedEnv\["importable-env_VAR"\] === "my importable env variable"/
+	);
+});
+
+test("the fetch handler env contains the correct entries", async () => {
+	const json = await getJsonResponse();
+	expect(json?.["entires of the fetch handler env"]).toEqual([
path: packages/vite-plugin-cloudflare/playground/importable-env/__tests__/env-entries.spec.ts
user: login: jamesopstad
body: ```suggestion
	expect(json?.["entries of the fetch handler env"]).toEqual([
```
created_at: 2025-03-20T16:28:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,27 @@
+import { env as importedEnv } from "cloudflare:workers";
+
+type Env = Record<string, unknown>;
+
+const key = "importable-env_VAR";
+console.log(
+	`outside of request handler: importedEnv["${key}"] === "${(importedEnv as Env)[key]}"`
+);
+
+export default {
+	async fetch(_req, argEnv) {
+		const entriesOfArgEnv = getEntriesOf(argEnv);
+		const entriesOfImportedEnv = getEntriesOf(importedEnv);
+
+		return Response.json({
+			"entires of the fetch handler env": entriesOfArgEnv,
path: packages/vite-plugin-cloudflare/playground/importable-env/src/index.ts
user: login: jamesopstad
body: ```suggestion
			"entries of the fetch handler env": entriesOfArgEnv,
```
created_at: 2025-03-20T16:29:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,41 @@
+import { expect, test } from "vitest";
+import { getJsonResponse, serverLogs } from "../../__test-utils__";
+
+test("the importable env is accessible from outside the request handler", async () => {
+	expect(serverLogs.info.join()).toMatch(
+		/outside of request handler: importedEnv\["importable-env_VAR"\] === "my importable env variable"/
+	);
+});
+
+test("the fetch handler env contains the correct entries", async () => {
+	const json = await getJsonResponse();
+	expect(json?.["entires of the fetch handler env"]).toEqual([
path: packages/vite-plugin-cloudflare/playground/importable-env/__tests__/env-entries.spec.ts
user: login: dario-piotrowicz
body: oops! thanks! 🙂 
created_at: 2025-03-20T17:59:22Z
author_association: MEMBER

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-03-14T18:35:45Z
body: ###  🦋  Changeset detected

Latest commit: 6339128868b9d5ce69d86c1352dbcf363f1b6630

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name                    | Type  |
| ----------------------- | ----- |
| @cloudflare/vite-plugin | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/cloudflare/workers-sdk/new/dario/8458/vite-plugin/strip-importable-env?filename=.changeset/loud-pillows-act.md&value=---%0A%22%40cloudflare%2Fvite-plugin%22%3A%20patch%0A%22%40playground%2Fimportable-env%22%3A%20patch%0A%22%40vite-plugin-cloudflare%2Fplayground%22%3A%20patch%0A---%0A%0A%5Bvite-plugin%5D%20fix%3A%20make%20sure%20that%20internal%20variables%20are%20not%20exposed%20in%20the%20importable%20%60env%60%20object%0A)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-19T12:52:31Z
body: A wrangler prerelease is available for testing. You can install this latest build in your project with:

```sh
npm install --save-dev https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-wrangler-8507
```

You can reference the automatically updated head of this PR with:

```sh
npm install --save-dev https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/prs/8507/npm-package-wrangler-8507
```

Or you can use `npx` with this latest build directly:

```sh
npx https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-wrangler-8507 dev path/to/script.js
```

<details><summary>Additional artifacts:</summary>


cloudflare-workers-bindings-extension:
```sh
wget https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-workers-bindings-extension-8507 -O ./cloudflare-workers-bindings-extension.0.0.0-v8cb4fc430.vsix && code --install-extension ./cloudflare-workers-bindings-extension.0.0.0-v8cb4fc430.vsix
```



create-cloudflare:
```sh
npx https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-create-cloudflare-8507 --no-auto-update
```



@cloudflare/kv-asset-handler:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-kv-asset-handler-8507
```



miniflare:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-miniflare-8507
```



@cloudflare/pages-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-pages-shared-8507
```



@cloudflare/unenv-preset:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-unenv-preset-8507
```



@cloudflare/vite-plugin:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-vite-plugin-8507
```



@cloudflare/vitest-pool-workers:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-vitest-pool-workers-8507
```



@cloudflare/workers-editor-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-workers-editor-shared-8507
```



@cloudflare/workers-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-workers-shared-8507
```



@cloudflare/workflows-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/13995658386/npm-package-cloudflare-workflows-shared-8507
```


Note that these links will no longer work once [the GitHub Actions artifact expires](https://docs.github.com/en/organizations/managing-organization-settings/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organization).

</details>

---

`wrangler@4.3.0` includes the following runtime dependencies:

|Package|Constraint|Resolved|
|-------|----------|--------|
|`miniflare`|workspace:*|4.20250319.0|
|`workerd`|1.20250320.0|1.20250320.0|
|`workerd --version`|1.20250320.0|2025-03-20|

Please ensure constraints are pinned, and `miniflare`/`workerd` minor versions match.
<!-- Sticky Pull Request Comment -->
author_association: CONTRIBUTOR