env-runner 0.1.16 → 0.2.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/README.md CHANGED
@@ -41,6 +41,8 @@ npx env-runner app.ts
41
41
  | `--host <host>` | Host to bind to | `localhost` |
42
42
  | `-w, --watch` | Watch entry file for changes and auto-reload | |
43
43
 
44
+ `--runner miniflare` needs `miniflare` installed in your project — the runner imports it optionally when no module is passed.
45
+
44
46
  ### Server (`EnvServer`)
45
47
 
46
48
  High-level API that combines runner loading, file watching, and auto-reload:
@@ -54,6 +56,8 @@ const envServer = new EnvServer({
54
56
  entry: "./app.ts",
55
57
  watch: true,
56
58
  watchPaths: ["./src"],
59
+ // Runner-specific constructor options, e.g. `{ miniflare }` for `runner: "miniflare"`
60
+ runnerOptions: {},
57
61
  });
58
62
 
59
63
  envServer.onReady((_runner, address) => {
@@ -157,6 +161,29 @@ import { VercelEnvRunner } from "env-runner/runners/vercel";
157
161
  import { NetlifyEnvRunner } from "env-runner/runners/netlify";
158
162
  ```
159
163
 
164
+ #### Runtime dependencies
165
+
166
+ `env-runner` declares **no peer dependencies**. Runners that build on external packages take them as explicit options instead, and every such option accepts the **same three shapes**:
167
+
168
+ | Value | Meaning |
169
+ | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
170
+ | the imported module (`import * as miniflare from "miniflare"`) | the version you installed is the version that runs |
171
+ | a specifier — `"miniflare"`, `import.meta.resolve("miniflare")`, or a `URL` | resolved from the current working directory, so bare specifiers hit your `node_modules`, not `env-runner`'s |
172
+ | `false` | opt out of the package entirely |
173
+
174
+ Omitting the option falls back to an optional dynamic import of the package; only then does the runner error (`miniflare`) or degrade (minimal wrangler reader, Netlify shim, queue no-op).
175
+
176
+ | Runner | Package | Option | Without it |
177
+ | ----------- | ------------------ | ---------------------------------------- | ------------------------------------- |
178
+ | `miniflare` | `miniflare` | `miniflare` | throws — the runner cannot run |
179
+ | `miniflare` | `wrangler` | `wranglerModule` | built-in minimal JSON reader |
180
+ | `vercel` | `@vercel/queue` | `sdk` (on `registerVercelQueueConsumer`) | warn-once no-op |
181
+ | `netlify` | `@netlify/runtime` | `netlifyRuntime` | lightweight `globalThis.Netlify` shim |
182
+
183
+ `netlifyRuntime` is the one exception to the table above: the runtime has to start **inside** the worker thread, where a live module instance cannot be handed over, so it accepts a specifier (or `false`) only.
184
+
185
+ The shared resolver is exported as `resolveRuntimeDep()` (type `RuntimeDep<T>`) if you build runners of your own.
186
+
160
187
  All runners implement the [`EnvRunner`](./src/types.ts) interface:
161
188
 
162
189
  ```ts
@@ -315,16 +342,20 @@ On `MiniflareEnvRunner` there is no in-worker registration: the runner's module
315
342
 
316
343
  #### Miniflare Runner
317
344
 
318
- Run your app in the Cloudflare Workers runtime using [miniflare](https://github.com/cloudflare/workers-sdk/tree/main/packages/miniflare):
345
+ Run your app in the Cloudflare Workers runtime using [miniflare](https://github.com/cloudflare/workers-sdk/tree/main/packages/miniflare).
346
+
347
+ `env-runner` declares no peer dependencies — install `miniflare` yourself and pass it to the runner (see [Runtime dependencies](#runtime-dependencies)):
319
348
 
320
349
  ```bash
321
350
  npm install miniflare
322
351
  ```
323
352
 
324
353
  ```ts
354
+ import * as miniflare from "miniflare";
325
355
  import { MiniflareEnvRunner } from "env-runner/runners/miniflare";
326
356
 
327
357
  await using runner = new MiniflareEnvRunner({
358
+ miniflare,
328
359
  name: "my-worker",
329
360
  data: { entry: "./worker.ts" },
330
361
  miniflareOptions: {
@@ -336,7 +367,7 @@ await using runner = new MiniflareEnvRunner({
336
367
  const response = await runner.fetch("http://localhost/api");
337
368
  ```
338
369
 
339
- 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.
370
+ Passing `miniflare` explicitly is preferred — the version you install is then the version that runs. A specifier works too (`miniflare: "miniflare"`). If you omit it, the runner imports `miniflare` itself and only fails (with an actionable error) when the package isn't installed either. 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.
340
371
 
341
372
  When you don't set a `compatibilityDate` (via `miniflareOptions` or a wrangler config), 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.
342
373
 
@@ -348,6 +379,7 @@ Set the `wrangler` option to load a Cloudflare [Wrangler config](https://develop
348
379
  import { MiniflareEnvRunner } from "env-runner/runners/miniflare";
349
380
 
350
381
  await using runner = new MiniflareEnvRunner({
382
+ miniflare,
351
383
  name: "my-worker",
352
384
  data: { entry: "./worker.ts" },
353
385
  wrangler: true, // auto-discover wrangler.{json,jsonc,toml} next to the entry, then cwd
@@ -362,6 +394,7 @@ You can also pass an **inline** config object (raw `wrangler.json` shape) instea
362
394
 
363
395
  ```ts
364
396
  await using runner = new MiniflareEnvRunner({
397
+ miniflare,
365
398
  name: "my-worker",
366
399
  data: { entry: "./worker.ts" },
367
400
  wrangler: {
@@ -375,7 +408,22 @@ await using runner = new MiniflareEnvRunner({
375
408
 
376
409
  When an inline config is passed, a `wrangler.{json,jsonc,toml}` file is still auto-discovered (next to the entry, then cwd) 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.
377
410
 
378
- When the [`wrangler`](https://www.npmjs.com/package/wrangler) package is installed (an optional peer dependency), it is used for full fidelity — TOML, `env` inheritance, `.dev.vars`, and every binding type. When `wrangler` is **not** installed, a built-in minimal reader handles plain JSON files and inline objects (common fields only) and logs a one-time warning; JSONC and TOML files are skipped with a warning (they need `wrangler` to parse). Values you pass in `miniflareOptions` always take precedence over config-derived ones — binding records (e.g. `bindings`) merge per key, and `compatibilityFlags` are merged.
411
+ Pass the [`wrangler`](https://www.npmjs.com/package/wrangler) package as `wranglerModule` — the imported module or a specifier — for full fidelity: TOML, `env` inheritance, `.dev.vars`, and every binding type.
412
+
413
+ ```ts
414
+ import * as miniflare from "miniflare";
415
+ import * as wrangler from "wrangler";
416
+
417
+ await using runner = new MiniflareEnvRunner({
418
+ miniflare,
419
+ wranglerModule: wrangler,
420
+ name: "my-worker",
421
+ data: { entry: "./worker.ts" },
422
+ wrangler: true,
423
+ });
424
+ ```
425
+
426
+ Without `wranglerModule`, `wrangler` is imported optionally; if that fails too, a built-in minimal reader handles plain JSON files and inline objects (common fields only) and JSONC/TOML files are skipped with a warning (they need `wrangler` to parse). 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.
379
427
 
380
428
  #### Module Transform Pipeline
381
429
 
@@ -385,6 +433,7 @@ Pass a `transformRequest` callback to route module resolution through Vite's (or
385
433
  import { MiniflareEnvRunner } from "env-runner/runners/miniflare";
386
434
 
387
435
  await using runner = new MiniflareEnvRunner({
436
+ miniflare,
388
437
  name: "my-worker",
389
438
  data: { entry: "./worker.ts" },
390
439
  // Route module resolution through Vite's transform pipeline
@@ -424,6 +473,7 @@ To explicitly declare exports or override auto-detection:
424
473
 
425
474
  ```ts
426
475
  await using runner = new MiniflareEnvRunner({
476
+ miniflare,
427
477
  name: "my-worker",
428
478
  data: { entry: "./worker.ts" },
429
479
  // Explicit exports (merged with auto-detected ones)
@@ -453,6 +503,7 @@ By default, `close()` disposes the Miniflare instance. With `persistent: true`,
453
503
 
454
504
  ```ts
455
505
  const runner1 = new MiniflareEnvRunner({
506
+ miniflare,
456
507
  name: "my-worker",
457
508
  data: { entry: "./worker.ts" },
458
509
  persistent: true,
@@ -463,6 +514,7 @@ const runner1 = new MiniflareEnvRunner({
463
514
  await runner1.close();
464
515
 
465
516
  const runner2 = new MiniflareEnvRunner({
517
+ miniflare,
466
518
  name: "my-worker",
467
519
  data: { entry: "./worker.ts" },
468
520
  persistent: true,
@@ -484,6 +536,25 @@ await using runner = new VercelEnvRunner({
484
536
  });
485
537
  ```
486
538
 
539
+ #### Vercel Queues (local delivery)
540
+
541
+ Framework integrations running inside the vercel runner can bind a topic to a handler for local delivery. Pass [`@vercel/queue`](https://www.npmjs.com/package/@vercel/queue) as `sdk` — the imported module or a specifier (omit it and the SDK is imported optionally; if it isn't installed, registration warns once and becomes a no-op so dev startup is never blocked):
542
+
543
+ ```ts
544
+ import * as sdk from "@vercel/queue";
545
+ import { registerVercelQueueConsumer } from "env-runner/runners/vercel/queue-dev";
546
+
547
+ const unregister = await registerVercelQueueConsumer({
548
+ sdk,
549
+ topic: "orders",
550
+ handler: (message, metadata) => dispatch(message, metadata),
551
+ consumerGroup: "my-framework", // re-registering the same group replaces the handler (HMR-safe)
552
+ retryAfterSeconds: 5, // or `retry: (error, metadata) => ({ acknowledge: true })`
553
+ });
554
+ ```
555
+
556
+ One `QueueClient` is constructed per SDK instance and shared across registrations.
557
+
487
558
  #### Netlify Runner
488
559
 
489
560
  Simulates a Netlify deployment environment with automatic header injection (`x-nf-client-connection-ip`, `x-nf-account-id`, `x-nf-site-id`, `x-nf-deploy-id`, `x-nf-deploy-context`, `x-nf-geo`, `x-nf-request-id`, forwarding headers) and `globalThis.Netlify` setup:
@@ -497,6 +568,18 @@ await using runner = new NetlifyEnvRunner({
497
568
  });
498
569
  ```
499
570
 
571
+ For the full compute runtime — `globalThis.Netlify` with context plus `globalThis.caches` — install [`@netlify/runtime`](https://www.npmjs.com/package/@netlify/runtime) and point the runner at it with `netlifyRuntime`:
572
+
573
+ ```ts
574
+ await using runner = new NetlifyEnvRunner({
575
+ name: "my-app",
576
+ netlifyRuntime: import.meta.resolve("@netlify/runtime"),
577
+ data: { entry: "./app.ts" },
578
+ });
579
+ ```
580
+
581
+ The runtime has to start inside the worker thread, so this is the one runtime-dependency option that takes a module _specifier_ rather than an imported instance — a live module cannot cross that boundary. A bare specifier (`"@netlify/runtime"`) is resolved from the current working directory. If it cannot be imported, the runner warns and falls back to the shim, and `netlifyRuntime: false` forces the shim outright.
582
+
500
583
  ### Vite Environment API
501
584
 
502
585
  env-runner provides helpers for integrating with Vite's [Environment API](https://vite.dev/guide/api-environment-runtimes.html):
@@ -536,6 +619,7 @@ import { MiniflareEnvRunner } from "env-runner/runners/miniflare";
536
619
  import { createViteHotChannel } from "env-runner/vite";
537
620
 
538
621
  const runner = new MiniflareEnvRunner({
622
+ miniflare,
539
623
  name: "worker",
540
624
  data: { entry: "./src/worker.ts" },
541
625
  transformRequest: (id) => devEnvironment.transformRequest(id),
@@ -0,0 +1,51 @@
1
+ /**
2
+ * A runtime dependency the application owns, not `env-runner`.
3
+ *
4
+ * Every runner option that names an external package accepts the same three
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.
16
+ */
17
+ type RuntimeDep<T> = T | string | URL | false;
18
+ interface ResolveRuntimeDepOptions<T> {
19
+ /** Package name, used for the fallback import and in messages. */
20
+ name: string;
21
+ /** Constructor/function option name, used in messages. */
22
+ option: string;
23
+ /** Value as passed by the caller. */
24
+ 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
+ */
29
+ expect?: string;
30
+ /** Directory bare specifiers resolve from. @default process.cwd() */
31
+ 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
+ */
37
+ required?: boolean;
38
+ /** Extra sentence appended to the "not installed" error when `required`. */
39
+ hint?: string;
40
+ }
41
+ /**
42
+ * Resolve a {@link RuntimeDep} to an imported module.
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.
49
+ */
50
+ declare function resolveRuntimeDep<T>(opts: ResolveRuntimeDepOptions<T>): Promise<T | undefined>;
51
+ export { RuntimeDep, resolveRuntimeDep };
@@ -0,0 +1,46 @@
1
+ import { pathToFileURL } from "node:url";
2
+ import { resolveModulePath } from "exsolve";
3
+ function isSpecifier(value) {
4
+ return typeof value === "string" || value instanceof URL;
5
+ }
6
+ function resolveSpecifier(value, from = process.cwd()) {
7
+ if (value instanceof URL) return value.href;
8
+ if (value.includes("://")) return value;
9
+ const resolved = resolveModulePath(value, {
10
+ from: from.endsWith("/") ? from : from + "/",
11
+ try: true
12
+ });
13
+ return resolved ? pathToFileURL(resolved).href : value;
14
+ }
15
+ async function resolveRuntimeDep(opts) {
16
+ const { name, option, value, expect, from, required, hint } = opts;
17
+ if (value === false) return;
18
+ if (value !== void 0) {
19
+ if (!isSpecifier(value)) return validate(value, expect, name, option);
20
+ const raw = typeof value === "string" ? value : value.href;
21
+ let mod;
22
+ try {
23
+ mod = await import(resolveSpecifier(value, from));
24
+ } catch (error) {
25
+ throw new TypeError(`[env-runner] failed to import \`${name}\` from the \`${option}\` specifier "${raw}".`, { cause: error });
26
+ }
27
+ return validate(mod, expect, name, option);
28
+ }
29
+ try {
30
+ return validate(await import(resolveSpecifier(name, from)), expect, name, option);
31
+ } catch (error) {
32
+ if (required) throw new TypeError(`[env-runner] the \`${name}\` package is required: install it, or pass it as the \`${option}\` option (the imported module or a specifier).` + (hint ? ` ${hint}` : ""), { cause: error });
33
+ return;
34
+ }
35
+ }
36
+ function validate(mod, expect, name, option) {
37
+ if (expect && typeof mod?.[expect] !== "function") throw new TypeError(`[env-runner] the \`${option}\` option does not export \`${expect}\` — pass the imported \`${name}\` package or a specifier for it.`);
38
+ return mod;
39
+ }
40
+ function resolveRuntimeDepSpecifier(value, option, from) {
41
+ if (value === false) return false;
42
+ if (value === void 0) return;
43
+ if (!isSpecifier(value)) throw new TypeError(`[env-runner] the \`${option}\` option must be a module specifier (string or URL): the package is imported inside the worker, so an imported module cannot be passed. Use \`import.meta.resolve()\`.`);
44
+ return resolveSpecifier(value, from);
45
+ }
46
+ export { resolveRuntimeDep, resolveRuntimeDepSpecifier };
@@ -2,82 +2,82 @@
2
2
  return A[A.Static = 1] = "Static", A[A.Dynamic = 2] = "Dynamic", A[A.ImportMeta = 3] = "ImportMeta", A[A.StaticSourcePhase = 4] = "StaticSourcePhase", A[A.DynamicSourcePhase = 5] = "DynamicSourcePhase", A[A.StaticDeferPhase = 6] = "StaticDeferPhase", A[A.DynamicDeferPhase = 7] = "DynamicDeferPhase", A;
3
3
  })({});
4
4
  const A = 1 === new Uint8Array(new Uint16Array([1]).buffer)[0];
5
- function parse(E, g = "@") {
6
- if (!C) return init.then(() => parse(E));
7
- const I = E.length + 1, D = (C.__heap_base.value || C.__heap_base) + 4 * I - C.memory.buffer.byteLength;
8
- D > 0 && C.memory.grow(Math.ceil(D / 65536));
9
- const w = C.sa(I - 1);
10
- if ((A ? B : Q)(E, new Uint16Array(C.memory.buffer, w, I)), !C.parse()) throw Object.assign(/* @__PURE__ */ new Error(`Parse error ${g}:${E.slice(0, C.e()).split("\n").length}:${C.e() - E.lastIndexOf("\n", C.e() - 1)}`), { idx: C.e() });
11
- const i = [], G = [];
12
- for (; C.ri();) {
13
- const A = C.is(), Q = C.ie(), B = C.it(), g = C.ai(), I = C.id(), D = C.ss(), w = C.se();
5
+ function parse(C, g = "@") {
6
+ if (!E) return init.then(() => parse(C, g));
7
+ const I = C.length + 1, w = (E.__heap_base.value || E.__heap_base) + 4 * I - E.memory.buffer.byteLength;
8
+ w > 0 && E.memory.grow(Math.ceil(w / 65536));
9
+ const D = E.sa(I - 1);
10
+ if ("undefined" != typeof Buffer ? Buffer.from(E.memory.buffer, D, 2 * (I - 1)).write(C, "utf16le") : (A ? Q : B)(C, new Uint16Array(E.memory.buffer, D, I)), !E.parse()) throw Object.assign(/* @__PURE__ */ new Error(`Parse error ${g}:${C.slice(0, E.e()).split("\n").length}:${E.e() - C.lastIndexOf("\n", E.e() - 1)}`), { idx: E.e() });
11
+ const o = [], G = [];
12
+ for (; E.ri();) {
13
+ const A = E.is(), B = E.ie(), Q = E.it(), g = E.ai(), I = E.id(), w = E.ss(), D = E.se();
14
14
  let G;
15
- C.ip() && (G = o(E.slice(-1 === I ? A - 1 : A, -1 === I ? Q + 1 : Q)));
16
- const R = [];
17
- for (C.rsa(); C.ra();) {
18
- const A = C.aks(), Q = C.ake(), B = C.avs(), g = C.ave();
19
- R.push([s(E.slice(A, Q)), s(E.slice(B, g))]);
15
+ E.ip() && (G = i(C.slice(-1 === I ? A - 1 : A, -1 === I ? B + 1 : B)));
16
+ let J = null;
17
+ for (J = [], E.rsa(); E.ra();) {
18
+ const A = E.aks(), B = E.ake(), Q = E.avs(), g = E.ave();
19
+ J.push([s(C.slice(A, B)), s(C.slice(Q, g))]);
20
20
  }
21
- i.push({
21
+ 0 === J.length && (J = null), o.push({
22
22
  n: G,
23
- t: B,
23
+ t: Q,
24
24
  s: A,
25
- e: Q,
26
- ss: D,
27
- se: w,
25
+ e: B,
26
+ ss: w,
27
+ se: D,
28
28
  d: I,
29
29
  a: g,
30
- at: R.length > 0 ? R : null
30
+ at: J
31
31
  });
32
32
  }
33
- for (; C.re();) {
34
- const A = C.es(), Q = C.ee(), B = C.els(), g = C.ele(), I = C.ess(), D = s(E.slice(A, Q)), w = B < 0 ? void 0 : s(E.slice(B, g));
33
+ for (; E.re();) {
34
+ const A = E.es(), B = E.ee(), Q = E.els(), g = E.ele(), I = Q < 0 ? void 0 : s(C.slice(Q, g)), w = s(C.slice(A, B));
35
35
  G.push({
36
36
  s: A,
37
- e: Q,
38
- ls: B,
37
+ e: B,
38
+ ls: Q,
39
39
  le: g,
40
- ss: I,
41
- n: D,
42
- ln: w
40
+ ss: E.ess(),
41
+ n: w,
42
+ ln: I
43
43
  });
44
44
  }
45
- function o(A) {
45
+ function i(A) {
46
46
  try {
47
47
  return (0, eval)(A);
48
48
  } catch (A) {}
49
49
  }
50
50
  function s(A) {
51
51
  if (!A) return A;
52
- const Q = A[0];
53
- return ("\"" === Q || "'" === Q) && o(A) || A;
52
+ const B = A[0];
53
+ return ("\"" === B || "'" === B) && i(A) || A;
54
54
  }
55
55
  return [
56
- i,
56
+ o,
57
57
  G,
58
- !!C.f(),
59
- !!C.ms()
58
+ !!E.f(),
59
+ !!E.ms()
60
60
  ];
61
61
  }
62
- function Q(A, Q) {
63
- const B = A.length;
64
- let C = 0;
65
- for (; C < B;) {
66
- const B = A.charCodeAt(C);
67
- Q[C++] = (255 & B) << 8 | B >>> 8;
62
+ function B(A, B) {
63
+ const Q = A.length;
64
+ let E = 0;
65
+ for (; E < Q;) {
66
+ const Q = A.charCodeAt(E);
67
+ B[E++] = (255 & Q) << 8 | Q >>> 8;
68
68
  }
69
69
  }
70
- function B(A, Q) {
71
- const B = A.length;
72
- let C = 0;
73
- for (; C < B;) Q[C] = A.charCodeAt(C++);
70
+ function Q(A, B) {
71
+ const Q = A.length;
72
+ let E = 0;
73
+ for (; E < Q;) B[E] = A.charCodeAt(E++);
74
74
  }
75
- let C;
76
- const E = () => {
77
- return A = "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", "undefined" != typeof Buffer ? Buffer.from(A, "base64") : Uint8Array.from(atob(A), (A) => A.charCodeAt(0));
75
+ let E;
76
+ const C = () => {
77
+ return A = "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DQECQAJAIABBAmoiAC8BACIHQdwAaw4FAAICAgUBCyACQQRqIQAMAQsgB0EkRw0AIAIvAQRB+wBHDQALC0GYCiABQQJrNgIADwsgABAmQZgKKAIAIQALQZgKIABBAmoiADYCAAJAAkACQEEBECVBKWsOBAECAgACC0GYCkGYCigCAEECajYCAEEBECUaIAMgADYCBEGYCigCACEAIANBAToAGCADIAA2AhAMCAtBggogBTsBACADIAA2AgRBmAooAgAhACADQQE6ABggAyAAQQJqNgIMQYAKIAQ7AQAPC0GYCkGYCigCAEECazYCAA8LIAdFIABB+wBHckUEQEGYCigCACEAQYIKLwEADQZBnAooAgAhAQNAAkACQCAAIAFJBEBBARAlIgBBIkYgAEEnRnINASAAQf0ARw0CQZgKQZgKKAIAQQJqNgIAC0EBECUhAUGYCigCACEAIAFB5gBGBEAgAEECakGcCEEGEB8NBwtBmAogAEEIajYCAEEBECUiAEEiRyAAQSdHcQ0GIAYgAEEAEDkPCyAAECYLQZgKQZgKKAIAQQJqIgA2AgAMAAsACwJAAkAgAEEnaw4EAwEBAwALIABBIkYNAgtBmAooAgAhBAsgBCAJRw0AQZgKIARBAms2AgAPCyAAQSpHIAVxDQJBggovAQANAkGYCigCACEAQZwKKAIAIQIDQCAAIAJPDQEgAC8BACIBQSdHIAFBIkdxBEBBmAogAEECaiIANgIADAEFIAYgASADEDkPCwALAAsQMgsPC0GYCkGYCigCAEECazYCAA8LQZgKIABBAms2AgALQwEDf0GYCigCACEAQZwKKAIAIQIDQAJAIABBAmohASAAIAJPDQAgASEAIAEvAQBBCmsOBAABAQABCwtBmAogATYCAAtwAQR/QZgKKAIAQQJqIQFBnAooAgAhBAJAA0AgASICQQJqIQEgAiAETw0BIAEvAQAhAwJAIABFBEAgA0EqRg0BIANBCmsOBAMCAgMCCyADQSpHDQELIAIvAQRBL0cNAAsgAkEEaiEBC0GYCiABNgIACwsAIABBn4CABBA8C30BBH9BnAooAgAhA0GYCigCACEBA0ACQAJAAkAgAS8BACICQS9GBEAgAS8BAiIBQSpHBEAgAUEvRg0CQS8PCyAAECMMAgsgAARAIAIQJA0CDAMLIAIQLg0BDAILECIL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", "undefined" != typeof Buffer ? Buffer.from(A, "base64") : Uint8Array.from(atob(A), (A) => A.charCodeAt(0));
78
78
  var A;
79
79
  };
80
- const init = WebAssembly.compile(E()).then(WebAssembly.instantiate).then(({ exports: A }) => {
81
- C = A;
80
+ const init = WebAssembly.compile(C()).then(WebAssembly.instantiate).then(({ exports: A }) => {
81
+ E = A;
82
82
  });
83
83
  export { init, parse };
@@ -1,7 +1,21 @@
1
1
  import { WorkerHooks } from "./types.mjs";
2
2
  import { BaseEnvRunner, EnvRunnerData } from "./common-base-runner.mjs";
3
+ import { RuntimeDep } from "./common-runtime-deps.mjs";
3
4
  import { IncomingMessage } from "node:http";
4
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
+ */
14
+ interface WranglerModule {
15
+ unstable_readConfig?: (...args: any[]) => any;
16
+ unstable_getMiniflareWorkerOptions?: (...args: any[]) => any;
17
+ [key: string]: unknown;
18
+ }
5
19
  /** Raw (snake_case) Wrangler config object, mirroring `wrangler.json` contents. */
6
20
  type WranglerInlineConfig = Record<string, unknown>;
7
21
  /** Result from a module transform (compatible with Vite's `TransformResult`). */
@@ -12,10 +26,45 @@ interface TransformResult {
12
26
  interface MiniflareExportInfo {
13
27
  type?: "DurableObject" | "WorkerEntrypoint" | "class";
14
28
  }
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
+ */
37
+ interface MiniflareModule {
38
+ 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
+ */
43
+ supportedCompatibilityDate?: string;
44
+ [key: string]: unknown;
45
+ }
15
46
  interface MiniflareEnvRunnerOptions {
16
47
  name: string;
17
48
  hooks?: WorkerHooks;
18
49
  data?: EnvRunnerData;
50
+ /**
51
+ * The `miniflare` package: the imported module, or a specifier for it.
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.
66
+ */
67
+ miniflare?: RuntimeDep<MiniflareModule>;
19
68
  /** Options passed directly to the Miniflare constructor. */
20
69
  miniflareOptions?: Record<string, unknown>;
21
70
  /**
@@ -68,12 +117,12 @@ interface MiniflareEnvRunnerOptions {
68
117
  * merged on top of it (inline wins per key, binding records merge,
69
118
  * `compatibilityFlags` are unioned).
70
119
  *
71
- * The installed `wrangler` package is preferred (full fidelity: TOML,
120
+ * The `wrangler` package is used for full fidelity when available (TOML,
72
121
  * `env` inheritance, `.dev.vars`, every binding type; an inline config is
73
- * normalized through a short-lived temp file). When `wrangler` is not
74
- * installed, a built-in minimal reader handles plain JSON files and inline
75
- * objects (common fields only) and a one-time warning is logged. JSONC and
76
- * TOML files without `wrangler` are skipped with a warning. Values from
122
+ * normalized through a short-lived temp file) — passed explicitly as
123
+ * `wranglerModule`, or imported optionally. Otherwise a built-in minimal
124
+ * reader handles plain JSON files and inline objects (common fields only);
125
+ * JSONC and TOML files are skipped with a warning. Values from
77
126
  * `miniflareOptions` always win over config-derived ones; binding records
78
127
  * (e.g. `bindings`) merge per key and `compatibilityFlags` are unioned.
79
128
  */
@@ -83,6 +132,16 @@ interface MiniflareEnvRunnerOptions {
83
132
  * Defaults to the `CLOUDFLARE_ENV` environment variable.
84
133
  */
85
134
  wranglerEnv?: string;
135
+ /**
136
+ * The imported `wrangler` package (`import * as wrangler from "wrangler"`),
137
+ * used to parse the {@link MiniflareEnvRunnerOptions.wrangler} config with
138
+ * full fidelity. When omitted, `import("wrangler")` is tried, and a built-in
139
+ * minimal reader (plain JSON configs and inline objects) handles the rest.
140
+ *
141
+ * Pass `false` to skip the `wrangler` package entirely and always use the
142
+ * built-in minimal reader.
143
+ */
144
+ wranglerModule?: RuntimeDep<WranglerModule>;
86
145
  }
87
146
  declare class MiniflareEnvRunner extends BaseEnvRunner {
88
147
  #private;
@@ -124,4 +183,4 @@ declare class MiniflareEnvRunner extends BaseEnvRunner {
124
183
  };
125
184
  }): Promise<void>;
126
185
  }
127
- export { MiniflareEnvRunner, MiniflareEnvRunnerOptions, MiniflareExportInfo, TransformResult, WranglerInlineConfig };
186
+ export { MiniflareEnvRunner, MiniflareEnvRunnerOptions, MiniflareExportInfo, MiniflareModule, TransformResult, WranglerInlineConfig, WranglerModule };
@@ -1,5 +1,6 @@
1
1
  import { expandVirtualInvalidation, stripVirtualTypeScript, virtualModuleFormat } from "./virtual-loader.mjs";
2
2
  import { BaseEnvRunner } from "./common-base-runner.mjs";
3
+ import { resolveRuntimeDep } from "./common-runtime-deps.mjs";
3
4
  import { init, parse } from "./libs/cjs-module-lexer.mjs";
4
5
  import { init as init$1, parse as parse$1 } from "./libs/es-module-lexer.mjs";
5
6
  import { isVirtualSpecifier } from "./common-worker-utils.mjs";
@@ -7,8 +8,8 @@ import { createRequire } from "node:module";
7
8
  import { proxyUpgrade } from "httpxy";
8
9
  import { fileURLToPath } from "node:url";
9
10
  import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
10
- import { basename, dirname, extname, isAbsolute, join, resolve } from "node:path";
11
11
  import { resolveModulePath } from "exsolve";
12
+ import { basename, dirname, extname, isAbsolute, join, resolve } from "node:path";
12
13
  import { tmpdir } from "node:os";
13
14
  const IPC_PATH = "/__env_runner_ipc";
14
15
  const IPC_BINDING = "__ENV_RUNNER_IPC";
@@ -180,10 +181,6 @@ export default {
180
181
  };
181
182
  `;
182
183
  }
183
- function importWrangler() {
184
- return import("wrangler");
185
- }
186
- let _warnedNoWrangler = false;
187
184
  const WRANGLER_CONFIG_FILENAMES = [
188
185
  "wrangler.json",
189
186
  "wrangler.jsonc",
@@ -207,7 +204,7 @@ function isPlainObject(value) {
207
204
  function isInlineWranglerConfig(opt) {
208
205
  return isPlainObject(opt);
209
206
  }
210
- async function loadWranglerConfig(opt, env, entryPath) {
207
+ async function loadWranglerConfig(opt, env, entryPath, wranglerModule) {
211
208
  if (!opt) return;
212
209
  const inline = isInlineWranglerConfig(opt) ? opt : void 0;
213
210
  let configPath;
@@ -224,16 +221,12 @@ async function loadWranglerConfig(opt, env, entryPath) {
224
221
  return;
225
222
  }
226
223
  } else configPath = findWranglerConfig(entryPath);
227
- let wrangler;
228
- try {
229
- wrangler = await importWrangler();
230
- } catch {
231
- if (!_warnedNoWrangler) {
232
- _warnedNoWrangler = true;
233
- console.warn("[env-runner] 'wrangler' is not installed; using the built-in minimal config reader (plain JSON, common fields only). Install 'wrangler' for full fidelity (JSONC, TOML, env inheritance, all binding types).");
234
- }
235
- return mergeWranglerMiniflareOptions(configPath ? readWranglerConfigMinimal(configPath, env) : void 0, inline ? mapWranglerConfigToMiniflare(applyWranglerEnv(inline, env)) : void 0);
236
- }
224
+ const wrangler = await resolveRuntimeDep({
225
+ name: "wrangler",
226
+ option: "wranglerModule",
227
+ value: wranglerModule
228
+ });
229
+ if (!wrangler?.unstable_readConfig || !wrangler.unstable_getMiniflareWorkerOptions) return mergeWranglerMiniflareOptions(configPath ? readWranglerConfigMinimal(configPath, env) : void 0, inline ? mapWranglerConfigToMiniflare(applyWranglerEnv(inline, env)) : void 0);
237
230
  try {
238
231
  return mergeWranglerMiniflareOptions(configPath ? pickWranglerMiniflareOptions(wrangler.unstable_getMiniflareWorkerOptions(wrangler.unstable_readConfig({
239
232
  config: configPath,
@@ -374,11 +367,14 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
374
367
  #exportConditions;
375
368
  #wrangler;
376
369
  #wranglerEnv;
370
+ #wranglerModule;
371
+ #miniflareModule;
377
372
  constructor(opts) {
378
373
  super({
379
374
  ...opts,
380
375
  workerEntry: ""
381
376
  });
377
+ this.#miniflareModule = opts.miniflare;
382
378
  this.#miniflareOptions = opts.miniflareOptions || {};
383
379
  this.#transformRequest = opts.transformRequest;
384
380
  this.#persistent = opts.persistent ?? false;
@@ -387,6 +383,7 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
387
383
  this.#exportConditions = opts.exportConditions ?? ["workerd", "worker"];
388
384
  this.#wrangler = opts.wrangler ?? false;
389
385
  this.#wranglerEnv = opts.wranglerEnv ?? process.env.CLOUDFLARE_ENV;
386
+ this.#wranglerModule = opts.wranglerModule;
390
387
  this._initWithVirtualData(() => this.#init());
391
388
  }
392
389
  static async disposeAll() {
@@ -482,6 +479,17 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
482
479
  } else await this.#miniflare.dispose();
483
480
  this.#miniflare = void 0;
484
481
  }
482
+ async #resolveMiniflare() {
483
+ this.#miniflareModule = await resolveRuntimeDep({
484
+ name: "miniflare",
485
+ option: "miniflare",
486
+ value: this.#miniflareModule,
487
+ expect: "Miniflare",
488
+ required: true,
489
+ hint: "MiniflareEnvRunner cannot run without it (`import * as miniflare from \"miniflare\"`)."
490
+ });
491
+ return this.#miniflareModule;
492
+ }
485
493
  #init() {
486
494
  this.#initAsync().catch((error) => {
487
495
  console.error("Miniflare runner init error:", error);
@@ -517,11 +525,11 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
517
525
  });
518
526
  }
519
527
  async #initAsync() {
520
- const { Miniflare, supportedCompatibilityDate } = await import("miniflare");
528
+ const { Miniflare, supportedCompatibilityDate } = await this.#resolveMiniflare();
521
529
  const entryPath = this._data?.entry;
522
530
  const virtual = await this.#prepareVirtualModules();
523
531
  this.#virtual = virtual;
524
- const wranglerOptions = await loadWranglerConfig(this.#wrangler, this.#wranglerEnv, entryPath);
532
+ const wranglerOptions = await loadWranglerConfig(this.#wrangler, this.#wranglerEnv, entryPath, this.#wranglerModule);
525
533
  const userFlags = this.#miniflareOptions.compatibilityFlags || [];
526
534
  const wranglerFlags = wranglerOptions?.compatibilityFlags || [];
527
535
  const userDirectSockets = this.#miniflareOptions.unsafeDirectSockets || [];
@@ -662,7 +670,8 @@ var MiniflareEnvRunner = class extends BaseEnvRunner {
662
670
  }
663
671
  } else {
664
672
  const referrerKey = referrer.startsWith("/") ? referrer.slice(1) : referrer;
665
- const referrerDir = dirname(modulePathMap.get(referrerKey) || (referrer.startsWith("/") ? referrer : "/" + referrer));
673
+ const referrerReal = modulePathMap.get(referrerKey) || (referrer.startsWith("/") ? referrer : "/" + referrer);
674
+ const referrerDir = dirname(referrerReal);
666
675
  const raw = cleanRaw || cleanSpecifier;
667
676
  if (raw.startsWith(".")) resolvedPath = resolve(referrerDir, raw);
668
677
  else if (cleanSpecifier.startsWith("/")) resolvedPath = cleanSpecifier;
@@ -1,14 +1,39 @@
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 {
5
+ name: string;
6
+ workerEntry?: string;
7
+ hooks?: WorkerHooks;
8
+ data?: EnvRunnerData;
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.
31
+ */
32
+ netlifyRuntime?: string | URL | false;
33
+ }
4
34
  declare class NetlifyEnvRunner extends NodeWorkerEnvRunner {
5
- constructor(opts: {
6
- name: string;
7
- workerEntry?: string;
8
- hooks?: WorkerHooks;
9
- data?: EnvRunnerData;
10
- });
35
+ constructor(opts: NetlifyEnvRunnerOptions);
11
36
  fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
12
37
  protected _runtimeType(): string;
13
38
  }
14
- export { NetlifyEnvRunner };
39
+ export { NetlifyEnvRunner, NetlifyEnvRunnerOptions };
@@ -1,12 +1,18 @@
1
+ import { resolveRuntimeDepSpecifier } from "./common-runtime-deps.mjs";
1
2
  import { NodeWorkerEnvRunner } from "./node-worker-runner.mjs";
2
3
  import { fileURLToPath } from "node:url";
3
4
  let _defaultEntry;
4
5
  var NetlifyEnvRunner = class extends NodeWorkerEnvRunner {
5
6
  constructor(opts) {
6
7
  _defaultEntry ||= fileURLToPath(import.meta.resolve("env-runner/runners/netlify/worker"));
8
+ const netlifyRuntime = resolveNetlifyRuntime(opts.netlifyRuntime);
7
9
  super({
8
10
  ...opts,
9
- workerEntry: opts.workerEntry || _defaultEntry
11
+ workerEntry: opts.workerEntry || _defaultEntry,
12
+ data: netlifyRuntime === void 0 ? opts.data : {
13
+ ...opts.data,
14
+ netlifyRuntime
15
+ }
10
16
  });
11
17
  }
12
18
  async fetch(input, init) {
@@ -43,4 +49,7 @@ var NetlifyEnvRunner = class extends NodeWorkerEnvRunner {
43
49
  return "netlify";
44
50
  }
45
51
  };
52
+ function resolveNetlifyRuntime(runtime) {
53
+ return resolveRuntimeDepSpecifier(runtime, "netlifyRuntime");
54
+ }
46
55
  export { NetlifyEnvRunner };
@@ -300,6 +300,7 @@ var EnvServer = class extends RunnerManager {
300
300
  }
301
301
  async _createRunner() {
302
302
  return loadRunner(this._opts.runner || "node-worker", {
303
+ ...this._opts.runnerOptions,
303
304
  name: this._opts.name || this._opts.entry,
304
305
  hooks: this._opts.hooks,
305
306
  data: {
package/dist/cli.d.mts CHANGED
@@ -1 +1 @@
1
- export { };
1
+ export {}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { EnvRunner, FetchHandler, NodeUpgradeContext, RPCOptions, RunnerMessageListener, RunnerRPCHooks, UpgradeContext, UpgradeHandler, WorkerAddress, WorkerHooks } from "./_chunks/types.mjs";
2
2
  import { BaseEnvRunner, EnvRunnerData, VirtualModuleSource, VirtualModules } from "./_chunks/common-base-runner.mjs";
3
+ import { RuntimeDep, resolveRuntimeDep } from "./_chunks/common-runtime-deps.mjs";
3
4
  import { DenoProcessEnvRunner } from "./_chunks/deno-process-runner.mjs";
4
5
  import { MiniflareEnvRunner, MiniflareEnvRunnerOptions, MiniflareExportInfo, TransformResult } from "./_chunks/miniflare-runner.mjs";
5
6
  import { VercelEnvRunner } from "./_chunks/vercel-runner.mjs";
@@ -84,7 +85,11 @@ interface LoadRunnerOptions {
84
85
  hooks?: WorkerHooks;
85
86
  data?: EnvRunnerData;
86
87
  execArgv?: string[];
87
- /** Additional runner-specific options (passed through to the runner constructor). */
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
+ */
88
93
  [key: string]: unknown;
89
94
  }
90
95
  declare function loadRunner(runner: RunnerName, opts: LoadRunnerOptions): Promise<EnvRunner>;
@@ -105,6 +110,14 @@ interface EnvServerOptions {
105
110
  watch?: boolean;
106
111
  /** Additional paths to watch (directories or files). */
107
112
  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
+ */
120
+ runnerOptions?: Record<string, unknown>;
108
121
  }
109
122
  declare class EnvServer extends RunnerManager {
110
123
  private _opts;
@@ -156,4 +169,4 @@ interface AppEntry {
156
169
  plugins?: ServerOptions["plugins"];
157
170
  ipc?: AppEntryIPC;
158
171
  }
159
- 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 TransformResult, type UpgradeContext, type UpgradeHandler, VercelEnvRunner, type VirtualModuleSource, type VirtualModules, type WorkerAddress, type WorkerHooks, loadRunner };
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 };
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { BaseEnvRunner } from "./_chunks/common-base-runner.mjs";
2
2
  import { EnvServer, RunnerManager, loadRunner } from "./_chunks/server.mjs";
3
+ import { resolveRuntimeDep } from "./_chunks/common-runtime-deps.mjs";
3
4
  import { DenoProcessEnvRunner } from "./_chunks/deno-process-runner.mjs";
4
5
  import { MiniflareEnvRunner } from "./_chunks/miniflare-runner.mjs";
5
6
  import { VercelEnvRunner } from "./_chunks/vercel-runner.mjs";
6
7
  import { NetlifyEnvRunner } from "./_chunks/netlify-runner.mjs";
7
- export { BaseEnvRunner, DenoProcessEnvRunner, EnvServer, MiniflareEnvRunner, NetlifyEnvRunner, RunnerManager, VercelEnvRunner, loadRunner };
8
+ export { BaseEnvRunner, DenoProcessEnvRunner, EnvServer, MiniflareEnvRunner, NetlifyEnvRunner, RunnerManager, VercelEnvRunner, loadRunner, resolveRuntimeDep };
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -1,3 +1,3 @@
1
1
  import { EnvRunnerData } from "../../_chunks/common-base-runner.mjs";
2
- import { MiniflareEnvRunner, MiniflareEnvRunnerOptions, MiniflareExportInfo, TransformResult, WranglerInlineConfig } from "../../_chunks/miniflare-runner.mjs";
3
- export { MiniflareEnvRunner, type EnvRunnerData as MiniflareEnvRunnerData, MiniflareEnvRunnerOptions, MiniflareExportInfo, TransformResult, type WranglerInlineConfig };
2
+ import { MiniflareEnvRunner, MiniflareEnvRunnerOptions, MiniflareExportInfo, MiniflareModule, TransformResult, WranglerInlineConfig, WranglerModule } from "../../_chunks/miniflare-runner.mjs";
3
+ export { MiniflareEnvRunner, type EnvRunnerData as MiniflareEnvRunnerData, MiniflareEnvRunnerOptions, MiniflareExportInfo, MiniflareModule, TransformResult, type WranglerInlineConfig, type WranglerModule };
@@ -1,3 +1,3 @@
1
1
  import { EnvRunnerData } from "../../_chunks/common-base-runner.mjs";
2
- import { NetlifyEnvRunner } from "../../_chunks/netlify-runner.mjs";
3
- export { type EnvRunnerData, NetlifyEnvRunner };
2
+ import { NetlifyEnvRunner, NetlifyEnvRunnerOptions } from "../../_chunks/netlify-runner.mjs";
3
+ export { type EnvRunnerData, NetlifyEnvRunner, NetlifyEnvRunnerOptions };
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -1,41 +1,40 @@
1
- try {
2
- const { startRuntime } = await import("@netlify/runtime");
1
+ import { resolveRuntimeDep } from "../../_chunks/common-runtime-deps.mjs";
2
+ import { workerData } from "node:worker_threads";
3
+ const netlifyEnv = {
4
+ get: (key) => process.env[key],
5
+ has: (key) => key in process.env,
6
+ set: (key, value) => {
7
+ process.env[key] = value;
8
+ },
9
+ delete: (key) => {
10
+ delete process.env[key];
11
+ },
12
+ toObject: () => ({ ...process.env })
13
+ };
14
+ const runtimeSpecifier = (workerData || {}).netlifyRuntime;
15
+ let started = false;
16
+ if (runtimeSpecifier !== false) try {
17
+ const startRuntime = (await resolveRuntimeDep({
18
+ name: "@netlify/runtime",
19
+ option: "netlifyRuntime",
20
+ value: runtimeSpecifier,
21
+ expect: "startRuntime"
22
+ }))?.startRuntime;
23
+ if (!startRuntime) throw new Error("`@netlify/runtime` is not installed");
3
24
  startRuntime({
4
25
  deployID: "0",
5
26
  siteID: "0",
6
- env: {
7
- get: (key) => process.env[key],
8
- has: (key) => key in process.env,
9
- set: (key, value) => {
10
- process.env[key] = value;
11
- },
12
- delete: (key) => {
13
- delete process.env[key];
14
- },
15
- toObject: () => ({ ...process.env })
16
- },
27
+ env: netlifyEnv,
17
28
  getRequestContext: () => null,
18
29
  cache: { getCacheAPIContext: () => null }
19
30
  });
20
- } catch {
21
- if (!process.env.__ENV_RUNNER_NETLIFY_WARNED) {
22
- process.env.__ENV_RUNNER_NETLIFY_WARNED = "1";
23
- console.warn("@netlify/runtime is not installed. Install it for full Netlify runtime emulation: npx nypm i -D @netlify/runtime");
24
- }
25
- globalThis.Netlify = {
26
- context: null,
27
- env: {
28
- get: (key) => process.env[key],
29
- has: (key) => key in process.env,
30
- set: (key, value) => {
31
- process.env[key] = value;
32
- },
33
- delete: (key) => {
34
- delete process.env[key];
35
- },
36
- toObject: () => ({ ...process.env })
37
- }
38
- };
31
+ started = true;
32
+ } catch (error) {
33
+ if (runtimeSpecifier) console.warn(`[env-runner] failed to start the Netlify runtime from "${runtimeSpecifier}": ${error?.cause?.message || error?.message || error}`);
39
34
  }
35
+ if (!started) globalThis.Netlify = {
36
+ context: null,
37
+ env: netlifyEnv
38
+ };
40
39
  await import("../node-worker/worker.mjs");
41
40
  export {};
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -1,9 +1,64 @@
1
- import { MessageHandler, RetryHandler } from "@vercel/queue";
1
+ import { RuntimeDep } from "../../_chunks/common-runtime-deps.mjs";
2
+ /** Metadata passed alongside each delivered message (`MessageMetadata`). */
3
+ interface VercelQueueMessageMetadata {
4
+ messageId: string;
5
+ deliveryCount: number;
6
+ createdAt: Date;
7
+ expiresAt: Date;
8
+ topicName: string;
9
+ consumerGroup: string;
10
+ /** Vercel region the client is targeting. */
11
+ region: string;
12
+ }
13
+ /** Instruction returned by a retry handler when the message handler throws. */
14
+ type VercelQueueRetryDirective = {
15
+ afterSeconds: number;
16
+ } | {
17
+ acknowledge: true;
18
+ };
19
+ /** Function invoked with each delivered message (`MessageHandler`). */
20
+ type VercelQueueMessageHandler<T = unknown> = (message: T, metadata: VercelQueueMessageMetadata) => Promise<void> | void;
21
+ /** Called when the message handler throws (`RetryHandler`). */
22
+ type VercelQueueRetryHandler = (error: unknown, metadata: VercelQueueMessageMetadata) => VercelQueueRetryDirective | void | undefined;
23
+ /**
24
+ * The `@vercel/queue` package, as imported by the consumer
25
+ * (`import * as queue from "@vercel/queue"`). Structurally typed so the real
26
+ * module namespace is assignable without env-runner depending on the package.
27
+ */
28
+ interface VercelQueueSdk {
29
+ QueueClient: new (options?: any) => any;
30
+ registerDevConsumer?: (options: {
31
+ topic: string;
32
+ client: any;
33
+ handler: VercelQueueMessageHandler;
34
+ consumerGroup?: string;
35
+ visibilityTimeoutSeconds?: number;
36
+ retry?: VercelQueueRetryHandler;
37
+ }) => () => void;
38
+ [key: string]: unknown;
39
+ }
2
40
  interface VercelQueueDevConsumer {
41
+ /**
42
+ * The `@vercel/queue` package: the imported module, or a specifier for it.
43
+ *
44
+ * ```ts
45
+ * import * as sdk from "@vercel/queue";
46
+ * await registerVercelQueueConsumer({ sdk, topic: "orders", handler });
47
+ *
48
+ * // or, equivalently
49
+ * await registerVercelQueueConsumer({ sdk: "@vercel/queue", topic, handler });
50
+ * ```
51
+ *
52
+ * Passing it explicitly is preferred (`@vercel/queue` is not a dependency of
53
+ * `env-runner`). Bare specifiers resolve from the current working directory.
54
+ * When omitted, `@vercel/queue` is imported optionally and registration
55
+ * becomes a no-op if the package isn't installed.
56
+ */
57
+ sdk?: RuntimeDep<VercelQueueSdk>;
3
58
  /** Topic name. Wildcard patterns (e.g. `"user-*"`) are supported. */
4
59
  topic: string;
5
60
  /** Function invoked with each delivered message. */
6
- handler: MessageHandler;
61
+ handler: VercelQueueMessageHandler;
7
62
  /**
8
63
  * Logical consumer identifier. Re-registering with the same group on the same
9
64
  * topic replaces the previous handler (HMR-safe). Use distinct groups to fan
@@ -27,18 +82,18 @@ interface VercelQueueDevConsumer {
27
82
  * `{ afterSeconds }` to reschedule, `{ acknowledge: true }` to drop, or
28
83
  * `undefined` to let the error propagate.
29
84
  */
30
- retry?: RetryHandler;
85
+ retry?: VercelQueueRetryHandler;
31
86
  }
32
87
  /**
33
88
  * Bind a handler to a topic. Resolves to an unregister function.
34
89
  *
35
- * The first call across the worker process lazily loads `@vercel/queue` and
36
- * constructs a shared `QueueClient`. Re-registering with the same topic
90
+ * A shared `QueueClient` is constructed from `sdk` on first use and reused for
91
+ * later registrations with the same SDK. Re-registering with the same topic
37
92
  * replaces the handler (HMR-safe; the SDK keys consumers by `consumerGroup`,
38
93
  * so calling unregister on a replaced registration is a no-op).
39
94
  *
40
- * If `@vercel/queue` is not installed or does not expose `registerDevConsumer`,
95
+ * If no SDK is available, or it does not expose `registerDevConsumer`,
41
96
  * resolves to a no-op unregister and logs a one-time warning.
42
97
  */
43
98
  declare function registerVercelQueueConsumer(consumer: VercelQueueDevConsumer): Promise<() => void>;
44
- export { VercelQueueDevConsumer, registerVercelQueueConsumer };
99
+ export { VercelQueueDevConsumer, VercelQueueMessageHandler, VercelQueueMessageMetadata, VercelQueueRetryDirective, VercelQueueRetryHandler, VercelQueueSdk, registerVercelQueueConsumer };
@@ -1,10 +1,31 @@
1
+ import { resolveRuntimeDep } from "../../_chunks/common-runtime-deps.mjs";
1
2
  const DEFAULT_CONSUMER_GROUP = "env-runner-vercel-dev";
2
- let sdkPromise;
3
- let client;
3
+ const _clients = /* @__PURE__ */ new WeakMap();
4
+ const _warned = /* @__PURE__ */ new WeakSet();
5
+ let _warnedMissing = false;
6
+ let _importedSdk;
4
7
  const noop = () => {};
5
8
  async function registerVercelQueueConsumer(consumer) {
6
- const sdk = await ensureSdk();
7
- if (!sdk || !client) return noop;
9
+ const sdk = await resolveSdk(consumer.sdk);
10
+ if (!sdk) {
11
+ if (!_warnedMissing) {
12
+ _warnedMissing = true;
13
+ console.warn("[env-runner:vercel-queue] `@vercel/queue` is not installed and no `sdk` was passed. Local queue delivery is disabled.");
14
+ }
15
+ return noop;
16
+ }
17
+ if (typeof sdk.registerDevConsumer !== "function") {
18
+ if (!_warned.has(sdk)) {
19
+ _warned.add(sdk);
20
+ console.warn("[env-runner:vercel-queue] The `@vercel/queue` SDK in use does not export `registerDevConsumer`. Upgrade @vercel/queue@^0.2.0 to enable local queue delivery.");
21
+ }
22
+ return noop;
23
+ }
24
+ let client = _clients.get(sdk);
25
+ if (!client) {
26
+ client = new sdk.QueueClient();
27
+ _clients.set(sdk, client);
28
+ }
8
29
  return sdk.registerDevConsumer({
9
30
  topic: consumer.topic,
10
31
  client,
@@ -14,23 +35,16 @@ async function registerVercelQueueConsumer(consumer) {
14
35
  retry: consumer.retry ?? (consumer.retryAfterSeconds === void 0 ? void 0 : () => ({ afterSeconds: consumer.retryAfterSeconds }))
15
36
  });
16
37
  }
17
- function ensureSdk() {
18
- if (sdkPromise) return sdkPromise;
19
- sdkPromise = (async () => {
20
- let mod;
21
- try {
22
- mod = await import("@vercel/queue");
23
- } catch {
24
- console.warn("[env-runner:vercel-queue] `@vercel/queue` is not installed. Local queue delivery is disabled.");
25
- return null;
26
- }
27
- if (typeof mod.registerDevConsumer !== "function") {
28
- console.warn("[env-runner:vercel-queue] Installed `@vercel/queue` does not export `registerDevConsumer`. Upgrade @vercel/queue@^0.2.0 to enable local queue delivery.");
29
- return null;
30
- }
31
- client = new mod.QueueClient();
32
- return mod;
33
- })();
34
- return sdkPromise;
38
+ function resolveSdk(value) {
39
+ if (value !== void 0) return resolveRuntimeDep({
40
+ name: "@vercel/queue",
41
+ option: "sdk",
42
+ value
43
+ });
44
+ _importedSdk ??= resolveRuntimeDep({
45
+ name: "@vercel/queue",
46
+ option: "sdk"
47
+ });
48
+ return _importedSdk;
35
49
  }
36
50
  export { registerVercelQueueConsumer };
@@ -1 +1 @@
1
- export { };
1
+ export {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "env-runner",
3
- "version": "0.1.16",
3
+ "version": "0.2.0",
4
4
  "description": "Generic environment runner for JavaScript runtimes.",
5
5
  "license": "MIT",
6
6
  "repository": "unjs/env-runner",
@@ -40,52 +40,31 @@
40
40
  "env-runner": "node ./src/cli.ts",
41
41
  "release": "pnpm test && pnpm build && changelogen --release && npm publish && git push --follow-tags",
42
42
  "test": "pnpm lint && pnpm typecheck && vitest run --coverage",
43
- "typecheck": "tsgo --noEmit --skipLibCheck"
43
+ "typecheck": "tsc --noEmit --skipLibCheck"
44
44
  },
45
45
  "dependencies": {
46
- "crossws": "^0.4.8",
47
- "exsolve": "^1.1.0",
48
- "httpxy": "^0.5.4",
49
- "srvx": "^0.11.19"
46
+ "crossws": "^0.4.11",
47
+ "exsolve": "^1.1.1",
48
+ "httpxy": "^0.5.5",
49
+ "srvx": "^0.12.7"
50
50
  },
51
51
  "devDependencies": {
52
- "@netlify/runtime": "^4.1.25",
53
- "@types/node": "^26.0.1",
54
- "@typescript/native-preview": "7.0.0-dev.20260629.1",
55
- "@vercel/queue": "^0.3.1",
56
- "@vitest/coverage-v8": "^4.1.9",
52
+ "@netlify/runtime": "^5",
53
+ "@types/node": "^26.2.0",
54
+ "@vercel/queue": "^0.4",
55
+ "@vitest/coverage-v8": "^4.1.11",
57
56
  "automd": "^0.4.3",
58
57
  "changelogen": "^0.6.2",
59
- "cjs-module-lexer": "^2.2.0",
58
+ "cjs-module-lexer": "^2.2.1",
60
59
  "env-runner-fixture": "link:",
61
- "es-module-lexer": "^2.2.0",
62
- "miniflare": "^4.20260625.0",
63
- "obuild": "^0.4.37",
64
- "oxfmt": "^0.56.0",
65
- "oxlint": "^1.71.0",
66
- "typescript": "^6.0.3",
67
- "vitest": "^4.1.9",
68
- "wrangler": "^4.105.0"
60
+ "es-module-lexer": "^2.3.2",
61
+ "miniflare": "^4",
62
+ "obuild": "^0.4.38",
63
+ "oxfmt": ">=0.64.0",
64
+ "oxlint": "^1.79.0",
65
+ "typescript": "^7",
66
+ "vitest": "^4.1.11",
67
+ "wrangler": "^4.124.0"
69
68
  },
70
- "peerDependencies": {
71
- "@netlify/runtime": "^4.1.23",
72
- "@vercel/queue": ">=0.2.0",
73
- "miniflare": "^4.20260515.0",
74
- "wrangler": "^4.0.0"
75
- },
76
- "peerDependenciesMeta": {
77
- "miniflare": {
78
- "optional": true
79
- },
80
- "@netlify/runtime": {
81
- "optional": true
82
- },
83
- "@vercel/queue": {
84
- "optional": true
85
- },
86
- "wrangler": {
87
- "optional": true
88
- }
89
- },
90
- "packageManager": "pnpm@11.9.0"
69
+ "packageManager": "pnpm@11.22.0"
91
70
  }