@cloudflare/vite-plugin 1.29.0 → 1.30.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.
- package/README.md +4 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4097 -536
- package/dist/index.mjs.map +1 -1
- package/dist/{package-B8LLjfje.mjs → package--uDsBjBd.mjs} +11 -11
- package/dist/package--uDsBjBd.mjs.map +1 -0
- package/dist/workers/runner-worker/index.js +471 -0
- package/dist/workers/{runner-worker.js → runner-worker/module-runner-legacy.js} +33 -471
- package/dist/workers/runner-worker/module-runner.js +1220 -0
- package/package.json +23 -23
- package/dist/package-B8LLjfje.mjs.map +0 -1
- /package/dist/workers/{asset-worker.js → asset-worker/index.js} +0 -0
- /package/dist/workers/{router-worker.js → router-worker/index.js} +0 -0
- /package/dist/workers/{vite-proxy-worker.js → vite-proxy-worker/index.js} +0 -0
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
//#region package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "@cloudflare/vite-plugin",
|
|
4
|
-
version: "1.
|
|
4
|
+
version: "1.30.0",
|
|
5
5
|
description: "Cloudflare plugin for Vite",
|
|
6
6
|
keywords: [
|
|
7
7
|
"cloudflare",
|
|
8
|
-
"workers",
|
|
9
8
|
"cloudflare-workers",
|
|
10
9
|
"vite",
|
|
11
|
-
"vite-plugin"
|
|
10
|
+
"vite-plugin",
|
|
11
|
+
"workers"
|
|
12
12
|
],
|
|
13
13
|
homepage: "https://github.com/cloudflare/workers-sdk/tree/main/packages/vite-plugin-cloudflare#readme",
|
|
14
14
|
bugs: { "url": "https://github.com/cloudflare/workers-sdk/issues" },
|
|
15
|
+
license: "MIT",
|
|
15
16
|
repository: {
|
|
16
17
|
"type": "git",
|
|
17
18
|
"url": "https://github.com/cloudflare/workers-sdk.git",
|
|
18
19
|
"directory": "packages/vite-plugin-cloudflare"
|
|
19
20
|
},
|
|
20
|
-
|
|
21
|
-
sideEffects: false,
|
|
21
|
+
files: ["dist"],
|
|
22
22
|
type: "module",
|
|
23
|
+
sideEffects: false,
|
|
24
|
+
main: "./dist/index.mjs",
|
|
25
|
+
types: "./dist/index.d.mts",
|
|
23
26
|
exports: { ".": {
|
|
24
27
|
"types": "./dist/index.d.mts",
|
|
25
28
|
"import": "./dist/index.mjs"
|
|
26
29
|
} },
|
|
27
|
-
|
|
28
|
-
types: "./dist/index.d.mts",
|
|
29
|
-
files: ["dist"],
|
|
30
|
+
publishConfig: { "access": "public" },
|
|
30
31
|
scripts: {
|
|
31
32
|
"build": "tsdown",
|
|
32
|
-
"check:lint": "eslint . --max-warnings=0 --cache",
|
|
33
33
|
"check:type": "tsc --build",
|
|
34
34
|
"dev": "tsdown --watch",
|
|
35
35
|
"test": "vitest run",
|
|
@@ -66,16 +66,16 @@ var package_default = {
|
|
|
66
66
|
"tsdown": "0.16.3",
|
|
67
67
|
"typescript": "catalog:default",
|
|
68
68
|
"vite": "catalog:vite-plugin",
|
|
69
|
+
"vite-legacy": "npm:vite@7.1.12",
|
|
69
70
|
"vitest": "catalog:vitest-3"
|
|
70
71
|
},
|
|
71
72
|
peerDependencies: {
|
|
72
73
|
"vite": "^6.1.0 || ^7.0.0 || ^8.0.0",
|
|
73
74
|
"wrangler": "workspace:^"
|
|
74
75
|
},
|
|
75
|
-
publishConfig: { "access": "public" },
|
|
76
76
|
"workers-sdk": { "prerelease": true }
|
|
77
77
|
};
|
|
78
78
|
|
|
79
79
|
//#endregion
|
|
80
80
|
export { package_default as default };
|
|
81
|
-
//# sourceMappingURL=package
|
|
81
|
+
//# sourceMappingURL=package--uDsBjBd.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package--uDsBjBd.mjs","names":[],"sources":["../package.json"],"sourcesContent":["{\n\t\"name\": \"@cloudflare/vite-plugin\",\n\t\"version\": \"1.30.0\",\n\t\"description\": \"Cloudflare plugin for Vite\",\n\t\"keywords\": [\n\t\t\"cloudflare\",\n\t\t\"cloudflare-workers\",\n\t\t\"vite\",\n\t\t\"vite-plugin\",\n\t\t\"workers\"\n\t],\n\t\"homepage\": \"https://github.com/cloudflare/workers-sdk/tree/main/packages/vite-plugin-cloudflare#readme\",\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/cloudflare/workers-sdk/issues\"\n\t},\n\t\"license\": \"MIT\",\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/cloudflare/workers-sdk.git\",\n\t\t\"directory\": \"packages/vite-plugin-cloudflare\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"type\": \"module\",\n\t\"sideEffects\": false,\n\t\"main\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.mts\",\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\"import\": \"./dist/index.mjs\"\n\t\t}\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\"\n\t},\n\t\"scripts\": {\n\t\t\"build\": \"tsdown\",\n\t\t\"check:type\": \"tsc --build\",\n\t\t\"dev\": \"tsdown --watch\",\n\t\t\"test\": \"vitest run\",\n\t\t\"test:ci\": \"pnpm test\",\n\t\t\"test:e2e\": \"vitest run -c e2e/vitest.config.ts\",\n\t\t\"test:watch\": \"vitest\"\n\t},\n\t\"dependencies\": {\n\t\t\"@cloudflare/unenv-preset\": \"workspace:*\",\n\t\t\"miniflare\": \"workspace:*\",\n\t\t\"unenv\": \"2.0.0-rc.24\",\n\t\t\"wrangler\": \"workspace:*\",\n\t\t\"ws\": \"catalog:default\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@cloudflare/containers-shared\": \"workspace:*\",\n\t\t\"@cloudflare/mock-npm-registry\": \"workspace:*\",\n\t\t\"@cloudflare/workers-shared\": \"workspace:*\",\n\t\t\"@cloudflare/workers-tsconfig\": \"workspace:*\",\n\t\t\"@cloudflare/workers-types\": \"catalog:default\",\n\t\t\"@cloudflare/workers-utils\": \"workspace:*\",\n\t\t\"@remix-run/node-fetch-server\": \"^0.8.0\",\n\t\t\"@types/node\": \"catalog:vite-plugin\",\n\t\t\"@types/semver\": \"^7.5.1\",\n\t\t\"@types/ws\": \"^8.5.13\",\n\t\t\"defu\": \"^6.1.4\",\n\t\t\"get-port\": \"^7.1.0\",\n\t\t\"magic-string\": \"^0.30.12\",\n\t\t\"mlly\": \"^1.7.4\",\n\t\t\"picocolors\": \"^1.1.1\",\n\t\t\"semver\": \"^7.7.1\",\n\t\t\"tinyglobby\": \"^0.2.12\",\n\t\t\"tree-kill\": \"catalog:default\",\n\t\t\"tsdown\": \"0.16.3\",\n\t\t\"typescript\": \"catalog:default\",\n\t\t\"vite\": \"catalog:vite-plugin\",\n\t\t\"vite-legacy\": \"npm:vite@7.1.12\",\n\t\t\"vitest\": \"catalog:vitest-3\"\n\t},\n\t\"peerDependencies\": {\n\t\t\"vite\": \"^6.1.0 || ^7.0.0 || ^8.0.0\",\n\t\t\"wrangler\": \"workspace:^\"\n\t},\n\t\"workers-sdk\": {\n\t\t\"prerelease\": true\n\t}\n}\n"],"mappings":";sBAAA;OACS;UACG;cACI;WACH;EACX;EACA;EACA;EACA;EACA;EACA;WACW;OACJ,EACP,OAAO,oDACP;UACU;aACG;EACb,QAAQ;EACR,OAAO;EACP,aAAa;EACb;QACQ,CACR,OACA;OACO;cACO;OACP;QACC;UACE,EACV,KAAK;EACJ,SAAS;EACT,UAAU;EACV,EACD;gBACgB,EAChB,UAAU,UACV;UACU;EACV,SAAS;EACT,cAAc;EACd,OAAO;EACP,QAAQ;EACR,WAAW;EACX,YAAY;EACZ,cAAc;EACd;eACe;EACf,4BAA4B;EAC5B,aAAa;EACb,SAAS;EACT,YAAY;EACZ,MAAM;EACN;kBACkB;EAClB,iCAAiC;EACjC,iCAAiC;EACjC,8BAA8B;EAC9B,gCAAgC;EAChC,6BAA6B;EAC7B,6BAA6B;EAC7B,gCAAgC;EAChC,eAAe;EACf,iBAAiB;EACjB,aAAa;EACb,QAAQ;EACR,YAAY;EACZ,gBAAgB;EAChB,QAAQ;EACR,cAAc;EACd,UAAU;EACV,cAAc;EACd,aAAa;EACb,UAAU;EACV,cAAc;EACd,QAAQ;EACR,eAAe;EACf,UAAU;EACV;mBACmB;EACnB,QAAQ;EACR,YAAY;EACZ;CACD,eAAe,EACd,cAAc,MACd;CACD"}
|
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { DurableObject, WorkerEntrypoint, WorkflowEntrypoint } from "cloudflare:workers";
|
|
2
|
+
import { ModuleRunner, ssrModuleExportsKey } from "vite/module-runner";
|
|
3
|
+
|
|
4
|
+
//#region src/shared.ts
|
|
5
|
+
const UNKNOWN_HOST = "http://localhost";
|
|
6
|
+
const INIT_PATH = "/__vite_plugin_cloudflare_init__";
|
|
7
|
+
const GET_EXPORT_TYPES_PATH = "/__vite_plugin_cloudflare_get_export_types__";
|
|
8
|
+
const WORKER_ENTRY_PATH_HEADER = "__VITE_WORKER_ENTRY_PATH__";
|
|
9
|
+
const IS_ENTRY_WORKER_HEADER = "__VITE_IS_ENTRY_WORKER__";
|
|
10
|
+
const ENVIRONMENT_NAME_HEADER = "__VITE_ENVIRONMENT_NAME__";
|
|
11
|
+
const IS_PARENT_ENVIRONMENT_HEADER = "__VITE_IS_PARENT_ENVIRONMENT__";
|
|
12
|
+
const virtualPrefix = "virtual:cloudflare/";
|
|
13
|
+
const VIRTUAL_WORKER_ENTRY = `${virtualPrefix}worker-entry`;
|
|
14
|
+
const VIRTUAL_EXPORT_TYPES = `${virtualPrefix}export-types`;
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/workers/runner-worker/env.ts
|
|
18
|
+
/**
|
|
19
|
+
* Strips internal properties from the `env` object, returning only the user-defined properties.
|
|
20
|
+
* @param internalEnv - The full wrapper env, including internal properties
|
|
21
|
+
* @returns The user-defined env
|
|
22
|
+
*/
|
|
23
|
+
function stripInternalEnv(internalEnv) {
|
|
24
|
+
const { __VITE_RUNNER_OBJECT__: __VITE_RUNNER_OBJECT__$1, __VITE_INVOKE_MODULE__, __VITE_UNSAFE_EVAL__,...userEnv } = internalEnv;
|
|
25
|
+
return userEnv;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/workers/runner-worker/errors.ts
|
|
30
|
+
/**
|
|
31
|
+
* Converts an error to an object that can be be serialized and revived by Miniflare.
|
|
32
|
+
* Copied from `packages/wrangler/templates/middleware/middleware-miniflare3-json-error.ts`
|
|
33
|
+
*/
|
|
34
|
+
function reduceError(e) {
|
|
35
|
+
return {
|
|
36
|
+
name: e?.name,
|
|
37
|
+
message: e?.message ?? String(e),
|
|
38
|
+
stack: e?.stack,
|
|
39
|
+
cause: e?.cause === void 0 ? void 0 : reduceError(e.cause)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Captures errors in the `fetch` handler of the default export of the entry Worker.
|
|
44
|
+
* These are returned as a JSON response that is revived by Miniflare.
|
|
45
|
+
* See comment in `/packages/wrangler/src/deployment-bundle/bundle.ts` for more info.
|
|
46
|
+
*/
|
|
47
|
+
async function maybeCaptureError(options, fn) {
|
|
48
|
+
if (!options.isEntryWorker || options.exportName !== "default" || options.key !== "fetch") return fn();
|
|
49
|
+
try {
|
|
50
|
+
return await fn();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return Response.json(reduceError(error), {
|
|
53
|
+
status: 500,
|
|
54
|
+
headers: { "MF-Experimental-Error-Stack": "true" }
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/workers/runner-worker/keys.ts
|
|
61
|
+
/** Keys that should be ignored during RPC property access */
|
|
62
|
+
const IGNORED_KEYS = ["self"];
|
|
63
|
+
/** Available methods for `WorkerEntrypoint` class */
|
|
64
|
+
const WORKER_ENTRYPOINT_KEYS = [
|
|
65
|
+
"email",
|
|
66
|
+
"fetch",
|
|
67
|
+
"queue",
|
|
68
|
+
"tail",
|
|
69
|
+
"tailStream",
|
|
70
|
+
"test",
|
|
71
|
+
"trace",
|
|
72
|
+
"scheduled"
|
|
73
|
+
];
|
|
74
|
+
/** Available methods for `DurableObject` class */
|
|
75
|
+
const DURABLE_OBJECT_KEYS = [
|
|
76
|
+
"alarm",
|
|
77
|
+
"fetch",
|
|
78
|
+
"webSocketClose",
|
|
79
|
+
"webSocketError",
|
|
80
|
+
"webSocketMessage"
|
|
81
|
+
];
|
|
82
|
+
/** Available methods for `WorkflowEntrypoint` classes */
|
|
83
|
+
const WORKFLOW_ENTRYPOINT_KEYS = ["run"];
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/workers/runner-worker/module-runner.ts
|
|
87
|
+
/**
|
|
88
|
+
* Custom `ModuleRunner`.
|
|
89
|
+
* The `cachedModule` method is overridden to ensure compatibility with the Workers runtime.
|
|
90
|
+
*/
|
|
91
|
+
var CustomModuleRunner = class extends ModuleRunner {
|
|
92
|
+
#env;
|
|
93
|
+
#environmentName;
|
|
94
|
+
constructor(options, evaluator, env, environmentName) {
|
|
95
|
+
super(options, evaluator);
|
|
96
|
+
this.#env = env;
|
|
97
|
+
this.#environmentName = environmentName;
|
|
98
|
+
}
|
|
99
|
+
async cachedModule(url, importer) {
|
|
100
|
+
const moduleId = await this.#env.__VITE_RUNNER_OBJECT__.get("singleton").getFetchedModuleId(this.#environmentName, url, importer);
|
|
101
|
+
const module = this.evaluatedModules.getModuleById(moduleId);
|
|
102
|
+
if (!module) throw new Error(`Module "${moduleId}" is undefined`);
|
|
103
|
+
return module;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
/** Module runner instances keyed by environment name */
|
|
107
|
+
const moduleRunners = /* @__PURE__ */ new Map();
|
|
108
|
+
/** The parent environment name (set explicitly via IS_PARENT_ENVIRONMENT_HEADER) */
|
|
109
|
+
let parentEnvironmentName;
|
|
110
|
+
/**
|
|
111
|
+
* Durable Object that creates the module runner and handles WebSocket communication with the Vite dev server.
|
|
112
|
+
*/
|
|
113
|
+
var __VITE_RUNNER_OBJECT__ = class extends DurableObject {
|
|
114
|
+
/** Per-environment state containing WebSocket and concurrent module node promises */
|
|
115
|
+
#environments = /* @__PURE__ */ new Map();
|
|
116
|
+
/**
|
|
117
|
+
* Handles fetch requests to initialize a module runner for an environment.
|
|
118
|
+
* Creates a WebSocket pair for communication with the Vite dev server and initializes the ModuleRunner.
|
|
119
|
+
* @param request - The incoming fetch request
|
|
120
|
+
* @returns Response with WebSocket
|
|
121
|
+
* @throws Error if the path is invalid or the module runner is already initialized
|
|
122
|
+
*/
|
|
123
|
+
async fetch(request) {
|
|
124
|
+
const { pathname } = new URL(request.url);
|
|
125
|
+
if (pathname !== INIT_PATH) throw new Error(`__VITE_RUNNER_OBJECT__ received invalid pathname: "${pathname}"`);
|
|
126
|
+
const environmentName = request.headers.get(ENVIRONMENT_NAME_HEADER);
|
|
127
|
+
if (!environmentName) throw new Error(`__VITE_RUNNER_OBJECT__ received request without "${ENVIRONMENT_NAME_HEADER}" header`);
|
|
128
|
+
if (moduleRunners.has(environmentName)) throw new Error(`Module runner already initialized for environment: "${environmentName}"`);
|
|
129
|
+
if (request.headers.get(IS_PARENT_ENVIRONMENT_HEADER) === "true") parentEnvironmentName = environmentName;
|
|
130
|
+
const { 0: client, 1: server } = new WebSocketPair();
|
|
131
|
+
server.accept();
|
|
132
|
+
const environmentState = {
|
|
133
|
+
webSocket: server,
|
|
134
|
+
concurrentModuleNodePromises: /* @__PURE__ */ new Map()
|
|
135
|
+
};
|
|
136
|
+
this.#environments.set(environmentName, environmentState);
|
|
137
|
+
const moduleRunner = await createModuleRunner(this.env, environmentState.webSocket, environmentName);
|
|
138
|
+
moduleRunners.set(environmentName, moduleRunner);
|
|
139
|
+
return new Response(null, {
|
|
140
|
+
status: 101,
|
|
141
|
+
webSocket: client
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Sends data to the Vite dev server via the WebSocket for a specific environment.
|
|
146
|
+
* @param environmentName - The environment name
|
|
147
|
+
* @param data - The data to send as a string
|
|
148
|
+
* @throws Error if the WebSocket is not initialized
|
|
149
|
+
*/
|
|
150
|
+
send(environmentName, data) {
|
|
151
|
+
const environmentState = this.#environments.get(environmentName);
|
|
152
|
+
if (!environmentState) throw new Error(`Module runner WebSocket not initialized for environment: "${environmentName}"`);
|
|
153
|
+
environmentState.webSocket.send(data);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Based on the implementation of `cachedModule` from Vite's `ModuleRunner`.
|
|
157
|
+
* Running this in the DO enables us to share promises across invocations.
|
|
158
|
+
* @param environmentName - The environment name
|
|
159
|
+
* @param url - The module URL
|
|
160
|
+
* @param importer - The module's importer
|
|
161
|
+
* @returns The ID of the fetched module
|
|
162
|
+
*/
|
|
163
|
+
async getFetchedModuleId(environmentName, url, importer) {
|
|
164
|
+
const moduleRunner = moduleRunners.get(environmentName);
|
|
165
|
+
if (!moduleRunner) throw new Error(`Module runner not initialized for environment: "${environmentName}"`);
|
|
166
|
+
const environmentState = this.#environments.get(environmentName);
|
|
167
|
+
if (!environmentState) throw new Error(`Environment state not found for environment: "${environmentName}"`);
|
|
168
|
+
let cached = environmentState.concurrentModuleNodePromises.get(url);
|
|
169
|
+
if (!cached) {
|
|
170
|
+
const cachedModule = moduleRunner.evaluatedModules.getModuleByUrl(url);
|
|
171
|
+
cached = moduleRunner.getModuleInformation(url, importer, cachedModule).finally(() => {
|
|
172
|
+
environmentState.concurrentModuleNodePromises.delete(url);
|
|
173
|
+
});
|
|
174
|
+
environmentState.concurrentModuleNodePromises.set(url, cached);
|
|
175
|
+
} else moduleRunner.debug?.("[module runner] using cached module info for", url);
|
|
176
|
+
return (await cached).id;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Creates a new module runner instance with a WebSocket transport.
|
|
181
|
+
* @param env - The wrapper env
|
|
182
|
+
* @param webSocket - WebSocket connection for communication with Vite dev server
|
|
183
|
+
* @param environmentName - The name of the environment this runner is for
|
|
184
|
+
* @returns Configured module runner instance
|
|
185
|
+
*/
|
|
186
|
+
async function createModuleRunner(env, webSocket, environmentName) {
|
|
187
|
+
return new CustomModuleRunner({
|
|
188
|
+
sourcemapInterceptor: "prepareStackTrace",
|
|
189
|
+
transport: {
|
|
190
|
+
connect({ onMessage }) {
|
|
191
|
+
webSocket.addEventListener("message", async ({ data }) => {
|
|
192
|
+
onMessage(JSON.parse(data.toString()));
|
|
193
|
+
});
|
|
194
|
+
onMessage({
|
|
195
|
+
type: "custom",
|
|
196
|
+
event: "vite:ws:connect",
|
|
197
|
+
data: { webSocket }
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
disconnect() {
|
|
201
|
+
webSocket.close();
|
|
202
|
+
},
|
|
203
|
+
send(data) {
|
|
204
|
+
env.__VITE_RUNNER_OBJECT__.get("singleton").send(environmentName, JSON.stringify(data));
|
|
205
|
+
},
|
|
206
|
+
async invoke(data) {
|
|
207
|
+
return await (await env.__VITE_INVOKE_MODULE__.fetch(new Request(UNKNOWN_HOST, {
|
|
208
|
+
method: "POST",
|
|
209
|
+
headers: { [ENVIRONMENT_NAME_HEADER]: environmentName },
|
|
210
|
+
body: JSON.stringify(data)
|
|
211
|
+
}))).json();
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
hmr: true
|
|
215
|
+
}, {
|
|
216
|
+
async runInlinedModule(context, transformed, module) {
|
|
217
|
+
const code = `"use strict";async (${Object.keys(context).join(",")})=>{${transformed}}`;
|
|
218
|
+
await env.__VITE_UNSAFE_EVAL__.eval(code, module.id)(...Object.values(context));
|
|
219
|
+
Object.seal(context[ssrModuleExportsKey]);
|
|
220
|
+
},
|
|
221
|
+
async runExternalModule(filepath) {
|
|
222
|
+
if (filepath === "cloudflare:workers") {
|
|
223
|
+
const originalCloudflareWorkersModule = await import("cloudflare:workers");
|
|
224
|
+
return Object.seal({
|
|
225
|
+
...originalCloudflareWorkersModule,
|
|
226
|
+
env: stripInternalEnv(originalCloudflareWorkersModule.env)
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
return import(filepath);
|
|
230
|
+
}
|
|
231
|
+
}, env, environmentName);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Retrieves a specific export from a Worker entry module using the module runner.
|
|
235
|
+
* @param workerEntryPath - Path to the Worker entry module
|
|
236
|
+
* @param exportName - Name of the export to retrieve
|
|
237
|
+
* @returns The requested export value
|
|
238
|
+
* @throws Error if the module runner has not been initialized or the module does not define the requested export
|
|
239
|
+
*/
|
|
240
|
+
async function getWorkerEntryExport(workerEntryPath$1, exportName) {
|
|
241
|
+
if (!parentEnvironmentName) throw new Error(`Parent environment not initialized`);
|
|
242
|
+
const moduleRunner = moduleRunners.get(parentEnvironmentName);
|
|
243
|
+
if (!moduleRunner) throw new Error(`Module runner not initialized`);
|
|
244
|
+
const module = await moduleRunner.import(VIRTUAL_WORKER_ENTRY);
|
|
245
|
+
const exportValue = typeof module === "object" && module !== null && exportName in module && module[exportName];
|
|
246
|
+
if (!exportValue) throw new Error(`"${workerEntryPath$1}" does not define a "${exportName}" export.`);
|
|
247
|
+
return exportValue;
|
|
248
|
+
}
|
|
249
|
+
async function getWorkerEntryExportTypes() {
|
|
250
|
+
if (!parentEnvironmentName) throw new Error(`Parent environment not initialized`);
|
|
251
|
+
const moduleRunner = moduleRunners.get(parentEnvironmentName);
|
|
252
|
+
if (!moduleRunner) throw new Error(`Module runner not initialized`);
|
|
253
|
+
const { getExportTypes } = await moduleRunner.import(VIRTUAL_EXPORT_TYPES);
|
|
254
|
+
return getExportTypes(await moduleRunner.import(VIRTUAL_WORKER_ENTRY));
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Imports a module from a specific environment's module runner.
|
|
258
|
+
* @param environmentName - The name of the environment to import from
|
|
259
|
+
* @param id - The module ID to import
|
|
260
|
+
* @returns The imported module
|
|
261
|
+
* @throws Error if the environment's module runner has not been initialized
|
|
262
|
+
*/
|
|
263
|
+
async function importFromEnvironment(environmentName, id) {
|
|
264
|
+
const moduleRunner = moduleRunners.get(environmentName);
|
|
265
|
+
if (!moduleRunner) throw new Error(`Module runner not initialized for environment: "${environmentName}". Do you need to set \`childEnvironments: ["${environmentName}"]\` in the plugin config?`);
|
|
266
|
+
return moduleRunner.import(id);
|
|
267
|
+
}
|
|
268
|
+
globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__ = importFromEnvironment;
|
|
269
|
+
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/workers/runner-worker/index.ts
|
|
272
|
+
/** The path to the Worker entry file. We store it in the module scope so that it is easily accessible in error messages etc.. */
|
|
273
|
+
let workerEntryPath = "";
|
|
274
|
+
let isEntryWorker = false;
|
|
275
|
+
/**
|
|
276
|
+
* Creates a callable thenable that is used to access the properties of an RPC target.
|
|
277
|
+
* It can be both awaited and invoked as a function.
|
|
278
|
+
* This enables RPC properties to be used both as promises and callable functions.
|
|
279
|
+
* @param key - The property key name used for error messages
|
|
280
|
+
* @param property - The promise that resolves to the property value
|
|
281
|
+
* @returns A callable thenable that implements both Promise and function interfaces
|
|
282
|
+
*/
|
|
283
|
+
function getRpcPropertyCallableThenable(key, property) {
|
|
284
|
+
const fn = async function(...args) {
|
|
285
|
+
const maybeFn = await property;
|
|
286
|
+
if (typeof maybeFn !== "function") throw new TypeError(`"${key}" is not a function.`);
|
|
287
|
+
return maybeFn(...args);
|
|
288
|
+
};
|
|
289
|
+
fn.then = (onFulfilled, onRejected) => property.then(onFulfilled, onRejected);
|
|
290
|
+
fn.catch = (onRejected) => property.catch(onRejected);
|
|
291
|
+
fn.finally = (onFinally) => property.finally(onFinally);
|
|
292
|
+
return fn;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Retrieves an RPC property from a constructor prototype, ensuring it exists on the prototype rather than the instance to maintain RPC compatibility.
|
|
296
|
+
* @param ctor - The constructor function (`WorkerEntrypoint` or `DurableObject`)
|
|
297
|
+
* @param instance - The instance to bind methods to
|
|
298
|
+
* @param key - The property key to retrieve
|
|
299
|
+
* @returns The property value from the prototype
|
|
300
|
+
* @throws TypeError if the property doesn't exist on the prototype
|
|
301
|
+
*/
|
|
302
|
+
function getRpcProperty(ctor, instance, key) {
|
|
303
|
+
if (!Reflect.has(ctor.prototype, key)) {
|
|
304
|
+
if (Reflect.has(instance, key)) throw new TypeError([
|
|
305
|
+
`The RPC receiver's prototype does not implement "${key}", but the receiver instance does.`,
|
|
306
|
+
"Only properties and methods defined on the prototype can be accessed over RPC.",
|
|
307
|
+
`Ensure properties are declared as \`get ${key}() { ... }\` instead of \`${key} = ...\`,`,
|
|
308
|
+
`and methods are declared as \`${key}() { ... }\` instead of \`${key} = () => { ... }\`.`
|
|
309
|
+
].join("\n"));
|
|
310
|
+
throw new TypeError(`The RPC receiver does not implement "${key}".`);
|
|
311
|
+
}
|
|
312
|
+
return Reflect.get(ctor.prototype, key, instance);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Retrieves an RPC property from a `WorkerEntrypoint` export, creating an instance and returning the bound method or property value.
|
|
316
|
+
* @param exportName - The name of the `WorkerEntrypoint` export
|
|
317
|
+
* @param key - The property key to access on the `WorkerEntrypoint` instance
|
|
318
|
+
* @returns The property value, with methods bound to the instance
|
|
319
|
+
* @throws TypeError if the export is not a `WorkerEntrypoint` subclass
|
|
320
|
+
*/
|
|
321
|
+
async function getWorkerEntrypointRpcProperty(exportName, key) {
|
|
322
|
+
const ctor = await getWorkerEntryExport(workerEntryPath, exportName);
|
|
323
|
+
const userEnv = stripInternalEnv(this.env);
|
|
324
|
+
const expectedWorkerEntrypointMessage = `Expected "${exportName}" export of "${workerEntryPath}" to be a subclass of \`WorkerEntrypoint\` for RPC.`;
|
|
325
|
+
if (typeof ctor !== "function") throw new TypeError(expectedWorkerEntrypointMessage);
|
|
326
|
+
const instance = new ctor(this.ctx, userEnv);
|
|
327
|
+
if (!(instance instanceof WorkerEntrypoint)) throw new TypeError(expectedWorkerEntrypointMessage);
|
|
328
|
+
const value = getRpcProperty(ctor, instance, key);
|
|
329
|
+
if (typeof value === "function") return value.bind(instance);
|
|
330
|
+
return value;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Creates a proxy wrapper for `WorkerEntrypoint` classes that enables RPC functionality.
|
|
334
|
+
* The wrapper intercepts property access and delegates to the user code, handling both direct method calls and RPC property access.
|
|
335
|
+
* @param exportName - The name of the `WorkerEntrypoint` export to wrap
|
|
336
|
+
* @returns A `WorkerEntrypoint` constructor that acts as a proxy to the user code
|
|
337
|
+
*/
|
|
338
|
+
function createWorkerEntrypointWrapper(exportName) {
|
|
339
|
+
class Wrapper extends WorkerEntrypoint {
|
|
340
|
+
constructor(ctx, env) {
|
|
341
|
+
super(ctx, env);
|
|
342
|
+
return new Proxy(this, { get(target, key, receiver) {
|
|
343
|
+
const value = Reflect.get(target, key, receiver);
|
|
344
|
+
if (value !== void 0) return value;
|
|
345
|
+
if (typeof key === "symbol" || IGNORED_KEYS.includes(key) || DURABLE_OBJECT_KEYS.includes(key)) return;
|
|
346
|
+
return getRpcPropertyCallableThenable(key, getWorkerEntrypointRpcProperty.call(receiver, exportName, key));
|
|
347
|
+
} });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
for (const key of WORKER_ENTRYPOINT_KEYS) Wrapper.prototype[key] = async function(arg) {
|
|
351
|
+
return maybeCaptureError({
|
|
352
|
+
isEntryWorker,
|
|
353
|
+
exportName,
|
|
354
|
+
key
|
|
355
|
+
}, async () => {
|
|
356
|
+
if (key === "fetch") {
|
|
357
|
+
const request = arg;
|
|
358
|
+
const url = new URL(request.url);
|
|
359
|
+
if (url.pathname === INIT_PATH) {
|
|
360
|
+
if (request.headers.get(IS_PARENT_ENVIRONMENT_HEADER) === "true") {
|
|
361
|
+
const workerEntryPathHeader = request.headers.get(WORKER_ENTRY_PATH_HEADER);
|
|
362
|
+
if (!workerEntryPathHeader) throw new Error(`Unexpected error: "${WORKER_ENTRY_PATH_HEADER}" header not set.`);
|
|
363
|
+
const isEntryWorkerHeader = request.headers.get(IS_ENTRY_WORKER_HEADER);
|
|
364
|
+
if (!isEntryWorkerHeader) throw new Error(`Unexpected error: "${IS_ENTRY_WORKER_HEADER}" header not set.`);
|
|
365
|
+
workerEntryPath = decodeURIComponent(workerEntryPathHeader);
|
|
366
|
+
isEntryWorker = isEntryWorkerHeader === "true";
|
|
367
|
+
}
|
|
368
|
+
return this.env.__VITE_RUNNER_OBJECT__.get("singleton").fetch(request);
|
|
369
|
+
}
|
|
370
|
+
if (url.pathname === GET_EXPORT_TYPES_PATH) {
|
|
371
|
+
const workerEntryExportTypes = await getWorkerEntryExportTypes();
|
|
372
|
+
return Response.json(workerEntryExportTypes);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const exportValue = await getWorkerEntryExport(workerEntryPath, exportName);
|
|
376
|
+
const userEnv = stripInternalEnv(this.env);
|
|
377
|
+
if (typeof exportValue === "object" && exportValue !== null) {
|
|
378
|
+
const maybeFn = exportValue[key];
|
|
379
|
+
if (typeof maybeFn !== "function") throw new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to define a \`${key}()\` function.`);
|
|
380
|
+
return maybeFn.call(exportValue, arg, userEnv, this.ctx);
|
|
381
|
+
} else if (typeof exportValue === "function") {
|
|
382
|
+
const instance = new exportValue(this.ctx, userEnv);
|
|
383
|
+
if (!(instance instanceof WorkerEntrypoint)) throw new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to be a subclass of \`WorkerEntrypoint\`.`);
|
|
384
|
+
const maybeFn = instance[key];
|
|
385
|
+
if (typeof maybeFn !== "function") throw new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to define a \`${key}()\` method.`);
|
|
386
|
+
return maybeFn.call(instance, arg);
|
|
387
|
+
} else return /* @__PURE__ */ new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to be an object or a class.`);
|
|
388
|
+
});
|
|
389
|
+
};
|
|
390
|
+
return Wrapper;
|
|
391
|
+
}
|
|
392
|
+
/** Symbol key for storing the `DurableObject` instance */
|
|
393
|
+
const kInstance = Symbol("kInstance");
|
|
394
|
+
/** Symbol key for the instance initialization method */
|
|
395
|
+
const kEnsureInstance = Symbol("kEnsureInstance");
|
|
396
|
+
/**
|
|
397
|
+
* Retrieves an RPC property from a `DurableObject` export, ensuring an instance is properly initialized and returning the bound method or property value.
|
|
398
|
+
* @param exportName - The name of the `DurableObject` export
|
|
399
|
+
* @param key - The property key to access on the `DurableObject` instance
|
|
400
|
+
* @returns The property value, with methods bound to the instance
|
|
401
|
+
* @throws TypeError if the export is not a `DurableObject` subclass
|
|
402
|
+
*/
|
|
403
|
+
async function getDurableObjectRpcProperty(exportName, key) {
|
|
404
|
+
const { ctor, instance } = await this[kEnsureInstance]();
|
|
405
|
+
if (!(instance instanceof DurableObject)) throw new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to be a subclass of \`DurableObject\` for RPC.`);
|
|
406
|
+
const value = getRpcProperty(ctor, instance, key);
|
|
407
|
+
if (typeof value === "function") return value.bind(instance);
|
|
408
|
+
return value;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Creates a proxy wrapper for `DurableObject` classes that enables RPC functionality.
|
|
412
|
+
* The wrapper manages instance lifecycle and delegates method calls to the user code, handling both direct method calls and RPC property access.
|
|
413
|
+
* @param exportName - The name of the `DurableObject` export to wrap
|
|
414
|
+
* @returns A `DurableObject` constructor that acts as a proxy to the user code
|
|
415
|
+
*/
|
|
416
|
+
function createDurableObjectWrapper(exportName) {
|
|
417
|
+
class Wrapper extends DurableObject {
|
|
418
|
+
[kInstance];
|
|
419
|
+
constructor(ctx, env) {
|
|
420
|
+
super(ctx, env);
|
|
421
|
+
return new Proxy(this, { get(target, key, receiver) {
|
|
422
|
+
const value = Reflect.get(target, key, receiver);
|
|
423
|
+
if (value !== void 0) return value;
|
|
424
|
+
if (typeof key === "symbol" || IGNORED_KEYS.includes(key) || WORKER_ENTRYPOINT_KEYS.includes(key)) return;
|
|
425
|
+
return getRpcPropertyCallableThenable(key, getDurableObjectRpcProperty.call(receiver, exportName, key));
|
|
426
|
+
} });
|
|
427
|
+
}
|
|
428
|
+
async [kEnsureInstance]() {
|
|
429
|
+
const ctor = await getWorkerEntryExport(workerEntryPath, exportName);
|
|
430
|
+
if (typeof ctor !== "function") throw new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to be a subclass of \`DurableObject\`.`);
|
|
431
|
+
if (!this[kInstance] || this[kInstance].ctor !== ctor) {
|
|
432
|
+
const userEnv = stripInternalEnv(this.env);
|
|
433
|
+
this[kInstance] = {
|
|
434
|
+
ctor,
|
|
435
|
+
instance: new ctor(this.ctx, userEnv)
|
|
436
|
+
};
|
|
437
|
+
await this.ctx.blockConcurrencyWhile(async () => {});
|
|
438
|
+
}
|
|
439
|
+
return this[kInstance];
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
for (const key of DURABLE_OBJECT_KEYS) Wrapper.prototype[key] = async function(...args) {
|
|
443
|
+
const { instance } = await this[kEnsureInstance]();
|
|
444
|
+
const maybeFn = instance[key];
|
|
445
|
+
if (typeof maybeFn !== "function") throw new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to define a \`${key}()\` function.`);
|
|
446
|
+
return maybeFn.apply(instance, args);
|
|
447
|
+
};
|
|
448
|
+
return Wrapper;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Creates a proxy wrapper for `WorkflowEntrypoint` classes.
|
|
452
|
+
* The wrapper delegates method calls to the user code.
|
|
453
|
+
* @param exportName - The name of the `WorkflowEntrypoint` export to wrap
|
|
454
|
+
* @returns A `WorkflowEntrypoint` constructor that acts as a proxy to the user code
|
|
455
|
+
*/
|
|
456
|
+
function createWorkflowEntrypointWrapper(exportName) {
|
|
457
|
+
class Wrapper extends WorkflowEntrypoint {}
|
|
458
|
+
for (const key of WORKFLOW_ENTRYPOINT_KEYS) Wrapper.prototype[key] = async function(...args) {
|
|
459
|
+
const ctor = await getWorkerEntryExport(workerEntryPath, exportName);
|
|
460
|
+
const userEnv = stripInternalEnv(this.env);
|
|
461
|
+
const instance = new ctor(this.ctx, userEnv);
|
|
462
|
+
if (!(instance instanceof WorkflowEntrypoint)) throw new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to be a subclass of \`WorkflowEntrypoint\`.`);
|
|
463
|
+
const maybeFn = instance[key];
|
|
464
|
+
if (typeof maybeFn !== "function") throw new TypeError(`Expected "${exportName}" export of "${workerEntryPath}" to define a \`${key}()\` function.`);
|
|
465
|
+
return maybeFn.apply(instance, args);
|
|
466
|
+
};
|
|
467
|
+
return Wrapper;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
//#endregion
|
|
471
|
+
export { __VITE_RUNNER_OBJECT__, createDurableObjectWrapper, createWorkerEntrypointWrapper, createWorkflowEntrypointWrapper };
|