env-runner 0.2.0 → 0.2.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 +14 -0
- package/dist/_chunks/common-base-runner.d.mts +5 -6
- package/dist/_chunks/common-host-env.mjs +11 -0
- package/dist/_chunks/common-runtime-deps.d.mts +2 -3
- package/dist/_chunks/common-worker-utils.mjs +50 -1
- package/dist/_chunks/deno-process-runner.d.mts +2 -3
- package/dist/_chunks/deno-process-runner.mjs +3 -3
- package/dist/_chunks/libs/es-module-lexer.mjs +225 -65
- package/dist/_chunks/miniflare-runner.d.mts +8 -9
- package/dist/_chunks/miniflare-runner.mjs +99 -20
- package/dist/_chunks/netlify-runner.d.mts +3 -4
- package/dist/_chunks/node-worker-runner.d.mts +2 -3
- package/dist/_chunks/node-worker-runner.mjs +2 -1
- package/dist/_chunks/types.d.mts +11 -12
- package/dist/_chunks/vercel-runner.d.mts +2 -3
- package/dist/cli.mjs +0 -0
- package/dist/index.d.mts +38 -7
- package/dist/index.mjs +2 -1
- package/dist/runners/bun-process/runner.d.mts +2 -2
- package/dist/runners/bun-process/runner.mjs +4 -4
- package/dist/runners/bun-process/worker.mjs +8 -11
- package/dist/runners/deno-process/worker.mjs +8 -11
- package/dist/runners/node-process/runner.d.mts +2 -2
- package/dist/runners/node-process/runner.mjs +3 -3
- package/dist/runners/node-process/worker.mjs +8 -11
- package/dist/runners/node-worker/worker.mjs +8 -11
- package/dist/runners/self/runner.d.mts +2 -2
- package/dist/runners/vercel/queue-dev.d.mts +7 -8
- package/dist/vite.d.mts +4 -5
- package/package.json +30 -29
|
@@ -11,19 +11,19 @@ import { Socket } from "node:net";
|
|
|
11
11
|
* dependency stays owned by the application. It is only imported here as a
|
|
12
12
|
* fallback when neither is passed.
|
|
13
13
|
*/
|
|
14
|
-
interface WranglerModule {
|
|
14
|
+
export interface WranglerModule {
|
|
15
15
|
unstable_readConfig?: (...args: any[]) => any;
|
|
16
16
|
unstable_getMiniflareWorkerOptions?: (...args: any[]) => any;
|
|
17
17
|
[key: string]: unknown;
|
|
18
18
|
}
|
|
19
19
|
/** Raw (snake_case) Wrangler config object, mirroring `wrangler.json` contents. */
|
|
20
|
-
type WranglerInlineConfig = Record<string, unknown>;
|
|
20
|
+
export type WranglerInlineConfig = Record<string, unknown>;
|
|
21
21
|
/** Result from a module transform (compatible with Vite's `TransformResult`). */
|
|
22
|
-
interface TransformResult {
|
|
22
|
+
export interface TransformResult {
|
|
23
23
|
code: string;
|
|
24
24
|
}
|
|
25
25
|
/** Detected or declared export for auto-wiring Durable Object / Entrypoint bindings. */
|
|
26
|
-
interface MiniflareExportInfo {
|
|
26
|
+
export interface MiniflareExportInfo {
|
|
27
27
|
type?: "DurableObject" | "WorkerEntrypoint" | "class";
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
@@ -34,7 +34,7 @@ interface MiniflareExportInfo {
|
|
|
34
34
|
* the application. The runner only falls back to importing it itself when this
|
|
35
35
|
* is omitted.
|
|
36
36
|
*/
|
|
37
|
-
interface MiniflareModule {
|
|
37
|
+
export interface MiniflareModule {
|
|
38
38
|
Miniflare: new (options: any) => any;
|
|
39
39
|
/**
|
|
40
40
|
* Newest compatibility date supported by the installed `workerd` binary,
|
|
@@ -43,7 +43,7 @@ interface MiniflareModule {
|
|
|
43
43
|
supportedCompatibilityDate?: string;
|
|
44
44
|
[key: string]: unknown;
|
|
45
45
|
}
|
|
46
|
-
interface MiniflareEnvRunnerOptions {
|
|
46
|
+
export interface MiniflareEnvRunnerOptions {
|
|
47
47
|
name: string;
|
|
48
48
|
hooks?: WorkerHooks;
|
|
49
49
|
data?: EnvRunnerData;
|
|
@@ -143,7 +143,7 @@ interface MiniflareEnvRunnerOptions {
|
|
|
143
143
|
*/
|
|
144
144
|
wranglerModule?: RuntimeDep<WranglerModule>;
|
|
145
145
|
}
|
|
146
|
-
declare class MiniflareEnvRunner extends BaseEnvRunner {
|
|
146
|
+
export declare class MiniflareEnvRunner extends BaseEnvRunner {
|
|
147
147
|
#private;
|
|
148
148
|
constructor(opts: MiniflareEnvRunnerOptions);
|
|
149
149
|
/** Dispose all persistent Miniflare instances from the cache. */
|
|
@@ -182,5 +182,4 @@ declare class MiniflareEnvRunner extends BaseEnvRunner {
|
|
|
182
182
|
head: any;
|
|
183
183
|
};
|
|
184
184
|
}): Promise<void>;
|
|
185
|
-
}
|
|
186
|
-
export { MiniflareEnvRunner, MiniflareEnvRunnerOptions, MiniflareExportInfo, MiniflareModule, TransformResult, WranglerInlineConfig, WranglerModule };
|
|
185
|
+
}
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { expandVirtualInvalidation, stripVirtualTypeScript, virtualModuleFormat } from "./virtual-loader.mjs";
|
|
2
2
|
import { BaseEnvRunner } from "./common-base-runner.mjs";
|
|
3
|
+
import { isVirtualSpecifier } from "./common-worker-utils.mjs";
|
|
3
4
|
import { resolveRuntimeDep } from "./common-runtime-deps.mjs";
|
|
4
5
|
import { init, parse } from "./libs/cjs-module-lexer.mjs";
|
|
5
6
|
import { init as init$1, parse as parse$1 } from "./libs/es-module-lexer.mjs";
|
|
6
|
-
import { isVirtualSpecifier } from "./common-worker-utils.mjs";
|
|
7
7
|
import { createRequire } from "node:module";
|
|
8
8
|
import { proxyUpgrade } from "httpxy";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
10
|
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
11
|
-
import { resolveModulePath } from "exsolve";
|
|
12
11
|
import { basename, dirname, extname, isAbsolute, join, resolve } from "node:path";
|
|
12
|
+
import { resolveModulePath } from "exsolve";
|
|
13
13
|
import { tmpdir } from "node:os";
|
|
14
14
|
const IPC_PATH = "/__env_runner_ipc";
|
|
15
15
|
const IPC_BINDING = "__ENV_RUNNER_IPC";
|
|
16
|
+
const UNSAFE_EVAL_BINDING = "__ENV_RUNNER_UNSAFE_EVAL__";
|
|
16
17
|
function generateWrapper(entryPath, opts) {
|
|
17
18
|
const staticReExport = opts?.dynamicOnly ? "" : `export * from ${JSON.stringify(entryPath)};`;
|
|
18
19
|
const explicitExports = opts?.dynamicOnly && opts.exports?.length ? opts.exports.map((name) => `export { ${name} } from ${JSON.stringify(entryPath)};`).join("\n") : "";
|
|
19
20
|
const fetchBody = opts?.captureErrors ?? true ? `try {
|
|
20
|
-
return await
|
|
21
|
+
return await __server.fetch(request, env, ctx);
|
|
21
22
|
} catch (e) {
|
|
22
23
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
23
24
|
const body = JSON.stringify({
|
|
@@ -29,7 +30,7 @@ function generateWrapper(entryPath, opts) {
|
|
|
29
30
|
status: 500,
|
|
30
31
|
headers: { "Content-Type": "application/json", "X-Env-Runner-Error": "1" },
|
|
31
32
|
});
|
|
32
|
-
}` : `return
|
|
33
|
+
}` : `return __server.fetch(request, env, ctx);`;
|
|
33
34
|
return `import __process from "node:process";
|
|
34
35
|
if (!globalThis.process) { globalThis.process = __process; }
|
|
35
36
|
${staticReExport}
|
|
@@ -37,12 +38,87 @@ ${explicitExports}
|
|
|
37
38
|
|
|
38
39
|
const __IPC_PATH = "${IPC_PATH}";
|
|
39
40
|
const __IPC_BINDING = "${IPC_BINDING}";
|
|
41
|
+
const __UNSAFE_EVAL_BINDING = "${UNSAFE_EVAL_BINDING}";
|
|
40
42
|
const __entryPath = ${JSON.stringify(entryPath)};
|
|
41
43
|
let __userEntry;
|
|
44
|
+
let __server;
|
|
42
45
|
let __ipcInitialized = false;
|
|
43
46
|
let __serverWs;
|
|
44
47
|
let __currentEnv;
|
|
45
48
|
|
|
49
|
+
const __userEnvs = new WeakMap();
|
|
50
|
+
|
|
51
|
+
// \`env\` without env-runner's internal bindings (cached per env object).
|
|
52
|
+
function __userEnv(env) {
|
|
53
|
+
let userEnv = __userEnvs.get(env);
|
|
54
|
+
if (!userEnv) {
|
|
55
|
+
userEnv = { ...env };
|
|
56
|
+
delete userEnv[__IPC_BINDING];
|
|
57
|
+
delete userEnv[__UNSAFE_EVAL_BINDING];
|
|
58
|
+
__userEnvs.set(env, userEnv);
|
|
59
|
+
}
|
|
60
|
+
return userEnv;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Mirrors srvx's CloudflareServer (srvx/cloudflare): plugins, then the
|
|
64
|
+
// \`error\` handler as the outermost middleware, then the middleware chain.
|
|
65
|
+
function __createServer(entry) {
|
|
66
|
+
const server = {
|
|
67
|
+
runtime: "cloudflare",
|
|
68
|
+
options: {
|
|
69
|
+
...entry,
|
|
70
|
+
middleware: [...(entry.middleware || [])],
|
|
71
|
+
fetch: entry.fetch
|
|
72
|
+
? (request) =>
|
|
73
|
+
entry.fetch(request, request.runtime?.cloudflare?.env, request.runtime?.cloudflare?.context)
|
|
74
|
+
: () => new Response("No fetch handler exported", { status: 500 }),
|
|
75
|
+
},
|
|
76
|
+
serve() {},
|
|
77
|
+
ready: () => Promise.resolve(server),
|
|
78
|
+
close: () => Promise.resolve(),
|
|
79
|
+
};
|
|
80
|
+
for (const plugin of entry.plugins || []) {
|
|
81
|
+
plugin(server);
|
|
82
|
+
}
|
|
83
|
+
const errorHandler = server.options.error;
|
|
84
|
+
if (errorHandler) {
|
|
85
|
+
server.options.middleware.unshift((_request, next) => {
|
|
86
|
+
try {
|
|
87
|
+
const res = next();
|
|
88
|
+
return typeof res?.then === "function" ? res.then(undefined, (error) => errorHandler(error)) : res;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return errorHandler(error);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
let handler = server.options.fetch;
|
|
95
|
+
const middleware = server.options.middleware;
|
|
96
|
+
for (let i = middleware.length - 1; i >= 0; i--) {
|
|
97
|
+
const mw = middleware[i];
|
|
98
|
+
const next = handler;
|
|
99
|
+
handler = (request) => mw(request, () => next(request));
|
|
100
|
+
}
|
|
101
|
+
server.fetch = (request, env, context) => {
|
|
102
|
+
const userEnv = __userEnv(env);
|
|
103
|
+
Object.defineProperties(request, {
|
|
104
|
+
waitUntil: { value: context.waitUntil.bind(context) },
|
|
105
|
+
runtime: {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
value: { name: "cloudflare", cloudflare: { env: userEnv, context } },
|
|
108
|
+
},
|
|
109
|
+
ip: {
|
|
110
|
+
enumerable: true,
|
|
111
|
+
configurable: true,
|
|
112
|
+
get() {
|
|
113
|
+
return request.headers.get("cf-connecting-ip");
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
return handler(request);
|
|
118
|
+
};
|
|
119
|
+
return server;
|
|
120
|
+
}
|
|
121
|
+
|
|
46
122
|
async function __loadEntry(env, path) {
|
|
47
123
|
globalThis.__ENV_RUNNER_UNSAFE_EVAL__ = env.__ENV_RUNNER_UNSAFE_EVAL__;
|
|
48
124
|
const importFn = env.__ENV_RUNNER_UNSAFE_EVAL__.newAsyncFunction(
|
|
@@ -84,10 +160,12 @@ async function __handleWsMessage(env, data) {
|
|
|
84
160
|
const version = msg.version || 0;
|
|
85
161
|
try {
|
|
86
162
|
const newEntry = await __loadEntry(env, __entryPath + "?t=" + version);
|
|
163
|
+
const newServer = __createServer(newEntry);
|
|
87
164
|
if (__userEntry?.ipc?.onClose) {
|
|
88
165
|
await __userEntry.ipc.onClose();
|
|
89
166
|
}
|
|
90
167
|
__userEntry = newEntry;
|
|
168
|
+
__server = newServer;
|
|
91
169
|
__crosswsAdapter = undefined;
|
|
92
170
|
__ipcInitialized = false;
|
|
93
171
|
if (__userEntry.ipc?.onOpen) {
|
|
@@ -130,7 +208,9 @@ export default {
|
|
|
130
208
|
if (url.pathname === __IPC_PATH && request.headers.get("upgrade") === "websocket") {
|
|
131
209
|
try {
|
|
132
210
|
if (!__userEntry) {
|
|
133
|
-
|
|
211
|
+
const entry = await __loadEntry(env, __entryPath);
|
|
212
|
+
__server = __createServer(entry);
|
|
213
|
+
__userEntry = entry;
|
|
134
214
|
}
|
|
135
215
|
} catch (e) {
|
|
136
216
|
return new Response("Failed to load entry: " + String(e), { status: 500 });
|
|
@@ -164,13 +244,9 @@ export default {
|
|
|
164
244
|
// Handle WebSocket upgrade via crossws cloudflare adapter
|
|
165
245
|
if (__userEntry.websocket && request.headers.get("upgrade") === "websocket") {
|
|
166
246
|
const adapter = await __initCrossws(env, __userEntry.websocket);
|
|
167
|
-
return adapter.handleUpgrade(request, env, ctx);
|
|
247
|
+
return adapter.handleUpgrade(request, __userEnv(env), ctx);
|
|
168
248
|
}
|
|
169
249
|
|
|
170
|
-
const entryFetch = __userEntry.fetch;
|
|
171
|
-
if (!entryFetch) {
|
|
172
|
-
return new Response("No fetch handler exported", { status: 500 });
|
|
173
|
-
}
|
|
174
250
|
__currentEnv = env;
|
|
175
251
|
try {
|
|
176
252
|
${fetchBody}
|
|
@@ -408,8 +484,12 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
408
484
|
for (let i = 0; i < 5 && !this._address && !this.closed; i++) await new Promise((r) => setTimeout(r, 100 * Math.pow(2, i)));
|
|
409
485
|
if (!this.#miniflare || this.closed) return new Response("miniflare env runner is unavailable", { status: 503 });
|
|
410
486
|
const resolved = this._resolveFetchInput(input);
|
|
411
|
-
const
|
|
412
|
-
|
|
487
|
+
const request = typeof resolved === "string" || resolved instanceof URL ? new Request(resolved, init) : new Request(new Request(resolved.url, resolved), {
|
|
488
|
+
...init,
|
|
489
|
+
referrer: init?.referrer ?? resolved.referrer,
|
|
490
|
+
referrerPolicy: init?.referrerPolicy ?? resolved.referrerPolicy
|
|
491
|
+
});
|
|
492
|
+
const res = await this.#miniflare.dispatchFetch(request.url, request);
|
|
413
493
|
if (res instanceof Response) return res;
|
|
414
494
|
return new Response(res.body, {
|
|
415
495
|
status: res.status,
|
|
@@ -578,7 +658,7 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
|
|
|
578
658
|
});
|
|
579
659
|
options.scriptPath = entryDir + "/__env_runner_wrapper.mjs";
|
|
580
660
|
if (!options.modulesRoot) options.modulesRoot = "/";
|
|
581
|
-
options.unsafeEvalBinding =
|
|
661
|
+
options.unsafeEvalBinding = UNSAFE_EVAL_BINDING;
|
|
582
662
|
options.serviceBindings = {
|
|
583
663
|
...options.serviceBindings || {},
|
|
584
664
|
[IPC_BINDING]: async (request) => {
|
|
@@ -799,16 +879,15 @@ function applyVirtualVersions(code, versions) {
|
|
|
799
879
|
let out = "";
|
|
800
880
|
let last = 0;
|
|
801
881
|
for (const imp of imports) {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
882
|
+
if (imp.type === "import-meta") continue;
|
|
883
|
+
const dynamic = imp.type === "dynamic";
|
|
884
|
+
if (dynamic && imp.glob) continue;
|
|
885
|
+
const specifier = imp.specifier;
|
|
807
886
|
const version = specifier === void 0 ? void 0 : versions.get(specifier);
|
|
808
887
|
if (!version) continue;
|
|
809
888
|
const versioned = `${specifier}?v=${version}`;
|
|
810
|
-
out += code.slice(last, imp.
|
|
811
|
-
last = imp.
|
|
889
|
+
out += code.slice(last, imp.start) + (dynamic ? JSON.stringify(versioned) : versioned);
|
|
890
|
+
last = imp.end;
|
|
812
891
|
}
|
|
813
892
|
return out + code.slice(last);
|
|
814
893
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { WorkerHooks } from "./types.mjs";
|
|
2
2
|
import { EnvRunnerData } from "./common-base-runner.mjs";
|
|
3
3
|
import { NodeWorkerEnvRunner } from "./node-worker-runner.mjs";
|
|
4
|
-
interface NetlifyEnvRunnerOptions {
|
|
4
|
+
export interface NetlifyEnvRunnerOptions {
|
|
5
5
|
name: string;
|
|
6
6
|
workerEntry?: string;
|
|
7
7
|
hooks?: WorkerHooks;
|
|
@@ -31,9 +31,8 @@ interface NetlifyEnvRunnerOptions {
|
|
|
31
31
|
*/
|
|
32
32
|
netlifyRuntime?: string | URL | false;
|
|
33
33
|
}
|
|
34
|
-
declare class NetlifyEnvRunner extends NodeWorkerEnvRunner {
|
|
34
|
+
export declare class NetlifyEnvRunner extends NodeWorkerEnvRunner {
|
|
35
35
|
constructor(opts: NetlifyEnvRunnerOptions);
|
|
36
36
|
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
37
37
|
protected _runtimeType(): string;
|
|
38
|
-
}
|
|
39
|
-
export { NetlifyEnvRunner, NetlifyEnvRunnerOptions };
|
|
38
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorkerHooks } from "./types.mjs";
|
|
2
2
|
import { BaseEnvRunner, EnvRunnerData } from "./common-base-runner.mjs";
|
|
3
|
-
declare class NodeWorkerEnvRunner extends BaseEnvRunner {
|
|
3
|
+
export declare class NodeWorkerEnvRunner extends BaseEnvRunner {
|
|
4
4
|
#private;
|
|
5
5
|
constructor(opts: {
|
|
6
6
|
name: string;
|
|
@@ -12,5 +12,4 @@ declare class NodeWorkerEnvRunner extends BaseEnvRunner {
|
|
|
12
12
|
protected _hasRuntime(): boolean;
|
|
13
13
|
protected _runtimeType(): string;
|
|
14
14
|
protected _closeRuntime(): Promise<void>;
|
|
15
|
-
}
|
|
16
|
-
export { NodeWorkerEnvRunner };
|
|
15
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseEnvRunner } from "./common-base-runner.mjs";
|
|
2
|
+
import { hostEnv } from "./common-host-env.mjs";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
4
5
|
import { Worker } from "node:worker_threads";
|
|
@@ -37,7 +38,7 @@ var NodeWorkerEnvRunner = class extends BaseEnvRunner {
|
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
40
|
const worker = new Worker(this._workerEntry, {
|
|
40
|
-
env:
|
|
41
|
+
env: hostEnv(),
|
|
41
42
|
workerData: {
|
|
42
43
|
name: this._name,
|
|
43
44
|
...this._data
|
package/dist/_chunks/types.d.mts
CHANGED
|
@@ -6,23 +6,23 @@ import { Socket } from "node:net";
|
|
|
6
6
|
* A relative string input (e.g. `"/path"`) is resolved against a placeholder
|
|
7
7
|
* `http://localhost` origin before dispatching.
|
|
8
8
|
*/
|
|
9
|
-
type FetchHandler = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
9
|
+
export type FetchHandler = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
10
10
|
/** Callback for receiving messages from the worker. */
|
|
11
|
-
type RunnerMessageListener = (data: unknown) => void;
|
|
11
|
+
export type RunnerMessageListener = (data: unknown) => void;
|
|
12
12
|
/** Raw Node.js upgrade request context. */
|
|
13
|
-
interface NodeUpgradeContext {
|
|
13
|
+
export interface NodeUpgradeContext {
|
|
14
14
|
req: IncomingMessage;
|
|
15
15
|
socket: Socket;
|
|
16
16
|
head: any;
|
|
17
17
|
}
|
|
18
18
|
/** Context passed to the upgrade handler for WebSocket upgrades. */
|
|
19
|
-
interface UpgradeContext {
|
|
19
|
+
export interface UpgradeContext {
|
|
20
20
|
node: NodeUpgradeContext;
|
|
21
21
|
}
|
|
22
22
|
/** Handler for proxying WebSocket upgrade requests to the worker. */
|
|
23
|
-
type UpgradeHandler = (context: UpgradeContext) => void;
|
|
23
|
+
export type UpgradeHandler = (context: UpgradeContext) => void;
|
|
24
24
|
/** Bidirectional RPC messaging interface between the runner and worker. */
|
|
25
|
-
interface RunnerRPCHooks {
|
|
25
|
+
export interface RunnerRPCHooks {
|
|
26
26
|
/** Send a message to the worker. */
|
|
27
27
|
sendMessage: (message: unknown) => void;
|
|
28
28
|
/** Register a listener for messages from the worker. */
|
|
@@ -35,7 +35,7 @@ interface RunnerRPCHooks {
|
|
|
35
35
|
*
|
|
36
36
|
* Either a TCP `host`/`port` pair or a Unix `socketPath`.
|
|
37
37
|
*/
|
|
38
|
-
type WorkerAddress = {
|
|
38
|
+
export type WorkerAddress = {
|
|
39
39
|
host?: string;
|
|
40
40
|
port: number;
|
|
41
41
|
socketPath?: undefined;
|
|
@@ -45,19 +45,19 @@ type WorkerAddress = {
|
|
|
45
45
|
socketPath: string;
|
|
46
46
|
};
|
|
47
47
|
/** Lifecycle hooks for observing runner state changes. */
|
|
48
|
-
interface WorkerHooks {
|
|
48
|
+
export interface WorkerHooks {
|
|
49
49
|
/** Called when the worker closes, optionally with the cause. */
|
|
50
50
|
onClose?: (worker: EnvRunner, cause?: unknown) => void;
|
|
51
51
|
/** Called when the worker is ready and listening at the given address. */
|
|
52
52
|
onReady?: (worker: EnvRunner, address?: WorkerAddress) => void;
|
|
53
53
|
}
|
|
54
54
|
/** Options for the `rpc()` method. */
|
|
55
|
-
interface RPCOptions {
|
|
55
|
+
export interface RPCOptions {
|
|
56
56
|
/** Timeout in milliseconds before the RPC call rejects. Default: 3000. */
|
|
57
57
|
timeout?: number;
|
|
58
58
|
}
|
|
59
59
|
/** Core runner interface combining lifecycle hooks, RPC, and request proxying. */
|
|
60
|
-
interface EnvRunner extends RunnerRPCHooks, AsyncDisposable {
|
|
60
|
+
export interface EnvRunner extends RunnerRPCHooks, AsyncDisposable {
|
|
61
61
|
/** Whether the worker is ready to accept requests. */
|
|
62
62
|
readonly ready: boolean;
|
|
63
63
|
/** Whether the runner has been closed. */
|
|
@@ -83,5 +83,4 @@ interface EnvRunner extends RunnerRPCHooks, AsyncDisposable {
|
|
|
83
83
|
close(): Promise<void>;
|
|
84
84
|
/** Alias for `close()`, enabling `await using` (explicit resource management). */
|
|
85
85
|
[Symbol.asyncDispose](): Promise<void>;
|
|
86
|
-
}
|
|
87
|
-
export { EnvRunner, FetchHandler, NodeUpgradeContext, RPCOptions, RunnerMessageListener, RunnerRPCHooks, UpgradeContext, UpgradeHandler, WorkerAddress, WorkerHooks };
|
|
86
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { WorkerHooks } from "./types.mjs";
|
|
2
2
|
import { EnvRunnerData } from "./common-base-runner.mjs";
|
|
3
3
|
import { NodeWorkerEnvRunner } from "./node-worker-runner.mjs";
|
|
4
|
-
declare class VercelEnvRunner extends NodeWorkerEnvRunner {
|
|
4
|
+
export declare class VercelEnvRunner extends NodeWorkerEnvRunner {
|
|
5
5
|
constructor(opts: {
|
|
6
6
|
name: string;
|
|
7
7
|
workerEntry?: string;
|
|
@@ -10,5 +10,4 @@ declare class VercelEnvRunner extends NodeWorkerEnvRunner {
|
|
|
10
10
|
});
|
|
11
11
|
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
12
12
|
protected _runtimeType(): string;
|
|
13
|
-
}
|
|
14
|
-
export { VercelEnvRunner };
|
|
13
|
+
}
|
package/dist/cli.mjs
CHANGED
|
File without changes
|
package/dist/index.d.mts
CHANGED
|
@@ -11,7 +11,7 @@ import { Hooks } from "crossws";
|
|
|
11
11
|
* Manages an active `EnvRunner` instance, proxying all calls to it.
|
|
12
12
|
* Supports hot-reload, auto-restart on unexpected exit, and message queueing.
|
|
13
13
|
*/
|
|
14
|
-
declare class RunnerManager implements EnvRunner, AsyncDisposable {
|
|
14
|
+
export declare class RunnerManager implements EnvRunner, AsyncDisposable {
|
|
15
15
|
private _runner;
|
|
16
16
|
private _messageQueue;
|
|
17
17
|
private _messageListeners;
|
|
@@ -92,7 +92,7 @@ interface LoadRunnerOptions {
|
|
|
92
92
|
*/
|
|
93
93
|
[key: string]: unknown;
|
|
94
94
|
}
|
|
95
|
-
declare function loadRunner(runner: RunnerName, opts: LoadRunnerOptions): Promise<EnvRunner>;
|
|
95
|
+
export declare function loadRunner(runner: RunnerName, opts: LoadRunnerOptions): Promise<EnvRunner>;
|
|
96
96
|
interface EnvServerOptions {
|
|
97
97
|
/** Runner implementation to use (defaults to `"node-worker"`). */
|
|
98
98
|
runner?: RunnerName;
|
|
@@ -119,7 +119,7 @@ interface EnvServerOptions {
|
|
|
119
119
|
*/
|
|
120
120
|
runnerOptions?: Record<string, unknown>;
|
|
121
121
|
}
|
|
122
|
-
declare class EnvServer extends RunnerManager {
|
|
122
|
+
export declare class EnvServer extends RunnerManager {
|
|
123
123
|
private _opts;
|
|
124
124
|
private _watchers;
|
|
125
125
|
private _reloadTimeout;
|
|
@@ -161,12 +161,43 @@ interface AppEntryIPC {
|
|
|
161
161
|
onMessage?: (message: unknown) => void | Promise<void>;
|
|
162
162
|
onClose?: () => void | Promise<void>;
|
|
163
163
|
}
|
|
164
|
-
|
|
164
|
+
/**
|
|
165
|
+
* User entry module shape. Besides `fetch` and the env-runner specific hooks
|
|
166
|
+
* (`upgrade`, `websocket`, `ipc`), any srvx `ServerOptions` (e.g. `error`,
|
|
167
|
+
* `maxRequestBodySize`, `trustProxy`, `node`/`bun`/`deno`) is forwarded to
|
|
168
|
+
* `serve()` by the built-in workers. The listener-related keys in
|
|
169
|
+
* {@link RESERVED_SERVER_OPTIONS} are owned by the worker (it sits behind the
|
|
170
|
+
* runner's proxy) and are ignored if set.
|
|
171
|
+
*/
|
|
172
|
+
interface AppEntry extends Omit<ServerOptions, "fetch"> {
|
|
165
173
|
fetch: ServerOptions["fetch"];
|
|
166
174
|
upgrade?: (context: UpgradeContext) => void;
|
|
167
175
|
websocket?: Partial<Hooks>;
|
|
168
|
-
middleware?: ServerOptions["middleware"];
|
|
169
|
-
plugins?: ServerOptions["plugins"];
|
|
170
176
|
ipc?: AppEntryIPC;
|
|
171
177
|
}
|
|
172
|
-
|
|
178
|
+
/**
|
|
179
|
+
* srvx options the built-in workers always control themselves: the worker
|
|
180
|
+
* listens on a random loopback port behind the runner's proxy, so the entry
|
|
181
|
+
* must not be able to relocate or TLS-terminate it.
|
|
182
|
+
*/
|
|
183
|
+
export declare const RESERVED_SERVER_OPTIONS: ["port", "hostname", "protocol", "tls", "silent", "manual", "gracefulShutdown"];
|
|
184
|
+
/**
|
|
185
|
+
* Listener/TLS keys inside the runtime-specific option objects. srvx spreads
|
|
186
|
+
* `node`/`bun`/`deno` *after* its resolved port/host/tls, so these would
|
|
187
|
+
* otherwise bypass {@link RESERVED_SERVER_OPTIONS}. `node.http2` is dropped
|
|
188
|
+
* too: srvx requires a TLS certificate for it, which the worker never has.
|
|
189
|
+
*/
|
|
190
|
+
export declare const RESERVED_RUNTIME_OPTIONS: {
|
|
191
|
+
readonly node: readonly ["port", "host", "path", "http2", "cert", "key", "passphrase"];
|
|
192
|
+
readonly bun: readonly ["port", "hostname", "unix", "tls"];
|
|
193
|
+
readonly deno: readonly ["port", "hostname", "path", "cert", "key"];
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Build the srvx `serve()` options for a user entry: forwards every srvx
|
|
197
|
+
* option exported by the entry, drops env-runner specific keys (`fetch`,
|
|
198
|
+
* `upgrade`, `websocket`, `ipc`) and pins the worker-owned listener options
|
|
199
|
+
* (top-level and nested in `node`/`bun`/`deno`). Callers add `fetch` (bound
|
|
200
|
+
* lazily so module reloads swap the handler) and the crossws plugin themselves.
|
|
201
|
+
*/
|
|
202
|
+
export declare function toServerOptions(entry: AppEntry): Omit<ServerOptions, "fetch">;
|
|
203
|
+
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 VirtualModuleSource, type VirtualModules, type WorkerAddress, type WorkerHooks, resolveRuntimeDep };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { BaseEnvRunner } from "./_chunks/common-base-runner.mjs";
|
|
2
2
|
import { EnvServer, RunnerManager, loadRunner } from "./_chunks/server.mjs";
|
|
3
|
+
import { RESERVED_RUNTIME_OPTIONS, RESERVED_SERVER_OPTIONS, toServerOptions } from "./_chunks/common-worker-utils.mjs";
|
|
3
4
|
import { resolveRuntimeDep } from "./_chunks/common-runtime-deps.mjs";
|
|
4
5
|
import { DenoProcessEnvRunner } from "./_chunks/deno-process-runner.mjs";
|
|
5
6
|
import { MiniflareEnvRunner } from "./_chunks/miniflare-runner.mjs";
|
|
6
7
|
import { VercelEnvRunner } from "./_chunks/vercel-runner.mjs";
|
|
7
8
|
import { NetlifyEnvRunner } from "./_chunks/netlify-runner.mjs";
|
|
8
|
-
export { BaseEnvRunner, DenoProcessEnvRunner, EnvServer, MiniflareEnvRunner, NetlifyEnvRunner, RunnerManager, VercelEnvRunner, loadRunner, resolveRuntimeDep };
|
|
9
|
+
export { BaseEnvRunner, DenoProcessEnvRunner, EnvServer, MiniflareEnvRunner, NetlifyEnvRunner, RESERVED_RUNTIME_OPTIONS, RESERVED_SERVER_OPTIONS, RunnerManager, VercelEnvRunner, loadRunner, resolveRuntimeDep, toServerOptions };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
2
|
import { BaseEnvRunner, EnvRunnerData } from "../../_chunks/common-base-runner.mjs";
|
|
3
|
-
declare class BunProcessEnvRunner extends BaseEnvRunner {
|
|
3
|
+
export declare class BunProcessEnvRunner extends BaseEnvRunner {
|
|
4
4
|
#private;
|
|
5
5
|
constructor(opts: {
|
|
6
6
|
name: string;
|
|
@@ -14,4 +14,4 @@ declare class BunProcessEnvRunner extends BaseEnvRunner {
|
|
|
14
14
|
protected _runtimeType(): string;
|
|
15
15
|
protected _closeRuntime(): Promise<void>;
|
|
16
16
|
}
|
|
17
|
-
export {
|
|
17
|
+
export type { EnvRunnerData as BunProcessEnvRunnerData };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { BaseEnvRunner } from "../../_chunks/common-base-runner.mjs";
|
|
2
|
+
import { hostEnv } from "../../_chunks/common-host-env.mjs";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
4
|
-
import { execSync, spawn } from "node:child_process";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
+
import { execSync, spawn } from "node:child_process";
|
|
6
7
|
import { homedir } from "node:os";
|
|
7
8
|
let _defaultEntry;
|
|
8
9
|
let _bunPath;
|
|
@@ -56,11 +57,10 @@ var BunProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
56
57
|
this.close(`process entry not found in "${this._workerEntry}".`);
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
|
-
const env = {
|
|
60
|
-
...process.env,
|
|
60
|
+
const env = hostEnv({
|
|
61
61
|
ENV_RUNNER_NAME: this._name,
|
|
62
62
|
ENV_RUNNER_DATA: JSON.stringify(this._data || {})
|
|
63
|
-
};
|
|
63
|
+
});
|
|
64
64
|
if (_isBun) this.#initBunProcess(execArgv, env);
|
|
65
65
|
else this.#initNodeProcess(execArgv, env);
|
|
66
66
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { handleInvalidateModule, isVirtualSpecifier, parseServerAddress, registerVirtualModules, reloadEntryModule, resolveEntry } from "../../_chunks/common-worker-utils.mjs";
|
|
1
|
+
import { handleInvalidateModule, isVirtualSpecifier, parseServerAddress, registerVirtualModules, reloadEntryModule, resolveEntry, toServerOptions } from "../../_chunks/common-worker-utils.mjs";
|
|
2
2
|
import { serve } from "srvx";
|
|
3
3
|
import { plugin } from "crossws/server";
|
|
4
4
|
process.on("disconnect", () => process.exit(0));
|
|
@@ -7,9 +7,16 @@ const sendMessage = (message) => process.send(message);
|
|
|
7
7
|
const virtualEntry = isVirtualSpecifier(data.entry, data.virtual);
|
|
8
8
|
let unregisterVirtualModules;
|
|
9
9
|
let entry;
|
|
10
|
+
let server;
|
|
10
11
|
try {
|
|
11
12
|
unregisterVirtualModules = await registerVirtualModules(data.virtual);
|
|
12
13
|
entry = await resolveEntry(data.entry, virtualEntry);
|
|
14
|
+
server = serve({
|
|
15
|
+
...toServerOptions(entry),
|
|
16
|
+
fetch: (request) => entry.fetch(request),
|
|
17
|
+
plugins: [...entry.plugins || [], ...entry.websocket ? [plugin(entry.websocket)] : []]
|
|
18
|
+
});
|
|
19
|
+
await server.ready();
|
|
13
20
|
} catch (error) {
|
|
14
21
|
const message = error?.message || String(error);
|
|
15
22
|
sendMessage({
|
|
@@ -19,16 +26,6 @@ try {
|
|
|
19
26
|
console.error(`[env-runner] worker init failed: ${message}`);
|
|
20
27
|
process.exit(1);
|
|
21
28
|
}
|
|
22
|
-
const server = serve({
|
|
23
|
-
port: 0,
|
|
24
|
-
hostname: "127.0.0.1",
|
|
25
|
-
silent: true,
|
|
26
|
-
fetch: (request) => entry.fetch(request),
|
|
27
|
-
middleware: entry.middleware,
|
|
28
|
-
plugins: [...entry.plugins || [], ...entry.websocket ? [plugin(entry.websocket)] : []],
|
|
29
|
-
gracefulShutdown: false
|
|
30
|
-
});
|
|
31
|
-
await server.ready();
|
|
32
29
|
if (entry.upgrade) server.node?.server?.on("upgrade", (req, socket, head) => {
|
|
33
30
|
entry.upgrade({ node: {
|
|
34
31
|
req,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { handleInvalidateModule, isVirtualSpecifier, parseServerAddress, registerVirtualModules, reloadEntryModule, resolveEntry } from "../../_chunks/common-worker-utils.mjs";
|
|
1
|
+
import { handleInvalidateModule, isVirtualSpecifier, parseServerAddress, registerVirtualModules, reloadEntryModule, resolveEntry, toServerOptions } from "../../_chunks/common-worker-utils.mjs";
|
|
2
2
|
import { serve } from "srvx";
|
|
3
3
|
import { plugin } from "crossws/server";
|
|
4
4
|
const data = JSON.parse(process.env.ENV_RUNNER_DATA || "{}");
|
|
@@ -8,9 +8,16 @@ const _stdin = globalThis.Deno?.stdin?.readable || process.stdin;
|
|
|
8
8
|
const virtualEntry = isVirtualSpecifier(data.entry, data.virtual);
|
|
9
9
|
let unregisterVirtualModules;
|
|
10
10
|
let entry;
|
|
11
|
+
let server;
|
|
11
12
|
try {
|
|
12
13
|
unregisterVirtualModules = await registerVirtualModules(data.virtual);
|
|
13
14
|
entry = await resolveEntry(data.entry, virtualEntry);
|
|
15
|
+
server = serve({
|
|
16
|
+
...toServerOptions(entry),
|
|
17
|
+
fetch: (request) => entry.fetch(request),
|
|
18
|
+
plugins: [...entry.plugins || [], ...entry.websocket ? [plugin(entry.websocket)] : []]
|
|
19
|
+
});
|
|
20
|
+
await server.ready();
|
|
14
21
|
} catch (error) {
|
|
15
22
|
const message = error?.message || String(error);
|
|
16
23
|
sendMessage({
|
|
@@ -20,16 +27,6 @@ try {
|
|
|
20
27
|
console.error(`[env-runner] worker init failed: ${message}`);
|
|
21
28
|
process.exit(1);
|
|
22
29
|
}
|
|
23
|
-
const server = serve({
|
|
24
|
-
port: 0,
|
|
25
|
-
hostname: "127.0.0.1",
|
|
26
|
-
silent: true,
|
|
27
|
-
fetch: (request) => entry.fetch(request),
|
|
28
|
-
middleware: entry.middleware,
|
|
29
|
-
plugins: [...entry.plugins || [], ...entry.websocket ? [plugin(entry.websocket)] : []],
|
|
30
|
-
gracefulShutdown: false
|
|
31
|
-
});
|
|
32
|
-
await server.ready();
|
|
33
30
|
if (entry.upgrade) server.node?.server?.on("upgrade", (req, socket, head) => {
|
|
34
31
|
entry.upgrade({ node: {
|
|
35
32
|
req,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorkerHooks } from "../../_chunks/types.mjs";
|
|
2
2
|
import { BaseEnvRunner, EnvRunnerData } from "../../_chunks/common-base-runner.mjs";
|
|
3
|
-
declare class NodeProcessEnvRunner extends BaseEnvRunner {
|
|
3
|
+
export declare class NodeProcessEnvRunner extends BaseEnvRunner {
|
|
4
4
|
#private;
|
|
5
5
|
constructor(opts: {
|
|
6
6
|
name: string;
|
|
@@ -14,4 +14,4 @@ declare class NodeProcessEnvRunner extends BaseEnvRunner {
|
|
|
14
14
|
protected _runtimeType(): string;
|
|
15
15
|
protected _closeRuntime(): Promise<void>;
|
|
16
16
|
}
|
|
17
|
-
export {
|
|
17
|
+
export type { EnvRunnerData as ProcessEnvRunnerData };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseEnvRunner } from "../../_chunks/common-base-runner.mjs";
|
|
2
|
+
import { hostEnv } from "../../_chunks/common-host-env.mjs";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
4
5
|
import { fork } from "node:child_process";
|
|
@@ -35,11 +36,10 @@ var NodeProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
38
|
const child = fork(this._workerEntry, [], {
|
|
38
|
-
env: {
|
|
39
|
-
...process.env,
|
|
39
|
+
env: hostEnv({
|
|
40
40
|
ENV_RUNNER_NAME: this._name,
|
|
41
41
|
ENV_RUNNER_DATA: JSON.stringify(this._data || {})
|
|
42
|
-
},
|
|
42
|
+
}),
|
|
43
43
|
stdio: [
|
|
44
44
|
"pipe",
|
|
45
45
|
"pipe",
|