env-runner 0.2.2 → 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.
- package/README.md +51 -9
- package/dist/_chunks/common-base-runner.d.mts +16 -47
- package/dist/_chunks/common-base-runner.mjs +4 -1
- package/dist/_chunks/common-runtime-deps.d.mts +7 -30
- package/dist/_chunks/deno-process-runner.mjs +14 -36
- package/dist/_chunks/miniflare-runner.d.mts +45 -105
- package/dist/_chunks/miniflare-runner.mjs +571 -61
- package/dist/_chunks/netlify-runner.d.mts +3 -21
- package/dist/_chunks/types.d.mts +2 -11
- package/dist/_chunks/vercel-runner.mjs +1 -0
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +17 -68
- package/dist/runners/deno-process/worker.mjs +9 -31
- package/dist/runners/vercel/queue-dev.d.mts +9 -45
- package/dist/vite.d.mts +2 -12
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -373,7 +373,9 @@ Passing `miniflare` explicitly is preferred — the version you install is then
|
|
|
373
373
|
|
|
374
374
|
The entry uses the same `AppEntry` format as the other runners. Requests are handled like srvx's Cloudflare adapter (`srvx/cloudflare`): the entry's `plugins`, `middleware` and `error` handler are applied, and the request carries `request.runtime` (`{ name: "cloudflare", cloudflare: { env, context } }`), `request.ip` (from `cf-connecting-ip`) and `request.waitUntil()`. For Workers-style entries, `fetch` still receives `(request, env, ctx)`. env-runner's internal bindings are never exposed on `env`. Listener-level srvx options (`maxRequestBodySize`, `trustProxy`, `node`/`bun`/`deno`, ...) do not apply to miniflare.
|
|
375
375
|
|
|
376
|
-
When you don't set a
|
|
376
|
+
When you don't set a compatibility date, it defaults to the date supported by the installed `workerd` binary rather than today's date — the binary always lags the calendar slightly, and pinning a future date makes `workerd` refuse to start. Set the runner's `compatibilityDate` option to pin one, or to `"latest"` to use the installed `workerd`'s supported date explicitly (no need to import `miniflare` for `supportedCompatibilityDate`). Precedence: `miniflareOptions.compatibilityDate` > `compatibilityDate` > the wrangler config's `compatibility_date` > the supported date. Whatever the source, a date newer than the installed `workerd` supports falls back to the supported date with a warning (like `wrangler dev`).
|
|
377
|
+
|
|
378
|
+
The runner enables the `nodejs_compat` compatibility flag by default. Set `no_nodejs_compat` (in the wrangler config's `compatibility_flags` or in `miniflareOptions.compatibilityFlags`) to opt out; the generated wrapper then avoids Node.js built-ins. If the two sources disagree, `miniflareOptions` wins.
|
|
377
379
|
|
|
378
380
|
#### Wrangler Config
|
|
379
381
|
|
|
@@ -386,12 +388,15 @@ await using runner = new MiniflareEnvRunner({
|
|
|
386
388
|
miniflare,
|
|
387
389
|
name: "my-worker",
|
|
388
390
|
data: { entry: "./worker.ts" },
|
|
389
|
-
wrangler: true, // auto-discover wrangler.{json,jsonc,toml}
|
|
391
|
+
wrangler: true, // auto-discover wrangler.{json,jsonc,toml} (see below)
|
|
390
392
|
// wrangler: "./config/wrangler.toml", // or an explicit path
|
|
391
393
|
// wranglerEnv: "production", // select a `[env.production]` block
|
|
394
|
+
// compatibilityDate: "latest", // override the config's compatibility_date
|
|
392
395
|
});
|
|
393
396
|
```
|
|
394
397
|
|
|
398
|
+
Auto-discovery searches parent directories: when the entry file is inside the current working directory, it walks up from the entry's directory to the filesystem root (so a config at a monorepo root is found for an entry in `apps/web/src/`); when the entry lives elsewhere (e.g. a framework entry hoisted under `node_modules/.pnpm`), only the entry's own directory is checked before walking up from the cwd, so the cwd's config is never shadowed by one above the entry. The nearest directory wins; within one directory `wrangler.json` is preferred over `wrangler.jsonc`, then `wrangler.toml` (unlike `wrangler`, which looks for each filename all the way up before trying the next). A config found in a parent directory is logged once.
|
|
399
|
+
|
|
395
400
|
`wranglerEnv` selects a named Wrangler environment (`--env`). When omitted, it defaults to the `CLOUDFLARE_ENV` environment variable, so `CLOUDFLARE_ENV=production` selects the `production` env without passing the option.
|
|
396
401
|
|
|
397
402
|
You can also pass an **inline** config object (raw `wrangler.json` shape) instead of (or in addition to) a file — handy for programmatic setups:
|
|
@@ -410,9 +415,27 @@ await using runner = new MiniflareEnvRunner({
|
|
|
410
415
|
});
|
|
411
416
|
```
|
|
412
417
|
|
|
413
|
-
When an inline config is passed, a `wrangler.{json,jsonc,toml}` file is still auto-discovered (
|
|
418
|
+
When an inline config is passed, a `wrangler.{json,jsonc,toml}` file is still auto-discovered (as above) and loaded, and the inline config is **merged on top of it** — inline values win per key, binding records (e.g. `vars`) merge, and `compatibilityFlags` are unioned. This lets you keep a committed `wrangler` file and override a few fields programmatically. If the inline config doesn't define the selected `wranglerEnv`, its top level is used as-is (the file's env still applies), and a config that fails to load only warns without discarding the other one.
|
|
419
|
+
|
|
420
|
+
Set `wranglerConfigPath` to load a specific config file instead of auto-discovering one — with `wrangler: true` or an inline config (which still merges on top), and without changing the working directory:
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
await using runner = new MiniflareEnvRunner({
|
|
424
|
+
miniflare,
|
|
425
|
+
name: "my-worker",
|
|
426
|
+
data: { entry: "./.nitro/dev/index.mjs" },
|
|
427
|
+
wrangler: { vars: { GREETING: "hello" } },
|
|
428
|
+
wranglerConfigPath: "./wrangler.jsonc", // relative to cwd
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
A missing `wranglerConfigPath` file warns (an inline config is still applied). When `wrangler` is itself a string path, that path wins and `wranglerConfigPath` is ignored.
|
|
414
433
|
|
|
415
|
-
|
|
434
|
+
The runner hosts a single fetch-only worker, so config entries it can't run are **dropped**: `assets`, `services`, `queues.consumers`, `workflows`, `tail_consumers`/`streaming_tail_consumers`, and Durable Object bindings to another script (`script_name`). Durable Object bindings to classes exported by your entry are kept — including bindings whose `script_name` is the worker's own `name` (the inline config's `name` when set, else the file's; with `wranglerEnv` suffixed `-<env>` unless the env section sets a `name`, e.g. `my-worker-staging`), which are local in `wrangler dev` too — and merged with [auto-detected exports](#auto-detected-exports). Pass any of the dropped options via `miniflareOptions` to opt back in.
|
|
435
|
+
|
|
436
|
+
Whenever `wrangler` is enabled (`true`, a path, or an inline config), local state (KV, D1, R2, Durable Objects, ...) persists under `<dir>/.wrangler/state/v3` — the same place `wrangler dev` uses, so both share data. `<dir>` is the directory of the loaded config file, else of the requested config path (`wrangler` string or `wranglerConfigPath`, even if the file is missing), else the current working directory (e.g. inline-only configs, or `wrangler: true` with no file found). Set `miniflareOptions.defaultPersistRoot` (or any `*Persist` option, e.g. `kvPersist: false`) to opt out.
|
|
437
|
+
|
|
438
|
+
Pass the [`wrangler`](https://www.npmjs.com/package/wrangler) package as `wranglerModule` — the imported module or a specifier — for full fidelity: TOML, config validation, and every binding type.
|
|
416
439
|
|
|
417
440
|
```ts
|
|
418
441
|
import * as miniflare from "miniflare";
|
|
@@ -427,7 +450,26 @@ await using runner = new MiniflareEnvRunner({
|
|
|
427
450
|
});
|
|
428
451
|
```
|
|
429
452
|
|
|
430
|
-
|
|
453
|
+
With the `wrangler` package, wrangler's own config warnings (e.g. unexpected/misspelled keys, or a `wranglerEnv` the config doesn't define) are printed for a config file — once per file version and env, so hot reloads don't repeat them. Inline configs are validated without printing wrangler's warnings (load errors still warn). As in `wrangler dev`, unexpected keys also trigger wrangler's npm update check (cached for a day), which may print a "newer version of Wrangler available" hint.
|
|
454
|
+
|
|
455
|
+
Set `wranglerEnvFiles` to load local dev vars/secrets from custom `.env` files, like `getPlatformProxy({ envFiles })`:
|
|
456
|
+
|
|
457
|
+
```ts
|
|
458
|
+
await using runner = new MiniflareEnvRunner({
|
|
459
|
+
miniflare,
|
|
460
|
+
wranglerModule: wrangler,
|
|
461
|
+
name: "my-worker",
|
|
462
|
+
data: { entry: "./worker.ts" },
|
|
463
|
+
wrangler: true,
|
|
464
|
+
wranglerEnvFiles: [".env", ".env.development"], // relative to the config file's dir
|
|
465
|
+
});
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Paths resolve against the loaded config file's directory (else the current working directory) and later files override earlier ones. When set (non-empty), `.dev.vars` is not read; when unset, wrangler's defaults apply (`.dev.vars[.<env>]`, else `.env*`); an empty array reads `.dev.vars` but no `.env*` files. Both the `wrangler` package and the built-in minimal reader honor it.
|
|
469
|
+
|
|
470
|
+
Without `wranglerModule`, `wrangler` is imported optionally; if that fails too, a built-in minimal reader handles JSON/JSONC files and inline objects (TOML files are skipped with a warning). It follows wrangler's semantics for `env` selection (bindings and `vars` are not inherited into a named env), local ids (`preview_id` / `preview_bucket_name` / `preview_database_id` first, so state is shared with `wrangler dev`), SQLite-backed Durable Objects (`migrations[].new_sqlite_classes`) and dev vars (`.dev.vars[.<env>]`, `.env*`, `secrets.required`), but only maps common bindings (`vars`, KV, R2, D1, Durable Objects, queue producers); other bindings (e.g. `hyperdrive`, `ai`, `ratelimits`) are ignored with a warning. Pass `wranglerModule: false` to always use the minimal reader. Values you pass in `miniflareOptions` always take precedence over config-derived ones — binding records (e.g. `bindings`) merge per key, and `compatibilityFlags` are merged.
|
|
471
|
+
|
|
472
|
+
Config options a single dev worker can't run — `services`, `assets`, `queues.consumers`, `workflows`, `tail_consumers`/`streaming_tail_consumers`, and `durable_objects` bindings with a `script_name` naming another worker — are ignored with one warning listing them (e.g. `services (MY_SERVICE)`); pass the equivalent Miniflare options via `miniflareOptions` to opt in.
|
|
431
473
|
|
|
432
474
|
#### Module Transform Pipeline
|
|
433
475
|
|
|
@@ -465,9 +507,9 @@ export class Counter {
|
|
|
465
507
|
|
|
466
508
|
export default {
|
|
467
509
|
async fetch(request, env) {
|
|
468
|
-
// env.
|
|
469
|
-
const id = env.
|
|
470
|
-
const stub = env.
|
|
510
|
+
// env.COUNTER is auto-wired — no manual config needed
|
|
511
|
+
const id = env.COUNTER.idFromName("test");
|
|
512
|
+
const stub = env.COUNTER.get(id);
|
|
471
513
|
return stub.fetch(request);
|
|
472
514
|
},
|
|
473
515
|
};
|
|
@@ -485,7 +527,7 @@ await using runner = new MiniflareEnvRunner({
|
|
|
485
527
|
});
|
|
486
528
|
```
|
|
487
529
|
|
|
488
|
-
Set `exports: false` to disable auto-detection entirely.
|
|
530
|
+
Auto-wired bindings are merged with Durable Object bindings from `miniflareOptions` and a wrangler config: exports whose class is already bound (or whose binding name is taken) are skipped. Set `exports: false` to disable auto-detection entirely.
|
|
489
531
|
|
|
490
532
|
#### Error Capture
|
|
491
533
|
|
|
@@ -1,33 +1,16 @@
|
|
|
1
1
|
import { EnvRunner, RunnerMessageListener, WorkerAddress, WorkerHooks } from "./types.mjs";
|
|
2
2
|
import { IncomingMessage } from "node:http";
|
|
3
3
|
import { Socket } from "node:net";
|
|
4
|
-
/**
|
|
5
|
-
* Source for a virtual module: either a literal ES module string or a factory
|
|
6
|
-
* that returns one (sync or async).
|
|
7
|
-
*
|
|
8
|
-
* Factories are evaluated **once on the host side** before the worker is spawned
|
|
9
|
-
* (functions can't cross the `workerData`/`JSON` boundary, and Node's synchronous
|
|
10
|
-
* load hook can't await), so the worker always receives plain strings. See
|
|
11
|
-
* {@link resolveVirtualModules}.
|
|
12
|
-
*/
|
|
4
|
+
/** Factories run once on the host, before the worker spawns. */
|
|
13
5
|
export type VirtualModuleSource = string | (() => string | Promise<string>);
|
|
14
6
|
/** Virtual modules as a `specifier => source` map. */
|
|
15
7
|
export type VirtualModules = Record<string, VirtualModuleSource>;
|
|
16
8
|
export interface EnvRunnerData {
|
|
17
9
|
name?: string;
|
|
18
10
|
/**
|
|
19
|
-
* Virtual modules
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* (and its dependencies) can `import` them, e.g.
|
|
23
|
-
* `{ "#virtual-import": "export const foo = 1" }`.
|
|
24
|
-
*
|
|
25
|
-
* Each source may be a string or a factory `() => string | Promise<string>`.
|
|
26
|
-
* Factories are evaluated once on the host before the worker is spawned (so the
|
|
27
|
-
* worker always receives plain strings).
|
|
28
|
-
*
|
|
29
|
-
* Supported by the `node-worker`, `node-process`, `bun-process`,
|
|
30
|
-
* `deno-process`, `vercel`, `netlify`, and `miniflare` runners.
|
|
11
|
+
* Virtual modules importable from the entry, e.g.
|
|
12
|
+
* `{ "#virtual-import": "export const foo = 1" }`. Factory sources run once
|
|
13
|
+
* on the host before spawn. Not supported by the `self` runner.
|
|
31
14
|
*/
|
|
32
15
|
virtual?: VirtualModules;
|
|
33
16
|
[key: string]: unknown;
|
|
@@ -69,25 +52,19 @@ export declare abstract class BaseEnvRunner implements EnvRunner, AsyncDisposabl
|
|
|
69
52
|
reloadModule(timeout?: number): Promise<void>;
|
|
70
53
|
/**
|
|
71
54
|
* Invalidate a virtual module so the next `reloadModule()` re-evaluates it.
|
|
72
|
-
*
|
|
73
|
-
* source is shipped to the worker along with the invalidation. Rejects when
|
|
74
|
-
* the specifier is not a registered virtual module.
|
|
55
|
+
* Factory sources are re-run on the host. Rejects for unknown specifiers.
|
|
75
56
|
*/
|
|
76
57
|
invalidateModule(specifier: string, timeout?: number): Promise<void>;
|
|
77
58
|
close(cause?: unknown): Promise<void>;
|
|
78
59
|
[Symbol.asyncDispose](): Promise<void>;
|
|
79
|
-
/**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* placeholder — requests are dispatched to the worker address regardless.
|
|
83
|
-
*/
|
|
60
|
+
/** Briefly back off (~3s total) while the worker is still starting. */
|
|
61
|
+
protected _waitForAddress(): Promise<void>;
|
|
62
|
+
/** Placeholder origin for relative inputs; requests go to the worker address regardless. */
|
|
84
63
|
protected _resolveFetchInput(input: string | URL | Request): string | URL | Request;
|
|
85
64
|
protected _handleMessage(message: any): void;
|
|
86
65
|
/**
|
|
87
|
-
* Send a message and await
|
|
88
|
-
* `
|
|
89
|
-
* response carrying an `error`, and promptly when the runner closes mid-wait
|
|
90
|
-
* (instead of letting callers wait out the timeout on a dead worker).
|
|
66
|
+
* Send a message and await the matching response. Rejects on timeout, on an
|
|
67
|
+
* `error` response, and as soon as the runner closes.
|
|
91
68
|
*/
|
|
92
69
|
protected _request<T = unknown>(message: unknown, opts: {
|
|
93
70
|
match: (msg: any) => boolean;
|
|
@@ -96,24 +73,16 @@ export declare abstract class BaseEnvRunner implements EnvRunner, AsyncDisposabl
|
|
|
96
73
|
send?: (message: unknown) => void;
|
|
97
74
|
}): Promise<T>;
|
|
98
75
|
/**
|
|
99
|
-
* Resolve
|
|
100
|
-
* worker
|
|
101
|
-
*
|
|
102
|
-
* keep their synchronous spawn path. Factories must be resolved here because
|
|
103
|
-
* functions can't cross the worker boundary and the load hook can't await.
|
|
76
|
+
* Resolve factory `data.virtual` sources before spawn (functions can't cross
|
|
77
|
+
* the worker boundary; the load hook can't await). `undefined` when there is
|
|
78
|
+
* no factory, so subclasses can spawn synchronously.
|
|
104
79
|
*/
|
|
105
80
|
protected _resolveVirtualData(): Promise<void> | undefined;
|
|
106
|
-
/**
|
|
107
|
-
* Re-run a factory-valued virtual source on the host and sync the resolved
|
|
108
|
-
* `data.virtual` map. Returns the fresh source, or `undefined` when the
|
|
109
|
-
* source is a plain string or unknown (nothing to re-evaluate).
|
|
110
|
-
*/
|
|
81
|
+
/** Re-run a factory virtual source and sync `data.virtual`; `undefined` if not a factory. */
|
|
111
82
|
protected _refreshVirtualSource(specifier: string): Promise<string | undefined>;
|
|
112
83
|
/**
|
|
113
|
-
* Run
|
|
114
|
-
*
|
|
115
|
-
* `init` until factories resolve. A throwing/rejecting factory closes the
|
|
116
|
-
* runner with the error as cause instead of leaving an unhandled rejection.
|
|
84
|
+
* Run `init` once `data.virtual` is resolved (synchronously without factories).
|
|
85
|
+
* A failing factory closes the runner with the error as cause.
|
|
117
86
|
*/
|
|
118
87
|
protected _initWithVirtualData(init: () => void): void;
|
|
119
88
|
protected _closeSocket(): Promise<void>;
|
|
@@ -27,7 +27,7 @@ var BaseEnvRunner = class {
|
|
|
27
27
|
return this._address;
|
|
28
28
|
}
|
|
29
29
|
async fetch(input, init) {
|
|
30
|
-
|
|
30
|
+
await this._waitForAddress();
|
|
31
31
|
if (!this._address) return new Response(`${this._runtimeType()} env runner is unavailable`, { status: 503 });
|
|
32
32
|
return proxyFetch(this._address, this._resolveFetchInput(input), init);
|
|
33
33
|
}
|
|
@@ -118,6 +118,9 @@ var BaseEnvRunner = class {
|
|
|
118
118
|
const status = this.closed ? "closed" : this.ready ? "ready" : "pending";
|
|
119
119
|
return `${this.constructor.name}#${this._name}(${status})`;
|
|
120
120
|
}
|
|
121
|
+
async _waitForAddress() {
|
|
122
|
+
for (let i = 0; i < 5 && !this._address && !this.closed; i++) await new Promise((r) => setTimeout(r, 100 * Math.pow(2, i)));
|
|
123
|
+
}
|
|
121
124
|
_resolveFetchInput(input) {
|
|
122
125
|
if (typeof input === "string" && !URL.canParse(input)) return new URL(input, "http://localhost");
|
|
123
126
|
return input;
|
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* shapes, so the choice is about ergonomics rather than per-runner API:
|
|
6
|
-
*
|
|
7
|
-
* - the **imported module** (`import * as miniflare from "miniflare"`) — the
|
|
8
|
-
* version installed by the app is the version that runs
|
|
9
|
-
* - a **module specifier** (`"miniflare"`, `import.meta.resolve("miniflare")`,
|
|
10
|
-
* or a `URL`) — resolved from {@link ResolveRuntimeDepOptions.from} (cwd by
|
|
11
|
-
* default), so a bare specifier resolves against the app rather than against
|
|
12
|
-
* `env-runner`'s own `node_modules`
|
|
13
|
-
* - `false` — opt out of the package entirely
|
|
14
|
-
*
|
|
15
|
-
* Omitting the option falls back to an optional `import()` of the package.
|
|
2
|
+
* An app-owned package: the imported module, a specifier (resolved from the
|
|
3
|
+
* app, not `env-runner`), or `false` to opt out. Omitted falls back to an
|
|
4
|
+
* optional `import()`.
|
|
16
5
|
*/
|
|
17
6
|
export type RuntimeDep<T> = T | string | URL | false;
|
|
18
7
|
interface ResolveRuntimeDepOptions<T> {
|
|
@@ -22,29 +11,17 @@ interface ResolveRuntimeDepOptions<T> {
|
|
|
22
11
|
option: string;
|
|
23
12
|
/** Value as passed by the caller. */
|
|
24
13
|
value?: RuntimeDep<T>;
|
|
25
|
-
/**
|
|
26
|
-
* Named export the resolved module must expose. A module that lacks it is
|
|
27
|
-
* treated as the wrong package (throws for an explicit value).
|
|
28
|
-
*/
|
|
14
|
+
/** Named export identifying the package (a mismatch throws for an explicit value). */
|
|
29
15
|
expect?: string;
|
|
30
16
|
/** Directory bare specifiers resolve from. @default process.cwd() */
|
|
31
17
|
from?: string;
|
|
32
|
-
/**
|
|
33
|
-
* Throw when the package cannot be resolved at all. Otherwise an
|
|
34
|
-
* unavailable optional package resolves to `undefined` and the caller
|
|
35
|
-
* degrades (minimal reader, shim, no-op).
|
|
36
|
-
*/
|
|
18
|
+
/** Throw when unresolvable instead of resolving `undefined` (callers degrade). */
|
|
37
19
|
required?: boolean;
|
|
38
20
|
/** Extra sentence appended to the "not installed" error when `required`. */
|
|
39
21
|
hint?: string;
|
|
40
22
|
}
|
|
41
23
|
/**
|
|
42
|
-
* Resolve a {@link RuntimeDep} to
|
|
43
|
-
*
|
|
44
|
-
* Resolution order: `false` → `undefined`; an imported module → validated and
|
|
45
|
-
* returned as-is; a specifier → imported (errors propagate, since an explicit
|
|
46
|
-
* specifier that cannot load is a mistake worth surfacing); omitted → optional
|
|
47
|
-
* `import(name)`, which yields `undefined` when the package isn't installed
|
|
48
|
-
* unless {@link ResolveRuntimeDepOptions.required} is set.
|
|
24
|
+
* Resolve a {@link RuntimeDep} to a module. An explicit specifier that fails to
|
|
25
|
+
* import throws; an omitted one resolves `undefined` unless `required`.
|
|
49
26
|
*/
|
|
50
27
|
export declare function resolveRuntimeDep<T>(opts: ResolveRuntimeDepOptions<T>): Promise<T | undefined>;
|
|
@@ -26,7 +26,7 @@ var DenoProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
26
26
|
}
|
|
27
27
|
async _closeRuntime() {
|
|
28
28
|
if (!this.#process) return;
|
|
29
|
-
this.#process.removeAllListeners
|
|
29
|
+
this.#process.removeAllListeners();
|
|
30
30
|
try {
|
|
31
31
|
this.#process.kill();
|
|
32
32
|
} catch {}
|
|
@@ -37,10 +37,6 @@ var DenoProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
37
37
|
this.close(`process entry not found in "${this._workerEntry}".`);
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
-
const env = hostEnv({
|
|
41
|
-
ENV_RUNNER_NAME: this._name,
|
|
42
|
-
ENV_RUNNER_DATA: JSON.stringify(this._data || {})
|
|
43
|
-
});
|
|
44
40
|
const child = spawn("deno", [
|
|
45
41
|
"run",
|
|
46
42
|
"-A",
|
|
@@ -49,28 +45,20 @@ var DenoProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
49
45
|
...execArgv || [],
|
|
50
46
|
this._workerEntry
|
|
51
47
|
], {
|
|
52
|
-
env
|
|
48
|
+
env: hostEnv({
|
|
49
|
+
ENV_RUNNER_NAME: this._name,
|
|
50
|
+
ENV_RUNNER_DATA: JSON.stringify(this._data || {})
|
|
51
|
+
}),
|
|
53
52
|
stdio: [
|
|
54
53
|
"pipe",
|
|
55
54
|
"pipe",
|
|
56
|
-
"pipe"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
child.once("exit", (code) => resolve(code ?? 1));
|
|
55
|
+
"pipe",
|
|
56
|
+
"ipc"
|
|
57
|
+
],
|
|
58
|
+
serialization: "json"
|
|
61
59
|
});
|
|
62
|
-
const handle = {
|
|
63
|
-
pid: child.pid,
|
|
64
|
-
kill: () => child.kill(),
|
|
65
|
-
send: (message) => {
|
|
66
|
-
child.stdin.write(JSON.stringify(message) + "\n");
|
|
67
|
-
},
|
|
68
|
-
exited,
|
|
69
|
-
_exitCode: void 0,
|
|
70
|
-
removeAllListeners: () => child.removeAllListeners()
|
|
71
|
-
};
|
|
72
60
|
child.once("exit", (code) => {
|
|
73
|
-
|
|
61
|
+
child._exitCode = code;
|
|
74
62
|
this.close(`process exited with code ${code}`);
|
|
75
63
|
});
|
|
76
64
|
child.on("error", (error) => {
|
|
@@ -79,22 +67,12 @@ var DenoProcessEnvRunner = class extends BaseEnvRunner {
|
|
|
79
67
|
this.close(error);
|
|
80
68
|
}
|
|
81
69
|
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
buffer += chunk.toString();
|
|
85
|
-
let newlineIdx;
|
|
86
|
-
while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
|
|
87
|
-
const line = buffer.slice(0, newlineIdx);
|
|
88
|
-
buffer = buffer.slice(newlineIdx + 1);
|
|
89
|
-
if (line.startsWith("{")) try {
|
|
90
|
-
this._handleMessage(JSON.parse(line));
|
|
91
|
-
continue;
|
|
92
|
-
} catch {}
|
|
93
|
-
process.stdout.write(line + "\n");
|
|
94
|
-
}
|
|
70
|
+
child.on("message", (message) => {
|
|
71
|
+
this._handleMessage(message);
|
|
95
72
|
});
|
|
73
|
+
child.stdout?.pipe(process.stdout);
|
|
96
74
|
child.stderr?.pipe(process.stderr);
|
|
97
|
-
this.#process =
|
|
75
|
+
this.#process = child;
|
|
98
76
|
}
|
|
99
77
|
};
|
|
100
78
|
export { DenoProcessEnvRunner };
|
|
@@ -3,14 +3,7 @@ import { BaseEnvRunner, EnvRunnerData } from "./common-base-runner.mjs";
|
|
|
3
3
|
import { RuntimeDep } from "./common-runtime-deps.mjs";
|
|
4
4
|
import { IncomingMessage } from "node:http";
|
|
5
5
|
import { Socket } from "node:net";
|
|
6
|
-
/**
|
|
7
|
-
* The `wrangler` package, as imported by the consumer.
|
|
8
|
-
*
|
|
9
|
-
* `wrangler` is not a dependency of `env-runner` — pass the module namespace
|
|
10
|
-
* (`import * as wrangler from "wrangler"`) or a specifier for it, so the
|
|
11
|
-
* dependency stays owned by the application. It is only imported here as a
|
|
12
|
-
* fallback when neither is passed.
|
|
13
|
-
*/
|
|
6
|
+
/** The `wrangler` package namespace, as imported by the app. */
|
|
14
7
|
export interface WranglerModule {
|
|
15
8
|
unstable_readConfig?: (...args: any[]) => any;
|
|
16
9
|
unstable_getMiniflareWorkerOptions?: (...args: any[]) => any;
|
|
@@ -26,20 +19,10 @@ export interface TransformResult {
|
|
|
26
19
|
export interface MiniflareExportInfo {
|
|
27
20
|
type?: "DurableObject" | "WorkerEntrypoint" | "class";
|
|
28
21
|
}
|
|
29
|
-
/**
|
|
30
|
-
* The `miniflare` package, as imported by the consumer.
|
|
31
|
-
*
|
|
32
|
-
* `miniflare` is not a dependency of `env-runner` — pass the module namespace
|
|
33
|
-
* (`import * as miniflare from "miniflare"`) so the dependency stays owned by
|
|
34
|
-
* the application. The runner only falls back to importing it itself when this
|
|
35
|
-
* is omitted.
|
|
36
|
-
*/
|
|
22
|
+
/** The `miniflare` package namespace, as imported by the app. */
|
|
37
23
|
export interface MiniflareModule {
|
|
38
24
|
Miniflare: new (options: any) => any;
|
|
39
|
-
/**
|
|
40
|
-
* Newest compatibility date supported by the installed `workerd` binary,
|
|
41
|
-
* clamped to today. Used as the default `compatibilityDate`.
|
|
42
|
-
*/
|
|
25
|
+
/** Newest date the installed `workerd` supports, clamped to today. */
|
|
43
26
|
supportedCompatibilityDate?: string;
|
|
44
27
|
[key: string]: unknown;
|
|
45
28
|
}
|
|
@@ -48,98 +31,68 @@ export interface MiniflareEnvRunnerOptions {
|
|
|
48
31
|
hooks?: WorkerHooks;
|
|
49
32
|
data?: EnvRunnerData;
|
|
50
33
|
/**
|
|
51
|
-
* The `miniflare` package
|
|
52
|
-
*
|
|
53
|
-
* ```ts
|
|
54
|
-
* import * as miniflare from "miniflare";
|
|
55
|
-
* new MiniflareEnvRunner({ name: "app", miniflare, data: { entry } });
|
|
56
|
-
*
|
|
57
|
-
* // or, equivalently
|
|
58
|
-
* new MiniflareEnvRunner({ name: "app", miniflare: "miniflare", data: { entry } });
|
|
59
|
-
* ```
|
|
60
|
-
*
|
|
61
|
-
* Passing it explicitly is preferred (`miniflare` is not a dependency of
|
|
62
|
-
* `env-runner`, so the version you install is the version that runs). Bare
|
|
63
|
-
* specifiers resolve from the current working directory. When omitted, the
|
|
64
|
-
* runner falls back to importing `miniflare` itself and only fails if that
|
|
65
|
-
* is unavailable too.
|
|
34
|
+
* The `miniflare` package (`import * as miniflare from "miniflare"`) or a
|
|
35
|
+
* specifier resolved from cwd. Omitted: imported optionally.
|
|
66
36
|
*/
|
|
67
37
|
miniflare?: RuntimeDep<MiniflareModule>;
|
|
68
38
|
/** Options passed directly to the Miniflare constructor. */
|
|
69
39
|
miniflareOptions?: Record<string, unknown>;
|
|
70
40
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* This enables integration with Vite's transform pipeline — pass
|
|
75
|
-
* `environment.transformRequest` to get TS/JSX/etc. compiled on the fly.
|
|
76
|
-
*
|
|
77
|
-
* @param id - Absolute file path of the module to transform
|
|
78
|
-
* @returns Transformed code, or null/undefined to fall back to raw disk read
|
|
41
|
+
* `"latest"` uses the installed workerd's newest date. Precedence:
|
|
42
|
+
* `miniflareOptions` > this > wrangler config > newest supported. Dates newer
|
|
43
|
+
* than workerd supports fall back with a warning (workerd refuses them).
|
|
79
44
|
*/
|
|
80
|
-
|
|
45
|
+
compatibilityDate?: "latest" | (string & {});
|
|
81
46
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* When set to `true`, `export class` declarations are auto-detected from
|
|
86
|
-
* the entry file. When set to a record, the listed exports are used
|
|
87
|
-
* (merged with auto-detected ones). Disabled by default.
|
|
47
|
+
* Transform modules served by the fallback service (e.g. Vite's
|
|
48
|
+
* `environment.transformRequest`). `id` is an absolute path; return nullish to
|
|
49
|
+
* read from disk.
|
|
88
50
|
*/
|
|
89
|
-
|
|
51
|
+
transformRequest?: (id: string) => Promise<TransformResult | null | undefined>;
|
|
90
52
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* keeps Miniflare alive. Call `dispose()` to fully destroy it.
|
|
53
|
+
* Named exports (Durable Objects, WorkerEntrypoints) to bind and re-export.
|
|
54
|
+
* `true` detects `export class`; a record merges with detected ones.
|
|
94
55
|
*/
|
|
56
|
+
exports?: Record<string, MiniflareExportInfo> | boolean;
|
|
57
|
+
/** Reuse the Miniflare instance across runner swaps; only `dispose()` destroys it. */
|
|
95
58
|
persistent?: boolean;
|
|
96
59
|
/** Wrap the user's `fetch` in a try/catch that returns structured JSON error responses. Default: `true`. */
|
|
97
60
|
captureErrors?: boolean;
|
|
98
|
-
/**
|
|
99
|
-
* Export conditions for bare-specifier module resolution in the module
|
|
100
|
-
* fallback service. Ensures packages with conditional exports (e.g.
|
|
101
|
-
* `"workerd"`) resolve to the correct entry instead of the Node.js one.
|
|
102
|
-
*
|
|
103
|
-
* Defaults to `["workerd", "worker"]`.
|
|
104
|
-
*/
|
|
61
|
+
/** Export conditions for the fallback service (default `["workerd", "worker"]`). */
|
|
105
62
|
exportConditions?: string[];
|
|
106
63
|
/**
|
|
107
|
-
* Load a
|
|
108
|
-
* (compatibility date/flags and bindings: `vars`, KV, R2, D1, Durable
|
|
109
|
-
* Objects, queues).
|
|
64
|
+
* Load a wrangler config into Miniflare options (compat date/flags, bindings).
|
|
110
65
|
*
|
|
111
|
-
* - `true` — auto-discover `wrangler.{json,jsonc,toml}`
|
|
112
|
-
*
|
|
113
|
-
* - `
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* auto-discovered (next to the entry, then cwd) and the inline config is
|
|
117
|
-
* merged on top of it (inline wins per key, binding records merge,
|
|
118
|
-
* `compatibilityFlags` are unioned).
|
|
66
|
+
* - `true` — auto-discover `wrangler.{json,jsonc,toml}` near the entry or cwd
|
|
67
|
+
* - `string` — config file path
|
|
68
|
+
* - `object` — inline raw config merged over the file config (inline wins per
|
|
69
|
+
* key, binding records merge, flags union); its top level is used when it
|
|
70
|
+
* lacks the selected env
|
|
119
71
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* `
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* `miniflareOptions` always win over config-derived ones; binding records
|
|
127
|
-
* (e.g. `bindings`) merge per key and `compatibilityFlags` are unioned.
|
|
72
|
+
* Options a single dev worker can't run (`assets`, services, queue consumers,
|
|
73
|
+
* workflows, tails, other-script Durable Objects) are dropped with a warning.
|
|
74
|
+
* `defaultPersistRoot` defaults to `.wrangler/state/v3` next to the config
|
|
75
|
+
* (else cwd), shared with `wrangler dev`. The `wrangler` package gives full
|
|
76
|
+
* fidelity (and may run its npm update check); without it only plain JSON is
|
|
77
|
+
* read. `miniflareOptions` always win.
|
|
128
78
|
*/
|
|
129
79
|
wrangler?: boolean | string | WranglerInlineConfig;
|
|
130
80
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
81
|
+
* Config file instead of auto-discovery when `wrangler` is `true` or inline
|
|
82
|
+
* (resolved from cwd). Ignored when `wrangler` is a path.
|
|
133
83
|
*/
|
|
84
|
+
wranglerConfigPath?: string;
|
|
85
|
+
/** Wrangler `--env` to select (default: `CLOUDFLARE_ENV`). */
|
|
134
86
|
wranglerEnv?: string;
|
|
135
87
|
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
*
|
|
88
|
+
* `.env` files for dev vars (like `getPlatformProxy({ envFiles })`), resolved
|
|
89
|
+
* from the config dir; later files win. Non-empty skips `.dev.vars`; `[]`
|
|
90
|
+
* reads only `.dev.vars`. Requires the `wrangler` package.
|
|
91
|
+
*/
|
|
92
|
+
wranglerEnvFiles?: string[];
|
|
93
|
+
/**
|
|
94
|
+
* The `wrangler` package for full-fidelity config parsing. Omitted: imported
|
|
95
|
+
* optionally. `false`: always use the minimal JSON reader.
|
|
143
96
|
*/
|
|
144
97
|
wranglerModule?: RuntimeDep<WranglerModule>;
|
|
145
98
|
}
|
|
@@ -152,24 +105,11 @@ export declare class MiniflareEnvRunner extends BaseEnvRunner {
|
|
|
152
105
|
dispose(): Promise<void>;
|
|
153
106
|
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
154
107
|
sendMessage(message: unknown): void;
|
|
155
|
-
/**
|
|
156
|
-
* Hot-reload the user entry module without recreating the Miniflare instance.
|
|
157
|
-
*
|
|
158
|
-
* Sends `reload-module` event over the WebSocket. The worker wrapper uses
|
|
159
|
-
* `unsafeEvalBinding` to re-import the entry with a cache-busting query string
|
|
160
|
-
* and responds with `module-reloaded` when done.
|
|
161
|
-
*/
|
|
108
|
+
/** Hot-reload the entry without recreating the Miniflare instance. */
|
|
162
109
|
reloadModule(timeout?: number): Promise<void>;
|
|
163
110
|
/**
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* Host-side only (no worker round-trip): the module fallback service serves
|
|
167
|
-
* virtual sources from a live map, so re-running a factory source and
|
|
168
|
-
* bumping the per-specifier versions — the module plus its transitive
|
|
169
|
-
* virtual importers — is enough. Import specifiers in re-served module code
|
|
170
|
-
* are rewritten to the versioned form, giving workerd fresh module
|
|
171
|
-
* identities (it caches by name). A `persistent` instance is evicted from
|
|
172
|
-
* the cache, since its served sources no longer match the cache key.
|
|
111
|
+
* Host-side only: the fallback service serves a live map, so bumping versions
|
|
112
|
+
* (see {@link rewriteVirtualImports}) is enough.
|
|
173
113
|
*/
|
|
174
114
|
invalidateModule(specifier: string, _timeout?: number): Promise<void>;
|
|
175
115
|
protected _hasRuntime(): boolean;
|