env-runner 0.2.1 → 0.2.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.
@@ -1,39 +1,20 @@
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;
8
8
  data?: EnvRunnerData;
9
9
  /**
10
- * Module specifier for the `@netlify/runtime` package, used inside the
11
- * worker to call `startRuntime()` (full `globalThis.Netlify` + `caches`
12
- * setup). `env-runner` does not depend on `@netlify/runtime`.
13
- *
14
- * Unlike the other runtime-dependency options, this one takes a **specifier
15
- * only**: the runtime has to be instantiated inside the worker thread, and a
16
- * live module instance cannot cross that boundary.
17
- *
18
- * ```ts
19
- * new NetlifyEnvRunner({
20
- * name: "app",
21
- * netlifyRuntime: import.meta.resolve("@netlify/runtime"),
22
- * data: { entry },
23
- * });
24
- * ```
25
- *
26
- * A bare specifier (e.g. `"@netlify/runtime"`) is resolved from the current
27
- * working directory. When omitted, the worker tries
28
- * `import("@netlify/runtime")` and falls back to a lightweight
29
- * `globalThis.Netlify` shim (env access only) if it isn't installed. Pass
30
- * `false` to always use the shim.
10
+ * `@netlify/runtime` specifier (resolved from cwd), imported inside the worker
11
+ * since a module instance can't cross into it. Omitted: imported optionally,
12
+ * else an env-only `globalThis.Netlify` shim. `false` forces the shim.
31
13
  */
32
14
  netlifyRuntime?: string | URL | false;
33
15
  }
34
- declare class NetlifyEnvRunner extends NodeWorkerEnvRunner {
16
+ export declare class NetlifyEnvRunner extends NodeWorkerEnvRunner {
35
17
  constructor(opts: NetlifyEnvRunnerOptions);
36
18
  fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
37
19
  protected _runtimeType(): string;
38
- }
39
- export { NetlifyEnvRunner, NetlifyEnvRunnerOptions };
20
+ }
@@ -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,28 +1,23 @@
1
1
  import { IncomingMessage } from "node:http";
2
2
  import { Socket } from "node:net";
3
- /**
4
- * Handler for proxying HTTP requests to the worker.
5
- *
6
- * A relative string input (e.g. `"/path"`) is resolved against a placeholder
7
- * `http://localhost` origin before dispatching.
8
- */
9
- type FetchHandler = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
3
+ /** Proxy a request to the worker; relative inputs resolve against `http://localhost`. */
4
+ export type FetchHandler = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
10
5
  /** Callback for receiving messages from the worker. */
11
- type RunnerMessageListener = (data: unknown) => void;
6
+ export type RunnerMessageListener = (data: unknown) => void;
12
7
  /** Raw Node.js upgrade request context. */
13
- interface NodeUpgradeContext {
8
+ export interface NodeUpgradeContext {
14
9
  req: IncomingMessage;
15
10
  socket: Socket;
16
11
  head: any;
17
12
  }
18
13
  /** Context passed to the upgrade handler for WebSocket upgrades. */
19
- interface UpgradeContext {
14
+ export interface UpgradeContext {
20
15
  node: NodeUpgradeContext;
21
16
  }
22
17
  /** Handler for proxying WebSocket upgrade requests to the worker. */
23
- type UpgradeHandler = (context: UpgradeContext) => void;
18
+ export type UpgradeHandler = (context: UpgradeContext) => void;
24
19
  /** Bidirectional RPC messaging interface between the runner and worker. */
25
- interface RunnerRPCHooks {
20
+ export interface RunnerRPCHooks {
26
21
  /** Send a message to the worker. */
27
22
  sendMessage: (message: unknown) => void;
28
23
  /** Register a listener for messages from the worker. */
@@ -30,12 +25,8 @@ interface RunnerRPCHooks {
30
25
  /** Remove a previously registered message listener. */
31
26
  offMessage: (listener: RunnerMessageListener) => void;
32
27
  }
33
- /**
34
- * Address reported by the worker once it is ready.
35
- *
36
- * Either a TCP `host`/`port` pair or a Unix `socketPath`.
37
- */
38
- type WorkerAddress = {
28
+ /** Address reported by the worker once it is ready. */
29
+ export type WorkerAddress = {
39
30
  host?: string;
40
31
  port: number;
41
32
  socketPath?: undefined;
@@ -45,19 +36,19 @@ type WorkerAddress = {
45
36
  socketPath: string;
46
37
  };
47
38
  /** Lifecycle hooks for observing runner state changes. */
48
- interface WorkerHooks {
39
+ export interface WorkerHooks {
49
40
  /** Called when the worker closes, optionally with the cause. */
50
41
  onClose?: (worker: EnvRunner, cause?: unknown) => void;
51
42
  /** Called when the worker is ready and listening at the given address. */
52
43
  onReady?: (worker: EnvRunner, address?: WorkerAddress) => void;
53
44
  }
54
45
  /** Options for the `rpc()` method. */
55
- interface RPCOptions {
46
+ export interface RPCOptions {
56
47
  /** Timeout in milliseconds before the RPC call rejects. Default: 3000. */
57
48
  timeout?: number;
58
49
  }
59
50
  /** Core runner interface combining lifecycle hooks, RPC, and request proxying. */
60
- interface EnvRunner extends RunnerRPCHooks, AsyncDisposable {
51
+ export interface EnvRunner extends RunnerRPCHooks, AsyncDisposable {
61
52
  /** Whether the worker is ready to accept requests. */
62
53
  readonly ready: boolean;
63
54
  /** Whether the runner has been closed. */
@@ -83,5 +74,4 @@ interface EnvRunner extends RunnerRPCHooks, AsyncDisposable {
83
74
  close(): Promise<void>;
84
75
  /** Alias for `close()`, enabling `await using` (explicit resource management). */
85
76
  [Symbol.asyncDispose](): Promise<void>;
86
- }
87
- export { EnvRunner, FetchHandler, NodeUpgradeContext, RPCOptions, RunnerMessageListener, RunnerRPCHooks, UpgradeContext, UpgradeHandler, WorkerAddress, WorkerHooks };
77
+ }
@@ -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
+ }
@@ -61,6 +61,7 @@ var VercelEnvRunner = class extends NodeWorkerEnvRunner {
61
61
  input = this._resolveFetchInput(input);
62
62
  const headers = new Headers(input instanceof Request ? input.headers : init?.headers);
63
63
  const requestId = generateVercelId();
64
+ await this._waitForAddress();
64
65
  if (this._address && this._address.port != null && !headers.has("x-vercel-deployment-url")) {
65
66
  const host = this._address.host || "127.0.0.1";
66
67
  headers.set("x-vercel-deployment-url", `http://${host}:${this._address.port}`);
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { EnvServer } from "./_chunks/server.mjs";
2
2
  import { resolve } from "node:path";
3
- import { serve } from "srvx";
4
3
  import { parseArgs } from "node:util";
4
+ import { serve } from "srvx";
5
5
  const { values, positionals } = parseArgs({
6
6
  allowPositionals: true,
7
7
  options: {
package/dist/index.d.mts CHANGED
@@ -7,11 +7,8 @@ import { VercelEnvRunner } from "./_chunks/vercel-runner.mjs";
7
7
  import { NetlifyEnvRunner } from "./_chunks/netlify-runner.mjs";
8
8
  import { ServerOptions, ServerPlugin } from "srvx";
9
9
  import { Hooks } from "crossws";
10
- /**
11
- * Manages an active `EnvRunner` instance, proxying all calls to it.
12
- * Supports hot-reload, auto-restart on unexpected exit, and message queueing.
13
- */
14
- declare class RunnerManager implements EnvRunner, AsyncDisposable {
10
+ /** Proxies an active `EnvRunner` with hot-reload, auto-restart and message queueing. */
11
+ export declare class RunnerManager implements EnvRunner, AsyncDisposable {
15
12
  private _runner;
16
13
  private _messageQueue;
17
14
  private _messageListeners;
@@ -27,30 +24,18 @@ declare class RunnerManager implements EnvRunner, AsyncDisposable {
27
24
  get closed(): boolean;
28
25
  get address(): WorkerAddress | undefined;
29
26
  /**
30
- * Replace the active runner with a new one. Closes the previous runner.
31
- *
32
- * When called without a runner, a fresh one is created via `_createRunner()`
33
- * (only available on subclasses with a runner factory, e.g. `EnvServer`).
27
+ * Replace (and close) the active runner. Without an argument, subclasses with
28
+ * `_createRunner()` (e.g. `EnvServer`) create a fresh one.
34
29
  */
35
30
  reload(runner?: EnvRunner): Promise<void>;
36
31
  /** Create a fresh runner for argument-less `reload()`. Overridden by subclasses with a runner factory. */
37
32
  protected _createRunner(): EnvRunner | Promise<EnvRunner>;
38
33
  fetch: FetchHandler;
39
34
  protected _fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
40
- /**
41
- * Lazily satisfy a pending `invalidateModule()` with a single entry reload
42
- * before serving — concurrent fetches share the same reload. A failed reload
43
- * keeps the invalidation pending, so the next fetch retries.
44
- */
35
+ /** Apply a pending invalidation with one shared reload; a failure retries on the next fetch. */
45
36
  private _flushInvalidation;
46
37
  upgrade: UpgradeHandler;
47
- /**
48
- * Create a runtime-native WebSocket reverse-proxy plugin for the public srvx
49
- * server. Attach it via `serve({ plugins: [await manager.wsSrvxPlugin()] })`:
50
- * on Node it proxies the raw upgrade socket to the worker, and on Bun/Deno it
51
- * bridges the WebSocket with crossws. The plugin reads the active runner
52
- * lazily, so it keeps working across hot-reloads.
53
- */
38
+ /** WebSocket proxy plugin: `serve({ plugins: [await manager.wsSrvxPlugin()] })`. */
54
39
  wsSrvxPlugin(): Promise<ServerPlugin>;
55
40
  sendMessage(message: unknown): void;
56
41
  onMessage(listener: RunnerMessageListener): void;
@@ -60,11 +45,7 @@ declare class RunnerManager implements EnvRunner, AsyncDisposable {
60
45
  timeout?: number;
61
46
  }): Promise<T>;
62
47
  reloadModule(timeout?: number): Promise<void>;
63
- /**
64
- * Invalidate a virtual module on the active runner and mark the manager
65
- * dirty: the next `fetch()` reloads the entry automatically, so callers
66
- * don't need to pair the call with an explicit `reloadModule()`.
67
- */
48
+ /** Invalidate a virtual module; the next `fetch()` reloads the entry automatically. */
68
49
  invalidateModule(specifier: string, timeout?: number): Promise<void>;
69
50
  close(): Promise<void>;
70
51
  [Symbol.asyncDispose](): Promise<void>;
@@ -85,14 +66,10 @@ interface LoadRunnerOptions {
85
66
  hooks?: WorkerHooks;
86
67
  data?: EnvRunnerData;
87
68
  execArgv?: string[];
88
- /**
89
- * Additional runner-specific options (passed through to the runner
90
- * constructor) — e.g. `miniflare` (the imported `miniflare` package) for the
91
- * `miniflare` runner, which this package never imports itself.
92
- */
69
+ /** Runner-specific constructor options (e.g. `miniflare` for the `miniflare` runner). */
93
70
  [key: string]: unknown;
94
71
  }
95
- declare function loadRunner(runner: RunnerName, opts: LoadRunnerOptions): Promise<EnvRunner>;
72
+ export declare function loadRunner(runner: RunnerName, opts: LoadRunnerOptions): Promise<EnvRunner>;
96
73
  interface EnvServerOptions {
97
74
  /** Runner implementation to use (defaults to `"node-worker"`). */
98
75
  runner?: RunnerName;
@@ -110,16 +87,10 @@ interface EnvServerOptions {
110
87
  watch?: boolean;
111
88
  /** Additional paths to watch (directories or files). */
112
89
  watchPaths?: string[];
113
- /**
114
- * Extra runner-specific constructor options, spread into the runner.
115
- *
116
- * Runners that build on external packages take them as explicit options —
117
- * e.g. `{ miniflare }` for the `miniflare` runner (env-runner never imports
118
- * those packages itself).
119
- */
90
+ /** Runner-specific constructor options (e.g. `{ miniflare }`). */
120
91
  runnerOptions?: Record<string, unknown>;
121
92
  }
122
- declare class EnvServer extends RunnerManager {
93
+ export declare class EnvServer extends RunnerManager {
123
94
  private _opts;
124
95
  private _watchers;
125
96
  private _reloadTimeout;
@@ -132,17 +103,11 @@ declare class EnvServer extends RunnerManager {
132
103
  offReload(listener: () => void): void;
133
104
  constructor(opts: EnvServerOptions);
134
105
  /**
135
- * Start the server by loading and attaching the runner.
136
- *
137
- * Idempotent — concurrent and repeated calls share one startup. Calling
138
- * `start()` explicitly is optional: the first `fetch()` auto-starts the
139
- * server. A failed start resets so a later call can retry.
106
+ * Load and attach the runner. Idempotent and optional (the first `fetch()`
107
+ * auto-starts); a failed start can be retried.
140
108
  */
141
109
  start(): Promise<this>;
142
- /**
143
- * Replace the active runner. When called without an argument, a fresh
144
- * runner is created from the server options.
145
- */
110
+ /** Replace the active runner; without an argument, create one from the server options. */
146
111
  reload(runner?: EnvRunner): Promise<void>;
147
112
  close(): Promise<void>;
148
113
  /** Auto-start on first fetch so an explicit `start()` call is optional. */
@@ -161,12 +126,27 @@ interface AppEntryIPC {
161
126
  onMessage?: (message: unknown) => void | Promise<void>;
162
127
  onClose?: () => void | Promise<void>;
163
128
  }
164
- interface AppEntry {
129
+ /**
130
+ * User entry module. Other srvx `ServerOptions` are forwarded to `serve()`,
131
+ * except {@link RESERVED_SERVER_OPTIONS}.
132
+ */
133
+ interface AppEntry extends Omit<ServerOptions, "fetch"> {
165
134
  fetch: ServerOptions["fetch"];
166
135
  upgrade?: (context: UpgradeContext) => void;
167
136
  websocket?: Partial<Hooks>;
168
- middleware?: ServerOptions["middleware"];
169
- plugins?: ServerOptions["plugins"];
170
137
  ipc?: AppEntryIPC;
171
138
  }
172
- export { type AppEntry, type AppEntryIPC, type AppEntryIPCContext, BaseEnvRunner, DenoProcessEnvRunner, type EnvRunnerData as DenoProcessEnvRunnerData, type EnvRunner, type EnvRunnerData, EnvServer, type EnvServerOptions, type FetchHandler, type LoadRunnerOptions, MiniflareEnvRunner, type MiniflareEnvRunnerOptions, type MiniflareExportInfo, NetlifyEnvRunner, type NodeUpgradeContext, type RPCOptions, RunnerManager, type RunnerMessageListener, type RunnerName, type RunnerRPCHooks, type RuntimeDep, type TransformResult, type UpgradeContext, type UpgradeHandler, VercelEnvRunner, type VirtualModuleSource, type VirtualModules, type WorkerAddress, type WorkerHooks, loadRunner, resolveRuntimeDep };
139
+ /** Worker-owned srvx options: the worker listens on a random loopback port behind the proxy. */
140
+ export declare const RESERVED_SERVER_OPTIONS: ["port", "hostname", "protocol", "tls", "silent", "manual", "gracefulShutdown"];
141
+ /**
142
+ * srvx spreads `node`/`bun`/`deno` after its resolved listener options, so
143
+ * these would bypass {@link RESERVED_SERVER_OPTIONS}. `node.http2` needs TLS.
144
+ */
145
+ export declare const RESERVED_RUNTIME_OPTIONS: {
146
+ readonly node: readonly ["port", "host", "path", "http2", "cert", "key", "passphrase"];
147
+ readonly bun: readonly ["port", "hostname", "unix", "tls"];
148
+ readonly deno: readonly ["port", "hostname", "path", "cert", "key"];
149
+ };
150
+ /** Callers add `fetch` (bound lazily so reloads swap it) and the crossws plugin. */
151
+ export declare function toServerOptions(entry: AppEntry): Omit<ServerOptions, "fetch">;
152
+ 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 { BunProcessEnvRunner, type EnvRunnerData as BunProcessEnvRunnerData };
17
+ export type { EnvRunnerData as BunProcessEnvRunnerData };
@@ -2,8 +2,8 @@ import { BaseEnvRunner } from "../../_chunks/common-base-runner.mjs";
2
2
  import { hostEnv } from "../../_chunks/common-host-env.mjs";
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 { join } from "node:path";
6
+ import { execSync, spawn } from "node:child_process";
7
7
  import { homedir } from "node:os";
8
8
  let _defaultEntry;
9
9
  let _bunPath;
@@ -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,16 +1,22 @@
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
+ process.on("disconnect", () => process.exit(0));
4
5
  const data = JSON.parse(process.env.ENV_RUNNER_DATA || "{}");
5
- const _stdout = globalThis.Deno?.stdout ? { write: (s) => globalThis.Deno.stdout.writeSync(new TextEncoder().encode(s)) } : process.stdout;
6
- const sendMessage = (message) => _stdout.write(JSON.stringify(message) + "\n");
7
- const _stdin = globalThis.Deno?.stdin?.readable || process.stdin;
6
+ const sendMessage = (message) => process.send(message);
8
7
  const virtualEntry = isVirtualSpecifier(data.entry, data.virtual);
9
8
  let unregisterVirtualModules;
10
9
  let entry;
10
+ let server;
11
11
  try {
12
12
  unregisterVirtualModules = await registerVirtualModules(data.virtual);
13
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();
14
20
  } catch (error) {
15
21
  const message = error?.message || String(error);
16
22
  sendMessage({
@@ -20,16 +26,6 @@ try {
20
26
  console.error(`[env-runner] worker init failed: ${message}`);
21
27
  process.exit(1);
22
28
  }
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
29
  if (entry.upgrade) server.node?.server?.on("upgrade", (req, socket, head) => {
34
30
  entry.upgrade({ node: {
35
31
  req,
@@ -38,41 +34,21 @@ if (entry.upgrade) server.node?.server?.on("upgrade", (req, socket, head) => {
38
34
  } });
39
35
  });
40
36
  if (entry.ipc) await entry.ipc.onOpen?.({ sendMessage });
41
- sendMessage({ address: parseServerAddress(server) });
42
- async function readMessages() {
43
- const decoder = new TextDecoder();
44
- let buffer = "";
45
- for await (const chunk of _stdin) {
46
- buffer += decoder.decode(chunk, { stream: true });
47
- let newlineIdx;
48
- while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
49
- const line = buffer.slice(0, newlineIdx);
50
- buffer = buffer.slice(newlineIdx + 1);
51
- if (!line) continue;
52
- let message;
53
- try {
54
- message = JSON.parse(line);
55
- } catch {
56
- continue;
57
- }
58
- await handleMessage(message);
59
- }
60
- }
61
- }
62
- async function handleMessage(message) {
37
+ process.send({ address: parseServerAddress(server) });
38
+ process.on("message", async (message) => {
63
39
  if (message?.event === "shutdown") {
64
40
  Promise.resolve(entry.ipc?.onClose?.()).then(() => server.close()).then(() => {
65
41
  unregisterVirtualModules();
66
- sendMessage({ event: "exit" });
42
+ process.send({ event: "exit" });
67
43
  });
68
44
  return;
69
45
  }
70
46
  if (message?.event === "reload-module") {
71
47
  try {
72
48
  entry = await reloadEntryModule(data.entry, entry, sendMessage, virtualEntry);
73
- sendMessage({ event: "module-reloaded" });
49
+ process.send({ event: "module-reloaded" });
74
50
  } catch (error) {
75
- sendMessage({
51
+ process.send({
76
52
  event: "module-reloaded",
77
53
  error: error?.message || String(error)
78
54
  });
@@ -84,13 +60,12 @@ async function handleMessage(message) {
84
60
  return;
85
61
  }
86
62
  if (message?.type === "ping") {
87
- sendMessage({
63
+ process.send({
88
64
  type: "pong",
89
65
  data: message.data
90
66
  });
91
67
  return;
92
68
  }
93
69
  entry.ipc?.onMessage?.(message);
94
- }
95
- readMessages().catch(() => {});
70
+ });
96
71
  export {};
@@ -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 { NodeProcessEnvRunner, type EnvRunnerData as ProcessEnvRunnerData };
17
+ export type { EnvRunnerData as ProcessEnvRunnerData };
@@ -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 { parentPort, workerData } from "node:worker_threads";
3
3
  import { serve } from "srvx";
4
4
  import { plugin } from "crossws/server";
@@ -7,9 +7,16 @@ const sendMessage = (message) => parentPort?.postMessage(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,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 SelfEnvRunner extends BaseEnvRunner {
3
+ export declare class SelfEnvRunner extends BaseEnvRunner {
4
4
  #private;
5
5
  constructor(opts: {
6
6
  name: string;
@@ -22,4 +22,4 @@ declare class SelfEnvRunner extends BaseEnvRunner {
22
22
  protected _runtimeType(): string;
23
23
  protected _closeRuntime(): Promise<void>;
24
24
  }
25
- export { SelfEnvRunner, type EnvRunnerData as SelfEnvRunnerData };
25
+ export type { EnvRunnerData as SelfEnvRunnerData };