env-runner 0.1.1 → 0.1.3
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 +191 -8
- package/dist/_chunks/base-runner.d.mts +7 -62
- package/dist/_chunks/base-runner.mjs +65 -0
- package/dist/_chunks/libs/std-env.mjs +1 -1
- package/dist/_chunks/runner.d.mts +2 -1
- package/dist/_chunks/runner2.d.mts +60 -2
- package/dist/_chunks/runner2.mjs +474 -83
- package/dist/_chunks/server.mjs +48 -0
- package/dist/_chunks/types.d.mts +76 -0
- package/dist/_chunks/worker-utils.mjs +11 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +12 -3
- package/dist/runners/bun-process/runner.d.mts +2 -1
- package/dist/runners/bun-process/worker.mjs +28 -6
- package/dist/runners/deno-process/worker.mjs +28 -6
- package/dist/runners/miniflare/runner.d.mts +2 -2
- package/dist/runners/node-process/runner.d.mts +2 -1
- package/dist/runners/node-process/worker.mjs +28 -6
- package/dist/runners/node-worker/runner.d.mts +2 -1
- package/dist/runners/node-worker/worker.mjs +28 -6
- package/dist/runners/self/runner.d.mts +12 -1
- package/dist/runners/self/runner.mjs +13 -1
- package/dist/vite.d.mts +32 -0
- package/dist/vite.mjs +58 -0
- package/package.json +4 -2
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { IncomingMessage } from "node:http";
|
|
2
|
+
import { Socket } from "node:net";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
/** Handler for proxying HTTP requests to the worker. */
|
|
6
|
+
type FetchHandler = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
7
|
+
/** Callback for receiving messages from the worker. */
|
|
8
|
+
type RunnerMessageListener = (data: unknown) => void;
|
|
9
|
+
/** Raw Node.js upgrade request context. */
|
|
10
|
+
interface NodeUpgradeContext {
|
|
11
|
+
req: IncomingMessage;
|
|
12
|
+
socket: Socket;
|
|
13
|
+
head: any;
|
|
14
|
+
}
|
|
15
|
+
/** Context passed to the upgrade handler for WebSocket upgrades. */
|
|
16
|
+
interface UpgradeContext {
|
|
17
|
+
node: NodeUpgradeContext;
|
|
18
|
+
}
|
|
19
|
+
/** Handler for proxying WebSocket upgrade requests to the worker. */
|
|
20
|
+
type UpgradeHandler = (context: UpgradeContext) => void;
|
|
21
|
+
/** Bidirectional RPC messaging interface between the runner and worker. */
|
|
22
|
+
interface RunnerRPCHooks {
|
|
23
|
+
/** Send a message to the worker. */
|
|
24
|
+
sendMessage: (message: unknown) => void;
|
|
25
|
+
/** Register a listener for messages from the worker. */
|
|
26
|
+
onMessage: (listener: RunnerMessageListener) => void;
|
|
27
|
+
/** Remove a previously registered message listener. */
|
|
28
|
+
offMessage: (listener: RunnerMessageListener) => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Address reported by the worker once it is ready.
|
|
32
|
+
*
|
|
33
|
+
* Either a TCP `host`/`port` pair or a Unix `socketPath`.
|
|
34
|
+
*/
|
|
35
|
+
type WorkerAddress = {
|
|
36
|
+
host?: string;
|
|
37
|
+
port: number;
|
|
38
|
+
socketPath?: undefined;
|
|
39
|
+
} | {
|
|
40
|
+
host?: undefined;
|
|
41
|
+
port?: undefined;
|
|
42
|
+
socketPath: string;
|
|
43
|
+
};
|
|
44
|
+
/** Lifecycle hooks for observing runner state changes. */
|
|
45
|
+
interface WorkerHooks {
|
|
46
|
+
/** Called when the worker closes, optionally with the cause. */
|
|
47
|
+
onClose?: (worker: EnvRunner, cause?: unknown) => void;
|
|
48
|
+
/** Called when the worker is ready and listening at the given address. */
|
|
49
|
+
onReady?: (worker: EnvRunner, address?: WorkerAddress) => void;
|
|
50
|
+
}
|
|
51
|
+
/** Options for the `rpc()` method. */
|
|
52
|
+
interface RPCOptions {
|
|
53
|
+
/** Timeout in milliseconds before the RPC call rejects. Default: 3000. */
|
|
54
|
+
timeout?: number;
|
|
55
|
+
}
|
|
56
|
+
/** Core runner interface combining lifecycle hooks, RPC, and request proxying. */
|
|
57
|
+
interface EnvRunner extends WorkerHooks, RunnerRPCHooks {
|
|
58
|
+
/** Whether the worker is ready to accept requests. */
|
|
59
|
+
readonly ready: boolean;
|
|
60
|
+
/** Whether the runner has been closed. */
|
|
61
|
+
readonly closed: boolean;
|
|
62
|
+
/** Proxy an HTTP request to the worker. */
|
|
63
|
+
fetch: FetchHandler;
|
|
64
|
+
/** Proxy a WebSocket upgrade request to the worker. */
|
|
65
|
+
upgrade?: UpgradeHandler;
|
|
66
|
+
/** Returns a promise that resolves when the runner becomes ready. */
|
|
67
|
+
waitForReady(timeout?: number): Promise<void>;
|
|
68
|
+
/** Send an RPC request and wait for the response. */
|
|
69
|
+
rpc<T = unknown>(name: string, data?: unknown, opts?: RPCOptions): Promise<T>;
|
|
70
|
+
/** Re-import the entry module without restarting the worker/process. */
|
|
71
|
+
reloadModule?(timeout?: number): Promise<void>;
|
|
72
|
+
/** Gracefully shut down the worker. */
|
|
73
|
+
close(): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { RunnerMessageListener as a, UpgradeHandler as c, RPCOptions as i, WorkerAddress as l, FetchHandler as n, RunnerRPCHooks as o, NodeUpgradeContext as r, UpgradeContext as s, EnvRunner as t, WorkerHooks as u };
|
|
@@ -12,5 +12,15 @@ function parseServerAddress(server) {
|
|
|
12
12
|
port: Number(url.port)
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Re-import the user entry module with cache busting.
|
|
17
|
+
* Tears down old IPC hooks and re-initializes new ones.
|
|
18
|
+
*/
|
|
19
|
+
async function reloadEntryModule(entryPath, currentEntry, sendMessage) {
|
|
20
|
+
await currentEntry.ipc?.onClose?.();
|
|
21
|
+
const newEntry = await resolveEntry(entryPath + "?t=" + Date.now());
|
|
22
|
+
await newEntry.ipc?.onOpen?.({ sendMessage });
|
|
23
|
+
return newEntry;
|
|
24
|
+
}
|
|
15
25
|
//#endregion
|
|
16
|
-
export {
|
|
26
|
+
export { reloadEntryModule as n, resolveEntry as r, parseServerAddress as t };
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as RunnerMessageListener, c as UpgradeHandler, i as RPCOptions, l as WorkerAddress, n as FetchHandler, o as RunnerRPCHooks, r as NodeUpgradeContext, s as UpgradeContext, t as EnvRunner, u as WorkerHooks } from "./_chunks/types.mjs";
|
|
2
|
+
import { n as EnvRunnerData, t as BaseEnvRunner } from "./_chunks/base-runner.mjs";
|
|
2
3
|
import { t as DenoProcessEnvRunner } from "./_chunks/runner.mjs";
|
|
3
|
-
import { n as MiniflareEnvRunnerOptions, t as MiniflareEnvRunner } from "./_chunks/runner2.mjs";
|
|
4
|
+
import { i as TransformResult, n as MiniflareEnvRunnerOptions, r as MiniflareExportInfo, t as MiniflareEnvRunner } from "./_chunks/runner2.mjs";
|
|
4
5
|
import { ServerOptions } from "srvx";
|
|
6
|
+
import { Hooks } from "crossws";
|
|
5
7
|
|
|
6
8
|
//#region src/manager.d.ts
|
|
7
9
|
/**
|
|
@@ -24,6 +26,11 @@ declare class RunnerManager implements EnvRunner {
|
|
|
24
26
|
sendMessage(message: unknown): void;
|
|
25
27
|
onMessage(listener: RunnerMessageListener): void;
|
|
26
28
|
offMessage(listener: RunnerMessageListener): void;
|
|
29
|
+
waitForReady(timeout?: number): Promise<void>;
|
|
30
|
+
rpc<T = unknown>(name: string, data?: unknown, opts?: {
|
|
31
|
+
timeout?: number;
|
|
32
|
+
}): Promise<T>;
|
|
33
|
+
reloadModule(timeout?: number): Promise<void>;
|
|
27
34
|
close(): Promise<void>;
|
|
28
35
|
onClose?: (runner: EnvRunner, cause?: unknown) => void;
|
|
29
36
|
onReady?: (runner: EnvRunner, address?: WorkerAddress) => void;
|
|
@@ -92,9 +99,11 @@ interface AppEntryIPC {
|
|
|
92
99
|
}
|
|
93
100
|
interface AppEntry {
|
|
94
101
|
fetch: ServerOptions["fetch"];
|
|
102
|
+
upgrade?: (context: UpgradeContext) => void;
|
|
103
|
+
websocket?: Partial<Hooks>;
|
|
95
104
|
middleware?: ServerOptions["middleware"];
|
|
96
105
|
plugins?: ServerOptions["plugins"];
|
|
97
106
|
ipc?: AppEntryIPC;
|
|
98
107
|
}
|
|
99
108
|
//#endregion
|
|
100
|
-
export { type AppEntry, type AppEntryIPC, type AppEntryIPCContext, BaseEnvRunner, DenoProcessEnvRunner, type EnvRunnerData as DenoProcessEnvRunnerData, type EnvRunnerData, type EnvRunner, EnvServer, type EnvServerOptions, type FetchHandler, type LoadRunnerOptions, MiniflareEnvRunner, type MiniflareEnvRunnerOptions, type NodeUpgradeContext, RunnerManager, type RunnerMessageListener, type RunnerName, type RunnerRPCHooks, type UpgradeContext, type UpgradeHandler, type WorkerAddress, type WorkerHooks, loadRunner };
|
|
109
|
+
export { type AppEntry, type AppEntryIPC, type AppEntryIPCContext, BaseEnvRunner, DenoProcessEnvRunner, type EnvRunnerData as DenoProcessEnvRunnerData, type EnvRunnerData, type EnvRunner, EnvServer, type EnvServerOptions, type FetchHandler, type LoadRunnerOptions, MiniflareEnvRunner, type MiniflareEnvRunnerOptions, type MiniflareExportInfo, type NodeUpgradeContext, type RPCOptions, RunnerManager, type RunnerMessageListener, type RunnerName, type RunnerRPCHooks, type TransformResult, type UpgradeContext, type UpgradeHandler, type WorkerAddress, type WorkerHooks, loadRunner };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u as WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
|
+
import { n as EnvRunnerData, t as BaseEnvRunner } from "../../_chunks/base-runner.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/runners/bun-process/runner.d.ts
|
|
4
5
|
declare class BunProcessEnvRunner extends BaseEnvRunner {
|
|
@@ -1,26 +1,48 @@
|
|
|
1
|
-
import { n as resolveEntry, t as parseServerAddress } from "../../_chunks/worker-utils.mjs";
|
|
1
|
+
import { n as reloadEntryModule, r as resolveEntry, t as parseServerAddress } from "../../_chunks/worker-utils.mjs";
|
|
2
2
|
import { serve } from "srvx";
|
|
3
|
+
import { plugin } from "crossws/server";
|
|
3
4
|
//#region src/runners/bun-process/worker.ts
|
|
4
|
-
const
|
|
5
|
+
const data = JSON.parse(process.env.ENV_RUNNER_DATA || "{}");
|
|
6
|
+
let entry = await resolveEntry(data.entry);
|
|
7
|
+
const sendMessage = (message) => process.send(message);
|
|
5
8
|
const server = serve({
|
|
6
9
|
port: 0,
|
|
7
10
|
hostname: "127.0.0.1",
|
|
8
11
|
silent: true,
|
|
9
|
-
fetch: entry.fetch,
|
|
12
|
+
fetch: (request) => entry.fetch(request),
|
|
10
13
|
middleware: entry.middleware,
|
|
11
|
-
plugins: entry.plugins,
|
|
14
|
+
plugins: [...entry.plugins || [], ...entry.websocket ? [plugin(entry.websocket)] : []],
|
|
12
15
|
gracefulShutdown: false
|
|
13
16
|
});
|
|
14
17
|
await server.ready();
|
|
15
|
-
if (entry.
|
|
18
|
+
if (entry.upgrade) server.node?.server?.on("upgrade", (req, socket, head) => {
|
|
19
|
+
entry.upgrade({ node: {
|
|
20
|
+
req,
|
|
21
|
+
socket,
|
|
22
|
+
head
|
|
23
|
+
} });
|
|
24
|
+
});
|
|
25
|
+
if (entry.ipc) await entry.ipc.onOpen?.({ sendMessage });
|
|
16
26
|
process.send({ address: parseServerAddress(server) });
|
|
17
|
-
process.on("message", (message) => {
|
|
27
|
+
process.on("message", async (message) => {
|
|
18
28
|
if (message?.event === "shutdown") {
|
|
19
29
|
Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
|
|
20
30
|
process.send({ event: "exit" });
|
|
21
31
|
});
|
|
22
32
|
return;
|
|
23
33
|
}
|
|
34
|
+
if (message?.event === "reload-module") {
|
|
35
|
+
try {
|
|
36
|
+
entry = await reloadEntryModule(data.entry, entry, sendMessage);
|
|
37
|
+
process.send({ event: "module-reloaded" });
|
|
38
|
+
} catch (error) {
|
|
39
|
+
process.send({
|
|
40
|
+
event: "module-reloaded",
|
|
41
|
+
error: error?.message || String(error)
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
24
46
|
if (message?.type === "ping") {
|
|
25
47
|
process.send({
|
|
26
48
|
type: "pong",
|
|
@@ -1,26 +1,48 @@
|
|
|
1
|
-
import { n as resolveEntry, t as parseServerAddress } from "../../_chunks/worker-utils.mjs";
|
|
1
|
+
import { n as reloadEntryModule, r as resolveEntry, t as parseServerAddress } from "../../_chunks/worker-utils.mjs";
|
|
2
2
|
import { serve } from "srvx";
|
|
3
|
+
import { plugin } from "crossws/server";
|
|
3
4
|
//#region src/runners/deno-process/worker.ts
|
|
4
|
-
const
|
|
5
|
+
const data = JSON.parse(process.env.ENV_RUNNER_DATA || "{}");
|
|
6
|
+
let entry = await resolveEntry(data.entry);
|
|
7
|
+
const sendMessage = (message) => process.send(message);
|
|
5
8
|
const server = serve({
|
|
6
9
|
port: 0,
|
|
7
10
|
hostname: "127.0.0.1",
|
|
8
11
|
silent: true,
|
|
9
|
-
fetch: entry.fetch,
|
|
12
|
+
fetch: (request) => entry.fetch(request),
|
|
10
13
|
middleware: entry.middleware,
|
|
11
|
-
plugins: entry.plugins,
|
|
14
|
+
plugins: [...entry.plugins || [], ...entry.websocket ? [plugin(entry.websocket)] : []],
|
|
12
15
|
gracefulShutdown: false
|
|
13
16
|
});
|
|
14
17
|
await server.ready();
|
|
15
|
-
if (entry.
|
|
18
|
+
if (entry.upgrade) server.node?.server?.on("upgrade", (req, socket, head) => {
|
|
19
|
+
entry.upgrade({ node: {
|
|
20
|
+
req,
|
|
21
|
+
socket,
|
|
22
|
+
head
|
|
23
|
+
} });
|
|
24
|
+
});
|
|
25
|
+
if (entry.ipc) await entry.ipc.onOpen?.({ sendMessage });
|
|
16
26
|
process.send({ address: parseServerAddress(server) });
|
|
17
|
-
process.on("message", (message) => {
|
|
27
|
+
process.on("message", async (message) => {
|
|
18
28
|
if (message?.event === "shutdown") {
|
|
19
29
|
Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
|
|
20
30
|
process.send({ event: "exit" });
|
|
21
31
|
});
|
|
22
32
|
return;
|
|
23
33
|
}
|
|
34
|
+
if (message?.event === "reload-module") {
|
|
35
|
+
try {
|
|
36
|
+
entry = await reloadEntryModule(data.entry, entry, sendMessage);
|
|
37
|
+
process.send({ event: "module-reloaded" });
|
|
38
|
+
} catch (error) {
|
|
39
|
+
process.send({
|
|
40
|
+
event: "module-reloaded",
|
|
41
|
+
error: error?.message || String(error)
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
24
46
|
if (message?.type === "ping") {
|
|
25
47
|
process.send({
|
|
26
48
|
type: "pong",
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as EnvRunnerData } from "../../_chunks/base-runner.mjs";
|
|
2
|
-
import { n as MiniflareEnvRunnerOptions, t as MiniflareEnvRunner } from "../../_chunks/runner2.mjs";
|
|
3
|
-
export { MiniflareEnvRunner, EnvRunnerData as MiniflareEnvRunnerData, MiniflareEnvRunnerOptions };
|
|
2
|
+
import { i as TransformResult, n as MiniflareEnvRunnerOptions, r as MiniflareExportInfo, t as MiniflareEnvRunner } from "../../_chunks/runner2.mjs";
|
|
3
|
+
export { MiniflareEnvRunner, EnvRunnerData as MiniflareEnvRunnerData, MiniflareEnvRunnerOptions, MiniflareExportInfo, TransformResult };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u as WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
|
+
import { n as EnvRunnerData, t as BaseEnvRunner } from "../../_chunks/base-runner.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/runners/node-process/runner.d.ts
|
|
4
5
|
declare class NodeProcessEnvRunner extends BaseEnvRunner {
|
|
@@ -1,26 +1,48 @@
|
|
|
1
|
-
import { n as resolveEntry, t as parseServerAddress } from "../../_chunks/worker-utils.mjs";
|
|
1
|
+
import { n as reloadEntryModule, r as resolveEntry, t as parseServerAddress } from "../../_chunks/worker-utils.mjs";
|
|
2
2
|
import { serve } from "srvx";
|
|
3
|
+
import { plugin } from "crossws/server/node";
|
|
3
4
|
//#region src/runners/node-process/worker.ts
|
|
4
|
-
const
|
|
5
|
+
const data = JSON.parse(process.env.ENV_RUNNER_DATA || "{}");
|
|
6
|
+
let entry = await resolveEntry(data.entry);
|
|
7
|
+
const sendMessage = (message) => process.send(message);
|
|
5
8
|
const server = serve({
|
|
6
9
|
port: 0,
|
|
7
10
|
hostname: "127.0.0.1",
|
|
8
11
|
silent: true,
|
|
9
|
-
fetch: entry.fetch,
|
|
12
|
+
fetch: (request) => entry.fetch(request),
|
|
10
13
|
middleware: entry.middleware,
|
|
11
|
-
plugins: entry.plugins,
|
|
14
|
+
plugins: [...entry.plugins || [], ...entry.websocket ? [plugin(entry.websocket)] : []],
|
|
12
15
|
gracefulShutdown: false
|
|
13
16
|
});
|
|
14
17
|
await server.ready();
|
|
15
|
-
if (entry.
|
|
18
|
+
if (entry.upgrade) server.node?.server?.on("upgrade", (req, socket, head) => {
|
|
19
|
+
entry.upgrade({ node: {
|
|
20
|
+
req,
|
|
21
|
+
socket,
|
|
22
|
+
head
|
|
23
|
+
} });
|
|
24
|
+
});
|
|
25
|
+
if (entry.ipc) await entry.ipc.onOpen?.({ sendMessage });
|
|
16
26
|
process.send({ address: parseServerAddress(server) });
|
|
17
|
-
process.on("message", (message) => {
|
|
27
|
+
process.on("message", async (message) => {
|
|
18
28
|
if (message?.event === "shutdown") {
|
|
19
29
|
Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
|
|
20
30
|
process.send({ event: "exit" });
|
|
21
31
|
});
|
|
22
32
|
return;
|
|
23
33
|
}
|
|
34
|
+
if (message?.event === "reload-module") {
|
|
35
|
+
try {
|
|
36
|
+
entry = await reloadEntryModule(data.entry, entry, sendMessage);
|
|
37
|
+
process.send({ event: "module-reloaded" });
|
|
38
|
+
} catch (error) {
|
|
39
|
+
process.send({
|
|
40
|
+
event: "module-reloaded",
|
|
41
|
+
error: error?.message || String(error)
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
24
46
|
if (message?.type === "ping") {
|
|
25
47
|
process.send({
|
|
26
48
|
type: "pong",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u as WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
|
+
import { n as EnvRunnerData, t as BaseEnvRunner } from "../../_chunks/base-runner.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/runners/node-worker/runner.d.ts
|
|
4
5
|
declare class NodeWorkerEnvRunner extends BaseEnvRunner {
|
|
@@ -1,27 +1,49 @@
|
|
|
1
|
-
import { n as resolveEntry, t as parseServerAddress } from "../../_chunks/worker-utils.mjs";
|
|
1
|
+
import { n as reloadEntryModule, r as resolveEntry, t as parseServerAddress } from "../../_chunks/worker-utils.mjs";
|
|
2
2
|
import { parentPort, workerData } from "node:worker_threads";
|
|
3
3
|
import { serve } from "srvx";
|
|
4
|
+
import { plugin } from "crossws/server/node";
|
|
4
5
|
//#region src/runners/node-worker/worker.ts
|
|
5
|
-
const
|
|
6
|
+
const data = workerData || {};
|
|
7
|
+
let entry = await resolveEntry(data.entry);
|
|
8
|
+
const sendMessage = (message) => parentPort?.postMessage(message);
|
|
6
9
|
const server = serve({
|
|
7
10
|
port: 0,
|
|
8
11
|
hostname: "127.0.0.1",
|
|
9
12
|
silent: true,
|
|
10
|
-
fetch: entry.fetch,
|
|
13
|
+
fetch: (request) => entry.fetch(request),
|
|
11
14
|
middleware: entry.middleware,
|
|
12
|
-
plugins: entry.plugins,
|
|
15
|
+
plugins: [...entry.plugins || [], ...entry.websocket ? [plugin(entry.websocket)] : []],
|
|
13
16
|
gracefulShutdown: false
|
|
14
17
|
});
|
|
15
18
|
await server.ready();
|
|
16
|
-
if (entry.
|
|
19
|
+
if (entry.upgrade) server.node?.server?.on("upgrade", (req, socket, head) => {
|
|
20
|
+
entry.upgrade({ node: {
|
|
21
|
+
req,
|
|
22
|
+
socket,
|
|
23
|
+
head
|
|
24
|
+
} });
|
|
25
|
+
});
|
|
26
|
+
if (entry.ipc) await entry.ipc.onOpen?.({ sendMessage });
|
|
17
27
|
parentPort?.postMessage({ address: parseServerAddress(server) });
|
|
18
|
-
parentPort?.on("message", (message) => {
|
|
28
|
+
parentPort?.on("message", async (message) => {
|
|
19
29
|
if (message?.event === "shutdown") {
|
|
20
30
|
Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
|
|
21
31
|
parentPort?.postMessage({ event: "exit" });
|
|
22
32
|
});
|
|
23
33
|
return;
|
|
24
34
|
}
|
|
35
|
+
if (message?.event === "reload-module") {
|
|
36
|
+
try {
|
|
37
|
+
entry = await reloadEntryModule(data.entry, entry, sendMessage);
|
|
38
|
+
parentPort?.postMessage({ event: "module-reloaded" });
|
|
39
|
+
} catch (error) {
|
|
40
|
+
parentPort?.postMessage({
|
|
41
|
+
event: "module-reloaded",
|
|
42
|
+
error: error?.message || String(error)
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
25
47
|
if (message?.type === "ping") {
|
|
26
48
|
parentPort?.postMessage({
|
|
27
49
|
type: "pong",
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u as WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
|
+
import { n as EnvRunnerData, t as BaseEnvRunner } from "../../_chunks/base-runner.mjs";
|
|
3
|
+
import * as node_http0 from "node:http";
|
|
4
|
+
import * as node_net0 from "node:net";
|
|
2
5
|
|
|
3
6
|
//#region src/runners/self/runner.d.ts
|
|
4
7
|
declare class SelfEnvRunner extends BaseEnvRunner {
|
|
@@ -9,7 +12,15 @@ declare class SelfEnvRunner extends BaseEnvRunner {
|
|
|
9
12
|
data?: EnvRunnerData;
|
|
10
13
|
});
|
|
11
14
|
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
15
|
+
upgrade(context: {
|
|
16
|
+
node: {
|
|
17
|
+
req: node_http0.IncomingMessage;
|
|
18
|
+
socket: node_net0.Socket;
|
|
19
|
+
head: any;
|
|
20
|
+
};
|
|
21
|
+
}): Promise<void>;
|
|
12
22
|
sendMessage(message: unknown): void;
|
|
23
|
+
reloadModule(): Promise<void>;
|
|
13
24
|
protected _hasRuntime(): boolean;
|
|
14
25
|
protected _runtimeType(): string;
|
|
15
26
|
protected _closeRuntime(): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../../_chunks/libs/std-env.mjs";
|
|
2
2
|
import { t as BaseEnvRunner } from "../../_chunks/base-runner.mjs";
|
|
3
|
-
import { n as resolveEntry } from "../../_chunks/worker-utils.mjs";
|
|
3
|
+
import { n as reloadEntryModule, r as resolveEntry } from "../../_chunks/worker-utils.mjs";
|
|
4
4
|
//#region src/runners/self/runner.ts
|
|
5
5
|
var SelfEnvRunner = class extends BaseEnvRunner {
|
|
6
6
|
#active = false;
|
|
@@ -17,6 +17,10 @@ var SelfEnvRunner = class extends BaseEnvRunner {
|
|
|
17
17
|
const request = input instanceof Request ? input : new Request(input, init);
|
|
18
18
|
return this.#entry.fetch(request);
|
|
19
19
|
}
|
|
20
|
+
async upgrade(context) {
|
|
21
|
+
if (!this.#entry?.upgrade || this.closed) return;
|
|
22
|
+
this.#entry.upgrade(context);
|
|
23
|
+
}
|
|
20
24
|
sendMessage(message) {
|
|
21
25
|
if (!this.#active) throw new Error("Self env runner should be initialized before sending messages.");
|
|
22
26
|
if (message?.type === "ping") {
|
|
@@ -28,6 +32,14 @@ var SelfEnvRunner = class extends BaseEnvRunner {
|
|
|
28
32
|
}
|
|
29
33
|
this.#entry?.ipc?.onMessage?.(message);
|
|
30
34
|
}
|
|
35
|
+
async reloadModule() {
|
|
36
|
+
const entryPath = this._data?.entry;
|
|
37
|
+
if (!entryPath || !this.#entry) throw new Error("Cannot reload: no entry loaded");
|
|
38
|
+
const sendFn = (message) => {
|
|
39
|
+
queueMicrotask(() => this._handleMessage(message));
|
|
40
|
+
};
|
|
41
|
+
this.#entry = await reloadEntryModule(entryPath, this.#entry, sendFn);
|
|
42
|
+
}
|
|
31
43
|
_hasRuntime() {
|
|
32
44
|
return this.#active;
|
|
33
45
|
}
|
package/dist/vite.d.mts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { o as RunnerRPCHooks } from "./_chunks/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/vite.d.ts
|
|
4
|
+
/** Vite HotChannel-compatible interface (avoids hard dependency on vite types). */
|
|
5
|
+
interface ViteHotChannel {
|
|
6
|
+
send: (data: any) => void;
|
|
7
|
+
on: (event: string, handler: (...args: any[]) => void) => void;
|
|
8
|
+
off: (event: string, handler: (...args: any[]) => void) => void;
|
|
9
|
+
}
|
|
10
|
+
/** Vite ModuleRunner transport-compatible interface. */
|
|
11
|
+
interface ViteTransport {
|
|
12
|
+
connect: (handlers: {
|
|
13
|
+
onMessage: (payload: any) => void;
|
|
14
|
+
}) => void;
|
|
15
|
+
send: (payload: any) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a Vite `HotChannel` from an env-runner's RPC hooks.
|
|
19
|
+
*
|
|
20
|
+
* Use on the **host side** to bridge env-runner IPC → Vite's DevEnvironment transport.
|
|
21
|
+
* Messages are namespaced by `envName` so multiple Vite environments can share one runner.
|
|
22
|
+
*/
|
|
23
|
+
declare function createViteHotChannel(hooks: RunnerRPCHooks, envName: string): ViteHotChannel;
|
|
24
|
+
/**
|
|
25
|
+
* Create a Vite `ModuleRunner` transport from worker-side IPC primitives.
|
|
26
|
+
*
|
|
27
|
+
* Use on the **worker side** to bridge worker IPC → Vite's `ModuleRunner` transport.
|
|
28
|
+
* Filters messages by `envName` so multiple Vite environments can share one IPC channel.
|
|
29
|
+
*/
|
|
30
|
+
declare function createViteTransport(sendMessage: (data: any) => void, onMessage: (listener: (value: any) => void) => void, envName: string): ViteTransport;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { ViteHotChannel, ViteTransport, createViteHotChannel, createViteTransport };
|
package/dist/vite.mjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/vite.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a Vite `HotChannel` from an env-runner's RPC hooks.
|
|
4
|
+
*
|
|
5
|
+
* Use on the **host side** to bridge env-runner IPC → Vite's DevEnvironment transport.
|
|
6
|
+
* Messages are namespaced by `envName` so multiple Vite environments can share one runner.
|
|
7
|
+
*/
|
|
8
|
+
function createViteHotChannel(hooks, envName) {
|
|
9
|
+
const listeners = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
return {
|
|
11
|
+
send: (data) => hooks.sendMessage({
|
|
12
|
+
...data,
|
|
13
|
+
viteEnv: envName
|
|
14
|
+
}),
|
|
15
|
+
on: (event, handler) => {
|
|
16
|
+
if (event === "connection") return;
|
|
17
|
+
const listener = (value) => {
|
|
18
|
+
if (value?.type === "custom" && value.event === event && value.viteEnv === envName) handler(value.data, { send: (payload) => hooks.sendMessage({
|
|
19
|
+
...payload,
|
|
20
|
+
viteEnv: envName
|
|
21
|
+
}) });
|
|
22
|
+
};
|
|
23
|
+
listeners.set(handler, listener);
|
|
24
|
+
hooks.onMessage(listener);
|
|
25
|
+
},
|
|
26
|
+
off: (event, handler) => {
|
|
27
|
+
if (event === "connection") return;
|
|
28
|
+
const listener = listeners.get(handler);
|
|
29
|
+
if (listener) {
|
|
30
|
+
hooks.offMessage(listener);
|
|
31
|
+
listeners.delete(handler);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a Vite `ModuleRunner` transport from worker-side IPC primitives.
|
|
38
|
+
*
|
|
39
|
+
* Use on the **worker side** to bridge worker IPC → Vite's `ModuleRunner` transport.
|
|
40
|
+
* Filters messages by `envName` so multiple Vite environments can share one IPC channel.
|
|
41
|
+
*/
|
|
42
|
+
function createViteTransport(sendMessage, onMessage, envName) {
|
|
43
|
+
return {
|
|
44
|
+
connect({ onMessage: onRunnerMessage }) {
|
|
45
|
+
onMessage((payload) => {
|
|
46
|
+
if (payload?.type === "custom" && payload.viteEnv === envName) onRunnerMessage(payload);
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
send(payload) {
|
|
50
|
+
sendMessage?.({
|
|
51
|
+
...payload,
|
|
52
|
+
viteEnv: envName
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { createViteHotChannel, createViteTransport };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "env-runner",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Generic environment runner for JavaScript runtimes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "unjs/env-runner",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"./runners/deno-process": "./dist/runners/deno-process/runner.mjs",
|
|
24
24
|
"./runners/deno-process/worker": "./dist/runners/deno-process/worker.mjs",
|
|
25
25
|
"./runners/self": "./dist/runners/self/runner.mjs",
|
|
26
|
-
"./runners/miniflare": "./dist/runners/miniflare/runner.mjs"
|
|
26
|
+
"./runners/miniflare": "./dist/runners/miniflare/runner.mjs",
|
|
27
|
+
"./vite": "./dist/vite.mjs"
|
|
27
28
|
},
|
|
28
29
|
"scripts": {
|
|
29
30
|
"build": "obuild",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"typecheck": "tsgo --noEmit --skipLibCheck"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
41
|
+
"crossws": "^0.4.4",
|
|
40
42
|
"httpxy": "^0.3.1",
|
|
41
43
|
"srvx": "^0.11.9"
|
|
42
44
|
},
|