env-runner 0.3.0 → 0.3.2
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 +217 -2
- package/dist/_chunks/common-base-runner.d.mts +434 -1
- package/dist/_chunks/common-base-runner.mjs +596 -7
- package/dist/_chunks/common-worker-utils.mjs +19 -477
- package/dist/_chunks/deno-process-runner.d.mts +4 -1
- package/dist/_chunks/deno-process-runner.mjs +7 -0
- package/dist/_chunks/miniflare-runner.d.mts +5 -2
- package/dist/_chunks/miniflare-runner.mjs +169 -43
- package/dist/_chunks/netlify-runner.d.mts +3 -1
- package/dist/_chunks/node-worker-runner.d.mts +3 -1
- package/dist/_chunks/node-worker-runner.mjs +7 -2
- package/dist/_chunks/plugin-hooks.mjs +1656 -0
- package/dist/_chunks/server.mjs +1 -0
- package/dist/_chunks/types.d.mts +1 -1
- package/dist/_chunks/vercel-runner.d.mts +3 -1
- package/dist/index.d.mts +6 -2
- package/dist/runners/bun-process/runner.d.mts +4 -1
- package/dist/runners/bun-process/runner.mjs +8 -1
- package/dist/runners/bun-process/worker.mjs +5 -4
- package/dist/runners/deno-process/worker.mjs +5 -4
- package/dist/runners/node-process/runner.d.mts +3 -1
- package/dist/runners/node-process/worker.mjs +5 -4
- package/dist/runners/node-worker/worker.mjs +5 -4
- package/dist/runners/self/runner.d.mts +3 -1
- package/dist/runners/self/runner.mjs +4 -0
- package/package.json +7 -6
- package/dist/_chunks/virtual-loader.mjs +0 -345
package/dist/_chunks/server.mjs
CHANGED
|
@@ -317,6 +317,7 @@ var EnvServer = class extends RunnerManager {
|
|
|
317
317
|
...this._opts.runnerOptions,
|
|
318
318
|
name: this._opts.name || this._opts.entry,
|
|
319
319
|
hooks: this._opts.hooks,
|
|
320
|
+
plugins: this._opts.plugins,
|
|
320
321
|
data: {
|
|
321
322
|
...this._opts.data,
|
|
322
323
|
...this._virtual && { virtual: { ...this._virtual } },
|
package/dist/_chunks/types.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IncomingMessage } from "node:http";
|
|
2
1
|
import { Socket } from "node:net";
|
|
2
|
+
import { IncomingMessage } from "node:http";
|
|
3
3
|
/**
|
|
4
4
|
* How a virtual module is served. Code formats are Node's load formats, plus
|
|
5
5
|
* `jsx`/`tsx` (Bun only). Raw formats follow import attribute types: `text`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WorkerHooks } from "./types.mjs";
|
|
2
|
-
import { EnvRunnerData } from "./common-base-runner.mjs";
|
|
2
|
+
import { EnvRunnerData, EnvRunnerPluginOption } from "./common-base-runner.mjs";
|
|
3
3
|
import { NodeWorkerEnvRunner } from "./node-worker-runner.mjs";
|
|
4
4
|
export declare class VercelEnvRunner extends NodeWorkerEnvRunner {
|
|
5
5
|
constructor(opts: {
|
|
@@ -7,6 +7,8 @@ export declare class VercelEnvRunner extends NodeWorkerEnvRunner {
|
|
|
7
7
|
workerEntry?: string;
|
|
8
8
|
hooks?: WorkerHooks;
|
|
9
9
|
data?: EnvRunnerData;
|
|
10
|
+
/** Host-side transform plugins (see `EnvRunnerPluginOption`). */
|
|
11
|
+
plugins?: EnvRunnerPluginOption[];
|
|
10
12
|
});
|
|
11
13
|
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
12
14
|
protected _runtimeType(): string;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EnvRunner, FetchHandler, NodeUpgradeContext, RPCOptions, RunnerMessageListener, RunnerRPCHooks, UpgradeContext, UpgradeHandler, VirtualModule, VirtualModuleContent, VirtualModuleFormat, VirtualModuleSource, VirtualModuleUpdates, VirtualModules, WorkerAddress, WorkerHooks } from "./_chunks/types.mjs";
|
|
2
|
-
import { BaseEnvRunner, EnvRunnerData } from "./_chunks/common-base-runner.mjs";
|
|
2
|
+
import { BaseEnvRunner, EnvRunnerData, EnvRunnerPlugin, EnvRunnerPluginOption, PluginContext, PluginContextResolveOptions, PluginFilterExpression, PluginHook, PluginHookFilter, PluginLoadHandler, PluginLoadResult, PluginLog, PluginLogPosition, PluginModuleType, PluginResolveIdHandler, PluginResolveIdHook, PluginResolveIdOptions, PluginResolveIdResult, PluginResolvedId, PluginStringFilter, PluginTopLevelFilterExpression, PluginTransformFilter, PluginTransformHandler, PluginTransformMeta, PluginTransformResult } from "./_chunks/common-base-runner.mjs";
|
|
3
3
|
import { RuntimeDep, resolveRuntimeDep } from "./_chunks/common-runtime-deps.mjs";
|
|
4
4
|
import { DenoProcessEnvRunner } from "./_chunks/deno-process-runner.mjs";
|
|
5
5
|
import { MiniflareEnvRunner, MiniflareEnvRunnerOptions, MiniflareExportInfo, TransformResult } from "./_chunks/miniflare-runner.mjs";
|
|
@@ -71,6 +71,8 @@ interface LoadRunnerOptions {
|
|
|
71
71
|
workerEntry?: string;
|
|
72
72
|
hooks?: WorkerHooks;
|
|
73
73
|
data?: EnvRunnerData;
|
|
74
|
+
/** Host-side transform plugins (see `EnvRunnerPluginOption`). */
|
|
75
|
+
plugins?: EnvRunnerPluginOption[];
|
|
74
76
|
execArgv?: string[];
|
|
75
77
|
/** Runner-specific constructor options (e.g. `miniflare` for the `miniflare` runner). */
|
|
76
78
|
[key: string]: unknown;
|
|
@@ -87,6 +89,8 @@ interface EnvServerOptions {
|
|
|
87
89
|
hooks?: WorkerHooks;
|
|
88
90
|
/** Additional data passed to the runner. */
|
|
89
91
|
data?: Record<string, unknown>;
|
|
92
|
+
/** Host-side transform plugins, passed to every runner the server creates. */
|
|
93
|
+
plugins?: EnvRunnerPluginOption[];
|
|
90
94
|
/** Custom exec arguments (e.g. `--inspect`). */
|
|
91
95
|
execArgv?: string[];
|
|
92
96
|
/** Enable watch mode to auto-reload on entry file changes. */
|
|
@@ -162,4 +166,4 @@ export declare const RESERVED_RUNTIME_OPTIONS: {
|
|
|
162
166
|
};
|
|
163
167
|
/** Callers add `fetch` (bound lazily so reloads swap it) and the crossws plugin. */
|
|
164
168
|
export declare function toServerOptions(entry: AppEntry): Omit<ServerOptions, "fetch">;
|
|
165
|
-
export { type AppEntry, type AppEntryIPC, type AppEntryIPCContext, BaseEnvRunner, DenoProcessEnvRunner, type EnvRunnerData as DenoProcessEnvRunnerData, type EnvRunner, type EnvRunnerData, type EnvServerOptions, type FetchHandler, type LoadRunnerOptions, MiniflareEnvRunner, type MiniflareEnvRunnerOptions, type MiniflareExportInfo, NetlifyEnvRunner, type NodeUpgradeContext, type RPCOptions, type RunnerMessageListener, type RunnerName, type RunnerRPCHooks, type RuntimeDep, type TransformResult, type UpgradeContext, type UpgradeHandler, VercelEnvRunner, type VirtualModule, type VirtualModuleContent, type VirtualModuleFormat, type VirtualModuleSource, type VirtualModuleUpdates, type VirtualModules, type WorkerAddress, type WorkerHooks, resolveRuntimeDep };
|
|
169
|
+
export { type AppEntry, type AppEntryIPC, type AppEntryIPCContext, BaseEnvRunner, DenoProcessEnvRunner, type EnvRunnerData as DenoProcessEnvRunnerData, type EnvRunner, type EnvRunnerData, type EnvRunnerPlugin, type EnvRunnerPluginOption, type EnvServerOptions, type FetchHandler, type LoadRunnerOptions, MiniflareEnvRunner, type MiniflareEnvRunnerOptions, type MiniflareExportInfo, NetlifyEnvRunner, type NodeUpgradeContext, type PluginContext, type PluginContextResolveOptions, type PluginFilterExpression, type PluginHook, type PluginHookFilter, type PluginLoadHandler, type PluginLoadResult, type PluginLog, type PluginLogPosition, type PluginModuleType, type PluginResolveIdHandler, type PluginResolveIdHook, type PluginResolveIdOptions, type PluginResolveIdResult, type PluginResolvedId, type PluginStringFilter, type PluginTopLevelFilterExpression, type PluginTransformFilter, type PluginTransformHandler, type PluginTransformMeta, type PluginTransformResult, type RPCOptions, type RunnerMessageListener, type RunnerName, type RunnerRPCHooks, type RuntimeDep, type TransformResult, type UpgradeContext, type UpgradeHandler, VercelEnvRunner, type VirtualModule, type VirtualModuleContent, type VirtualModuleFormat, type VirtualModuleSource, type VirtualModuleUpdates, type VirtualModules, type WorkerAddress, type WorkerHooks, resolveRuntimeDep };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
|
-
import { BaseEnvRunner, EnvRunnerData } from "../../_chunks/common-base-runner.mjs";
|
|
2
|
+
import { BaseEnvRunner, EnvRunnerData, EnvRunnerPluginOption } from "../../_chunks/common-base-runner.mjs";
|
|
3
3
|
export declare class BunProcessEnvRunner extends BaseEnvRunner {
|
|
4
4
|
#private;
|
|
5
5
|
constructor(opts: {
|
|
@@ -7,11 +7,14 @@ export declare class BunProcessEnvRunner extends BaseEnvRunner {
|
|
|
7
7
|
workerEntry?: string;
|
|
8
8
|
hooks?: WorkerHooks;
|
|
9
9
|
data?: EnvRunnerData;
|
|
10
|
+
/** Host-side transform plugins (see `EnvRunnerPluginOption`). */
|
|
11
|
+
plugins?: EnvRunnerPluginOption[];
|
|
10
12
|
execArgv?: string[];
|
|
11
13
|
});
|
|
12
14
|
sendMessage(message: unknown): void;
|
|
13
15
|
protected _hasRuntime(): boolean;
|
|
14
16
|
protected _runtimeType(): string;
|
|
17
|
+
protected _resolveConditions(): string[];
|
|
15
18
|
protected _closeRuntime(): Promise<void>;
|
|
16
19
|
}
|
|
17
20
|
export type { EnvRunnerData as BunProcessEnvRunnerData };
|
|
@@ -2,8 +2,8 @@ import { BaseEnvRunner } from "../../_chunks/common-base-runner.mjs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
|
-
import { execSync, spawn } from "node:child_process";
|
|
6
5
|
import { homedir } from "node:os";
|
|
6
|
+
import { execSync, spawn } from "node:child_process";
|
|
7
7
|
let _defaultEntry;
|
|
8
8
|
let _bunPath;
|
|
9
9
|
const _isBun = typeof Bun !== "undefined";
|
|
@@ -43,6 +43,13 @@ var BunProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
43
43
|
_runtimeType() {
|
|
44
44
|
return "process";
|
|
45
45
|
}
|
|
46
|
+
_resolveConditions() {
|
|
47
|
+
return [
|
|
48
|
+
"bun",
|
|
49
|
+
"node",
|
|
50
|
+
"import"
|
|
51
|
+
];
|
|
52
|
+
}
|
|
46
53
|
async _closeRuntime() {
|
|
47
54
|
if (!this.#process) return;
|
|
48
55
|
this.#process.removeAllListeners?.();
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { handleUpdateVirtualModules } from "../../_chunks/plugin-hooks.mjs";
|
|
2
|
+
import { formatInitError, isVirtualEntry, parseServerAddress, registerWorkerHooks, reloadEntryModule, resolveEntry, toServerOptions } from "../../_chunks/common-worker-utils.mjs";
|
|
2
3
|
import { receiveProcessData } from "../../_chunks/common-process-data.mjs";
|
|
3
4
|
import { serve } from "srvx";
|
|
4
5
|
import { plugin } from "crossws/server";
|
|
5
6
|
process.on("disconnect", () => process.exit(0));
|
|
6
7
|
const data = await receiveProcessData();
|
|
7
8
|
const sendMessage = (message) => process.send(message);
|
|
8
|
-
let
|
|
9
|
+
let unregisterHooks;
|
|
9
10
|
let entry;
|
|
10
11
|
let server;
|
|
11
12
|
try {
|
|
12
|
-
|
|
13
|
+
unregisterHooks = await registerWorkerHooks(data);
|
|
13
14
|
entry = await resolveEntry(data.entry, isVirtualEntry(data.entry));
|
|
14
15
|
server = serve({
|
|
15
16
|
...toServerOptions(entry),
|
|
@@ -38,7 +39,7 @@ process.send({ address: parseServerAddress(server) });
|
|
|
38
39
|
process.on("message", async (message) => {
|
|
39
40
|
if (message?.event === "shutdown") {
|
|
40
41
|
Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
|
|
41
|
-
|
|
42
|
+
unregisterHooks();
|
|
42
43
|
process.send({ event: "exit" });
|
|
43
44
|
});
|
|
44
45
|
return;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { handleUpdateVirtualModules } from "../../_chunks/plugin-hooks.mjs";
|
|
2
|
+
import { formatInitError, isVirtualEntry, parseServerAddress, registerWorkerHooks, reloadEntryModule, resolveEntry, toServerOptions } from "../../_chunks/common-worker-utils.mjs";
|
|
2
3
|
import { receiveProcessData } from "../../_chunks/common-process-data.mjs";
|
|
3
4
|
import { serve } from "srvx";
|
|
4
5
|
import { plugin } from "crossws/server";
|
|
5
6
|
process.on("disconnect", () => process.exit(0));
|
|
6
7
|
const data = await receiveProcessData();
|
|
7
8
|
const sendMessage = (message) => process.send(message);
|
|
8
|
-
let
|
|
9
|
+
let unregisterHooks;
|
|
9
10
|
let entry;
|
|
10
11
|
let server;
|
|
11
12
|
try {
|
|
12
|
-
|
|
13
|
+
unregisterHooks = await registerWorkerHooks(data);
|
|
13
14
|
entry = await resolveEntry(data.entry, isVirtualEntry(data.entry));
|
|
14
15
|
server = serve({
|
|
15
16
|
...toServerOptions(entry),
|
|
@@ -38,7 +39,7 @@ process.send({ address: parseServerAddress(server) });
|
|
|
38
39
|
process.on("message", async (message) => {
|
|
39
40
|
if (message?.event === "shutdown") {
|
|
40
41
|
Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
|
|
41
|
-
|
|
42
|
+
unregisterHooks();
|
|
42
43
|
process.send({ event: "exit" });
|
|
43
44
|
});
|
|
44
45
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
|
-
import { BaseEnvRunner, EnvRunnerData } from "../../_chunks/common-base-runner.mjs";
|
|
2
|
+
import { BaseEnvRunner, EnvRunnerData, EnvRunnerPluginOption } from "../../_chunks/common-base-runner.mjs";
|
|
3
3
|
export declare class NodeProcessEnvRunner extends BaseEnvRunner {
|
|
4
4
|
#private;
|
|
5
5
|
constructor(opts: {
|
|
@@ -7,6 +7,8 @@ export declare class NodeProcessEnvRunner extends BaseEnvRunner {
|
|
|
7
7
|
workerEntry?: string;
|
|
8
8
|
hooks?: WorkerHooks;
|
|
9
9
|
data?: EnvRunnerData;
|
|
10
|
+
/** Host-side transform plugins (see `EnvRunnerPluginOption`). */
|
|
11
|
+
plugins?: EnvRunnerPluginOption[];
|
|
10
12
|
execArgv?: string[];
|
|
11
13
|
});
|
|
12
14
|
sendMessage(message: unknown): void;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { handleUpdateVirtualModules } from "../../_chunks/plugin-hooks.mjs";
|
|
2
|
+
import { formatInitError, isVirtualEntry, parseServerAddress, registerWorkerHooks, reloadEntryModule, resolveEntry, toServerOptions } from "../../_chunks/common-worker-utils.mjs";
|
|
2
3
|
import { receiveProcessData } from "../../_chunks/common-process-data.mjs";
|
|
3
4
|
import { serve } from "srvx";
|
|
4
5
|
import { plugin } from "crossws/server";
|
|
5
6
|
process.on("disconnect", () => process.exit(0));
|
|
6
7
|
const data = await receiveProcessData();
|
|
7
8
|
const sendMessage = (message) => process.send(message);
|
|
8
|
-
let
|
|
9
|
+
let unregisterHooks;
|
|
9
10
|
let entry;
|
|
10
11
|
let server;
|
|
11
12
|
try {
|
|
12
|
-
|
|
13
|
+
unregisterHooks = await registerWorkerHooks(data);
|
|
13
14
|
entry = await resolveEntry(data.entry, isVirtualEntry(data.entry));
|
|
14
15
|
server = serve({
|
|
15
16
|
...toServerOptions(entry),
|
|
@@ -38,7 +39,7 @@ process.send({ address: parseServerAddress(server) });
|
|
|
38
39
|
process.on("message", async (message) => {
|
|
39
40
|
if (message?.event === "shutdown") {
|
|
40
41
|
Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
|
|
41
|
-
|
|
42
|
+
unregisterHooks();
|
|
42
43
|
process.send({ event: "exit" });
|
|
43
44
|
});
|
|
44
45
|
return;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { handleUpdateVirtualModules } from "../../_chunks/plugin-hooks.mjs";
|
|
2
|
+
import { formatInitError, isVirtualEntry, parseServerAddress, registerWorkerHooks, reloadEntryModule, resolveEntry, toServerOptions } from "../../_chunks/common-worker-utils.mjs";
|
|
2
3
|
import { parentPort, workerData } from "node:worker_threads";
|
|
3
4
|
import { serve } from "srvx";
|
|
4
5
|
import { plugin } from "crossws/server";
|
|
5
6
|
const data = workerData || {};
|
|
6
7
|
const sendMessage = (message) => parentPort?.postMessage(message);
|
|
7
|
-
let
|
|
8
|
+
let unregisterHooks;
|
|
8
9
|
let entry;
|
|
9
10
|
let server;
|
|
10
11
|
try {
|
|
11
|
-
|
|
12
|
+
unregisterHooks = await registerWorkerHooks(data);
|
|
12
13
|
entry = await resolveEntry(data.entry, isVirtualEntry(data.entry));
|
|
13
14
|
server = serve({
|
|
14
15
|
...toServerOptions(entry),
|
|
@@ -37,7 +38,7 @@ parentPort?.postMessage({ address: parseServerAddress(server) });
|
|
|
37
38
|
parentPort?.on("message", async (message) => {
|
|
38
39
|
if (message?.event === "shutdown") {
|
|
39
40
|
Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
|
|
40
|
-
|
|
41
|
+
unregisterHooks();
|
|
41
42
|
parentPort?.postMessage({ event: "exit" });
|
|
42
43
|
});
|
|
43
44
|
return;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { VirtualModuleUpdates, WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
|
-
import { BaseEnvRunner, EnvRunnerData } from "../../_chunks/common-base-runner.mjs";
|
|
2
|
+
import { BaseEnvRunner, EnvRunnerData, EnvRunnerPluginOption } from "../../_chunks/common-base-runner.mjs";
|
|
3
3
|
export declare class SelfEnvRunner extends BaseEnvRunner {
|
|
4
4
|
#private;
|
|
5
5
|
constructor(opts: {
|
|
6
6
|
name: string;
|
|
7
7
|
hooks?: WorkerHooks;
|
|
8
8
|
data?: EnvRunnerData;
|
|
9
|
+
/** Not supported: the runner closes with an error. */
|
|
10
|
+
plugins?: EnvRunnerPluginOption[];
|
|
9
11
|
});
|
|
10
12
|
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
11
13
|
upgrade(context: {
|
|
@@ -86,6 +86,10 @@ var SelfEnvRunner = class extends BaseEnvRunner {
|
|
|
86
86
|
this.close(/* @__PURE__ */ new Error("Cannot use data.virtual: the self runner does not support virtual modules"));
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
|
+
if (this._plugins) {
|
|
90
|
+
this.close(/* @__PURE__ */ new Error("Cannot use plugins: the self runner does not support them"));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
89
93
|
this.#active = true;
|
|
90
94
|
resolveEntry(entryPath).then(async (entry) => {
|
|
91
95
|
if (this.closed) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "env-runner",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Generic environment runner for JavaScript runtimes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@netlify/runtime": "^5.0.5",
|
|
45
|
-
"@types/node": "^26.6.
|
|
46
|
-
"@vercel/queue": "^0.
|
|
47
|
-
"@vitest/coverage-v8": "^5.0.
|
|
45
|
+
"@types/node": "^26.6.3",
|
|
46
|
+
"@vercel/queue": "^0.7.0",
|
|
47
|
+
"@vitest/coverage-v8": "^5.0.2",
|
|
48
48
|
"automd": "^0.4.3",
|
|
49
49
|
"changelogen": "^0.6.2",
|
|
50
50
|
"cjs-module-lexer": "^2.2.1",
|
|
@@ -52,11 +52,12 @@
|
|
|
52
52
|
"es-module-lexer": "^3.0.2",
|
|
53
53
|
"miniflare": "^5.20260921.1-alpha",
|
|
54
54
|
"obuild": "^0.4.40",
|
|
55
|
+
"oxc-transform": "^0.151.0",
|
|
55
56
|
"oxfmt": ">=0.70.0",
|
|
56
57
|
"oxlint": "^1.85.0",
|
|
57
58
|
"typescript": "^7.0.2",
|
|
58
|
-
"vitest": "^5.0.
|
|
59
|
-
"wrangler": "^4.
|
|
59
|
+
"vitest": "^5.0.2",
|
|
60
|
+
"wrangler": "^4.141.0"
|
|
60
61
|
},
|
|
61
62
|
"scripts": {
|
|
62
63
|
"build": "obuild",
|
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
import { Buffer } from "node:buffer";
|
|
2
|
-
import { isAbsolute } from "node:path";
|
|
3
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
-
const VIRTUAL_MODULE_FORMATS = /* @__PURE__ */ new Set([
|
|
5
|
-
"module",
|
|
6
|
-
"commonjs",
|
|
7
|
-
"module-typescript",
|
|
8
|
-
"commonjs-typescript",
|
|
9
|
-
"jsx",
|
|
10
|
-
"tsx",
|
|
11
|
-
"json",
|
|
12
|
-
"text",
|
|
13
|
-
"bytes",
|
|
14
|
-
"wasm"
|
|
15
|
-
]);
|
|
16
|
-
const EXTENSION_FORMATS = {
|
|
17
|
-
".cjs": "commonjs",
|
|
18
|
-
".json": "json",
|
|
19
|
-
".ts": "module-typescript",
|
|
20
|
-
".mts": "module-typescript",
|
|
21
|
-
".cts": "commonjs-typescript",
|
|
22
|
-
".jsx": "jsx",
|
|
23
|
-
".tsx": "tsx",
|
|
24
|
-
".wasm": "wasm"
|
|
25
|
-
};
|
|
26
|
-
function virtualModuleFormat(key, module) {
|
|
27
|
-
return typeof module === "object" ? module.format : _extensionFormat(key) ?? "module";
|
|
28
|
-
}
|
|
29
|
-
function virtualModuleCodeSource(key, module) {
|
|
30
|
-
if (module === void 0) return;
|
|
31
|
-
const format = virtualModuleFormat(key, module);
|
|
32
|
-
if (format === "json" || format === "text" || _isBinaryFormat(format)) return;
|
|
33
|
-
return typeof module === "string" ? module : module.source;
|
|
34
|
-
}
|
|
35
|
-
function normalizeVirtualModule(key, content) {
|
|
36
|
-
const module = typeof content === "string" || content instanceof Uint8Array ? { source: content } : content;
|
|
37
|
-
const source = module?.source;
|
|
38
|
-
if (typeof source !== "string" && !(source instanceof Uint8Array)) throw new TypeError(`[env-runner] virtual module "${key}" must be a string, a Uint8Array or { source, format }.`);
|
|
39
|
-
const binary = typeof source !== "string";
|
|
40
|
-
const format = module.format ?? _extensionFormat(key) ?? (binary ? "bytes" : "module");
|
|
41
|
-
if (!VIRTUAL_MODULE_FORMATS.has(format)) throw new TypeError(`[env-runner] virtual module "${key}" has an unknown format "${format}" (expected one of: ${[...VIRTUAL_MODULE_FORMATS].join(", ")}).`);
|
|
42
|
-
if (binary !== _isBinaryFormat(format)) throw new TypeError(`[env-runner] virtual module "${key}" has format "${format}", which needs ${binary ? "a string" : "a Uint8Array"} source.`);
|
|
43
|
-
if (format === "wasm" && !WebAssembly.validate(source)) throw new TypeError(`[env-runner] virtual module "${key}" is not a valid WebAssembly binary.`);
|
|
44
|
-
if (typeof content === "string") return content;
|
|
45
|
-
return {
|
|
46
|
-
source: binary ? new Uint8Array(source) : source,
|
|
47
|
-
format
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function normalizeVirtualModules(virtual) {
|
|
51
|
-
const out = {};
|
|
52
|
-
for (const [key, content] of Object.entries(virtual)) out[key] = normalizeVirtualModule(key, content);
|
|
53
|
-
return out;
|
|
54
|
-
}
|
|
55
|
-
async function resolveVirtualModules(virtual) {
|
|
56
|
-
const entries = await Promise.all(Object.entries(virtual).map(async ([key, value]) => {
|
|
57
|
-
return [key, normalizeVirtualModule(key, typeof value === "function" ? await value() : value)];
|
|
58
|
-
}));
|
|
59
|
-
return Object.fromEntries(entries);
|
|
60
|
-
}
|
|
61
|
-
function encodeVirtualModules(virtual) {
|
|
62
|
-
const out = {};
|
|
63
|
-
for (const [key, module] of Object.entries(virtual)) out[key] = module !== null && typeof module === "object" && typeof module.source !== "string" ? {
|
|
64
|
-
source: _toBase64(module.source),
|
|
65
|
-
format: module.format,
|
|
66
|
-
encoding: "base64"
|
|
67
|
-
} : module;
|
|
68
|
-
return out;
|
|
69
|
-
}
|
|
70
|
-
function decodeVirtualModules(virtual) {
|
|
71
|
-
const out = {};
|
|
72
|
-
for (const [key, module] of Object.entries(virtual)) out[key] = module !== null && typeof module === "object" && "encoding" in module ? {
|
|
73
|
-
source: new Uint8Array(Buffer.from(module.source, "base64")),
|
|
74
|
-
format: module.format
|
|
75
|
-
} : module;
|
|
76
|
-
return out;
|
|
77
|
-
}
|
|
78
|
-
function virtualModuleCode(format, source) {
|
|
79
|
-
if (format === "text") return `export default ${JSON.stringify(source)};\n`;
|
|
80
|
-
const bytes = [
|
|
81
|
-
`const base64 = ${JSON.stringify(_toBase64(source))};`,
|
|
82
|
-
`let bytes;`,
|
|
83
|
-
`if (typeof Uint8Array.fromBase64 === "function") {`,
|
|
84
|
-
` bytes = Uint8Array.fromBase64(base64);`,
|
|
85
|
-
`} else {`,
|
|
86
|
-
` const binary = atob(base64);`,
|
|
87
|
-
` bytes = new Uint8Array(binary.length);`,
|
|
88
|
-
` for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);`,
|
|
89
|
-
`}`
|
|
90
|
-
];
|
|
91
|
-
const value = format === "wasm" ? "new WebAssembly.Module(bytes)" : "bytes";
|
|
92
|
-
return `${bytes.join("\n")}\nexport default ${value};\n`;
|
|
93
|
-
}
|
|
94
|
-
function unsupportedVirtualJSXError(key, format, runtime) {
|
|
95
|
-
return /* @__PURE__ */ new TypeError(`[env-runner] virtual module "${key}" has format "${format}", which ${runtime} can't load from memory; pre-transpile it to JavaScript (and pass { source, format: "module" } to keep the key).`);
|
|
96
|
-
}
|
|
97
|
-
const VIRTUAL_SCHEME = "virtual:";
|
|
98
|
-
function createVirtualHooks(virtual, opts = {}) {
|
|
99
|
-
const { versions, importers, forcePlainModule } = opts;
|
|
100
|
-
const baseURL = opts.baseURL ?? _defaultBaseURL();
|
|
101
|
-
const keyURLs = /* @__PURE__ */ new Map();
|
|
102
|
-
const urlKeys = /* @__PURE__ */ new Map();
|
|
103
|
-
for (const key of Object.keys(virtual)) {
|
|
104
|
-
const url = _virtualKeyURL(key);
|
|
105
|
-
if (url) {
|
|
106
|
-
keyURLs.set(key, url);
|
|
107
|
-
urlKeys.set(url, key);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
const keyOf = (url) => {
|
|
111
|
-
if (url.startsWith(VIRTUAL_SCHEME)) {
|
|
112
|
-
const key = _virtualURLKey(url);
|
|
113
|
-
return key !== void 0 && Object.hasOwn(virtual, key) ? key : void 0;
|
|
114
|
-
}
|
|
115
|
-
return urlKeys.size > 0 && url.startsWith("file:") ? urlKeys.get(_bareURL(url)) : void 0;
|
|
116
|
-
};
|
|
117
|
-
const moduleFiles = importers && /* @__PURE__ */ new Set();
|
|
118
|
-
const track = (node, context) => {
|
|
119
|
-
const { parentURL } = context;
|
|
120
|
-
if (!importers || !parentURL) return;
|
|
121
|
-
let importer = keyOf(parentURL);
|
|
122
|
-
if (importer === void 0 && !context.conditions?.includes("require")) {
|
|
123
|
-
const file = _bareURL(parentURL);
|
|
124
|
-
importer = moduleFiles.has(file) ? file : void 0;
|
|
125
|
-
}
|
|
126
|
-
if (importer !== void 0 && importer !== node) {
|
|
127
|
-
let set = importers.get(node);
|
|
128
|
-
if (!set) importers.set(node, set = /* @__PURE__ */ new Set());
|
|
129
|
-
set.add(importer);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
const serve = (key, url, context) => {
|
|
133
|
-
track(key, context);
|
|
134
|
-
if (opts.opaquePathURL && keyURLs.has(key) && opts.opaquePathURL(keyURLs.get(key))) url = _virtualURL(key) + url.slice(_bareURL(url).length);
|
|
135
|
-
const version = versions?.get(key);
|
|
136
|
-
return {
|
|
137
|
-
url: version ? _appendQuery(url, `v=${version}`) : url,
|
|
138
|
-
shortCircuit: true
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
|
-
const resolve = (specifier, context, nextResolve) => {
|
|
142
|
-
const key = _stripQuery(specifier);
|
|
143
|
-
if (Object.hasOwn(virtual, key)) {
|
|
144
|
-
const keyURL = keyURLs.get(key);
|
|
145
|
-
const url = keyURL ? keyURL + specifier.slice(key.length) : _virtualURL(specifier);
|
|
146
|
-
return serve(key, url, context);
|
|
147
|
-
}
|
|
148
|
-
let parentURL = context.parentURL;
|
|
149
|
-
if (parentURL?.startsWith(VIRTUAL_SCHEME)) {
|
|
150
|
-
const parentKey = keyOf(parentURL);
|
|
151
|
-
parentURL = parentKey !== void 0 && keyURLs.get(parentKey) || baseURL;
|
|
152
|
-
}
|
|
153
|
-
if (urlKeys.size > 0) {
|
|
154
|
-
const url = _resolvePathSpecifier(specifier, parentURL);
|
|
155
|
-
const pathKey = url && urlKeys.get(_bareURL(url));
|
|
156
|
-
if (pathKey) return serve(pathKey, url, context);
|
|
157
|
-
}
|
|
158
|
-
const result = nextResolve(specifier, parentURL === context.parentURL ? context : {
|
|
159
|
-
...context,
|
|
160
|
-
parentURL
|
|
161
|
-
});
|
|
162
|
-
const resolvedKey = urlKeys.size > 0 ? urlKeys.get(_bareURL(result.url)) : void 0;
|
|
163
|
-
if (resolvedKey) return serve(resolvedKey, result.url, context);
|
|
164
|
-
if (result.url.startsWith("file:")) {
|
|
165
|
-
const file = _bareURL(result.url);
|
|
166
|
-
track(file, context);
|
|
167
|
-
const version = versions?.get(file);
|
|
168
|
-
if (version) return {
|
|
169
|
-
...result,
|
|
170
|
-
url: _appendQuery(result.url, `v=${version}`)
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
return result;
|
|
174
|
-
};
|
|
175
|
-
const load = (url, context, nextLoad) => {
|
|
176
|
-
const key = keyOf(url);
|
|
177
|
-
if (key !== void 0) {
|
|
178
|
-
const module = virtual[key];
|
|
179
|
-
if (forcePlainModule) return {
|
|
180
|
-
format: "module",
|
|
181
|
-
source: module,
|
|
182
|
-
shortCircuit: true
|
|
183
|
-
};
|
|
184
|
-
return {
|
|
185
|
-
..._nodeLoadResult(key, module),
|
|
186
|
-
shortCircuit: true
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
const result = nextLoad(url, context);
|
|
190
|
-
if (moduleFiles && url.startsWith("file:") && _isModuleFormat(result.format)) moduleFiles.add(_bareURL(url));
|
|
191
|
-
return result;
|
|
192
|
-
};
|
|
193
|
-
const updateKeys = (keys) => {
|
|
194
|
-
for (const key of keys) {
|
|
195
|
-
const url = keyURLs.get(key) ?? _virtualKeyURL(key);
|
|
196
|
-
if (!url) continue;
|
|
197
|
-
if (Object.hasOwn(virtual, key)) {
|
|
198
|
-
keyURLs.set(key, url);
|
|
199
|
-
urlKeys.set(url, key);
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
keyURLs.delete(key);
|
|
203
|
-
if (urlKeys.get(url) === key) {
|
|
204
|
-
urlKeys.delete(url);
|
|
205
|
-
for (const [other, otherURL] of keyURLs) if (otherURL === url) urlKeys.set(url, other);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
return {
|
|
210
|
-
resolve,
|
|
211
|
-
load,
|
|
212
|
-
updateKeys
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
function _nodeLoadResult(key, module) {
|
|
216
|
-
const format = virtualModuleFormat(key, module);
|
|
217
|
-
const source = typeof module === "string" ? module : module.source;
|
|
218
|
-
if (format === "text" || format === "bytes" || format === "wasm") return {
|
|
219
|
-
format: "module",
|
|
220
|
-
source: virtualModuleCode(format, source)
|
|
221
|
-
};
|
|
222
|
-
if (format === "jsx" || format === "tsx") throw unsupportedVirtualJSXError(key, format, "Node.js");
|
|
223
|
-
return {
|
|
224
|
-
format,
|
|
225
|
-
source
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
function stripVirtualTypeScript(specifier, source, stripTypeScriptTypes, hints) {
|
|
229
|
-
if (typeof stripTypeScriptTypes !== "function") throw new TypeError(`[env-runner] virtual TypeScript module "${specifier}" requires \`module.stripTypeScriptTypes\` ${hints.requirement}; ${hints.remedy} or provide a pre-transpiled JavaScript source instead.`);
|
|
230
|
-
try {
|
|
231
|
-
return stripTypeScriptTypes(source);
|
|
232
|
-
} catch (error) {
|
|
233
|
-
throw new SyntaxError(`[env-runner] failed to strip types from virtual module "${specifier}": ${error?.message || error}`, { cause: error });
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
function expandVirtualInvalidation(virtual, specifier, importers) {
|
|
237
|
-
const invalidated = [...new Set(typeof specifier === "string" ? [specifier] : specifier)];
|
|
238
|
-
const seen = new Set(invalidated);
|
|
239
|
-
const add = (key) => {
|
|
240
|
-
if (!seen.has(key)) {
|
|
241
|
-
seen.add(key);
|
|
242
|
-
invalidated.push(key);
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
for (const target of invalidated) {
|
|
246
|
-
for (const key of importers?.get(target) ?? []) add(key);
|
|
247
|
-
if (!Object.hasOwn(virtual, target)) continue;
|
|
248
|
-
const refs = [
|
|
249
|
-
`"${target}"`,
|
|
250
|
-
`'${target}'`,
|
|
251
|
-
"`" + target + "`"
|
|
252
|
-
];
|
|
253
|
-
for (const [key, module] of Object.entries(virtual)) {
|
|
254
|
-
const code = virtualModuleCodeSource(key, module);
|
|
255
|
-
if (code !== void 0 && refs.some((ref) => code.includes(ref))) add(key);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
return invalidated;
|
|
259
|
-
}
|
|
260
|
-
function findVirtualPathKey(virtual, specifier) {
|
|
261
|
-
const url = _virtualKeyURL(_stripQuery(specifier));
|
|
262
|
-
if (!url) return;
|
|
263
|
-
let match;
|
|
264
|
-
for (const key of Object.keys(virtual)) if (_virtualKeyURL(key) === url) match = key;
|
|
265
|
-
return match;
|
|
266
|
-
}
|
|
267
|
-
const _warnedPathCollisions = /* @__PURE__ */ new Set();
|
|
268
|
-
function warnVirtualPathCollisions(keys) {
|
|
269
|
-
try {
|
|
270
|
-
const urlKeys = /* @__PURE__ */ new Map();
|
|
271
|
-
for (const key of keys) {
|
|
272
|
-
const url = _virtualKeyURL(key);
|
|
273
|
-
if (!url) continue;
|
|
274
|
-
const other = urlKeys.get(url);
|
|
275
|
-
if (other !== void 0 && !_warnedPathCollisions.has(`${other}\0${key}`)) {
|
|
276
|
-
_warnedPathCollisions.add(`${other}\0${key}`);
|
|
277
|
-
console.warn(`[env-runner] virtual modules "${other}" and "${key}" name the same file; keep only one of them (which one is served depends on the runtime).`);
|
|
278
|
-
}
|
|
279
|
-
urlKeys.set(url, key);
|
|
280
|
-
}
|
|
281
|
-
} catch {}
|
|
282
|
-
}
|
|
283
|
-
const virtualKeyURL = _virtualKeyURL;
|
|
284
|
-
function virtualModuleCacheId(key) {
|
|
285
|
-
const url = _virtualKeyURL(key);
|
|
286
|
-
return url ? fileURLToPath(url) : _virtualURL(key);
|
|
287
|
-
}
|
|
288
|
-
function _virtualKeyURL(key) {
|
|
289
|
-
if (key.startsWith("file:")) try {
|
|
290
|
-
return _bareURL(new URL(key).href);
|
|
291
|
-
} catch {
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
return isAbsolute(key) ? pathToFileURL(key).href : void 0;
|
|
295
|
-
}
|
|
296
|
-
function _virtualURL(specifier) {
|
|
297
|
-
return VIRTUAL_SCHEME + specifier.replace(/[\0-\x20"%<>`\x7F-\u{10FFFF}]/gu, encodeURIComponent);
|
|
298
|
-
}
|
|
299
|
-
function _virtualURLKey(url) {
|
|
300
|
-
try {
|
|
301
|
-
return decodeURIComponent(_stripQuery(url.slice(8)));
|
|
302
|
-
} catch {
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
function _extensionFormat(key) {
|
|
307
|
-
const extension = /\.[^./\\]+$/.exec(key)?.[0];
|
|
308
|
-
return extension === void 0 ? void 0 : EXTENSION_FORMATS[extension];
|
|
309
|
-
}
|
|
310
|
-
function _isBinaryFormat(format) {
|
|
311
|
-
return format === "bytes" || format === "wasm";
|
|
312
|
-
}
|
|
313
|
-
function _toBase64(bytes) {
|
|
314
|
-
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
315
|
-
}
|
|
316
|
-
function _isModuleFormat(format) {
|
|
317
|
-
return format == null || format === "module" || format === "module-typescript";
|
|
318
|
-
}
|
|
319
|
-
function _stripQuery(specifier) {
|
|
320
|
-
const qIndex = specifier.indexOf("?");
|
|
321
|
-
return qIndex === -1 ? specifier : specifier.slice(0, qIndex);
|
|
322
|
-
}
|
|
323
|
-
function _bareURL(url) {
|
|
324
|
-
const index = url.search(/[?#]/);
|
|
325
|
-
return index === -1 ? url : url.slice(0, index);
|
|
326
|
-
}
|
|
327
|
-
function _appendQuery(url, param) {
|
|
328
|
-
const hashIndex = url.startsWith(VIRTUAL_SCHEME) ? -1 : url.indexOf("#");
|
|
329
|
-
const base = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
330
|
-
const hash = hashIndex === -1 ? "" : url.slice(hashIndex);
|
|
331
|
-
return base + (base.includes("?") ? "&" : "?") + param + hash;
|
|
332
|
-
}
|
|
333
|
-
function _resolvePathSpecifier(specifier, parentURL) {
|
|
334
|
-
try {
|
|
335
|
-
if (/^\.{0,2}\//.test(specifier) || specifier.startsWith("file:")) return new URL(specifier, parentURL).href;
|
|
336
|
-
if (isAbsolute(specifier)) {
|
|
337
|
-
const path = _stripQuery(specifier);
|
|
338
|
-
return pathToFileURL(path).href + specifier.slice(path.length);
|
|
339
|
-
}
|
|
340
|
-
} catch {}
|
|
341
|
-
}
|
|
342
|
-
function _defaultBaseURL() {
|
|
343
|
-
return pathToFileURL(process.cwd() + "/").href;
|
|
344
|
-
}
|
|
345
|
-
export { createVirtualHooks, decodeVirtualModules, encodeVirtualModules, expandVirtualInvalidation, findVirtualPathKey, normalizeVirtualModules, resolveVirtualModules, stripVirtualTypeScript, unsupportedVirtualJSXError, virtualKeyURL, virtualModuleCacheId, virtualModuleCode, virtualModuleCodeSource, virtualModuleFormat, warnVirtualPathCollisions };
|