env-runner 0.0.0 → 0.1.0
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/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/THIRD-PARTY-LICENSES.md +33 -0
- package/dist/_chunks/base-runner.d.mts +105 -0
- package/dist/_chunks/base-runner.mjs +79 -0
- package/dist/_chunks/libs/std-env.mjs +171 -0
- package/dist/_chunks/runner.d.mts +19 -0
- package/dist/_chunks/runner.mjs +87 -0
- package/dist/_chunks/runner2.d.mts +21 -0
- package/dist/_chunks/runner2.mjs +145 -0
- package/dist/_chunks/server.mjs +186 -0
- package/dist/_chunks/worker-utils.mjs +16 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +71 -0
- package/dist/index.d.mts +100 -0
- package/dist/index.mjs +6 -0
- package/dist/runners/bun-process/runner.d.mts +19 -0
- package/dist/runners/bun-process/runner.mjs +117 -0
- package/dist/runners/bun-process/worker.d.mts +1 -0
- package/dist/runners/bun-process/worker.mjs +34 -0
- package/dist/runners/deno-process/runner.d.mts +3 -0
- package/dist/runners/deno-process/runner.mjs +4 -0
- package/dist/runners/deno-process/worker.d.mts +1 -0
- package/dist/runners/deno-process/worker.mjs +34 -0
- package/dist/runners/miniflare/runner.d.mts +3 -0
- package/dist/runners/miniflare/runner.mjs +4 -0
- package/dist/runners/node-process/runner.d.mts +19 -0
- package/dist/runners/node-process/runner.mjs +73 -0
- package/dist/runners/node-process/worker.d.mts +1 -0
- package/dist/runners/node-process/worker.mjs +34 -0
- package/dist/runners/node-worker/runner.d.mts +18 -0
- package/dist/runners/node-worker/runner.mjs +68 -0
- package/dist/runners/node-worker/worker.d.mts +1 -0
- package/dist/runners/node-worker/worker.mjs +35 -0
- package/dist/runners/self/runner.d.mts +18 -0
- package/dist/runners/self/runner.mjs +66 -0
- package/package.json +64 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Pooya Parsa <pooya@pi0.io>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# env-runner
|
|
2
|
+
|
|
3
|
+
<!-- automd:badges color=yellow -->
|
|
4
|
+
|
|
5
|
+
[](https://npmjs.com/package/env-runner)
|
|
6
|
+
[](https://npm.chart.dev/env-runner)
|
|
7
|
+
|
|
8
|
+
<!-- /automd -->
|
|
9
|
+
|
|
10
|
+
Generic environment runner for JavaScript runtimes. Run your server apps across Node.js worker threads, child processes, Bun, Deno, Cloudflare Workers (via miniflare), or in-process — with hot-reload, WebSocket proxying, and bidirectional messaging.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### App Entry
|
|
15
|
+
|
|
16
|
+
Create a server entry module that exports a `fetch` handler:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// app.ts
|
|
20
|
+
export default {
|
|
21
|
+
fetch(request: Request) {
|
|
22
|
+
return new Response("Hello!");
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### CLI
|
|
28
|
+
|
|
29
|
+
The quickest way to run your app:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx env-runner app.ts
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Flags:**
|
|
36
|
+
|
|
37
|
+
| Flag | Description | Default |
|
|
38
|
+
| ----------------- | ------------------------------------------------------------------------------------------------- | -------------- |
|
|
39
|
+
| `--runner <name>` | Runner to use (`node-worker`, `node-process`, `bun-process`, `deno-process`, `self`, `miniflare`) | `node-process` |
|
|
40
|
+
| `--port <port>` | Port to listen on | `3000` |
|
|
41
|
+
| `--host <host>` | Host to bind to | `localhost` |
|
|
42
|
+
| `-w, --watch` | Watch entry file for changes and auto-reload | |
|
|
43
|
+
|
|
44
|
+
### Server (`EnvServer`)
|
|
45
|
+
|
|
46
|
+
High-level API that combines runner loading, file watching, and auto-reload:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { serve } from "srvx";
|
|
50
|
+
import { EnvServer } from "env-runner";
|
|
51
|
+
|
|
52
|
+
const envServer = new EnvServer({
|
|
53
|
+
runner: "node-process",
|
|
54
|
+
entry: "./app.ts",
|
|
55
|
+
watch: true,
|
|
56
|
+
watchPaths: ["./src"],
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
envServer.onReady = (_runner, address) => {
|
|
60
|
+
console.log(`Worker ready on ${address?.host}:${address?.port}`);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
envServer.onReload = () => {
|
|
64
|
+
console.log("Reloaded!");
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
await envServer.start();
|
|
68
|
+
|
|
69
|
+
// Use with any HTTP server
|
|
70
|
+
const server = serve({
|
|
71
|
+
fetch: (request) => envServer.fetch(request),
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Manager (`RunnerManager`)
|
|
76
|
+
|
|
77
|
+
Proxy manager for hot-reload with message queueing and listener forwarding:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { RunnerManager, NodeProcessEnvRunner } from "env-runner";
|
|
81
|
+
|
|
82
|
+
const manager = new RunnerManager();
|
|
83
|
+
|
|
84
|
+
manager.onReady = (_runner, address) => {
|
|
85
|
+
console.log("Ready:", address);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Load initial runner
|
|
89
|
+
const runner = new NodeProcessEnvRunner({
|
|
90
|
+
name: "my-app",
|
|
91
|
+
data: { entry: "./app.ts" },
|
|
92
|
+
});
|
|
93
|
+
await manager.reload(runner);
|
|
94
|
+
|
|
95
|
+
// Proxy requests
|
|
96
|
+
const response = await manager.fetch("http://localhost/hello");
|
|
97
|
+
|
|
98
|
+
// Hot-reload with a new runner
|
|
99
|
+
const newRunner = new NodeProcessEnvRunner({
|
|
100
|
+
name: "my-app",
|
|
101
|
+
data: { entry: "./app.ts" },
|
|
102
|
+
});
|
|
103
|
+
await manager.reload(newRunner); // old runner is closed automatically
|
|
104
|
+
|
|
105
|
+
// Bidirectional messaging (queued until runner is ready)
|
|
106
|
+
manager.sendMessage({ type: "config", value: 42 });
|
|
107
|
+
manager.onMessage((msg) => console.log("From worker:", msg));
|
|
108
|
+
|
|
109
|
+
await manager.close();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Runners
|
|
113
|
+
|
|
114
|
+
Use runners directly for lower-level control:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { NodeWorkerEnvRunner } from "env-runner/runners/node-worker";
|
|
118
|
+
import { NodeProcessEnvRunner } from "env-runner/runners/node-process";
|
|
119
|
+
import { BunProcessEnvRunner } from "env-runner/runners/bun-process";
|
|
120
|
+
import { DenoProcessEnvRunner } from "env-runner/runners/deno-process";
|
|
121
|
+
import { SelfEnvRunner } from "env-runner/runners/self";
|
|
122
|
+
import { MiniflareEnvRunner } from "env-runner/runners/miniflare";
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
All runners implement the [`EnvRunner`](./src/types.ts) interface:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const runner = new NodeProcessEnvRunner({
|
|
129
|
+
name: "my-app",
|
|
130
|
+
data: { entry: "./app.ts" },
|
|
131
|
+
hooks: {
|
|
132
|
+
onReady: (runner, address) => console.log("Listening on", address),
|
|
133
|
+
onClose: (runner, cause) => console.log("Closed", cause),
|
|
134
|
+
},
|
|
135
|
+
execArgv: ["--inspect"], // Node.js flags (process-based runners)
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Proxy HTTP requests (retries with exponential backoff)
|
|
139
|
+
const response = await runner.fetch("http://localhost/api");
|
|
140
|
+
|
|
141
|
+
// Proxy WebSocket upgrades
|
|
142
|
+
runner.upgrade?.({ node: { req, socket, head } });
|
|
143
|
+
|
|
144
|
+
// Bidirectional messaging
|
|
145
|
+
runner.sendMessage({ type: "ping" });
|
|
146
|
+
runner.onMessage((msg) => console.log(msg));
|
|
147
|
+
|
|
148
|
+
// Graceful shutdown
|
|
149
|
+
await runner.close();
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Available runners:**
|
|
153
|
+
|
|
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) | `serviceBindings` + `dispatchFetch` |
|
|
162
|
+
|
|
163
|
+
#### Miniflare Runner
|
|
164
|
+
|
|
165
|
+
Run your app in the Cloudflare Workers runtime using [miniflare](https://github.com/cloudflare/workers-sdk/tree/main/packages/miniflare):
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npm install miniflare
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { MiniflareEnvRunner } from "env-runner/runners/miniflare";
|
|
173
|
+
|
|
174
|
+
const runner = new MiniflareEnvRunner({
|
|
175
|
+
name: "my-worker",
|
|
176
|
+
data: { entry: "./worker.ts" },
|
|
177
|
+
miniflareOptions: {
|
|
178
|
+
compatibilityDate: "2024-01-01",
|
|
179
|
+
kvNamespaces: ["MY_KV"],
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const response = await runner.fetch("http://localhost/api");
|
|
184
|
+
await runner.close();
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
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
|
+
|
|
189
|
+
You can also use `loadRunner()` to dynamically load a runner by name:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
import { loadRunner } from "env-runner";
|
|
193
|
+
|
|
194
|
+
const runner = await loadRunner("node-worker", {
|
|
195
|
+
name: "my-app",
|
|
196
|
+
data: { entry: "./app.ts" },
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Workers
|
|
201
|
+
|
|
202
|
+
Each IPC-based runner includes a built-in worker that handles the srvx server boilerplate. You just provide an entry module:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
// app.ts
|
|
206
|
+
export default {
|
|
207
|
+
fetch(request: Request) {
|
|
208
|
+
return new Response("Hello!");
|
|
209
|
+
},
|
|
210
|
+
middleware: [], // Optional srvx middleware
|
|
211
|
+
plugins: [], // Optional srvx plugins
|
|
212
|
+
ipc: {
|
|
213
|
+
onOpen({ sendMessage }) {
|
|
214
|
+
// IPC channel is ready — send messages back to the runner
|
|
215
|
+
sendMessage({ type: "hello", from: "worker" });
|
|
216
|
+
},
|
|
217
|
+
onMessage(message) {
|
|
218
|
+
// Receive messages from the runner
|
|
219
|
+
console.log("Got message:", message);
|
|
220
|
+
},
|
|
221
|
+
onClose() {
|
|
222
|
+
// Runner is shutting down
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The built-in worker automatically:
|
|
229
|
+
|
|
230
|
+
1. Imports your entry module
|
|
231
|
+
2. Starts a [srvx](https://srvx.h3.dev) server on a random port
|
|
232
|
+
3. Reports the address back to the runner via IPC
|
|
233
|
+
4. Handles graceful shutdown
|
|
234
|
+
|
|
235
|
+
For advanced use cases, you can provide a custom worker entry:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
const runner = new NodeProcessEnvRunner({
|
|
239
|
+
name: "my-app",
|
|
240
|
+
workerEntry: "/path/to/custom-worker.ts",
|
|
241
|
+
data: { entry: "./app.ts" },
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Development
|
|
246
|
+
|
|
247
|
+
<details>
|
|
248
|
+
|
|
249
|
+
<summary>local development</summary>
|
|
250
|
+
|
|
251
|
+
- Clone this repository
|
|
252
|
+
- Install latest LTS version of [Node.js](https://nodejs.org/en/)
|
|
253
|
+
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
|
|
254
|
+
- Install dependencies using `pnpm install`
|
|
255
|
+
- Run interactive tests using `pnpm dev`
|
|
256
|
+
|
|
257
|
+
</details>
|
|
258
|
+
|
|
259
|
+
## License
|
|
260
|
+
|
|
261
|
+
Published under the [MIT](https://github.com/unjs/env-runner/blob/main/LICENSE) license 💛.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Licenses of Bundled Dependencies
|
|
2
|
+
|
|
3
|
+
The published artifact additionally contains code with the following licenses:
|
|
4
|
+
MIT
|
|
5
|
+
|
|
6
|
+
# Bundled Dependencies
|
|
7
|
+
|
|
8
|
+
## std-env
|
|
9
|
+
|
|
10
|
+
License: MIT
|
|
11
|
+
Repository: https://github.com/unjs/std-env
|
|
12
|
+
|
|
13
|
+
> MIT License
|
|
14
|
+
>
|
|
15
|
+
> Copyright (c) Pooya Parsa <pooya@pi0.io>
|
|
16
|
+
>
|
|
17
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
18
|
+
> of this software and associated documentation files (the "Software"), to deal
|
|
19
|
+
> in the Software without restriction, including without limitation the rights
|
|
20
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21
|
+
> copies of the Software, and to permit persons to whom the Software is
|
|
22
|
+
> furnished to do so, subject to the following conditions:
|
|
23
|
+
>
|
|
24
|
+
> The above copyright notice and this permission notice shall be included in all
|
|
25
|
+
> copies or substantial portions of the Software.
|
|
26
|
+
>
|
|
27
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
33
|
+
> SOFTWARE.
|
|
@@ -0,0 +1,105 @@
|
|
|
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
|
+
/** 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
|
+
//#region src/common/base-runner.d.ts
|
|
66
|
+
interface EnvRunnerData {
|
|
67
|
+
name?: string;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
70
|
+
declare abstract class BaseEnvRunner implements EnvRunner {
|
|
71
|
+
closed: boolean;
|
|
72
|
+
protected _name: string;
|
|
73
|
+
protected _workerEntry: string;
|
|
74
|
+
protected _data?: EnvRunnerData;
|
|
75
|
+
protected _hooks: Partial<WorkerHooks>;
|
|
76
|
+
protected _address?: WorkerAddress;
|
|
77
|
+
protected _messageListeners: Set<(data: unknown) => void>;
|
|
78
|
+
constructor(opts: {
|
|
79
|
+
name: string;
|
|
80
|
+
workerEntry: string;
|
|
81
|
+
hooks?: WorkerHooks;
|
|
82
|
+
data?: EnvRunnerData;
|
|
83
|
+
});
|
|
84
|
+
get ready(): boolean;
|
|
85
|
+
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
86
|
+
upgrade(context: {
|
|
87
|
+
node: {
|
|
88
|
+
req: IncomingMessage;
|
|
89
|
+
socket: Socket;
|
|
90
|
+
head: any;
|
|
91
|
+
};
|
|
92
|
+
}): Promise<void>;
|
|
93
|
+
abstract sendMessage(message: unknown): void;
|
|
94
|
+
onMessage(listener: RunnerMessageListener): void;
|
|
95
|
+
offMessage(listener: RunnerMessageListener): void;
|
|
96
|
+
close(cause?: unknown): Promise<void>;
|
|
97
|
+
protected _handleMessage(message: any): void;
|
|
98
|
+
protected _closeSocket(): Promise<void>;
|
|
99
|
+
protected _requestGracefulShutdown(sendShutdown: () => void, listenForExit: (resolve: () => void) => void, hasExited: () => boolean): Promise<void>;
|
|
100
|
+
protected abstract _hasRuntime(): boolean;
|
|
101
|
+
protected abstract _closeRuntime(): Promise<void>;
|
|
102
|
+
protected abstract _runtimeType(): string;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
export { NodeUpgradeContext as a, UpgradeContext as c, WorkerHooks as d, FetchHandler as i, UpgradeHandler as l, EnvRunnerData as n, RunnerMessageListener as o, EnvRunner as r, RunnerRPCHooks as s, BaseEnvRunner as t, WorkerAddress as u };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { n as v, t as m } from "./libs/std-env.mjs";
|
|
2
|
+
import { rm } from "node:fs/promises";
|
|
3
|
+
import { proxyFetch, proxyUpgrade } from "httpxy";
|
|
4
|
+
//#region src/common/base-runner.ts
|
|
5
|
+
var BaseEnvRunner = class {
|
|
6
|
+
closed = false;
|
|
7
|
+
_name;
|
|
8
|
+
_workerEntry;
|
|
9
|
+
_data;
|
|
10
|
+
_hooks;
|
|
11
|
+
_address;
|
|
12
|
+
_messageListeners;
|
|
13
|
+
constructor(opts) {
|
|
14
|
+
this._name = opts.name;
|
|
15
|
+
this._workerEntry = opts.workerEntry;
|
|
16
|
+
this._data = opts.data;
|
|
17
|
+
this._hooks = opts.hooks || {};
|
|
18
|
+
this._messageListeners = /* @__PURE__ */ new Set();
|
|
19
|
+
}
|
|
20
|
+
get ready() {
|
|
21
|
+
return Boolean(!this.closed && this._address && this._hasRuntime());
|
|
22
|
+
}
|
|
23
|
+
async fetch(input, init) {
|
|
24
|
+
for (let i = 0; i < 5 && !this._address && !this.closed; i++) await new Promise((r) => setTimeout(r, 100 * Math.pow(2, i)));
|
|
25
|
+
if (!this._address) return new Response(`${this._runtimeType()} env runner is unavailable`, { status: 503 });
|
|
26
|
+
return proxyFetch(this._address, input, init);
|
|
27
|
+
}
|
|
28
|
+
async upgrade(context) {
|
|
29
|
+
if (!this.ready || !this._address) return;
|
|
30
|
+
await proxyUpgrade(this._address, context.node.req, context.node.socket, context.node.head);
|
|
31
|
+
}
|
|
32
|
+
onMessage(listener) {
|
|
33
|
+
this._messageListeners.add(listener);
|
|
34
|
+
}
|
|
35
|
+
offMessage(listener) {
|
|
36
|
+
this._messageListeners.delete(listener);
|
|
37
|
+
}
|
|
38
|
+
async close(cause) {
|
|
39
|
+
if (this.closed) return;
|
|
40
|
+
this.closed = true;
|
|
41
|
+
this._hooks.onClose?.(this, cause);
|
|
42
|
+
this._hooks = {};
|
|
43
|
+
const onError = (error) => console.error(error);
|
|
44
|
+
await this._closeRuntime().catch(onError);
|
|
45
|
+
await this._closeSocket().catch(onError);
|
|
46
|
+
}
|
|
47
|
+
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
48
|
+
const status = this.closed ? "closed" : this.ready ? "ready" : "pending";
|
|
49
|
+
return `${this.constructor.name}#${this._name}(${status})`;
|
|
50
|
+
}
|
|
51
|
+
_handleMessage(message) {
|
|
52
|
+
if (message?.address) {
|
|
53
|
+
this._address = message.address;
|
|
54
|
+
this._hooks.onReady?.(this, this._address);
|
|
55
|
+
}
|
|
56
|
+
for (const listener of this._messageListeners) listener(message);
|
|
57
|
+
}
|
|
58
|
+
async _closeSocket() {
|
|
59
|
+
const socketPath = this._address?.socketPath;
|
|
60
|
+
if (socketPath && socketPath[0] !== "\0" && !socketPath.startsWith(String.raw`\\.\\pipe`)) await rm(socketPath).catch(() => {});
|
|
61
|
+
this._address = void 0;
|
|
62
|
+
}
|
|
63
|
+
async _requestGracefulShutdown(sendShutdown, listenForExit, hasExited) {
|
|
64
|
+
sendShutdown();
|
|
65
|
+
if (!hasExited() && !v && !m) await new Promise((resolve) => {
|
|
66
|
+
const gracefulShutdownTimeoutMs = Number.parseInt(process.env.ENV_RUNNER_SHUTDOWN_TIMEOUT || "", 10) || 5e3;
|
|
67
|
+
const timeout = setTimeout(() => {
|
|
68
|
+
console.warn(`force closing node env runner ${this._runtimeType()}...`);
|
|
69
|
+
resolve();
|
|
70
|
+
}, gracefulShutdownTimeoutMs);
|
|
71
|
+
listenForExit(() => {
|
|
72
|
+
clearTimeout(timeout);
|
|
73
|
+
resolve();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
export { BaseEnvRunner as t };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
//#region node_modules/.deno/std-env@4.0.0-rc.1/node_modules/std-env/dist/index.mjs
|
|
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
|
+
[`claude`, [`CLAUDECODE`, `CLAUDE_CODE`]],
|
|
4
|
+
[`replit`, [`REPL_ID`]],
|
|
5
|
+
[`gemini`, [`GEMINI_CLI`]],
|
|
6
|
+
[`codex`, [`CODEX_SANDBOX`, `CODEX_THREAD_ID`]],
|
|
7
|
+
[`opencode`, [`OPENCODE`]],
|
|
8
|
+
[`pi`, [i(`PATH`, /\.pi[\\/]agent/)]],
|
|
9
|
+
[`auggie`, [`AUGMENT_AGENT`]],
|
|
10
|
+
[`goose`, [`GOOSE_PROVIDER`]],
|
|
11
|
+
[`devin`, [i(`EDITOR`, /devin/)]],
|
|
12
|
+
[`cursor`, [`CURSOR_AGENT`]],
|
|
13
|
+
[`kiro`, [i(`TERM_PROGRAM`, /kiro/)]]
|
|
14
|
+
];
|
|
15
|
+
function i(t, n) {
|
|
16
|
+
return () => {
|
|
17
|
+
let r = e[t];
|
|
18
|
+
return r ? n.test(r) : !1;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function a() {
|
|
22
|
+
let t = e.AI_AGENT;
|
|
23
|
+
if (t) return { name: t.toLowerCase() };
|
|
24
|
+
for (let [t, n] of r) for (let r of n) if (typeof r == `string` ? e[r] : r()) return { name: t };
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
const o = a();
|
|
28
|
+
o.name;
|
|
29
|
+
o.name;
|
|
30
|
+
const l = [
|
|
31
|
+
[`APPVEYOR`],
|
|
32
|
+
[
|
|
33
|
+
`AWS_AMPLIFY`,
|
|
34
|
+
`AWS_APP_ID`,
|
|
35
|
+
{ ci: !0 }
|
|
36
|
+
],
|
|
37
|
+
[`AZURE_PIPELINES`, `SYSTEM_TEAMFOUNDATIONCOLLECTIONURI`],
|
|
38
|
+
[`AZURE_STATIC`, `INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN`],
|
|
39
|
+
[`APPCIRCLE`, `AC_APPCIRCLE`],
|
|
40
|
+
[`BAMBOO`, `bamboo_planKey`],
|
|
41
|
+
[`BITBUCKET`, `BITBUCKET_COMMIT`],
|
|
42
|
+
[`BITRISE`, `BITRISE_IO`],
|
|
43
|
+
[`BUDDY`, `BUDDY_WORKSPACE_ID`],
|
|
44
|
+
[`BUILDKITE`],
|
|
45
|
+
[`CIRCLE`, `CIRCLECI`],
|
|
46
|
+
[`CIRRUS`, `CIRRUS_CI`],
|
|
47
|
+
[
|
|
48
|
+
`CLOUDFLARE_PAGES`,
|
|
49
|
+
`CF_PAGES`,
|
|
50
|
+
{ ci: !0 }
|
|
51
|
+
],
|
|
52
|
+
[
|
|
53
|
+
`CLOUDFLARE_WORKERS`,
|
|
54
|
+
`WORKERS_CI`,
|
|
55
|
+
{ ci: !0 }
|
|
56
|
+
],
|
|
57
|
+
[`GOOGLE_CLOUDRUN`, `K_SERVICE`],
|
|
58
|
+
[`GOOGLE_CLOUDRUN_JOB`, `CLOUD_RUN_JOB`],
|
|
59
|
+
[`CODEBUILD`, `CODEBUILD_BUILD_ARN`],
|
|
60
|
+
[`CODEFRESH`, `CF_BUILD_ID`],
|
|
61
|
+
[`DRONE`],
|
|
62
|
+
[`DRONE`, `DRONE_BUILD_EVENT`],
|
|
63
|
+
[`DSARI`],
|
|
64
|
+
[`GITHUB_ACTIONS`],
|
|
65
|
+
[`GITLAB`, `GITLAB_CI`],
|
|
66
|
+
[`GITLAB`, `CI_MERGE_REQUEST_ID`],
|
|
67
|
+
[`GOCD`, `GO_PIPELINE_LABEL`],
|
|
68
|
+
[`LAYERCI`],
|
|
69
|
+
[`JENKINS`, `JENKINS_URL`],
|
|
70
|
+
[`HUDSON`, `HUDSON_URL`],
|
|
71
|
+
[`MAGNUM`],
|
|
72
|
+
[`NETLIFY`],
|
|
73
|
+
[
|
|
74
|
+
`NETLIFY`,
|
|
75
|
+
`NETLIFY_LOCAL`,
|
|
76
|
+
{ ci: !1 }
|
|
77
|
+
],
|
|
78
|
+
[`NEVERCODE`],
|
|
79
|
+
[`RENDER`],
|
|
80
|
+
[`SAIL`, `SAILCI`],
|
|
81
|
+
[`SEMAPHORE`],
|
|
82
|
+
[`SCREWDRIVER`],
|
|
83
|
+
[`SHIPPABLE`],
|
|
84
|
+
[`SOLANO`, `TDDIUM`],
|
|
85
|
+
[`STRIDER`],
|
|
86
|
+
[`TEAMCITY`, `TEAMCITY_VERSION`],
|
|
87
|
+
[`TRAVIS`],
|
|
88
|
+
[`VERCEL`, `NOW_BUILDER`],
|
|
89
|
+
[
|
|
90
|
+
`VERCEL`,
|
|
91
|
+
`VERCEL`,
|
|
92
|
+
{ ci: !1 }
|
|
93
|
+
],
|
|
94
|
+
[
|
|
95
|
+
`VERCEL`,
|
|
96
|
+
`VERCEL_ENV`,
|
|
97
|
+
{ ci: !1 }
|
|
98
|
+
],
|
|
99
|
+
[`APPCENTER`, `APPCENTER_BUILD_ID`],
|
|
100
|
+
[
|
|
101
|
+
`CODESANDBOX`,
|
|
102
|
+
`CODESANDBOX_SSE`,
|
|
103
|
+
{ ci: !1 }
|
|
104
|
+
],
|
|
105
|
+
[
|
|
106
|
+
`CODESANDBOX`,
|
|
107
|
+
`CODESANDBOX_HOST`,
|
|
108
|
+
{ ci: !1 }
|
|
109
|
+
],
|
|
110
|
+
[`STACKBLITZ`],
|
|
111
|
+
[`STORMKIT`],
|
|
112
|
+
[`CLEAVR`],
|
|
113
|
+
[`ZEABUR`],
|
|
114
|
+
[
|
|
115
|
+
`CODESPHERE`,
|
|
116
|
+
`CODESPHERE_APP_ID`,
|
|
117
|
+
{ ci: !0 }
|
|
118
|
+
],
|
|
119
|
+
[`RAILWAY`, `RAILWAY_PROJECT_ID`],
|
|
120
|
+
[`RAILWAY`, `RAILWAY_SERVICE_ID`],
|
|
121
|
+
[`DENO-DEPLOY`, `DENO_DEPLOY`],
|
|
122
|
+
[`DENO-DEPLOY`, `DENO_DEPLOYMENT_ID`],
|
|
123
|
+
[
|
|
124
|
+
`FIREBASE_APP_HOSTING`,
|
|
125
|
+
`FIREBASE_APP_HOSTING`,
|
|
126
|
+
{ ci: !0 }
|
|
127
|
+
]
|
|
128
|
+
];
|
|
129
|
+
function u() {
|
|
130
|
+
for (let t of l) if (e[t[1] || t[0]]) return {
|
|
131
|
+
name: t[0].toLowerCase(),
|
|
132
|
+
...t[2]
|
|
133
|
+
};
|
|
134
|
+
return e.SHELL === `/bin/jsh` && t.versions?.webcontainer ? {
|
|
135
|
+
name: `stackblitz`,
|
|
136
|
+
ci: !1
|
|
137
|
+
} : {
|
|
138
|
+
name: ``,
|
|
139
|
+
ci: !1
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const d = u();
|
|
143
|
+
d.name;
|
|
144
|
+
const p = t.platform || ``, m = !!e.CI || d.ci !== !1, h = !!t.stdout?.isTTY;
|
|
145
|
+
e.DEBUG;
|
|
146
|
+
const v = n === `test` || !!e.TEST;
|
|
147
|
+
n === `production` || e.MODE;
|
|
148
|
+
n === `dev` || n === `development` || e.MODE;
|
|
149
|
+
e.MINIMAL;
|
|
150
|
+
const S = /^win/i.test(p);
|
|
151
|
+
/^linux/i.test(p);
|
|
152
|
+
/^darwin/i.test(p);
|
|
153
|
+
!e.NO_COLOR && (e.FORCE_COLOR || (h || S) && e.TERM);
|
|
154
|
+
const E = (t.versions?.node || ``).replace(/^v/, ``) || null;
|
|
155
|
+
Number(E?.split(`.`)[0]);
|
|
156
|
+
const O = !!t?.versions?.node, k = `Bun` in globalThis, A = `Deno` in globalThis, j = `fastly` in globalThis, M = `Netlify` in globalThis, N = `EdgeRuntime` in globalThis, P = globalThis.navigator?.userAgent === `Cloudflare-Workers`, F = [
|
|
157
|
+
[M, `netlify`],
|
|
158
|
+
[N, `edge-light`],
|
|
159
|
+
[P, `workerd`],
|
|
160
|
+
[j, `fastly`],
|
|
161
|
+
[A, `deno`],
|
|
162
|
+
[k, `bun`],
|
|
163
|
+
[O, `node`]
|
|
164
|
+
];
|
|
165
|
+
function I() {
|
|
166
|
+
let e = F.find((e) => e[0]);
|
|
167
|
+
if (e) return { name: e[1] };
|
|
168
|
+
}
|
|
169
|
+
I()?.name;
|
|
170
|
+
//#endregion
|
|
171
|
+
export { v as n, m as t };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { d as WorkerHooks, n as EnvRunnerData, t as BaseEnvRunner } from "./base-runner.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/runners/deno-process/runner.d.ts
|
|
4
|
+
declare class DenoProcessEnvRunner extends BaseEnvRunner {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(opts: {
|
|
7
|
+
name: string;
|
|
8
|
+
workerEntry?: string;
|
|
9
|
+
hooks?: WorkerHooks;
|
|
10
|
+
data?: EnvRunnerData;
|
|
11
|
+
execArgv?: string[];
|
|
12
|
+
});
|
|
13
|
+
sendMessage(message: unknown): void;
|
|
14
|
+
protected _hasRuntime(): boolean;
|
|
15
|
+
protected _runtimeType(): string;
|
|
16
|
+
protected _closeRuntime(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { DenoProcessEnvRunner as t };
|