@volter/tabnode 0.4.1 → 0.5.1

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.
Files changed (80) hide show
  1. package/dist/__sw__.js +259 -5
  2. package/dist/assets/{runtime-worker-LWfW6VWE.js → runtime-worker-DBZ2flHK.js} +4000 -2944
  3. package/dist/fetch-transport.d.ts +20 -0
  4. package/dist/guest-timers.d.ts +15 -0
  5. package/dist/http-client-transport.d.ts +19 -0
  6. package/dist/index.d.ts +11 -0
  7. package/dist/index.mjs +5196 -3062
  8. package/dist/native-stream-binding.d.ts +57 -0
  9. package/dist/native-stream-owner.d.ts +121 -0
  10. package/dist/node-lib/binding/duplex_stream.d.ts +26 -0
  11. package/dist/node-lib/binding/fds.d.ts +8 -0
  12. package/dist/node-lib/binding/fs.d.ts +311 -78
  13. package/dist/node-lib/binding/misc.d.ts +1 -0
  14. package/dist/node-lib/binding/pipe_wrap.d.ts +4 -4
  15. package/dist/node-lib/binding/process_wrap.d.ts +12 -1
  16. package/dist/node-lib/binding/stream_wrap.d.ts +27 -18
  17. package/dist/node-lib/binding/tcp_wrap.d.ts +0 -1
  18. package/dist/node-lib/binding/tty_wrap.d.ts +43 -2
  19. package/dist/node-lib/binding/util.d.ts +83 -0
  20. package/dist/node-lib/binding/uv.d.ts +4 -0
  21. package/dist/node-lib/fs-module.d.ts +1 -0
  22. package/dist/node-lib/internals/buffer-and-streams.d.ts +30 -17
  23. package/dist/node-lib/internals/index.d.ts +1 -1
  24. package/dist/node-lib/load.d.ts +17 -3
  25. package/dist/node-lib/module-hooks.d.ts +1 -0
  26. package/dist/node-lib/public-modules.d.ts +1 -1
  27. package/dist/node-lib/timers.d.ts +38 -0
  28. package/dist/node-process-host.d.ts +41 -0
  29. package/dist/process-registry.d.ts +39 -0
  30. package/dist/process-tokens.d.ts +11 -0
  31. package/dist/promise-ownership.d.ts +3 -0
  32. package/dist/runtime.d.ts +10 -9
  33. package/dist/shims/child_process.d.ts +2 -0
  34. package/dist/shims/crypto.d.ts +660 -119
  35. package/dist/shims/dns.d.ts +76 -2
  36. package/dist/shims/process.d.ts +1 -0
  37. package/dist/shims/string_decoder.d.ts +19 -3
  38. package/dist/shims/tls.d.ts +853 -31
  39. package/dist/source-edits.d.ts +7 -0
  40. package/package.json +1 -1
  41. package/src/code-transforms.ts +2 -3
  42. package/src/fetch-transport.ts +98 -0
  43. package/src/guest-timers.ts +89 -0
  44. package/src/http-client-transport.ts +169 -0
  45. package/src/index.ts +18 -0
  46. package/src/native-stream-binding.ts +393 -0
  47. package/src/native-stream-owner.ts +317 -0
  48. package/src/node-lib/binding/duplex_stream.ts +95 -0
  49. package/src/node-lib/binding/fds.ts +18 -1
  50. package/src/node-lib/binding/fs.ts +45 -17
  51. package/src/node-lib/binding/misc.ts +2 -0
  52. package/src/node-lib/binding/pipe_wrap.ts +35 -12
  53. package/src/node-lib/binding/process_wrap.ts +50 -9
  54. package/src/node-lib/binding/stream_wrap.ts +196 -72
  55. package/src/node-lib/binding/tcp_wrap.ts +43 -8
  56. package/src/node-lib/binding/tty_wrap.ts +135 -8
  57. package/src/node-lib/binding/util.ts +24 -15
  58. package/src/node-lib/binding/uv.ts +4 -0
  59. package/src/node-lib/fs-module.ts +2 -18
  60. package/src/node-lib/internal/navigator.js +149 -0
  61. package/src/node-lib/internals/buffer-and-streams.ts +50 -11
  62. package/src/node-lib/internals/events-util.ts +5 -0
  63. package/src/node-lib/internals/index.ts +12 -2
  64. package/src/node-lib/load.ts +170 -62
  65. package/src/node-lib/module-hooks.ts +5 -2
  66. package/src/node-lib/public-modules.ts +12 -48
  67. package/src/node-lib/sources.ts +4 -0
  68. package/src/node-lib/timers.ts +93 -0
  69. package/src/node-process-host.ts +124 -0
  70. package/src/process-registry.ts +144 -0
  71. package/src/process-tokens.ts +55 -6
  72. package/src/promise-ownership.ts +28 -0
  73. package/src/runtime.ts +90 -214
  74. package/src/shims/child_process.ts +310 -80
  75. package/src/shims/crypto.ts +115 -100
  76. package/src/shims/dns.ts +17 -1
  77. package/src/shims/process.ts +33 -11
  78. package/src/shims/string_decoder.ts +10 -6
  79. package/src/shims/tls.ts +49 -19
  80. package/src/source-edits.ts +20 -0
package/src/runtime.ts CHANGED
@@ -6,6 +6,8 @@
6
6
  */
7
7
 
8
8
  import { VirtualFS } from './virtual-fs';
9
+ import { guestPromise, intrinsicPromise } from './promise-ownership';
10
+ import { guestFetch, rememberRequestBodySource } from './fetch-transport';
9
11
  import { forGuestRealm, installGuestRealm, takeFromHost, defineOnHost, heldWork } from './host-globals';
10
12
  import type { IRuntime, IExecuteResult, IRuntimeOptions } from './runtime-interface';
11
13
  import type { PackageJson } from './types/package-json';
@@ -13,21 +15,23 @@ import { simpleHash } from './utils/hash';
13
15
  import { uint8ToBase64, uint8ToHex } from './utils/binary-encoding';
14
16
  import { createFsShim, FsShim } from './shims/fs';
15
17
  import * as pathShim from './shims/path';
16
- import { createProcess, Process, __reportUncaughtException } from './shims/process';
18
+ import { createProcess, Process } from './shims/process';
17
19
  import {
18
20
  httpModule, httpsModule, httpCommonModule, httpIncomingModule, httpOutgoingModule,
19
21
  httpServerModule, httpClientModule, httpAgentModule,
20
22
  } from './node-lib/http-module';
21
23
  import { netModule as netShim } from './node-lib/net-module';
22
24
  import { errname as __uvErrname } from './node-lib/binding/uv';
23
- import { nodeTimeout, timerHandleOf } from './node-lib/timers';
25
+ import { createTimersModule } from './node-lib/timers';
26
+ import { guestTimerFunctions } from './guest-timers';
27
+ export { pendingGuestTimers, stopGuestTimers } from './guest-timers';
24
28
  import eventsShim from './node-lib/events-module';
25
29
  import { streamModule as streamShim, streamPromisesModule as streamPromises } from './node-lib/stream-module';
26
30
  import * as urlShim from './shims/url';
27
31
  import utilShim from './node-lib/util-module';
28
32
  import * as cryptoShim from './shims/crypto';
29
33
  import * as stringDecoderShim from './shims/string_decoder';
30
- import * as dnsShim from './shims/dns';
34
+ import { createDnsModule } from './shims/dns';
31
35
  import { bufferModule as bufferShim } from './node-lib/buffer-module';
32
36
  import { initChildProcess } from './shims/child_process';
33
37
  import { childProcessModule as childProcessShim } from './node-lib/child-process-module';
@@ -35,7 +39,7 @@ import { getServerBridge } from './server-bridge';
35
39
  import * as moduleShim from './shims/module';
36
40
  import { RunModuleHooks, CJS_CONDITIONS } from './node-lib/module-hooks';
37
41
  import { kRunFilesystem } from './node-lib/binding/fs';
38
- import { esmNamespaceOf, syncBuiltinESMExports } from './node-lib/load';
42
+ import { esmNamespaceOf, syncBuiltinESMExports, loadNodeLibFor, hasNodeLibModule, nativeModuleFor } from './node-lib/load';
39
43
  import { fsModule, fsModuleFor } from './node-lib/fs-module';
40
44
  import {
41
45
  assertModule, querystringModule, punycodeModule, constantsModule,
@@ -62,6 +66,7 @@ import { createWasiModule, type WasiHostFs, type WasiModule } from './shims/wasi
62
66
 
63
67
  import { resolve as resolveExports, imports as resolveImports } from 'resolve.exports';
64
68
  import { transformEsmToCjsSimple, setNodeLowering, __cjsExports, __substrateHasEsmSyntax } from './code-transforms';
69
+ import { applySourceEdits } from './source-edits';
65
70
  import * as acorn from 'acorn';
66
71
 
67
72
  /**
@@ -98,95 +103,10 @@ function walkAst(node: any, callback: (node: any) => void): void {
98
103
  * answers for them.
99
104
  */
100
105
  const __substrateGuestGlobals = new WeakMap<Process, Record<string, unknown>>();
101
- /**
102
- * The timers a guest process has pending: what Node's loop counts to decide
103
- * a program is done. A timer the guest sets through its global view is
104
- * held here until it fires, is cleared, or is unref'd, and the `node`
105
- * command's end-of-program rule asks how many remain.
106
- */
107
- const __substratePendingTimers = new WeakMap<Process, Set<unknown>>();
108
- export function pendingGuestTimers(process: Process): number {
109
- return __substratePendingTimers.get(process)?.size ?? 0;
110
- }
111
- /**
112
- * Clear every timer a guest still holds, as ending a Node process clears the
113
- * ones its loop was waiting on. The ids were made by the host's own
114
- * `setTimeout`/`setInterval` through the guest's global view, so the host's
115
- * own clears end them; a `Timeout` is cleared by either in Node, and either
116
- * refusing an id of the other kind is not an error here.
117
- */
118
- export function stopGuestTimers(process: Process): void {
119
- const held = __substratePendingTimers.get(process);
120
- if (!held) return;
121
- const host = globalThis as unknown as Record<string, unknown>;
122
- const clearOnce = host.clearTimeout as ((id: unknown) => void) | undefined;
123
- const clearRepeating = host.clearInterval as ((id: unknown) => void) | undefined;
124
- for (const id of [...held]) {
125
- try { clearOnce?.call(host, id); } catch {}
126
- try { clearRepeating?.call(host, id); } catch {}
127
- }
128
- held.clear();
129
- }
130
- function __substrateTimerFunctions(process: Process, host: Record<string, unknown>): Record<string, unknown> {
131
- let pending = __substratePendingTimers.get(process);
132
- if (!pending) { pending = new Set(); __substratePendingTimers.set(process, pending); }
133
- const held = pending;
134
- const hostSetTimeout = host.setTimeout as (fn: (...a: unknown[]) => void, ms?: number, ...rest: unknown[]) => unknown;
135
- const hostSetInterval = host.setInterval as (fn: (...a: unknown[]) => void, ms?: number, ...rest: unknown[]) => unknown;
136
- const hostClearTimeout = host.clearTimeout as (id: unknown) => void;
137
- const hostClearInterval = host.clearInterval as (id: unknown) => void;
138
- // Node's timers answer a `Timeout`: an object with `ref`, `unref`,
139
- // `hasRef` and `refresh`, which vitest and many packages call. A browser's
140
- // answer a number. The engine used to correct this by replacing the realm's
141
- // `setTimeout`, which in a Node host replaced the host's own; the
142
- // correction belongs to the guest that reads Node's shape, so it is made
143
- // here, on the guest's timer, and a host that already answers a `Timeout`
144
- // keeps its own. The shape itself is `src/node-lib/timers.ts`: Node's own
145
- // files take their timers from `require('timers')` rather than from the
146
- // realm, and a timer made through one is cleared through the other.
147
- const handleOf = timerHandleOf;
148
- // An exception a timer callback throws is that program's uncaught
149
- // exception: Node gives it to the process's `uncaughtException` listeners,
150
- // else prints the stack to that process's stderr and exits it 1, and every
151
- // other process is untouched. The engine's timers are the realm's own, so
152
- // an uncaught throw left the guest's frames and reached the realm's global
153
- // `error` event — in the tab the worker's, which the substrate's container
154
- // reads as a dead host and disposes, killing openvscode-server's extension
155
- // host and every other program in the tab along with the one that threw.
156
- // A callback with no owning program (the engine imported as a library) is
157
- // rethrown, so the host reports it as it always did.
158
- const inProcess = (fn: (...a: unknown[]) => void) => (...args: unknown[]): void => {
159
- try { fn(...args); }
160
- catch (error) { if (!__reportUncaughtException(process, error)) throw error; }
161
- };
162
- const track = (id: unknown): unknown => {
163
- held.add(id);
164
- if (id && typeof id === "object" && typeof (id as { unref?: unknown }).unref === "function") {
165
- const handle = id as { unref: () => unknown; ref: () => unknown };
166
- const unref = handle.unref.bind(handle);
167
- const ref = handle.ref.bind(handle);
168
- handle.unref = () => { held.delete(id); return unref(); };
169
- handle.ref = () => { held.add(id); return ref(); };
170
- }
171
- return id;
172
- };
173
- return {
174
- setTimeout(fn: (...a: unknown[]) => void, ms?: number, ...rest: unknown[]) {
175
- let id: unknown;
176
- const call = inProcess(fn);
177
- id = nodeTimeout(hostSetTimeout.call(host, (...args: unknown[]) => { held.delete(id); call(...args); }, ms, ...rest));
178
- return track(id);
179
- },
180
- setInterval(fn: (...a: unknown[]) => void, ms?: number, ...rest: unknown[]) {
181
- return track(nodeTimeout(hostSetInterval.call(host, inProcess(fn), ms, ...rest)));
182
- },
183
- clearTimeout(id: unknown) { held.delete(id); return hostClearTimeout.call(host, handleOf(id)); },
184
- clearInterval(id: unknown) { held.delete(id); return hostClearInterval.call(host, handleOf(id)); },
185
- };
186
- }
187
106
  const __substrateAsyncFunction = (async function() {}).constructor;
188
107
  const __substrateFunctionScope = Function("__substrateFunctionGlobals", "__substrateFunctionSource", "with (__substrateFunctionGlobals) { return eval('(' + __substrateFunctionSource + ')'); }");
189
108
  function __substrateGuestConstructor(Constructor: unknown, process: Process): unknown {
109
+ if (Constructor === intrinsicPromise) return guestPromise(process);
190
110
  if (Constructor !== Function && Constructor !== __substrateAsyncFunction) return Constructor;
191
111
  return new Proxy(Constructor as object, { construct(target, args) {
192
112
  const compiled = Reflect.construct(target as new (...args: unknown[]) => unknown, args);
@@ -214,17 +134,21 @@ function __substrateSourceURL(resolvedPath: string): string {
214
134
  }
215
135
  return /[\n\r]/u.test(name) ? '' : `\n//# sourceURL=${name}`;
216
136
  }
217
- function __substrateScopeConstructors(code: string): string {
218
- if (!/\bnew\s/u.test(code)) return code;
137
+ function __substrateScopeGlobalCalls(code: string): string {
138
+ if (!/\b(?:new|fetch|Promise)\b/u.test(code)) return code;
219
139
  let ast;
220
140
  try { ast = acorn.parse(code, { ecmaVersion: "latest", sourceType: "module", allowReturnOutsideFunction: true }); }
221
141
  catch { return code; }
222
- const positions: Array<[number, number]> = [];
142
+ const positions: Array<[number, number, string]> = [];
223
143
  walkAst(ast, node => {
224
- if (node.type === "NewExpression" && node.callee.type === "Identifier") positions.push([node.callee.start, node.callee.end]);
144
+ if (node.type === "NewExpression" && node.callee.type === "Identifier") positions.push([node.callee.start, node.callee.end, "(__substrateGuestConstructor(" + code.slice(node.callee.start, node.callee.end) + ",$process))"]);
145
+ // The narrow with-scope below keeps global replacements dynamic.
146
+ // Remove its object receiver for ordinary calls (including local
147
+ // bindings, whose bare-call receiver was already undefined).
148
+ const called = node.type === "CallExpression" ? node.callee : node.type === "TaggedTemplateExpression" ? node.tag : undefined;
149
+ if (called?.type === "Identifier" && (called.name === "fetch" || called.name === "Promise")) positions.push([called.start, called.end, "(0," + code.slice(called.start, called.end) + ")"]);
225
150
  });
226
- for (const [start, end] of positions.sort((a,b) => b[0] - a[0])) code = code.slice(0,start) + "(__substrateGuestConstructor(" + code.slice(start,end) + ",$process))" + code.slice(end);
227
- return code;
151
+ return applySourceEdits(code, positions.sort((a,b) => b[0] - a[0]));
228
152
  }
229
153
  /**
230
154
  * Work the host is doing for a guest, counted while it is outstanding.
@@ -262,7 +186,7 @@ function __substrateGuestGlobal(process: Process): Record<string, unknown> {
262
186
  let guest = __substrateGuestGlobals.get(process);
263
187
  if (guest) return guest;
264
188
  const host = globalThis as unknown as Record<string, unknown>;
265
- let fetch = host.fetch;
189
+ let fetch = typeof host.fetch === 'function' ? guestFetch(process, host.fetch as typeof globalThis.fetch) : host.fetch;
266
190
  // The guest's `Buffer` is the one `require('buffer')` answers with, read
267
191
  // when the guest asks rather than when this closure is made: the name in
268
192
  // this file stands for the class until the loader has built it, and a guest
@@ -273,20 +197,34 @@ function __substrateGuestGlobal(process: Process): Record<string, unknown> {
273
197
  // holds non-configurable, `navigator` under a worker's authority) lives on
274
198
  // the proxy's own target, and is this guest's from then on.
275
199
  const shadowed = (target: object, key: string | symbol): boolean => Reflect.getOwnPropertyDescriptor(target, key) !== undefined;
276
- guest = new Proxy(Object.create(null), {
200
+ const localGlobals = Object.create(null);
201
+ Object.defineProperty(localGlobals, "Promise", { value: intrinsicPromise, writable: true, configurable: true, enumerable: false });
202
+ // Node's own navigator, scoped to this process; never expose WorkerNavigator.
203
+ Object.defineProperties(localGlobals, {
204
+ navigator: { configurable: true, enumerable: true,
205
+ get: () => loadNodeLibFor(process, 'internal/navigator').navigator },
206
+ Navigator: { configurable: true, enumerable: false,
207
+ get: () => loadNodeLibFor(process, 'internal/navigator').Navigator,
208
+ set: value => Object.defineProperty(localGlobals, 'Navigator', {
209
+ value, writable: true, configurable: true, enumerable: false,
210
+ }) },
211
+ });
212
+ const isLocalGlobal = (key: string | symbol) => key === 'Promise' || key === 'navigator' || key === 'Navigator';
213
+ guest = new Proxy(localGlobals, {
277
214
  get(target, key) {
278
215
  if (["document", "window", "location", "self"].includes(key as string)) return undefined;
279
216
  if (key === "fetch") return fetch;
280
- if (key === "Buffer") return buffer ?? bufferShim.Buffer;
217
+ if (key === "Buffer") return buffer ?? loadNodeLibFor(process, 'buffer').Buffer;
281
218
  if (key === "process") return process;
219
+ if (isLocalGlobal(key)) return Reflect.get(target, key, guest);
282
220
  if (key === "globalThis" || key === "global") return guest;
283
221
  if (shadowed(target, key)) return Reflect.get(target, key, guest);
284
222
  const value = Reflect.get(host, key, host);
285
223
  if (["setTimeout", "clearTimeout", "setInterval", "clearInterval"].includes(key as string) && typeof value === "function") {
286
224
  // The guest's timers, counted for it; rebuilt if the host's own change.
287
225
  if (boundGlobals.get(key)?.original !== value) {
288
- const timers = __substrateTimerFunctions(process, host);
289
- for (const name of ["setTimeout", "clearTimeout", "setInterval", "clearInterval"]) boundGlobals.set(name, { original: Reflect.get(host, name, host), bound: timers[name] });
226
+ const timers = guestTimerFunctions(process, host);
227
+ for (const name of ["setTimeout", "clearTimeout", "setInterval", "clearInterval"] as const) boundGlobals.set(name, { original: Reflect.get(host, name, host), bound: timers[name] });
290
228
  }
291
229
  return boundGlobals.get(key)!.bound;
292
230
  }
@@ -314,20 +252,22 @@ function __substrateGuestGlobal(process: Process): Record<string, unknown> {
314
252
  return value;
315
253
  },
316
254
  set(target, key, value) {
255
+ if (isLocalGlobal(key)) return Reflect.set(target, key, value, target);
317
256
  if (key === "fetch") { fetch = value; return true; }
318
257
  if (key === "Buffer") { buffer = value; return true; }
319
258
  if (shadowed(target, key)) return Reflect.set(target, key, value, target);
320
259
  return Reflect.set(host, key, value, host);
321
260
  },
322
- has(target, key) { return key === "global" || shadowed(target, key) || key in host; },
261
+ has(target, key) { return isLocalGlobal(key) ? Reflect.has(target, key) : key === "global" || shadowed(target, key) || key in host; },
323
262
  ownKeys(target) {
324
263
  const keys = Reflect.ownKeys(target);
325
- for (const key of Reflect.ownKeys(host)) if (!keys.includes(key)) keys.push(key);
264
+ for (const key of Reflect.ownKeys(host)) if (!isLocalGlobal(key) && !keys.includes(key)) keys.push(key);
326
265
  return keys;
327
266
  },
328
267
  getOwnPropertyDescriptor(target, key) {
268
+ if (isLocalGlobal(key)) return Reflect.getOwnPropertyDescriptor(target, key);
329
269
  if (key === "fetch") return { value: fetch, writable: true, configurable: true, enumerable: true };
330
- if (key === "Buffer") return { value: buffer ?? bufferShim.Buffer, writable: true, configurable: true, enumerable: true };
270
+ if (key === "Buffer") return { value: buffer ?? loadNodeLibFor(process, 'buffer').Buffer, writable: true, configurable: true, enumerable: true };
331
271
  // A key the guest defined non-configurable lives on the proxy's own
332
272
  // target as well, and is reported from there, as the proxy's
333
273
  // invariants require.
@@ -337,6 +277,7 @@ function __substrateGuestGlobal(process: Process): Record<string, unknown> {
337
277
  return descriptor ? { ...descriptor, configurable: true } : undefined;
338
278
  },
339
279
  defineProperty(target, key, descriptor) {
280
+ if (isLocalGlobal(key)) return Reflect.defineProperty(target, key, descriptor);
340
281
  if (key === "fetch") { if (!("value" in descriptor)) return false; fetch = descriptor.value; return true; }
341
282
  if (key === "Buffer") { if (!("value" in descriptor)) return false; buffer = descriptor.value; return true; }
342
283
  // A non-configurable define, undici's of its global dispatcher symbol,
@@ -662,7 +603,7 @@ async function __substrateImportChain(
662
603
  return doors.__loadFromURL(resolved.url, loaded.format ?? resolved.format, loaded.source ?? void 0);
663
604
  }
664
605
 
665
- function createDynamicImport(moduleRequire: RequireFunction, parentURL?: string): (specifier: unknown) => Promise<unknown> {
606
+ function createDynamicImport(moduleRequire: RequireFunction, process: Process, parentURL?: string): (specifier: unknown) => Promise<unknown> {
666
607
  return async (specifier: unknown): Promise<unknown> => {
667
608
  try {
668
609
  // The specifier of `import()` undergoes ToString, as Node's does. ESLint's
@@ -693,7 +634,7 @@ function createDynamicImport(moduleRequire: RequireFunction, parentURL?: string)
693
634
  if (mod && typeof mod === 'object' && '__esModule' in (mod as object)) {
694
635
  return mod;
695
636
  }
696
- return esmNamespaceOf(mod);
637
+ return esmNamespaceOf(mod, process);
697
638
  } catch (error) {
698
639
  // Re-throw as a rejected promise (which is what dynamic import does)
699
640
  throw error;
@@ -735,43 +676,6 @@ export interface RequireFunction {
735
676
  cache: Record<string, Module>;
736
677
  }
737
678
 
738
- /**
739
- * Create a basic timers module
740
- */
741
- function createTimersModule() {
742
- // Node's legacy timer list API, deprecated (DEP0095) and still exported:
743
- // an object with `_onTimeout` is enrolled for a duration, made active to
744
- // start or restart its countdown, and unenrolled to stop it.
745
- type Enrolled = { _onTimeout?: () => void; _idleTimeout?: number; _idleTimeoutId?: ReturnType<typeof setTimeout> | null };
746
- const unenroll = (item: Enrolled): void => {
747
- if (item._idleTimeoutId) globalThis.clearTimeout(item._idleTimeoutId);
748
- item._idleTimeoutId = null;
749
- item._idleTimeout = -1;
750
- };
751
- const enroll = (item: Enrolled, msecs: number): void => {
752
- if (item._idleTimeoutId) globalThis.clearTimeout(item._idleTimeoutId);
753
- item._idleTimeoutId = null;
754
- item._idleTimeout = msecs;
755
- };
756
- const active = (item: Enrolled): void => {
757
- const msecs = item._idleTimeout;
758
- if (typeof msecs !== 'number' || msecs < 0) return;
759
- if (item._idleTimeoutId) globalThis.clearTimeout(item._idleTimeoutId);
760
- item._idleTimeoutId = globalThis.setTimeout(() => { item._idleTimeoutId = null; if (typeof item._onTimeout === 'function') item._onTimeout(); }, msecs);
761
- };
762
- return {
763
- setTimeout: globalThis.setTimeout,
764
- setInterval: globalThis.setInterval,
765
- setImmediate: (fn: () => void) => setTimeout(fn, 0),
766
- clearTimeout: globalThis.clearTimeout,
767
- clearInterval: globalThis.clearInterval,
768
- clearImmediate: globalThis.clearTimeout,
769
- active,
770
- enroll,
771
- unenroll,
772
- };
773
- }
774
-
775
679
  /**
776
680
  * Minimal prettier shim - just returns input unchanged
777
681
  * This is needed because prettier uses createRequire which conflicts with our runtime
@@ -890,7 +794,7 @@ const builtinModules: Record<string, unknown> = {
890
794
  os: osModule,
891
795
  crypto: cryptoShim,
892
796
  zlib: zlibModule,
893
- dns: dnsShim,
797
+ dns: createDnsModule(),
894
798
  child_process: childProcessShim,
895
799
  assert: assertModule,
896
800
  string_decoder: stringDecoderShim,
@@ -981,13 +885,7 @@ const builtinModules: Record<string, unknown> = {
981
885
  // path.win32 name (Node's test-path-posix-exists.js asserts that identity).
982
886
  'path/posix': pathShim.posix,
983
887
  'path/win32': pathShim.win32,
984
- // timers subpaths
985
- 'timers/promises': {
986
- setTimeout: (ms: number) => new Promise(resolve => setTimeout(resolve, ms)),
987
- setInterval: globalThis.setInterval,
988
- setImmediate: (value?: unknown) => new Promise(resolve => setTimeout(() => resolve(value), 0)),
989
- scheduler: { wait: (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) },
990
- },
888
+
991
889
  };
992
890
  // Node's `assert/strict` is the module's own `strict` property, read when
993
891
  // a guest asks rather than when this table is built -- `assert` is a lazy
@@ -1088,37 +986,7 @@ function __browserRuntimeFillModules(table: Record<string, any>) {
1088
986
  // is Node's own code; `errorNames` above stays, because the engine's own
1089
987
  // parts still name an errno.
1090
988
 
1091
- // timers/promises.setInterval was the global setInterval, which answers a
1092
- // handle rather than the async generator Node does, so "for await" over it
1093
- // never yielded; setTimeout dropped the value it was given, and neither took
1094
- // a signal.
1095
- const timersPromises = {
1096
- setTimeout: (delay: any, value: any, options: any) => new Promise((resolve, reject) => {
1097
- const signal = options && options.signal;
1098
- if (signal && signal.aborted) { reject(abortError()); return; }
1099
- const onAbort = () => { clearTimeout(handle); reject(abortError()); };
1100
- const handle = setTimeout(() => {
1101
- if (signal) signal.removeEventListener("abort", onAbort);
1102
- resolve(value);
1103
- }, delay);
1104
- if (signal) signal.addEventListener("abort", onAbort, { once: true });
1105
- }),
1106
- setImmediate: (value: any, options: any) => timersPromises.setTimeout(0, value, options),
1107
- setInterval: async function* setInterval(delay: any, value: any, options: any) {
1108
- const signal = options && options.signal;
1109
- for (;;) {
1110
- await timersPromises.setTimeout(delay, void 0, options);
1111
- if (signal && signal.aborted) return;
1112
- yield value;
1113
- }
1114
- },
1115
- scheduler: {
1116
- wait: (delay: any, options: any) => timersPromises.setTimeout(delay, void 0, options),
1117
- yield: () => timersPromises.setTimeout(0, void 0, void 0)
1118
- }
1119
- };
1120
- table["timers/promises"] = timersPromises;
1121
- table.timers.promises = timersPromises;
989
+ table["timers/promises"] = table.timers.promises;
1122
990
 
1123
991
  // Node's punycode decoder, RFC 3492, so domainToUnicode answers the name a
1124
992
  // person reads rather than the xn-- label: the engine dropped the punycode
@@ -1247,21 +1115,7 @@ function __browserRuntimeFillModules(table: Record<string, any>) {
1247
1115
  availableParallelism: () => (typeof navigator === "object" && navigator && Number(navigator.hardwareConcurrency)) || 1
1248
1116
  });
1249
1117
 
1250
- // dns's error codes are the names a guest compares err.code against; the
1251
- // engine had none of them, and dns/promises was not a module at all.
1252
- const dnsCodes = {
1253
- NODATA: "ENODATA", FORMERR: "EFORMERR", SERVFAIL: "ESERVFAIL", NOTFOUND: "ENOTFOUND",
1254
- NOTIMP: "ENOTIMP", REFUSED: "EREFUSED", BADQUERY: "EBADQUERY", BADNAME: "EBADNAME",
1255
- BADFAMILY: "EBADFAMILY", BADRESP: "EBADRESP", CONNREFUSED: "ECONNREFUSED", TIMEOUT: "ETIMEOUT",
1256
- EOF: "EOF", FILE: "EFILE", NOMEM: "ENOMEM", DESTRUCTION: "EDESTRUCTION", BADSTR: "EBADSTR",
1257
- BADFLAGS: "EBADFLAGS", NONAME: "ENONAME", BADHINTS: "EBADHINTS", NOTINITIALIZED: "ENOTINITIALIZED",
1258
- LOADIPHLPAPI: "ELOADIPHLPAPI", ADDRGETNETWORKPARAMS: "EADDRGETNETWORKPARAMS", CANCELLED: "ECANCELLED"
1259
- };
1260
- const dnsModule = extend("dns", dnsCodes);
1261
- const dnsPromises = Object.assign({}, dnsModule.promises, dnsCodes);
1262
- dnsPromises.default = dnsPromises;
1263
- dnsModule.promises = dnsPromises;
1264
- table["dns/promises"] = dnsPromises;
1118
+ table["dns/promises"] = table.dns.promises;
1265
1119
 
1266
1120
  // readline/promises was not a module, and the engine's readline.promises
1267
1121
  // answered an object with only createInterface on it whose async iterator
@@ -1362,8 +1216,7 @@ function __browserRuntimeFillModules(table: Record<string, any>) {
1362
1216
  * async iterator on a Readable, `duplexPair`, `isDisturbed`, the high-water
1363
1217
  * marks) is Node's own file's now and is gone.
1364
1218
  */
1365
- function __browserRuntimeFillStreams(table: Record<string, any>) {
1366
- const Bytes = BufferPolyfill;
1219
+ function __browserRuntimeFillStreams(table: Record<string, any>, Bytes = BufferPolyfill) {
1367
1220
  const collect = async (source: any) => {
1368
1221
  const chunks: any[] = [];
1369
1222
  if (source && typeof source.getReader === "function") {
@@ -1585,7 +1438,7 @@ function __substrateModuleClassFor(moduleCache: Record<string, Module>, requireF
1585
1438
  Module._pathCache = Object.create(null);
1586
1439
  Module.builtinModules = moduleShim.builtinModules;
1587
1440
  Module.isBuiltin = moduleShim.isBuiltin;
1588
- Module.syncBuiltinESMExports = syncBuiltinESMExports;
1441
+ Module.syncBuiltinESMExports = () => syncBuiltinESMExports(process);
1589
1442
  Module.globalPaths = ["/node_modules"];
1590
1443
  Module._nodeModulePaths = (directory: string) => {
1591
1444
  const result = [];
@@ -1613,7 +1466,7 @@ function __substrateModuleClassFor(moduleCache: Record<string, Module>, requireF
1613
1466
  // the fast path Node keeps too. They hang off the Module class because that
1614
1467
  // class is this run's -- one per module cache -- and Node's are per process.
1615
1468
  Module.__substrateHooks = void 0;
1616
- const __substrateHooksOf = (): RunModuleHooks => (Module.__substrateHooks ??= new RunModuleHooks());
1469
+ const __substrateHooksOf = (): RunModuleHooks => (Module.__substrateHooks ??= new RunModuleHooks(process));
1617
1470
  Module.registerHooks = (hooks: { resolve?: unknown; load?: unknown }) => __substrateHooksOf().sync.registerHooks(hooks);
1618
1471
  Module.register = (specifier: unknown, parentURL?: unknown, options?: { parentURL?: unknown; data?: unknown; transferList?: unknown }) =>
1619
1472
  __substrateHooksOf().register(specifier, parentURL, options, (url: string, from: string) => Module.createRequire(from)(url));
@@ -1971,7 +1824,7 @@ function createRequire(
1971
1824
  try {
1972
1825
  const importMetaUrl = resolvedPath.startsWith('data:') ? resolvedPath : 'file://' + resolvedPath;
1973
1826
  const strictBody = code.startsWith(__substrateModuleMarker);
1974
- code = __substrateScopeConstructors(code);
1827
+ code = __substrateScopeGlobalCalls(code);
1975
1828
  // The wrapper is one line and the body begins on it, as Node's
1976
1829
  // `Module.wrap` is one line, so a module's line N is line N of the
1977
1830
  // script V8 compiles and a stack names the module's own lines. The
@@ -1979,8 +1832,8 @@ function createRequire(
1979
1832
  // `global` among them for code that reads the process off them
1980
1833
  // directly; the inner function is what lets the body's own `let` and
1981
1834
  // `const` shadow that scope. `__substrateSourceURL` names the script.
1982
- const wrappedCode = `(function($exports, $require, $module, $filename, $dirname, $process, $console, $importMeta, $dynamicImport, __substrateGuestGlobal, __substrateGuestConstructor) { var exports = $exports; var require = $require; var module = $module; var __filename = $filename; var __dirname = $dirname; var process = $process; var console = $console; var import_meta = $importMeta; var __dynamicImport = $dynamicImport; var document = void 0, window = void 0, location = void 0, self = void 0; var globalThis = __substrateGuestGlobal($process); var global = globalThis; var Buffer = globalThis.Buffer; var queueMicrotask = globalThis.queueMicrotask, atob = globalThis.atob, btoa = globalThis.btoa, structuredClone = globalThis.structuredClone, setTimeout = globalThis.setTimeout, clearTimeout = globalThis.clearTimeout, setInterval = globalThis.setInterval, clearInterval = globalThis.clearInterval; globalThis.process = $process; global.process = $process; return (function() {${code}
1983
- }).call(${strictBody ? 'void 0' : '$module.exports'});
1835
+ const wrappedCode = `(function($exports, $require, $module, $filename, $dirname, $process, $console, $importMeta, $dynamicImport, __substrateGuestGlobal, __substrateGuestConstructor) { var exports = $exports; var require = $require; var module = $module; var __filename = $filename; var __dirname = $dirname; var process = $process; var console = $console; var import_meta = $importMeta; var __dynamicImport = $dynamicImport; var document = void 0, window = void 0, location = void 0, self = void 0; var globalThis = __substrateGuestGlobal($process); var global = globalThis; var Buffer = globalThis.Buffer; var queueMicrotask = globalThis.queueMicrotask, atob = globalThis.atob, btoa = globalThis.btoa, structuredClone = globalThis.structuredClone, setTimeout = globalThis.setTimeout, clearTimeout = globalThis.clearTimeout, setInterval = globalThis.setInterval, clearInterval = globalThis.clearInterval; globalThis.process = $process; global.process = $process; with ({ __proto__: null, get navigator() { return globalThis.navigator; }, set navigator(value) { globalThis.navigator = value; }, get Navigator() { return globalThis.Navigator; }, set Navigator(value) { globalThis.Navigator = value; }, get Promise() { return globalThis.Promise; }, set Promise(value) { globalThis.Promise = value; }, get fetch() { return globalThis.fetch; }, set fetch(value) { globalThis.fetch = value; } }) { return (function() {${code}
1836
+ }).call(${strictBody ? 'void 0' : '$module.exports'}); }
1984
1837
  })${__substrateSourceURL(resolvedPath)}`;
1985
1838
 
1986
1839
  // A lowered ES module body is a generator that yields at each import
@@ -2004,7 +1857,7 @@ function createRequire(
2004
1857
  catch { throw new SyntaxError(`${msg} (in ${resolvedPath})`); }
2005
1858
  }
2006
1859
  // Create dynamic import function for this module context
2007
- const dynamicImport = createDynamicImport(moduleRequire, importMetaUrl);
1860
+ const dynamicImport = createDynamicImport(moduleRequire, process, importMetaUrl);
2008
1861
 
2009
1862
  const body = fn(
2010
1863
  module.exports,
@@ -2185,8 +2038,14 @@ function createRequire(
2185
2038
  if (id === 'wasi') {
2186
2039
  return __substrateGuestWasi(fsShim, process);
2187
2040
  }
2041
+ if (id === 'stream/consumers') return nativeModuleFor(process, id, () => {
2042
+ const table: Record<string, any> = {};
2043
+ __browserRuntimeFillStreams(table, loadNodeLibFor(process, 'buffer').Buffer);
2044
+ return table[id];
2045
+ });
2046
+ if (hasNodeLibModule(id)) return loadNodeLibFor(process, id);
2188
2047
  if (builtinModules[id] && !__substrateInstalledWins(id) && !(id === 'fsevents' || id === 'chokidar' || id === 'readdirp')) {
2189
- return id === 'esbuild' ? __substrateGuestEsbuild(process) : id === 'rollup' ? __substrateGuestRollup(process) : builtinModules[id];
2048
+ return id === 'esbuild' ? __substrateGuestEsbuild(process) : id === 'rollup' ? __substrateGuestRollup(process) : nativeModuleFor(process, id, () => builtinModules[id]);
2190
2049
  }
2191
2050
 
2192
2051
  if (!__substrateInstalledWins(id)) {
@@ -2209,7 +2068,7 @@ function createRequire(
2209
2068
 
2210
2069
  // If resolved to a built-in name (shouldn't happen but safety check)
2211
2070
  if (builtinModules[resolved] && !(resolved === 'fsevents' || resolved === 'chokidar' || resolved === 'readdirp')) {
2212
- return resolved === 'esbuild' ? __substrateGuestEsbuild(process) : resolved === 'rollup' ? __substrateGuestRollup(process) : builtinModules[resolved];
2071
+ return requirePlain(resolved);
2213
2072
  }
2214
2073
 
2215
2074
  // Also check if resolved path is to rollup, esbuild, or prettier in node_modules
@@ -2417,8 +2276,6 @@ export class Runtime {
2417
2276
  code: string,
2418
2277
  filename: string = '/index.js'
2419
2278
  ): { exports: unknown; module: Module } {
2420
- const dirname = pathShim.dirname(filename);
2421
-
2422
2279
  // The tree holds the file the run names; it is written only when the
2423
2280
  // text differs. Every run wrote it, and a file run as it stands in the
2424
2281
  // tree was rewritten with itself, which fired its watcher (a dev server
@@ -2427,6 +2284,19 @@ export class Runtime {
2427
2284
  let held: string | undefined;
2428
2285
  try { held = this.vfs.readFileSync(filename, 'utf8') as string; } catch { held = undefined; }
2429
2286
  if (held !== code) this.vfs.writeFileSync(filename, code);
2287
+ return this.evaluate(code, filename);
2288
+ }
2289
+
2290
+ /**
2291
+ * Runs source that is not a file of the tree -- `node -e`'s, named
2292
+ * `[eval]` in the directory it runs in, as Node names it -- the way
2293
+ * `execute` runs a file's, without writing it anywhere.
2294
+ */
2295
+ evaluate(
2296
+ code: string,
2297
+ filename: string
2298
+ ): { exports: unknown; module: Module } {
2299
+ const dirname = pathShim.dirname(filename);
2430
2300
 
2431
2301
  // Create require function
2432
2302
  const require = createRequire(
@@ -2486,7 +2356,7 @@ export class Runtime {
2486
2356
  try {
2487
2357
  const importMetaUrl = 'file://' + filename;
2488
2358
  const strictBody = code.startsWith(__substrateModuleMarker);
2489
- code = __substrateScopeConstructors(code);
2359
+ code = __substrateScopeGlobalCalls(code);
2490
2360
  // The wrapper is one line and the body begins on it, as Node's
2491
2361
  // `Module.wrap` is one line, so a module's line N is line N of the
2492
2362
  // script V8 compiles and a stack names the module's own lines. The
@@ -2494,12 +2364,12 @@ export class Runtime {
2494
2364
  // `global` among them for code that reads the process off them
2495
2365
  // directly; the inner function is what lets the body's own `let` and
2496
2366
  // `const` shadow that scope. `__substrateSourceURL` names the script.
2497
- const wrappedCode = `(function($exports, $require, $module, $filename, $dirname, $process, $console, $importMeta, $dynamicImport, __substrateGuestGlobal, __substrateGuestConstructor) { var exports = $exports; var require = $require; var module = $module; var __filename = $filename; var __dirname = $dirname; var process = $process; var console = $console; var import_meta = $importMeta; var __dynamicImport = $dynamicImport; var document = void 0, window = void 0, location = void 0, self = void 0; var globalThis = __substrateGuestGlobal($process); var global = globalThis; var Buffer = globalThis.Buffer; var queueMicrotask = globalThis.queueMicrotask, atob = globalThis.atob, btoa = globalThis.btoa, structuredClone = globalThis.structuredClone, setTimeout = globalThis.setTimeout, clearTimeout = globalThis.clearTimeout, setInterval = globalThis.setInterval, clearInterval = globalThis.clearInterval; globalThis.process = $process; global.process = $process; return (function() {${code}
2498
- }).call(${strictBody ? 'void 0' : '$module.exports'});
2367
+ const wrappedCode = `(function($exports, $require, $module, $filename, $dirname, $process, $console, $importMeta, $dynamicImport, __substrateGuestGlobal, __substrateGuestConstructor) { var exports = $exports; var require = $require; var module = $module; var __filename = $filename; var __dirname = $dirname; var process = $process; var console = $console; var import_meta = $importMeta; var __dynamicImport = $dynamicImport; var document = void 0, window = void 0, location = void 0, self = void 0; var globalThis = __substrateGuestGlobal($process); var global = globalThis; var Buffer = globalThis.Buffer; var queueMicrotask = globalThis.queueMicrotask, atob = globalThis.atob, btoa = globalThis.btoa, structuredClone = globalThis.structuredClone, setTimeout = globalThis.setTimeout, clearTimeout = globalThis.clearTimeout, setInterval = globalThis.setInterval, clearInterval = globalThis.clearInterval; globalThis.process = $process; global.process = $process; with ({ __proto__: null, get navigator() { return globalThis.navigator; }, set navigator(value) { globalThis.navigator = value; }, get Navigator() { return globalThis.Navigator; }, set Navigator(value) { globalThis.Navigator = value; }, get Promise() { return globalThis.Promise; }, set Promise(value) { globalThis.Promise = value; }, get fetch() { return globalThis.fetch; }, set fetch(value) { globalThis.fetch = value; } }) { return (function() {${code}
2368
+ }).call(${strictBody ? 'void 0' : '$module.exports'}); }
2499
2369
  })${__substrateSourceURL(filename)}`;
2500
2370
 
2501
2371
  // Create dynamic import function for this module context
2502
- const dynamicImport = createDynamicImport(require, filename.startsWith('data:') ? filename : `file://${filename}`);
2372
+ const dynamicImport = createDynamicImport(require, this.process, filename.startsWith('data:') ? filename : `file://${filename}`);
2503
2373
 
2504
2374
  // A module with top-level await runs. Node runs a `.js` file of a package
2505
2375
  // with `"type": "module"` as a module, where `await` is valid at the top;
@@ -2736,7 +2606,7 @@ forGuestRealm(() => {
2736
2606
  // That correction used to be made on the realm, which replaced the
2737
2607
  // `setTimeout` of any Node process that imported the engine. It is the
2738
2608
  // guest's, and it is made on the guest's own timers, in
2739
- // `__substrateTimerFunctions`.
2609
+ // `guestTimerFunctions`.
2740
2610
 
2741
2611
  forGuestRealm(() => {
2742
2612
  // Node's `fetch` does not apply the fetch specification's
@@ -2759,6 +2629,7 @@ forGuestRealm(() => {
2759
2629
  class NodeRequest extends Native {
2760
2630
  constructor(input: RequestInfo | URL, init?: RequestInit) {
2761
2631
  super(input as RequestInfo, init);
2632
+ rememberRequestBodySource(this, input, init);
2762
2633
  const asked = new Headers(init?.headers ?? (input instanceof Native ? (input as Request).headers : undefined));
2763
2634
  const headers = new Headers(super.headers);
2764
2635
  asked.forEach((value, name) => { if (!headers.has(name)) headers.set(name, value); });
@@ -2767,6 +2638,11 @@ forGuestRealm(() => {
2767
2638
  get headers(): Headers {
2768
2639
  return kept.get(this) ?? super.headers;
2769
2640
  }
2641
+ clone(): Request {
2642
+ const copy = super.clone();
2643
+ rememberRequestBodySource(copy, this);
2644
+ return new NodeRequest(copy, { headers: this.headers });
2645
+ }
2770
2646
  }
2771
2647
  Object.defineProperty(NodeRequest, '__substrateHeaderGuard', { value: true });
2772
2648
  Object.defineProperty(NodeRequest, 'name', { value: 'Request', configurable: true });