env-runner 0.1.0 → 0.1.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 +180 -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/runner.mjs +13 -5
- package/dist/_chunks/runner2.d.mts +51 -2
- package/dist/_chunks/runner2.mjs +404 -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 +10 -3
- package/dist/runners/bun-process/runner.d.mts +2 -1
- package/dist/runners/bun-process/runner.mjs +29 -8
- package/dist/runners/bun-process/worker.mjs +26 -5
- package/dist/runners/deno-process/worker.mjs +26 -5
- 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 +26 -5
- package/dist/runners/node-worker/runner.d.mts +2 -1
- package/dist/runners/node-worker/worker.mjs +26 -5
- 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 +3 -2
package/README.md
CHANGED
|
@@ -141,24 +141,33 @@ const response = await runner.fetch("http://localhost/api");
|
|
|
141
141
|
// Proxy WebSocket upgrades
|
|
142
142
|
runner.upgrade?.({ node: { req, socket, head } });
|
|
143
143
|
|
|
144
|
+
// Wait for runner to be ready
|
|
145
|
+
await runner.waitForReady();
|
|
146
|
+
|
|
144
147
|
// Bidirectional messaging
|
|
145
148
|
runner.sendMessage({ type: "ping" });
|
|
146
149
|
runner.onMessage((msg) => console.log(msg));
|
|
147
150
|
|
|
151
|
+
// Request-response RPC
|
|
152
|
+
const result = await runner.rpc<string>("transformHTML", "<html>...</html>");
|
|
153
|
+
|
|
154
|
+
// Hot-reload entry module without restarting the worker
|
|
155
|
+
await runner.reloadModule();
|
|
156
|
+
|
|
148
157
|
// Graceful shutdown
|
|
149
158
|
await runner.close();
|
|
150
159
|
```
|
|
151
160
|
|
|
152
161
|
**Available runners:**
|
|
153
162
|
|
|
154
|
-
| Runner | Isolation | IPC mechanism
|
|
155
|
-
| ---------------------- | ------------------------------ |
|
|
156
|
-
| `NodeWorkerEnvRunner` | Worker thread | `workerData` / `parentPort`
|
|
157
|
-
| `NodeProcessEnvRunner` | Child process (`fork`) | `ENV_RUNNER_DATA` / `process.send`
|
|
158
|
-
| `BunProcessEnvRunner` | Bun or Node.js process | `Bun.spawn` IPC or `fork()`
|
|
159
|
-
| `DenoProcessEnvRunner` | Deno process | `deno run` with IPC channel
|
|
160
|
-
| `SelfEnvRunner` | In-process | In-memory channel
|
|
161
|
-
| `MiniflareEnvRunner` | Cloudflare Workers (miniflare) |
|
|
163
|
+
| Runner | Isolation | IPC mechanism |
|
|
164
|
+
| ---------------------- | ------------------------------ | ---------------------------------- |
|
|
165
|
+
| `NodeWorkerEnvRunner` | Worker thread | `workerData` / `parentPort` |
|
|
166
|
+
| `NodeProcessEnvRunner` | Child process (`fork`) | `ENV_RUNNER_DATA` / `process.send` |
|
|
167
|
+
| `BunProcessEnvRunner` | Bun or Node.js process | `Bun.spawn` IPC or `fork()` |
|
|
168
|
+
| `DenoProcessEnvRunner` | Deno process | `deno run` with IPC channel |
|
|
169
|
+
| `SelfEnvRunner` | In-process | In-memory channel |
|
|
170
|
+
| `MiniflareEnvRunner` | Cloudflare Workers (miniflare) | WebSocket pair via `dispatchFetch` |
|
|
162
171
|
|
|
163
172
|
#### Miniflare Runner
|
|
164
173
|
|
|
@@ -186,6 +195,165 @@ await runner.close();
|
|
|
186
195
|
|
|
187
196
|
The `miniflareOptions` object is passed directly to the [Miniflare constructor](https://developers.cloudflare.com/workers/testing/miniflare/) — you can configure bindings, KV, D1, Durable Objects, and any other Miniflare option.
|
|
188
197
|
|
|
198
|
+
#### Module Transform Pipeline
|
|
199
|
+
|
|
200
|
+
Pass a `transformRequest` callback to route module resolution through Vite's (or any) transform pipeline. This enables TS, JSX, and other non-JS formats to be compiled on-the-fly inside the Workers runtime without pre-bundling:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { MiniflareEnvRunner } from "env-runner/runners/miniflare";
|
|
204
|
+
|
|
205
|
+
const runner = new MiniflareEnvRunner({
|
|
206
|
+
name: "my-worker",
|
|
207
|
+
data: { entry: "./worker.ts" },
|
|
208
|
+
// Route module resolution through Vite's transform pipeline
|
|
209
|
+
transformRequest: (id) => viteDevEnvironment.transformRequest(id),
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
When `transformRequest` is provided:
|
|
214
|
+
|
|
215
|
+
- The `unsafeModuleFallbackService` calls it with the resolved file path before falling back to raw disk reads
|
|
216
|
+
- Module rules for `.ts`, `.tsx`, `.jsx`, and `.mts` are added automatically
|
|
217
|
+
- Static `export *` re-exports are skipped in the wrapper to avoid miniflare's ModuleLocator pre-walking the import tree
|
|
218
|
+
|
|
219
|
+
The callback should return `{ code: string }` for transformed modules, or `null`/`undefined` to fall back to the default raw file read.
|
|
220
|
+
|
|
221
|
+
#### Auto-detected Exports
|
|
222
|
+
|
|
223
|
+
`MiniflareEnvRunner` automatically scans the entry file for `export class` declarations and wires them as Durable Object bindings (binding name = class name). This means you don't need to manually configure `miniflareOptions.durableObjects` for simple cases:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
// worker.ts
|
|
227
|
+
export class Counter {
|
|
228
|
+
/* ... Durable Object implementation ... */
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export default {
|
|
232
|
+
async fetch(request, env) {
|
|
233
|
+
// env.Counter is auto-wired — no manual config needed
|
|
234
|
+
const id = env.Counter.idFromName("test");
|
|
235
|
+
const stub = env.Counter.get(id);
|
|
236
|
+
return stub.fetch(request);
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
To explicitly declare exports or override auto-detection:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
const runner = new MiniflareEnvRunner({
|
|
245
|
+
name: "my-worker",
|
|
246
|
+
data: { entry: "./worker.ts" },
|
|
247
|
+
// Explicit exports (merged with auto-detected ones)
|
|
248
|
+
exports: { Counter: { type: "DurableObject" } },
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Set `exports: false` to disable auto-detection entirely.
|
|
253
|
+
|
|
254
|
+
#### Error Capture
|
|
255
|
+
|
|
256
|
+
By default, the runner wraps the user's `fetch` handler in a try/catch that returns structured JSON error responses with preserved stack traces:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"error": "Cannot read properties of undefined",
|
|
261
|
+
"stack": "Error: Cannot read properties...\n at fetch (worker.ts:10:5)",
|
|
262
|
+
"name": "TypeError"
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Error responses include `Content-Type: application/json` and `X-Env-Runner-Error: 1` headers. Disable with `captureErrors: false`.
|
|
267
|
+
|
|
268
|
+
#### Persistent Miniflare
|
|
269
|
+
|
|
270
|
+
By default, `close()` disposes the Miniflare instance. With `persistent: true`, the Miniflare instance is cached and reused across runner swaps — only the IPC connection is re-established:
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
const runner1 = new MiniflareEnvRunner({
|
|
274
|
+
name: "my-worker",
|
|
275
|
+
data: { entry: "./worker.ts" },
|
|
276
|
+
persistent: true,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Later, after close() + creating a new runner with the same config,
|
|
280
|
+
// the Miniflare instance is reused (faster startup)
|
|
281
|
+
await runner1.close();
|
|
282
|
+
|
|
283
|
+
const runner2 = new MiniflareEnvRunner({
|
|
284
|
+
name: "my-worker",
|
|
285
|
+
data: { entry: "./worker.ts" },
|
|
286
|
+
persistent: true,
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Fully destroy: runner.dispose() or MiniflareEnvRunner.disposeAll()
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Vite Environment API
|
|
293
|
+
|
|
294
|
+
env-runner provides helpers for integrating with Vite's [Environment API](https://vite.dev/guide/api-environment-runtimes.html):
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
import { createViteHotChannel, createViteTransport } from "env-runner/vite";
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**Host side** — create a Vite `HotChannel` from any runner's messaging hooks:
|
|
301
|
+
|
|
302
|
+
```ts
|
|
303
|
+
import { createViteHotChannel } from "env-runner/vite";
|
|
304
|
+
|
|
305
|
+
// Bridge env-runner IPC → Vite's DevEnvironment transport
|
|
306
|
+
const transport = createViteHotChannel(runner, "ssr");
|
|
307
|
+
const env = new DevEnvironment("ssr", config, { hot: true, transport });
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Worker side** — create a `ModuleRunner` transport:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
import { createViteTransport } from "env-runner/vite";
|
|
314
|
+
|
|
315
|
+
const transport = createViteTransport(sendMessage, onMessage, "ssr");
|
|
316
|
+
const runner = new ModuleRunner({ transport, sourcemapInterceptor: "prepareStackTrace" });
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Messages are namespaced by environment name, so multiple Vite environments can share a single runner's IPC channel.
|
|
320
|
+
|
|
321
|
+
**Miniflare + Vite** — combine `MiniflareEnvRunner.transformRequest` with Vite helpers for a full Cloudflare Workers dev environment with HMR and on-the-fly transforms:
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
import { MiniflareEnvRunner } from "env-runner/runners/miniflare";
|
|
325
|
+
import { createViteHotChannel } from "env-runner/vite";
|
|
326
|
+
|
|
327
|
+
const runner = new MiniflareEnvRunner({
|
|
328
|
+
name: "worker",
|
|
329
|
+
data: { entry: "./src/worker.ts" },
|
|
330
|
+
transformRequest: (id) => devEnvironment.transformRequest(id),
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const hotChannel = createViteHotChannel(runner, "worker");
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### RPC
|
|
337
|
+
|
|
338
|
+
Send request-response messages over IPC with automatic ID generation, timeout, and error propagation:
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
// Host side
|
|
342
|
+
const html = await runner.rpc<string>("transformHTML", rawHtml, { timeout: 5000 });
|
|
343
|
+
|
|
344
|
+
// Worker side (in entry's ipc.onMessage)
|
|
345
|
+
onMessage(msg) {
|
|
346
|
+
if (msg?.__rpc === "transformHTML") {
|
|
347
|
+
const result = await transform(msg.data);
|
|
348
|
+
sendMessage({ __rpc_id: msg.__rpc_id, data: result });
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Errors can be propagated back by sending `{ __rpc_id, error: "message" }`.
|
|
354
|
+
|
|
355
|
+
### Dynamic Runner Loading
|
|
356
|
+
|
|
189
357
|
You can also use `loadRunner()` to dynamically load a runner by name:
|
|
190
358
|
|
|
191
359
|
```ts
|
|
@@ -207,6 +375,10 @@ export default {
|
|
|
207
375
|
fetch(request: Request) {
|
|
208
376
|
return new Response("Hello!");
|
|
209
377
|
},
|
|
378
|
+
upgrade(context) {
|
|
379
|
+
// Optional: handle WebSocket upgrade requests (Node.js only)
|
|
380
|
+
// context.node gives { req, socket, head }
|
|
381
|
+
},
|
|
210
382
|
middleware: [], // Optional srvx middleware
|
|
211
383
|
plugins: [], // Optional srvx plugins
|
|
212
384
|
ipc: {
|
|
@@ -1,67 +1,7 @@
|
|
|
1
|
+
import { a as RunnerMessageListener, l as WorkerAddress, t as EnvRunner, u as WorkerHooks } from "./types.mjs";
|
|
1
2
|
import { IncomingMessage } from "node:http";
|
|
2
3
|
import { Socket } from "node:net";
|
|
3
4
|
|
|
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
|
-
/** Core runner interface combining lifecycle hooks, RPC, and request proxying. */
|
|
52
|
-
interface EnvRunner extends WorkerHooks, RunnerRPCHooks {
|
|
53
|
-
/** Whether the worker is ready to accept requests. */
|
|
54
|
-
readonly ready: boolean;
|
|
55
|
-
/** Whether the runner has been closed. */
|
|
56
|
-
readonly closed: boolean;
|
|
57
|
-
/** Proxy an HTTP request to the worker. */
|
|
58
|
-
fetch: FetchHandler;
|
|
59
|
-
/** Proxy a WebSocket upgrade request to the worker. */
|
|
60
|
-
upgrade?: UpgradeHandler;
|
|
61
|
-
/** Gracefully shut down the worker. */
|
|
62
|
-
close(): Promise<void>;
|
|
63
|
-
}
|
|
64
|
-
//#endregion
|
|
65
5
|
//#region src/common/base-runner.d.ts
|
|
66
6
|
interface EnvRunnerData {
|
|
67
7
|
name?: string;
|
|
@@ -93,6 +33,11 @@ declare abstract class BaseEnvRunner implements EnvRunner {
|
|
|
93
33
|
abstract sendMessage(message: unknown): void;
|
|
94
34
|
onMessage(listener: RunnerMessageListener): void;
|
|
95
35
|
offMessage(listener: RunnerMessageListener): void;
|
|
36
|
+
waitForReady(timeout?: number): Promise<void>;
|
|
37
|
+
rpc<T = unknown>(name: string, data?: unknown, opts?: {
|
|
38
|
+
timeout?: number;
|
|
39
|
+
}): Promise<T>;
|
|
40
|
+
reloadModule(timeout?: number): Promise<void>;
|
|
96
41
|
close(cause?: unknown): Promise<void>;
|
|
97
42
|
protected _handleMessage(message: any): void;
|
|
98
43
|
protected _closeSocket(): Promise<void>;
|
|
@@ -102,4 +47,4 @@ declare abstract class BaseEnvRunner implements EnvRunner {
|
|
|
102
47
|
protected abstract _runtimeType(): string;
|
|
103
48
|
}
|
|
104
49
|
//#endregion
|
|
105
|
-
export {
|
|
50
|
+
export { EnvRunnerData as n, BaseEnvRunner as t };
|
|
@@ -35,6 +35,71 @@ var BaseEnvRunner = class {
|
|
|
35
35
|
offMessage(listener) {
|
|
36
36
|
this._messageListeners.delete(listener);
|
|
37
37
|
}
|
|
38
|
+
waitForReady(timeout = 5e3) {
|
|
39
|
+
if (this.ready) return Promise.resolve();
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const timer = setTimeout(() => {
|
|
42
|
+
this._messageListeners.delete(listener);
|
|
43
|
+
reject(/* @__PURE__ */ new Error("Runner did not become ready in time"));
|
|
44
|
+
}, timeout);
|
|
45
|
+
const listener = () => {
|
|
46
|
+
if (this.ready) {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
this._messageListeners.delete(listener);
|
|
49
|
+
resolve();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
this._messageListeners.add(listener);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
rpc(name, data, opts) {
|
|
56
|
+
const id = Math.random().toString(36).slice(2);
|
|
57
|
+
const timeout = opts?.timeout ?? 3e3;
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
const timer = setTimeout(() => {
|
|
60
|
+
cleanup();
|
|
61
|
+
reject(/* @__PURE__ */ new Error(`RPC "${name}" timed out`));
|
|
62
|
+
}, timeout);
|
|
63
|
+
const listener = (msg) => {
|
|
64
|
+
if (msg?.__rpc_id === id) {
|
|
65
|
+
cleanup();
|
|
66
|
+
if (msg.error) reject(typeof msg.error === "string" ? new Error(msg.error) : msg.error);
|
|
67
|
+
else resolve(msg.data);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const cleanup = () => {
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
this.offMessage(listener);
|
|
73
|
+
};
|
|
74
|
+
this.onMessage(listener);
|
|
75
|
+
this.sendMessage({
|
|
76
|
+
__rpc: name,
|
|
77
|
+
__rpc_id: id,
|
|
78
|
+
data
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async reloadModule(timeout = 5e3) {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const timer = setTimeout(() => {
|
|
85
|
+
cleanup();
|
|
86
|
+
reject(/* @__PURE__ */ new Error("Module reload timed out"));
|
|
87
|
+
}, timeout);
|
|
88
|
+
const listener = (msg) => {
|
|
89
|
+
if (msg?.event === "module-reloaded") {
|
|
90
|
+
cleanup();
|
|
91
|
+
if (msg.error) reject(typeof msg.error === "string" ? new Error(msg.error) : msg.error);
|
|
92
|
+
else resolve();
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const cleanup = () => {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
this.offMessage(listener);
|
|
98
|
+
};
|
|
99
|
+
this.onMessage(listener);
|
|
100
|
+
this.sendMessage({ event: "reload-module" });
|
|
101
|
+
});
|
|
102
|
+
}
|
|
38
103
|
async close(cause) {
|
|
39
104
|
if (this.closed) return;
|
|
40
105
|
this.closed = true;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region node_modules/.
|
|
1
|
+
//#region node_modules/.pnpm/std-env@4.0.0-rc.1/node_modules/std-env/dist/index.mjs
|
|
2
2
|
const e = globalThis.process?.env || Object.create(null), t = globalThis.process || { env: e }, n = t !== void 0 && t.env && t.env.NODE_ENV || void 0, r = [
|
|
3
3
|
[`claude`, [`CLAUDECODE`, `CLAUDE_CODE`]],
|
|
4
4
|
[`replit`, [`REPL_ID`]],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u as WorkerHooks } from "./types.mjs";
|
|
2
|
+
import { n as EnvRunnerData, t as BaseEnvRunner } from "./base-runner.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/runners/deno-process/runner.d.ts
|
|
4
5
|
declare class DenoProcessEnvRunner extends BaseEnvRunner {
|
package/dist/_chunks/runner.mjs
CHANGED
|
@@ -26,11 +26,17 @@ var DenoProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
26
26
|
}
|
|
27
27
|
async _closeRuntime() {
|
|
28
28
|
if (!this.#process) return;
|
|
29
|
-
|
|
29
|
+
if (this.#process._exitCode == null) await this._requestGracefulShutdown(() => {
|
|
30
|
+
try {
|
|
31
|
+
this.#process.send({ event: "shutdown" });
|
|
32
|
+
} catch {}
|
|
33
|
+
}, (resolve) => {
|
|
30
34
|
this.#process?.exited.then(() => resolve());
|
|
31
35
|
}, () => this.#process?._exitCode != null);
|
|
32
36
|
this.#process.removeAllListeners?.();
|
|
33
|
-
|
|
37
|
+
try {
|
|
38
|
+
this.#process.kill();
|
|
39
|
+
} catch {}
|
|
34
40
|
this.#process = void 0;
|
|
35
41
|
}
|
|
36
42
|
#initProcess(execArgv) {
|
|
@@ -73,9 +79,11 @@ var DenoProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
73
79
|
handle._exitCode = code;
|
|
74
80
|
this.close(`process exited with code ${code}`);
|
|
75
81
|
});
|
|
76
|
-
child.
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
child.on("error", (error) => {
|
|
83
|
+
if (!this.closed) {
|
|
84
|
+
console.error(`Process error:`, error);
|
|
85
|
+
this.close(error);
|
|
86
|
+
}
|
|
79
87
|
});
|
|
80
88
|
child.on("message", (message) => {
|
|
81
89
|
this._handleMessage(message);
|
|
@@ -1,21 +1,70 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u as WorkerHooks } from "./types.mjs";
|
|
2
|
+
import { n as EnvRunnerData, t as BaseEnvRunner } from "./base-runner.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/runners/miniflare/runner.d.ts
|
|
5
|
+
/** Result from a module transform (compatible with Vite's `TransformResult`). */
|
|
6
|
+
interface TransformResult {
|
|
7
|
+
code: string;
|
|
8
|
+
}
|
|
9
|
+
/** Detected or declared export for auto-wiring Durable Object / Entrypoint bindings. */
|
|
10
|
+
interface MiniflareExportInfo {
|
|
11
|
+
type?: "DurableObject" | "WorkerEntrypoint" | "class";
|
|
12
|
+
}
|
|
4
13
|
interface MiniflareEnvRunnerOptions {
|
|
5
14
|
name: string;
|
|
6
15
|
hooks?: WorkerHooks;
|
|
7
16
|
data?: EnvRunnerData;
|
|
8
17
|
/** Options passed directly to the Miniflare constructor. */
|
|
9
18
|
miniflareOptions?: Record<string, unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* Optional module transform callback. When provided, the module fallback
|
|
21
|
+
* service calls this instead of reading raw files from disk.
|
|
22
|
+
*
|
|
23
|
+
* This enables integration with Vite's transform pipeline — pass
|
|
24
|
+
* `environment.transformRequest` to get TS/JSX/etc. compiled on the fly.
|
|
25
|
+
*
|
|
26
|
+
* @param id - Absolute file path of the module to transform
|
|
27
|
+
* @returns Transformed code, or null/undefined to fall back to raw disk read
|
|
28
|
+
*/
|
|
29
|
+
transformRequest?: (id: string) => Promise<TransformResult | null | undefined>;
|
|
30
|
+
/**
|
|
31
|
+
* Declare named exports (Durable Objects, WorkerEntrypoints) to auto-wire
|
|
32
|
+
* bindings and generate re-exports in the wrapper module.
|
|
33
|
+
*
|
|
34
|
+
* When set to `true`, `export class` declarations are auto-detected from
|
|
35
|
+
* the entry file. When set to a record, the listed exports are used
|
|
36
|
+
* (merged with auto-detected ones). Disabled by default.
|
|
37
|
+
*/
|
|
38
|
+
exports?: Record<string, MiniflareExportInfo> | boolean;
|
|
39
|
+
/**
|
|
40
|
+
* When `true`, the Miniflare instance is cached and reused across runner
|
|
41
|
+
* swaps (e.g. via `RunnerManager.reload()`). `close()` tears down IPC but
|
|
42
|
+
* keeps Miniflare alive. Call `dispose()` to fully destroy it.
|
|
43
|
+
*/
|
|
44
|
+
persistent?: boolean;
|
|
45
|
+
/** Wrap the user's `fetch` in a try/catch that returns structured JSON error responses. Default: `true`. */
|
|
46
|
+
captureErrors?: boolean;
|
|
10
47
|
}
|
|
11
48
|
declare class MiniflareEnvRunner extends BaseEnvRunner {
|
|
12
49
|
#private;
|
|
13
50
|
constructor(opts: MiniflareEnvRunnerOptions);
|
|
51
|
+
/** Dispose all persistent Miniflare instances from the cache. */
|
|
52
|
+
static disposeAll(): Promise<void>;
|
|
53
|
+
/** Fully dispose the Miniflare instance (even if persistent). */
|
|
54
|
+
dispose(): Promise<void>;
|
|
14
55
|
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
15
56
|
sendMessage(message: unknown): void;
|
|
57
|
+
/**
|
|
58
|
+
* Hot-reload the user entry module without recreating the Miniflare instance.
|
|
59
|
+
*
|
|
60
|
+
* Sends `reload-module` event over the WebSocket. The worker wrapper uses
|
|
61
|
+
* `unsafeEvalBinding` to re-import the entry with a cache-busting query string
|
|
62
|
+
* and responds with `module-reloaded` when done.
|
|
63
|
+
*/
|
|
64
|
+
reloadModule(timeout?: number): Promise<void>;
|
|
16
65
|
protected _hasRuntime(): boolean;
|
|
17
66
|
protected _runtimeType(): string;
|
|
18
67
|
protected _closeRuntime(): Promise<void>;
|
|
19
68
|
}
|
|
20
69
|
//#endregion
|
|
21
|
-
export { MiniflareEnvRunnerOptions as n, MiniflareEnvRunner as t };
|
|
70
|
+
export { TransformResult as i, MiniflareEnvRunnerOptions as n, MiniflareExportInfo as r, MiniflareEnvRunner as t };
|