env-runner 0.2.3 → 0.3.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 +154 -19
- package/dist/_chunks/common-base-runner.d.mts +52 -14
- package/dist/_chunks/common-base-runner.mjs +123 -32
- package/dist/_chunks/common-process-data.mjs +13 -0
- package/dist/_chunks/common-worker-utils.mjs +464 -73
- package/dist/_chunks/deno-process-runner.mjs +2 -6
- package/dist/_chunks/lexer.mjs +2 -0
- package/dist/_chunks/libs/cjs-module-lexer.mjs +6 -1
- package/dist/_chunks/miniflare-runner.d.mts +21 -12
- package/dist/_chunks/miniflare-runner.mjs +266 -96
- package/dist/_chunks/node-worker-runner.mjs +1 -2
- package/dist/_chunks/server.mjs +20 -5
- package/dist/_chunks/types.d.mts +36 -0
- package/dist/_chunks/virtual-loader.mjs +303 -29
- package/dist/index.d.mts +17 -4
- package/dist/runners/bun-process/runner.mjs +4 -8
- package/dist/runners/bun-process/worker.mjs +8 -8
- package/dist/runners/deno-process/worker.mjs +8 -8
- package/dist/runners/node-process/runner.mjs +2 -6
- package/dist/runners/node-process/worker.mjs +8 -8
- package/dist/runners/node-worker/worker.mjs +6 -7
- package/dist/runners/self/runner.d.mts +2 -1
- package/dist/runners/self/runner.mjs +8 -0
- package/package.json +11 -11
- package/dist/_chunks/common-host-env.mjs +0 -11
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import { expandVirtualInvalidation, stripVirtualTypeScript, virtualModuleFormat } from "./virtual-loader.mjs";
|
|
1
|
+
import { encodeVirtualModules, expandVirtualInvalidation, stripVirtualTypeScript, unsupportedVirtualJSXError, virtualModuleCode, virtualModuleCodeSource, virtualModuleFormat } from "./virtual-loader.mjs";
|
|
2
2
|
import { BaseEnvRunner } from "./common-base-runner.mjs";
|
|
3
|
-
import { isVirtualSpecifier } from "./common-worker-utils.mjs";
|
|
4
3
|
import { resolveRuntimeDep } from "./common-runtime-deps.mjs";
|
|
5
4
|
import { init, parse } from "./libs/cjs-module-lexer.mjs";
|
|
6
5
|
import { init as init$1, parse as parse$1 } from "./libs/es-module-lexer.mjs";
|
|
7
6
|
import { createRequire } from "node:module";
|
|
8
7
|
import { proxyUpgrade } from "httpxy";
|
|
9
|
-
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
11
8
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
10
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
12
11
|
import { resolveModulePath } from "exsolve";
|
|
13
12
|
import { tmpdir } from "node:os";
|
|
14
13
|
import { parseEnv } from "node:util";
|
|
15
|
-
const IPC_PATH = "/__env_runner_ipc";
|
|
14
|
+
const IPC_PATH$1 = "/__env_runner_ipc";
|
|
16
15
|
const IPC_BINDING = "__ENV_RUNNER_IPC";
|
|
17
16
|
const UNSAFE_EVAL_BINDING = "__ENV_RUNNER_UNSAFE_EVAL__";
|
|
18
17
|
function generateWrapper(entryPath, opts) {
|
|
19
18
|
const processShim = opts?.nodeCompat === false ? "" : `import __process from "node:process";
|
|
20
19
|
if (!globalThis.process) { globalThis.process = __process; }`;
|
|
21
20
|
const staticReExport = opts?.dynamicOnly ? "" : `export * from ${JSON.stringify(entryPath)};`;
|
|
22
|
-
const explicitExports = opts?.dynamicOnly && opts.exports?.length ? opts.exports.map((name) => `export { ${name} } from ${JSON.stringify(entryPath)};`).join("\n") : "";
|
|
21
|
+
const explicitExports = typeof opts?.exports === "string" ? `export * from ${JSON.stringify(opts.exports)};` : opts?.dynamicOnly && opts.exports?.length ? opts.exports.map((name) => `export { ${name} } from ${JSON.stringify(entryPath)};`).join("\n") : "";
|
|
23
22
|
const fetchBody = opts?.captureErrors ?? true ? `try {
|
|
24
23
|
return await __server.fetch(request, env, ctx);
|
|
25
24
|
} catch (e) {
|
|
@@ -38,7 +37,7 @@ if (!globalThis.process) { globalThis.process = __process; }`;
|
|
|
38
37
|
${staticReExport}
|
|
39
38
|
${explicitExports}
|
|
40
39
|
|
|
41
|
-
const __IPC_PATH = "${IPC_PATH}";
|
|
40
|
+
const __IPC_PATH = "${IPC_PATH$1}";
|
|
42
41
|
const __IPC_BINDING = "${IPC_BINDING}";
|
|
43
42
|
const __UNSAFE_EVAL_BINDING = "${UNSAFE_EVAL_BINDING}";
|
|
44
43
|
const __entryPath = ${JSON.stringify(entryPath)};
|
|
@@ -46,7 +45,10 @@ let __userEntry;
|
|
|
46
45
|
let __server;
|
|
47
46
|
let __ipcInitialized = false;
|
|
48
47
|
let __serverWs;
|
|
49
|
-
|
|
48
|
+
// Raw env of the latest user request. Kept after the request ends: requests
|
|
49
|
+
// overlap and streamed bodies outlive fetch(), and unlike \`__serverWs\` the
|
|
50
|
+
// IPC binding works from any request context.
|
|
51
|
+
let __ipcEnv;
|
|
50
52
|
|
|
51
53
|
const __userEnvs = new WeakMap();
|
|
52
54
|
|
|
@@ -132,9 +134,16 @@ async function __loadEntry(env, path) {
|
|
|
132
134
|
return mod.default || mod;
|
|
133
135
|
}
|
|
134
136
|
|
|
137
|
+
// Where an entry load error was thrown (first stack frame), so one thrown by a
|
|
138
|
+
// virtual module names its key (\`#config:2:7\`). workerd's messages don't.
|
|
139
|
+
function __errorLocation(e) {
|
|
140
|
+
const location = /\\n\\s+at (?:async )?(?:.* \\()?([^\\n()]+:\\d+:\\d+)\\)?/.exec(String(e?.stack))?.[1];
|
|
141
|
+
return location ? " (at " + location + ")" : "";
|
|
142
|
+
}
|
|
143
|
+
|
|
135
144
|
function __sendMessage(message) {
|
|
136
145
|
const payload = JSON.stringify(message);
|
|
137
|
-
const env =
|
|
146
|
+
const env = __ipcEnv;
|
|
138
147
|
if (env && env[__IPC_BINDING]) {
|
|
139
148
|
env[__IPC_BINDING].fetch("http://localhost/__ipc", {
|
|
140
149
|
method: "POST",
|
|
@@ -206,8 +215,9 @@ export default {
|
|
|
206
215
|
async fetch(request, env, ctx) {
|
|
207
216
|
const url = new URL(request.url);
|
|
208
217
|
|
|
209
|
-
//
|
|
210
|
-
|
|
218
|
+
// IPC: a plain request loads the entry (204, or a 500 with the error), then
|
|
219
|
+
// the WebSocket upgrade opens the channel.
|
|
220
|
+
if (url.pathname === __IPC_PATH) {
|
|
211
221
|
try {
|
|
212
222
|
if (!__userEntry) {
|
|
213
223
|
const entry = await __loadEntry(env, __entryPath);
|
|
@@ -215,7 +225,11 @@ export default {
|
|
|
215
225
|
__userEntry = entry;
|
|
216
226
|
}
|
|
217
227
|
} catch (e) {
|
|
218
|
-
|
|
228
|
+
const message = "Failed to load entry: " + String(e) + __errorLocation(e);
|
|
229
|
+
return new Response(message, { status: 500 });
|
|
230
|
+
}
|
|
231
|
+
if (request.headers.get("upgrade") !== "websocket") {
|
|
232
|
+
return new Response(null, { status: 204 });
|
|
219
233
|
}
|
|
220
234
|
|
|
221
235
|
const pair = new WebSocketPair();
|
|
@@ -243,18 +257,15 @@ export default {
|
|
|
243
257
|
return new Response("Worker not initialized", { status: 503 });
|
|
244
258
|
}
|
|
245
259
|
|
|
260
|
+
__ipcEnv = env;
|
|
261
|
+
|
|
246
262
|
// Handle WebSocket upgrade via crossws cloudflare adapter
|
|
247
263
|
if (__userEntry.websocket && request.headers.get("upgrade") === "websocket") {
|
|
248
264
|
const adapter = await __initCrossws(env, __userEntry.websocket);
|
|
249
265
|
return adapter.handleUpgrade(request, __userEnv(env), ctx);
|
|
250
266
|
}
|
|
251
267
|
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
${fetchBody}
|
|
255
|
-
} finally {
|
|
256
|
-
__currentEnv = undefined;
|
|
257
|
-
}
|
|
268
|
+
${fetchBody}
|
|
258
269
|
}
|
|
259
270
|
};
|
|
260
271
|
`;
|
|
@@ -895,6 +906,7 @@ function mapBindingArray(arr, keyField, value) {
|
|
|
895
906
|
}
|
|
896
907
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
897
908
|
}
|
|
909
|
+
const IPC_PATH = "/__env_runner_ipc";
|
|
898
910
|
const _miniflareCache = /* @__PURE__ */ new Map();
|
|
899
911
|
var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
900
912
|
#miniflare;
|
|
@@ -902,7 +914,6 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
902
914
|
#transformRequest;
|
|
903
915
|
#reloadCounter = 0;
|
|
904
916
|
#virtual;
|
|
905
|
-
#virtualVersions = /* @__PURE__ */ new Map();
|
|
906
917
|
#cacheEntry;
|
|
907
918
|
#ws;
|
|
908
919
|
#persistent;
|
|
@@ -959,8 +970,12 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
959
970
|
for (let i = 0; i < 5 && !this._address && !this.closed; i++) await new Promise((r) => setTimeout(r, 100 * Math.pow(2, i)));
|
|
960
971
|
if (!this.#miniflare || this.closed) return new Response("miniflare env runner is unavailable", { status: 503 });
|
|
961
972
|
const resolved = this._resolveFetchInput(input);
|
|
962
|
-
const request = typeof resolved === "string" || resolved instanceof URL ? new Request(resolved,
|
|
973
|
+
const request = typeof resolved === "string" || resolved instanceof URL ? new Request(resolved, {
|
|
974
|
+
...init,
|
|
975
|
+
redirect: "manual"
|
|
976
|
+
}) : new Request(new Request(resolved.url, resolved), {
|
|
963
977
|
...init,
|
|
978
|
+
redirect: "manual",
|
|
964
979
|
referrer: init?.referrer ?? resolved.referrer,
|
|
965
980
|
referrerPolicy: init?.referrerPolicy ?? resolved.referrerPolicy
|
|
966
981
|
});
|
|
@@ -987,6 +1002,7 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
987
1002
|
}));
|
|
988
1003
|
}
|
|
989
1004
|
async reloadModule(timeout = 5e3) {
|
|
1005
|
+
await this._virtualUpdates;
|
|
990
1006
|
if (!this.#ws) throw new Error("Miniflare env runner should be initialized before reloading.");
|
|
991
1007
|
if (!this._data?.entry) return;
|
|
992
1008
|
this.#reloadCounter++;
|
|
@@ -1000,15 +1016,27 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1000
1016
|
send: (message) => this.#ws.send(JSON.stringify(message))
|
|
1001
1017
|
});
|
|
1002
1018
|
}
|
|
1003
|
-
async
|
|
1019
|
+
async _applyVirtualUpdates(changes) {
|
|
1004
1020
|
const virtual = this.#virtual;
|
|
1005
|
-
if (!virtual
|
|
1006
|
-
|
|
1007
|
-
|
|
1021
|
+
if (!virtual) throw new Error("Miniflare env runner should be initialized before updating modules.");
|
|
1022
|
+
const prepared = {};
|
|
1023
|
+
for (const [key, module] of Object.entries(changes)) if (module !== null) prepared[key] = await this.#prepareVirtualModule(key, module);
|
|
1024
|
+
await init$1;
|
|
1025
|
+
const merged = {
|
|
1026
|
+
...virtual.sources,
|
|
1027
|
+
...prepared
|
|
1028
|
+
};
|
|
1029
|
+
const importers = virtualImporters(merged, createVirtualKeyResolver(Object.keys(merged)));
|
|
1030
|
+
const invalidated = expandVirtualInvalidation(merged, Object.keys(changes), importers);
|
|
1031
|
+
for (const key of Object.keys(changes)) if (Object.hasOwn(prepared, key)) {
|
|
1032
|
+
virtual.sources[key] = prepared[key];
|
|
1033
|
+
virtual.removed.delete(key);
|
|
1034
|
+
} else if (Object.hasOwn(virtual.sources, key)) {
|
|
1035
|
+
delete virtual.sources[key];
|
|
1036
|
+
virtual.removed.add(key);
|
|
1008
1037
|
}
|
|
1009
|
-
const
|
|
1010
|
-
|
|
1011
|
-
for (const key of expandVirtualInvalidation(virtual, specifier)) this.#virtualVersions.set(key, (this.#virtualVersions.get(key) ?? 0) + 1);
|
|
1038
|
+
for (const key of invalidated) virtual.versions.set(key, ++virtual.version);
|
|
1039
|
+
refreshVirtualKeyResolvers(virtual);
|
|
1012
1040
|
if (this.#cacheKey && _miniflareCache.get(this.#cacheKey) === this.#cacheEntry) _miniflareCache.delete(this.#cacheKey);
|
|
1013
1041
|
}
|
|
1014
1042
|
_hasRuntime() {
|
|
@@ -1066,23 +1094,37 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1066
1094
|
} catch {}
|
|
1067
1095
|
}
|
|
1068
1096
|
async #prepareVirtualModules() {
|
|
1069
|
-
const virtual = this._data?.virtual;
|
|
1070
|
-
if (!virtual || Object.keys(virtual).length === 0) return;
|
|
1097
|
+
const virtual = this._data?.virtual ?? {};
|
|
1071
1098
|
const out = {};
|
|
1072
|
-
for (const [
|
|
1099
|
+
for (const [key, module] of Object.entries(virtual)) out[key] = await this.#prepareVirtualModule(key, module);
|
|
1073
1100
|
return out;
|
|
1074
1101
|
}
|
|
1075
|
-
async #
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1102
|
+
async #prepareVirtualModule(key, module) {
|
|
1103
|
+
const format = virtualModuleFormat(key, module);
|
|
1104
|
+
const source = typeof module === "string" ? module : module.source;
|
|
1105
|
+
switch (format) {
|
|
1106
|
+
case "module-typescript":
|
|
1107
|
+
case "commonjs-typescript": return {
|
|
1108
|
+
source: stripVirtualTypeScript(key, source, await _getStripTypeScriptTypes(), {
|
|
1109
|
+
requirement: "on the host (workerd does not parse TypeScript)",
|
|
1110
|
+
remedy: "upgrade Node.js"
|
|
1111
|
+
}),
|
|
1112
|
+
format: format === "module-typescript" ? "module" : "commonjs"
|
|
1113
|
+
};
|
|
1114
|
+
case "jsx":
|
|
1115
|
+
case "tsx": throw unsupportedVirtualJSXError(key, format, "workerd");
|
|
1116
|
+
}
|
|
1117
|
+
return {
|
|
1118
|
+
source,
|
|
1119
|
+
format
|
|
1120
|
+
};
|
|
1081
1121
|
}
|
|
1082
1122
|
async #initAsync() {
|
|
1083
|
-
const
|
|
1123
|
+
const miniflare = await this.#resolveMiniflare();
|
|
1124
|
+
const supportedCompatibilityDate = await resolveSupportedCompatibilityDate(miniflare);
|
|
1084
1125
|
const entryPath = this._data?.entry;
|
|
1085
|
-
const
|
|
1126
|
+
const initialVirtual = await this.#prepareVirtualModules();
|
|
1127
|
+
const virtual = createMiniflareVirtualModules({ ...initialVirtual });
|
|
1086
1128
|
this.#virtual = virtual;
|
|
1087
1129
|
const { options: wranglerOptions, configFile: wranglerConfigFile } = await loadWranglerConfig({
|
|
1088
1130
|
wrangler: this.#wrangler,
|
|
@@ -1118,14 +1160,15 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1118
1160
|
...uValue
|
|
1119
1161
|
};
|
|
1120
1162
|
}
|
|
1163
|
+
const ipc = { runner: this };
|
|
1121
1164
|
if (entryPath && !options.script && !options.scriptPath) {
|
|
1122
|
-
const
|
|
1123
|
-
const
|
|
1165
|
+
const entryKey = virtual.keyOf(entryPath) ?? virtual.keyOf(resolve(entryPath));
|
|
1166
|
+
const entryIsVirtual = entryKey !== void 0;
|
|
1167
|
+
const resolvedEntry = entryIsVirtual ? virtualKeyPath(entryKey) ?? entryKey : resolve(entryPath);
|
|
1124
1168
|
const entryBase = isAbsolute(resolvedEntry) ? resolvedEntry : resolve("__env_runner_virtual_entry__.mjs");
|
|
1125
1169
|
const entryDir = dirname(entryBase);
|
|
1126
|
-
const entrySource = entryIsVirtual ? virtual[
|
|
1127
|
-
const detectedExports = this.#exports === false || this.#exports ===
|
|
1128
|
-
if (entryIsVirtual && detectedExports.length > 0) throw new Error(`[env-runner] named exports (${detectedExports.join(", ")}) are not supported with a virtual entry on the miniflare runner; pass \`exports: false\` or use a real entry file.`);
|
|
1170
|
+
const entrySource = entryIsVirtual ? virtualModuleCodeSource(entryKey, virtual.sources[entryKey]) : _tryReadFile(resolvedEntry);
|
|
1171
|
+
const detectedExports = this.#exports === false || typeof this.#exports === "string" ? [] : detectExportedClasses(entrySource, typeof this.#exports === "object" ? this.#exports : {});
|
|
1129
1172
|
if (detectedExports.length > 0) {
|
|
1130
1173
|
const existingDOs = isPlainObject(options.durableObjects) ? options.durableObjects : {};
|
|
1131
1174
|
const boundClasses = new Set(Object.values(existingDOs).map((b) => typeof b === "string" ? b : isPlainObject(b) && !b.scriptName ? b.className : void 0));
|
|
@@ -1136,13 +1179,23 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1136
1179
|
}
|
|
1137
1180
|
options.durableObjects = autoDOs;
|
|
1138
1181
|
}
|
|
1139
|
-
|
|
1182
|
+
const script = generateWrapper(entryIsVirtual ? toWorkerdPath(resolvedEntry) : resolvedEntry, {
|
|
1140
1183
|
dynamicOnly: true,
|
|
1141
1184
|
captureErrors: this.#captureErrors,
|
|
1142
|
-
exports: detectedExports,
|
|
1185
|
+
exports: typeof this.#exports === "string" ? this.#exports : detectedExports,
|
|
1143
1186
|
nodeCompat: !options.compatibilityFlags.includes("no_nodejs_compat")
|
|
1144
1187
|
});
|
|
1145
|
-
|
|
1188
|
+
const scriptPath = entryDir + "/__env_runner_wrapper.mjs";
|
|
1189
|
+
const skipLocator = typeof this.#exports === "string" || entryIsVirtual && detectedExports.length > 0;
|
|
1190
|
+
if (skipLocator) options.modules = [{
|
|
1191
|
+
type: "ESModule",
|
|
1192
|
+
path: scriptPath,
|
|
1193
|
+
contents: script
|
|
1194
|
+
}];
|
|
1195
|
+
else {
|
|
1196
|
+
options.script = script;
|
|
1197
|
+
options.scriptPath = scriptPath;
|
|
1198
|
+
}
|
|
1146
1199
|
if (!options.modulesRoot) options.modulesRoot = "/";
|
|
1147
1200
|
options.unsafeEvalBinding = UNSAFE_EVAL_BINDING;
|
|
1148
1201
|
options.serviceBindings = {
|
|
@@ -1150,12 +1203,12 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1150
1203
|
[IPC_BINDING]: async (request) => {
|
|
1151
1204
|
try {
|
|
1152
1205
|
const message = await request.json();
|
|
1153
|
-
|
|
1206
|
+
ipc.runner._handleMessage(message);
|
|
1154
1207
|
} catch {}
|
|
1155
1208
|
return new Response(null, { status: 204 });
|
|
1156
1209
|
}
|
|
1157
1210
|
};
|
|
1158
|
-
if (this.#transformRequest && !options.modulesRules) options.modulesRules = [{
|
|
1211
|
+
if (this.#transformRequest && !options.modulesRules && !miniflare.convertV4MiniflareOptions && !skipLocator) options.modulesRules = [{
|
|
1159
1212
|
type: "ESModule",
|
|
1160
1213
|
include: [
|
|
1161
1214
|
"**/*.ts",
|
|
@@ -1167,10 +1220,23 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1167
1220
|
if (!options.unsafeModuleFallbackService) {
|
|
1168
1221
|
const _require = createRequire(entryBase);
|
|
1169
1222
|
const _virtual = virtual;
|
|
1170
|
-
const _virtualVersions = this.#virtualVersions;
|
|
1171
1223
|
const _transformRequest = this.#transformRequest;
|
|
1172
1224
|
const _exportConditions = this.#exportConditions;
|
|
1173
|
-
const _applyVirtualVersions = (code) => applyVirtualVersions(code,
|
|
1225
|
+
const _applyVirtualVersions = (code, modulePath) => applyVirtualVersions(code, _virtual.versions, (specifier) => _virtual.versionedKeyOf(specifier, modulePath));
|
|
1226
|
+
const _serveVirtual = (module, modulePath) => {
|
|
1227
|
+
const { source } = module;
|
|
1228
|
+
switch (module.format) {
|
|
1229
|
+
case "module": return { esModule: _applyVirtualVersions(source, modulePath) };
|
|
1230
|
+
case "commonjs": return {
|
|
1231
|
+
commonJsModule: source,
|
|
1232
|
+
namedExports: commonJSExports(source).filter((e) => e !== "default")
|
|
1233
|
+
};
|
|
1234
|
+
case "json": return { json: source };
|
|
1235
|
+
case "text": return { text: source };
|
|
1236
|
+
case "bytes": return { esModule: virtualModuleCode("bytes", source) };
|
|
1237
|
+
case "wasm": return { wasm: Array.from(source) };
|
|
1238
|
+
}
|
|
1239
|
+
};
|
|
1174
1240
|
options.unsafeUseModuleFallbackService = true;
|
|
1175
1241
|
const modulePathMap = /* @__PURE__ */ new Map();
|
|
1176
1242
|
const _lexersReady = Promise.all([ensureCjsLexer(), init$1]);
|
|
@@ -1183,24 +1249,30 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1183
1249
|
if (!specifier) return new Response(null, { status: 404 });
|
|
1184
1250
|
const cleanSpecifier = specifier.split("?")[0] || specifier;
|
|
1185
1251
|
const cleanRaw = rawSpecifier?.split("?")[0];
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1252
|
+
const bareSpecifier = cleanSpecifier.startsWith("/") ? cleanSpecifier.slice(1) : cleanSpecifier;
|
|
1253
|
+
const referrerKey = referrer.startsWith("/") ? referrer.slice(1) : referrer;
|
|
1254
|
+
const referrerPath = modulePathMap.get(referrerKey);
|
|
1255
|
+
const virtualKey = [
|
|
1256
|
+
cleanRaw,
|
|
1257
|
+
cleanSpecifier,
|
|
1258
|
+
bareSpecifier
|
|
1259
|
+
].find((key) => key !== void 0 && Object.hasOwn(_virtual.sources, key)) ?? (cleanRaw ? _virtual.keyOf(cleanRaw, referrerPath) : void 0) ?? _virtual.keyOf(cleanSpecifier);
|
|
1260
|
+
if (virtualKey !== void 0) {
|
|
1261
|
+
const query = specifier.includes("?") ? specifier.slice(specifier.indexOf("?")) : "";
|
|
1262
|
+
const keyPath = virtualKeyPath(virtualKey);
|
|
1263
|
+
if (keyPath && cleanRaw?.startsWith("file:") && cleanSpecifier !== keyPath && cleanSpecifier.includes("file:")) {
|
|
1264
|
+
const location = Buffer.from(toWorkerdPath(keyPath) + query, "utf8").toString("latin1");
|
|
1265
|
+
return new Response(null, {
|
|
1266
|
+
status: 301,
|
|
1267
|
+
headers: { location }
|
|
1202
1268
|
});
|
|
1203
1269
|
}
|
|
1270
|
+
const name = bareSpecifier + query;
|
|
1271
|
+
if (keyPath) modulePathMap.set(name, keyPath);
|
|
1272
|
+
return Response.json({
|
|
1273
|
+
name,
|
|
1274
|
+
..._serveVirtual(_virtual.sources[virtualKey], keyPath)
|
|
1275
|
+
});
|
|
1204
1276
|
}
|
|
1205
1277
|
let resolvedPath;
|
|
1206
1278
|
const fileUrlRaw = cleanRaw || cleanSpecifier;
|
|
@@ -1209,9 +1281,8 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1209
1281
|
} catch {
|
|
1210
1282
|
return new Response(null, { status: 404 });
|
|
1211
1283
|
}
|
|
1212
|
-
else if (cleanRaw && !cleanRaw.startsWith(".") && !cleanRaw.startsWith("/")) {
|
|
1213
|
-
const
|
|
1214
|
-
const referrerReal = modulePathMap.get(referrerKey);
|
|
1284
|
+
else if (cleanRaw && !cleanRaw.startsWith(".") && !cleanRaw.startsWith("/") && !isAbsolute(cleanRaw)) {
|
|
1285
|
+
const referrerReal = referrerPath;
|
|
1215
1286
|
const contextRequire = referrerReal ? createRequire(referrerReal) : _require;
|
|
1216
1287
|
if (cleanRaw.startsWith("cloudflare:")) return new Response(null, { status: 404 });
|
|
1217
1288
|
if (cleanRaw.startsWith("node:")) {
|
|
@@ -1235,11 +1306,11 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1235
1306
|
});
|
|
1236
1307
|
}
|
|
1237
1308
|
} else {
|
|
1238
|
-
const
|
|
1239
|
-
const referrerReal = modulePathMap.get(referrerKey) || (referrer.startsWith("/") ? referrer : "/" + referrer);
|
|
1309
|
+
const referrerReal = referrerPath || (referrer.startsWith("/") ? referrer : "/" + referrer);
|
|
1240
1310
|
const referrerDir = dirname(referrerReal);
|
|
1241
1311
|
const raw = cleanRaw || cleanSpecifier;
|
|
1242
1312
|
if (raw.startsWith(".")) resolvedPath = resolve(referrerDir, raw);
|
|
1313
|
+
else if (cleanRaw && isAbsolute(cleanRaw) && !cleanRaw.startsWith("/")) resolvedPath = cleanRaw;
|
|
1243
1314
|
else if (cleanSpecifier.startsWith("/")) resolvedPath = cleanSpecifier;
|
|
1244
1315
|
else try {
|
|
1245
1316
|
resolvedPath = _require.resolve(raw);
|
|
@@ -1255,7 +1326,7 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1255
1326
|
modulePathMap.set(name, resolvedPath);
|
|
1256
1327
|
return Response.json({
|
|
1257
1328
|
name,
|
|
1258
|
-
esModule: _applyVirtualVersions(result.code)
|
|
1329
|
+
esModule: _applyVirtualVersions(result.code, resolvedPath)
|
|
1259
1330
|
});
|
|
1260
1331
|
}
|
|
1261
1332
|
} catch {}
|
|
@@ -1264,7 +1335,7 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1264
1335
|
modulePathMap.set(name, resolvedPath);
|
|
1265
1336
|
if (resolvedPath.endsWith(".mjs") || !resolvedPath.endsWith(".cjs") && /\b(import\s|import\(|export\s|export\{|import\.meta\b)/.test(contents)) return Response.json({
|
|
1266
1337
|
name,
|
|
1267
|
-
esModule: _applyVirtualVersions(contents)
|
|
1338
|
+
esModule: _applyVirtualVersions(contents, resolvedPath)
|
|
1268
1339
|
});
|
|
1269
1340
|
const cjsSuffix = "?__cjs";
|
|
1270
1341
|
if (specifier.endsWith(cjsSuffix)) return Response.json({
|
|
@@ -1286,31 +1357,35 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
1286
1357
|
this.#cacheKey = computeCacheKey(entryPath, {
|
|
1287
1358
|
...this.#miniflareOptions,
|
|
1288
1359
|
_exportConditions: this.#exportConditions,
|
|
1289
|
-
|
|
1360
|
+
_exports: this.#exports,
|
|
1361
|
+
_virtual: encodeVirtualModules(initialVirtual)
|
|
1290
1362
|
});
|
|
1291
1363
|
const cached = _miniflareCache.get(this.#cacheKey);
|
|
1292
1364
|
if (cached) {
|
|
1293
1365
|
this.#miniflare = cached.mf;
|
|
1294
1366
|
cached.refCount++;
|
|
1295
1367
|
this.#cacheEntry = cached;
|
|
1368
|
+
cached.ipc.runner = this;
|
|
1296
1369
|
this.#virtual = cached.virtual;
|
|
1297
|
-
this.#virtualVersions = cached.versions;
|
|
1298
1370
|
}
|
|
1299
1371
|
}
|
|
1300
1372
|
if (!this.#miniflare) {
|
|
1301
|
-
this.#miniflare = new Miniflare(options);
|
|
1373
|
+
this.#miniflare = new miniflare.Miniflare(toMiniflareOptions(miniflare, options));
|
|
1302
1374
|
await this.#miniflare.ready;
|
|
1303
1375
|
if (this.#persistent && this.#cacheKey) {
|
|
1304
1376
|
this.#cacheEntry = {
|
|
1305
1377
|
mf: this.#miniflare,
|
|
1306
1378
|
refCount: 1,
|
|
1307
1379
|
virtual,
|
|
1308
|
-
|
|
1380
|
+
ipc
|
|
1309
1381
|
};
|
|
1310
1382
|
_miniflareCache.set(this.#cacheKey, this.#cacheEntry);
|
|
1311
1383
|
}
|
|
1312
1384
|
}
|
|
1313
|
-
const
|
|
1385
|
+
const loadRes = await this.#miniflare.dispatchFetch("http://localhost" + IPC_PATH);
|
|
1386
|
+
const loadBody = await loadRes.text().catch(() => "");
|
|
1387
|
+
if (!loadRes.ok) throw new Error(`Failed to establish WebSocket IPC channel (${loadRes.status}: ${loadBody})`);
|
|
1388
|
+
const initRes = await this.#miniflare.dispatchFetch("http://localhost" + IPC_PATH, { headers: { upgrade: "websocket" } });
|
|
1314
1389
|
const ws = initRes.webSocket;
|
|
1315
1390
|
if (!ws) {
|
|
1316
1391
|
const body = await initRes.text().catch(() => "");
|
|
@@ -1339,6 +1414,31 @@ function detectExportedClasses(entrySource, explicit) {
|
|
|
1339
1414
|
}
|
|
1340
1415
|
return [...names];
|
|
1341
1416
|
}
|
|
1417
|
+
function toMiniflareOptions(miniflare, options) {
|
|
1418
|
+
if (!miniflare.convertV4MiniflareOptions) return options;
|
|
1419
|
+
const { defaultPersistRoot, ...rest } = options;
|
|
1420
|
+
return miniflare.convertV4MiniflareOptions({
|
|
1421
|
+
resourcePersistencePath: defaultPersistRoot,
|
|
1422
|
+
...rest
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
async function resolveSupportedCompatibilityDate(miniflare) {
|
|
1426
|
+
if (typeof miniflare.supportedCompatibilityDate === "string") return miniflare.supportedCompatibilityDate;
|
|
1427
|
+
try {
|
|
1428
|
+
const from = [process.cwd() + "/", import.meta.url];
|
|
1429
|
+
const miniflarePath = resolveModulePath("miniflare", {
|
|
1430
|
+
from,
|
|
1431
|
+
try: true
|
|
1432
|
+
});
|
|
1433
|
+
const workerdPath = resolveModulePath("workerd", { from: miniflarePath || from });
|
|
1434
|
+
const { compatibilityDate } = await import(pathToFileURL(workerdPath).href);
|
|
1435
|
+
if (!_isDateString(compatibilityDate)) return;
|
|
1436
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1437
|
+
return compatibilityDate > today ? today : compatibilityDate;
|
|
1438
|
+
} catch {
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1342
1442
|
function resolveCompatibilityDate(candidates, supported) {
|
|
1343
1443
|
const date = candidates.find((d) => typeof d === "string" && d) ?? supported;
|
|
1344
1444
|
if (date && supported && _isDateString(date) && _isDateString(supported) && date > supported) {
|
|
@@ -1357,7 +1457,7 @@ function _isDateString(value) {
|
|
|
1357
1457
|
return /^\d{4}-\d{2}-\d{2}$/.test(value);
|
|
1358
1458
|
}
|
|
1359
1459
|
function hasUserPersistOptions(options) {
|
|
1360
|
-
return Object.keys(options).some((key) => key === "defaultPersistRoot" || key.endsWith("Persist"));
|
|
1460
|
+
return Object.keys(options).some((key) => key === "defaultPersistRoot" || key === "resourcePersistencePath" || key.endsWith("Persist"));
|
|
1361
1461
|
}
|
|
1362
1462
|
function wranglerPersistRoot(configFile, explicitPath) {
|
|
1363
1463
|
const file = configFile ?? (explicitPath ? resolve(explicitPath) : void 0);
|
|
@@ -1378,26 +1478,93 @@ function computeCacheKey(entryPath, opts) {
|
|
|
1378
1478
|
for (const [k, v] of Object.entries(opts)) if (typeof v !== "function") serializableOpts[k] = v;
|
|
1379
1479
|
return `${resolve(entryPath)}::${JSON.stringify(serializableOpts)}`;
|
|
1380
1480
|
}
|
|
1381
|
-
|
|
1382
|
-
|
|
1481
|
+
const _isWin = process.platform === "win32";
|
|
1482
|
+
function virtualKeyPath(key) {
|
|
1483
|
+
if (_isWin && /^\/[A-Za-z]:\//.test(key)) key = key.slice(1);
|
|
1484
|
+
if (key.startsWith("file:")) try {
|
|
1485
|
+
return fileURLToPath(key);
|
|
1486
|
+
} catch {
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
return isAbsolute(key) ? resolve(key) : void 0;
|
|
1490
|
+
}
|
|
1491
|
+
function toWorkerdPath(path) {
|
|
1492
|
+
return _isWin && /^[A-Za-z]:[\\/]/.test(path) ? "/" + path.replaceAll("\\", "/") : path;
|
|
1493
|
+
}
|
|
1494
|
+
function createMiniflareVirtualModules(sources) {
|
|
1495
|
+
return refreshVirtualKeyResolvers({
|
|
1496
|
+
sources,
|
|
1497
|
+
removed: /* @__PURE__ */ new Set(),
|
|
1498
|
+
versions: /* @__PURE__ */ new Map(),
|
|
1499
|
+
version: 0
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
function refreshVirtualKeyResolvers(virtual) {
|
|
1503
|
+
const keys = Object.keys(virtual.sources);
|
|
1504
|
+
virtual.keyOf = createVirtualKeyResolver(keys);
|
|
1505
|
+
virtual.versionedKeyOf = virtual.removed.size > 0 ? createVirtualKeyResolver([...keys, ...virtual.removed]) : virtual.keyOf;
|
|
1506
|
+
return virtual;
|
|
1507
|
+
}
|
|
1508
|
+
function createVirtualKeyResolver(keys) {
|
|
1509
|
+
const verbatim = new Set(keys);
|
|
1510
|
+
const pathKeys = /* @__PURE__ */ new Map();
|
|
1511
|
+
for (const key of verbatim) {
|
|
1512
|
+
const path = virtualKeyPath(key);
|
|
1513
|
+
if (path !== void 0) pathKeys.set(path, key);
|
|
1514
|
+
}
|
|
1515
|
+
return (specifier, importerPath) => {
|
|
1516
|
+
const clean = specifier.split("?")[0];
|
|
1517
|
+
if (verbatim.has(clean)) return clean;
|
|
1518
|
+
if (pathKeys.size === 0) return;
|
|
1519
|
+
const path = /^\.\.?\//.test(clean) ? importerPath && resolve(dirname(importerPath), clean) : virtualKeyPath(clean);
|
|
1520
|
+
return path ? pathKeys.get(path) : void 0;
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
function virtualImporters(virtual, keyOf) {
|
|
1524
|
+
const importers = /* @__PURE__ */ new Map();
|
|
1525
|
+
for (const [importer, { source, format }] of Object.entries(virtual)) {
|
|
1526
|
+
if (format !== "module") continue;
|
|
1527
|
+
const importerPath = virtualKeyPath(importer);
|
|
1528
|
+
for (const { specifier } of versionableImports(source) ?? []) {
|
|
1529
|
+
const key = keyOf(specifier, importerPath);
|
|
1530
|
+
if (key !== void 0 && key !== importer) {
|
|
1531
|
+
let set = importers.get(key);
|
|
1532
|
+
if (!set) importers.set(key, set = /* @__PURE__ */ new Set());
|
|
1533
|
+
set.add(importer);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
return importers;
|
|
1538
|
+
}
|
|
1539
|
+
function versionableImports(code) {
|
|
1383
1540
|
let imports;
|
|
1384
1541
|
try {
|
|
1385
1542
|
[imports] = parse$1(code);
|
|
1386
1543
|
} catch {
|
|
1387
|
-
return
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
const result = [];
|
|
1547
|
+
for (const imp of imports) {
|
|
1548
|
+
if (typeof imp.specifier !== "string" || imp.type === "dynamic" && imp.glob) continue;
|
|
1549
|
+
result.push({
|
|
1550
|
+
specifier: imp.specifier,
|
|
1551
|
+
end: imp.type === "dynamic" ? imp.end - 1 : imp.end
|
|
1552
|
+
});
|
|
1388
1553
|
}
|
|
1554
|
+
return result;
|
|
1555
|
+
}
|
|
1556
|
+
function applyVirtualVersions(code, versions, keyOf) {
|
|
1557
|
+
if (versions.size === 0) return code;
|
|
1558
|
+
const imports = versionableImports(code);
|
|
1559
|
+
if (!imports) return code;
|
|
1389
1560
|
let out = "";
|
|
1390
1561
|
let last = 0;
|
|
1391
|
-
for (const
|
|
1392
|
-
|
|
1393
|
-
const
|
|
1394
|
-
if (dynamic && imp.glob) continue;
|
|
1395
|
-
const specifier = imp.specifier;
|
|
1396
|
-
const version = specifier === void 0 ? void 0 : versions.get(specifier);
|
|
1562
|
+
for (const { specifier, end } of imports) {
|
|
1563
|
+
const key = keyOf(specifier);
|
|
1564
|
+
const version = key === void 0 ? void 0 : versions.get(key);
|
|
1397
1565
|
if (!version) continue;
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
last = imp.end;
|
|
1566
|
+
out += code.slice(last, end) + (specifier.includes("?") ? "&" : "?") + `v=${version}`;
|
|
1567
|
+
last = end;
|
|
1401
1568
|
}
|
|
1402
1569
|
return out + code.slice(last);
|
|
1403
1570
|
}
|
|
@@ -1411,12 +1578,15 @@ function ensureCjsLexer() {
|
|
|
1411
1578
|
if (!_cjsLexerReady) _cjsLexerReady = init();
|
|
1412
1579
|
return _cjsLexerReady;
|
|
1413
1580
|
}
|
|
1414
|
-
function
|
|
1415
|
-
let namedExports = [];
|
|
1581
|
+
function commonJSExports(contents) {
|
|
1416
1582
|
try {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1583
|
+
return parse(contents).exports;
|
|
1584
|
+
} catch {
|
|
1585
|
+
return [];
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
function createCjsEsmShim(cjsSpecifier, contents) {
|
|
1589
|
+
const namedExports = commonJSExports(contents).filter((e) => e !== "default" && e !== "__esModule");
|
|
1420
1590
|
let shim = `import __cjs_mod__ from ${JSON.stringify(cjsSpecifier)};\nexport default __cjs_mod__;\n`;
|
|
1421
1591
|
for (const name of namedExports) shim += `export var ${name} = __cjs_mod__["${name}"];\n`;
|
|
1422
1592
|
return shim;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { BaseEnvRunner } from "./common-base-runner.mjs";
|
|
2
|
-
import { hostEnv } from "./common-host-env.mjs";
|
|
1
|
+
import { BaseEnvRunner, hostEnv } from "./common-base-runner.mjs";
|
|
3
2
|
import { fileURLToPath } from "node:url";
|
|
4
3
|
import { existsSync } from "node:fs";
|
|
5
4
|
import { Worker } from "node:worker_threads";
|