@ai-ecoverse/slicc-jsh 0.3.3 → 0.3.5

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/dist/node.mjs CHANGED
@@ -1536,56 +1536,10 @@ ${e3}`;
1536
1536
  }
1537
1537
  });
1538
1538
 
1539
- // src/runtime/exit.mjs
1540
- var NodeExitError = class extends Error {
1541
- constructor(code) {
1542
- super(`Process exited with code ${code}`);
1543
- this.name = "NodeExitError";
1544
- this.code = code;
1545
- }
1546
- };
1547
- function numericExitCode(value) {
1548
- const n = Number(value);
1549
- return Number.isFinite(n) ? n & 255 : 0;
1550
- }
1551
- function describeReceived(value) {
1552
- if (typeof value === "string") return `type string ('${value}')`;
1553
- if (typeof value === "boolean") return `type boolean (${value})`;
1554
- if (typeof value === "bigint") return `type bigint (${value}n)`;
1555
- if (Array.isArray(value)) return "an instance of Array";
1556
- if (typeof value === "object" && value !== null) return "an instance of Object";
1557
- return `type ${typeof value}`;
1558
- }
1559
- function assignProcessExitCode(value) {
1560
- if (value === null || value === void 0) return void 0;
1561
- if (typeof value === "string") {
1562
- const n = Number(value);
1563
- if (value !== "" && Number.isInteger(n)) return n === 0 ? 0 : n;
1564
- const err2 = new TypeError(
1565
- `The "code" argument must be of type number. Received ${describeReceived(value)}`
1566
- );
1567
- err2.code = "ERR_INVALID_ARG_TYPE";
1568
- throw err2;
1569
- }
1570
- if (typeof value === "number") {
1571
- if (Number.isInteger(value)) return value === 0 ? 0 : value;
1572
- const err2 = new RangeError(
1573
- `The value of "code" is out of range. It must be an integer. Received ${String(value)}`
1574
- );
1575
- err2.code = "ERR_OUT_OF_RANGE";
1576
- throw err2;
1577
- }
1578
- const err = new TypeError(
1579
- `The "code" argument must be of type number. Received ${describeReceived(value)}`
1580
- );
1581
- err.code = "ERR_INVALID_ARG_TYPE";
1582
- throw err;
1583
- }
1584
-
1585
1539
  // package.json
1586
1540
  var package_default = {
1587
1541
  name: "@ai-ecoverse/slicc-jsh",
1588
- version: "0.3.3",
1542
+ version: "0.3.5",
1589
1543
  description: "Node.js-compatible runtime for slicc-kernel: the node and jsh commands (abi: js)",
1590
1544
  type: "module",
1591
1545
  license: "Apache-2.0",
@@ -1655,7 +1609,7 @@ var package_default = {
1655
1609
  "trust:dry": "npx fledgling sync --dry-run -y --skip-publish"
1656
1610
  },
1657
1611
  devDependencies: {
1658
- "@ai-ecoverse/slicc-kernel": "1.61.0",
1612
+ "@ai-ecoverse/slicc-kernel": "1.63.0",
1659
1613
  "@ai-ecoverse/wasi-pnpm": "12.9.1-8",
1660
1614
  "abort-controller": "3.0.0",
1661
1615
  acorn: "8.19.0",
@@ -2318,16 +2272,12 @@ async function runJsh({ filename, engine, process: process2, console: console2 }
2318
2272
  const baseRequire = engine.createRequire(filename);
2319
2273
  const requireSliccy = createSliccyResolver({ engine, process: process2, require: baseRequire });
2320
2274
  const require2 = wrapRequire(baseRequire, requireSliccy, module);
2321
- try {
2275
+ const body = (async () => {
2322
2276
  const fn = engine.compile(prepareSource(source), filename);
2323
2277
  await fn(process2, console2, require2, module, module.exports, engine.fetch, dirname2, filename);
2324
2278
  module.loaded = true;
2325
- } catch (err) {
2326
- if (engine.isExit(err)) return engine.exit(err.code);
2327
- engine.writeStderr(`${err?.stack ?? err}
2328
- `);
2329
- return engine.exit(1);
2330
- }
2279
+ })();
2280
+ engine.started?.(body);
2331
2281
  return void 0;
2332
2282
  }
2333
2283
 
@@ -2365,7 +2315,7 @@ async function writeAll(stream, data2) {
2365
2315
  } catch {
2366
2316
  }
2367
2317
  }
2368
- function kernelSpawn(ctx, process2) {
2318
+ function kernelSpawn(ctx, process2, track) {
2369
2319
  return (argv, { stdin } = {}) => {
2370
2320
  let child = null;
2371
2321
  const done = (async () => {
@@ -2396,7 +2346,7 @@ function kernelSpawn(ctx, process2) {
2396
2346
  })();
2397
2347
  return {
2398
2348
  kill: async (sig = "SIGTERM") => child ? child.kill(sig) : false,
2399
- done
2349
+ done: track(done)
2400
2350
  };
2401
2351
  };
2402
2352
  }
@@ -2420,7 +2370,7 @@ async function runKernelJsh(ctx, rt, filename) {
2420
2370
  const { process: process2, console: console2 } = rt;
2421
2371
  let stdoutIsTTY = false;
2422
2372
  try {
2423
- stdoutIsTTY = !!await ctx.isatty?.(1);
2373
+ stdoutIsTTY = !!await rt.track(Promise.resolve(ctx.isatty?.(1)));
2424
2374
  } catch {
2425
2375
  stdoutIsTTY = false;
2426
2376
  }
@@ -2432,11 +2382,11 @@ async function runKernelJsh(ctx, rt, filename) {
2432
2382
  writeStdout: (s) => process2.stdout.write(String(s)),
2433
2383
  writeStderr: (s) => process2.stderr.write(String(s)),
2434
2384
  stdoutIsTTY,
2435
- spawn: kernelSpawn(ctx, process2),
2385
+ spawn: kernelSpawn(ctx, process2, rt.track),
2436
2386
  shell: ["sh", "-c"],
2437
2387
  fetch: rt.fetch,
2438
- isExit: (err) => err instanceof NodeExitError,
2439
- exit: (code) => process2.exit(code)
2388
+ exit: (code) => process2.exit(code),
2389
+ started: (body) => rt.setEntry(body, "jsh")
2440
2390
  };
2441
2391
  await runJsh({ filename, engine, process: process2, console: console2 });
2442
2392
  }
@@ -2517,7 +2467,14 @@ async function checkpoint(nextTick) {
2517
2467
  if (idle >= 6) break;
2518
2468
  }
2519
2469
  }
2520
- async function drainLoop(handles, nextTick, { onBeforeExit, shouldStop } = {}) {
2470
+ var nativeSetTimeout = globalThis.setTimeout.bind(globalThis);
2471
+ var ENTRY_GRACE_TURNS = 8;
2472
+ function macrotask() {
2473
+ return new Promise((resolve2) => {
2474
+ nativeSetTimeout(resolve2, 0);
2475
+ });
2476
+ }
2477
+ async function drainLoop(handles, nextTick, { onBeforeExit, shouldStop, weakPending } = {}) {
2521
2478
  for (; ; ) {
2522
2479
  await checkpoint(nextTick);
2523
2480
  if (shouldStop?.()) return;
@@ -2527,6 +2484,15 @@ async function drainLoop(handles, nextTick, { onBeforeExit, shouldStop } = {}) {
2527
2484
  await checkpoint(nextTick);
2528
2485
  continue;
2529
2486
  }
2487
+ if (weakPending?.()) {
2488
+ for (let i2 = 0; i2 < ENTRY_GRACE_TURNS; i2++) {
2489
+ await macrotask();
2490
+ await checkpoint(nextTick);
2491
+ if (shouldStop?.() || handles.refCount > 0 || !weakPending()) break;
2492
+ }
2493
+ if (shouldStop?.()) return;
2494
+ if (handles.refCount > 0 || !weakPending()) continue;
2495
+ }
2530
2496
  if (onBeforeExit) {
2531
2497
  onBeforeExit();
2532
2498
  await checkpoint(nextTick);
@@ -15618,20 +15584,12 @@ ${parts.join("\n")}`
15618
15584
  return cjs.runMain(filename, src);
15619
15585
  }
15620
15586
  const { hasTopLevelAwait } = transformEsm(src, filename);
15621
- if (hasTopLevelAwait) {
15622
- const p = evaluateEsmAsync(filename, src);
15623
- if (trackPromise2 && handles) trackPromise2(handles, p);
15624
- return p;
15625
- }
15587
+ if (hasTopLevelAwait) return evaluateEsmAsync(filename, src);
15626
15588
  return evaluateEsm(filename, src);
15627
15589
  }
15628
15590
  function runEsmEval(code, filename = "[eval]") {
15629
15591
  const { hasTopLevelAwait } = transformEsm(code, filename);
15630
- if (hasTopLevelAwait) {
15631
- const p = evaluateEsmAsync(filename, code);
15632
- if (trackPromise2 && handles) trackPromise2(handles, p);
15633
- return p;
15634
- }
15592
+ if (hasTopLevelAwait) return evaluateEsmAsync(filename, code);
15635
15593
  return evaluateEsm(filename, code);
15636
15594
  }
15637
15595
  function requireEsm(filename) {
@@ -15848,7 +15806,7 @@ function frameLocation(stack) {
15848
15806
  const file = m[1] === void 0 || m[0].includes("[eval]") ? "[eval]" : m[1];
15849
15807
  return { file, line: Number(m[2]), column: Number(m[3]) };
15850
15808
  }
15851
- function snippetFor(ctx, loc, evalCode) {
15809
+ function snippetFor(ctx, loc, evalCode, fromPromise = false) {
15852
15810
  if (!loc) return null;
15853
15811
  let source;
15854
15812
  if (loc.file === "[eval]") source = evalCode;
@@ -15868,7 +15826,9 @@ function snippetFor(ctx, loc, evalCode) {
15868
15826
  let col2 = loc.column;
15869
15827
  const throwAt = text.search(/\bthrow\b/);
15870
15828
  const isAsyncLine = /\basync\b/.test(text);
15871
- if (loc.file === "[eval]" && throwAt === 0) {
15829
+ if (fromPromise && loc.column >= 1) {
15830
+ col2 = loc.column;
15831
+ } else if (loc.file === "[eval]" && throwAt === 0) {
15872
15832
  col2 = 1;
15873
15833
  } else if (throwAt >= 0 && isAsyncLine && /\bthrow\s+new\b/.test(text)) {
15874
15834
  col2 = text.indexOf("new", throwAt) + 1;
@@ -15931,7 +15891,7 @@ function glueStackAndProps(stack, props) {
15931
15891
  if (!props) return frames;
15932
15892
  return `${frames} ${finalizeProps(props)}`;
15933
15893
  }
15934
- function formatUncaughtError(err, { ctx, util: util2, version: version2, evalCode } = {}) {
15894
+ function formatUncaughtError(err, { ctx, util: util2, version: version2, evalCode, fromPromise } = {}) {
15935
15895
  const trailer = `
15936
15896
  Node.js v${version2}
15937
15897
  `;
@@ -16005,7 +15965,7 @@ ${trailer}` };
16005
15965
  }
16006
15966
  }
16007
15967
  const loc = frameLocation(rawStack);
16008
- const snip = snippetFor(ctx, loc, evalCode);
15968
+ const snip = snippetFor(ctx, loc, evalCode, fromPromise);
16009
15969
  if (snip) head = `${snip.file}:${snip.lineNo}
16010
15970
  ${snip.text}
16011
15971
  ${snip.caret}
@@ -16102,7 +16062,7 @@ function collapseMatchingCauseFrames(body, err) {
16102
16062
  }
16103
16063
  function formatUnhandledRejection(reason, { ctx, util: util2, version: version2, evalCode } = {}) {
16104
16064
  if (reason instanceof Error) {
16105
- return formatUncaughtError(reason, { ctx, util: util2, version: version2, evalCode });
16065
+ return formatUncaughtError(reason, { ctx, util: util2, version: version2, evalCode, fromPromise: true });
16106
16066
  }
16107
16067
  const trailer = `
16108
16068
  Node.js v${version2}
@@ -16114,13 +16074,84 @@ Node.js v${version2}
16114
16074
  new UnhandledPromiseRejection(reason);
16115
16075
  ^
16116
16076
 
16117
- UnhandledPromiseRejection: ${msg} {
16077
+ UnhandledPromiseRejection: ${msg}
16078
+ at throwUnhandledRejectionsMode (node:internal/process/promises:392:7)
16079
+ at processPromiseRejections (node:internal/process/promises:475:17)
16080
+ at process.processTicksAndRejections (node:internal/process/task_queues:106:32) {
16118
16081
  code: 'ERR_UNHANDLED_REJECTION'
16119
16082
  }
16120
16083
  `;
16121
16084
  return { body: body + trailer };
16122
16085
  }
16123
16086
 
16087
+ // src/runtime/exit.mjs
16088
+ var NodeExitError = class extends Error {
16089
+ constructor(code) {
16090
+ super(`Process exited with code ${code}`);
16091
+ this.name = "NodeExitError";
16092
+ this.code = code;
16093
+ this.status = code;
16094
+ }
16095
+ };
16096
+ function isExitError2(err) {
16097
+ return err instanceof NodeExitError || err?.name === "NodeExitError" || err?.name === "JsExit";
16098
+ }
16099
+ function hardExitError(ctx, code) {
16100
+ if (typeof ctx?.exit === "function") {
16101
+ try {
16102
+ ctx.exit(code);
16103
+ } catch (err) {
16104
+ if (err && typeof err === "object" && err.name === "JsExit") {
16105
+ try {
16106
+ Object.defineProperty(err, "name", { value: "NodeExitError", configurable: true, writable: true });
16107
+ err.message = `Process exited with code ${code}`;
16108
+ err.code = code;
16109
+ } catch {
16110
+ }
16111
+ return err;
16112
+ }
16113
+ }
16114
+ }
16115
+ return new NodeExitError(code);
16116
+ }
16117
+ function numericExitCode(value) {
16118
+ const n = Number(value);
16119
+ return Number.isFinite(n) ? n & 255 : 0;
16120
+ }
16121
+ function describeReceived(value) {
16122
+ if (typeof value === "string") return `type string ('${value}')`;
16123
+ if (typeof value === "boolean") return `type boolean (${value})`;
16124
+ if (typeof value === "bigint") return `type bigint (${value}n)`;
16125
+ if (Array.isArray(value)) return "an instance of Array";
16126
+ if (typeof value === "object" && value !== null) return "an instance of Object";
16127
+ return `type ${typeof value}`;
16128
+ }
16129
+ function assignProcessExitCode(value) {
16130
+ if (value === null || value === void 0) return void 0;
16131
+ if (typeof value === "string") {
16132
+ const n = Number(value);
16133
+ if (value !== "" && Number.isInteger(n)) return n === 0 ? 0 : n;
16134
+ const err2 = new TypeError(
16135
+ `The "code" argument must be of type number. Received ${describeReceived(value)}`
16136
+ );
16137
+ err2.code = "ERR_INVALID_ARG_TYPE";
16138
+ throw err2;
16139
+ }
16140
+ if (typeof value === "number") {
16141
+ if (Number.isInteger(value)) return value === 0 ? 0 : value;
16142
+ const err2 = new RangeError(
16143
+ `The value of "code" is out of range. It must be an integer. Received ${String(value)}`
16144
+ );
16145
+ err2.code = "ERR_OUT_OF_RANGE";
16146
+ throw err2;
16147
+ }
16148
+ const err = new TypeError(
16149
+ `The "code" argument must be of type number. Received ${describeReceived(value)}`
16150
+ );
16151
+ err.code = "ERR_INVALID_ARG_TYPE";
16152
+ throw err;
16153
+ }
16154
+
16124
16155
  // src/runtime/handles.mjs
16125
16156
  function createHandleTable() {
16126
16157
  const refed = /* @__PURE__ */ new Set();
@@ -16156,6 +16187,7 @@ function createHandleTable() {
16156
16187
  // src/runtime/next-tick.mjs
16157
16188
  function createNextTick() {
16158
16189
  const queue = [];
16190
+ let stopped = false;
16159
16191
  return {
16160
16192
  nextTick(fn, ...args) {
16161
16193
  if (typeof fn !== "function") {
@@ -16171,7 +16203,12 @@ function createNextTick() {
16171
16203
  err.code = "ERR_INVALID_ARG_TYPE";
16172
16204
  throw err;
16173
16205
  }
16174
- queue.push(() => fn(...args));
16206
+ if (!stopped) queue.push(() => fn(...args));
16207
+ },
16208
+ /** process.exit(): drop what is queued and ignore new ticks. */
16209
+ stop() {
16210
+ stopped = true;
16211
+ queue.length = 0;
16175
16212
  },
16176
16213
  /** Run queued ticks synchronously. */
16177
16214
  flushSync() {
@@ -16444,6 +16481,25 @@ function readProcessCreds(ctx) {
16444
16481
  }
16445
16482
  return { uid: 0, euid: 0, gid: 0, egid: 0, groups: [0] };
16446
16483
  }
16484
+ function resolveNodeExecPath(ctx) {
16485
+ const fs = ctx?.sync?.fs;
16486
+ const pathEnv = ctx?.env?.PATH ?? "/usr/local/bin:/usr/bin:/bin";
16487
+ for (const dir of String(pathEnv).split(":")) {
16488
+ if (!dir) continue;
16489
+ const candidate = dir.endsWith("/") ? `${dir}node` : `${dir}/node`;
16490
+ try {
16491
+ if (fs?.exists?.(candidate)) {
16492
+ try {
16493
+ return typeof fs.realpath === "function" ? fs.realpath(candidate) : candidate;
16494
+ } catch {
16495
+ return candidate;
16496
+ }
16497
+ }
16498
+ } catch {
16499
+ }
16500
+ }
16501
+ return "/usr/bin/node";
16502
+ }
16447
16503
  var Process = class extends EventEmitter {
16448
16504
  constructor({ ctx, argv, nextTick, onExit, handles, Buffer: Buffer2 }) {
16449
16505
  super();
@@ -16464,7 +16520,7 @@ var Process = class extends EventEmitter {
16464
16520
  this.arch = "x64";
16465
16521
  this.pid = ctx.pid;
16466
16522
  this.ppid = void 0;
16467
- this.execPath = "/node_modules/@ai-ecoverse/slicc-jsh/dist/node.mjs";
16523
+ this.execPath = resolveNodeExecPath(ctx);
16468
16524
  this.execArgv = [];
16469
16525
  this.nextTick = nextTick.nextTick.bind(nextTick);
16470
16526
  this._umask = 18;
@@ -16494,8 +16550,12 @@ var Process = class extends EventEmitter {
16494
16550
  tls: false,
16495
16551
  cached_builtins: true
16496
16552
  };
16497
- const writeStdout = (value) => ctx.sync.write(1, toBytes2(value));
16498
- const writeStderr = (value) => ctx.sync.write(2, toBytes2(value));
16553
+ const writeStdout = (value) => {
16554
+ if (!this._silenced) ctx.sync.write(1, toBytes2(value));
16555
+ };
16556
+ const writeStderr = (value) => {
16557
+ if (!this._silenced) ctx.sync.write(2, toBytes2(value));
16558
+ };
16499
16559
  this._writeStdout = writeStdout;
16500
16560
  this._writeStderr = writeStderr;
16501
16561
  this.stdout = writableStream(1, writeStdout, false);
@@ -16621,24 +16681,29 @@ var Process = class extends EventEmitter {
16621
16681
  }
16622
16682
  this._cwd = this._ctx.resolve(path);
16623
16683
  }
16684
+ /**
16685
+ * Node's process.exit: 'exit' listeners run, then the program ends. The
16686
+ * kernel is told the status at once (see hardExitError); what still runs
16687
+ * while the throw unwinds — a user `catch` or `finally` — is silenced:
16688
+ * its output is dropped, a second exit() keeps the first status, and
16689
+ * timers and ticks are stopped.
16690
+ */
16624
16691
  exit(...args) {
16625
- if (args.length === 0) {
16626
- const code2 = numericExitCode(this._assignedExitCode);
16627
- this._recordExit(code2);
16628
- try {
16629
- this.emit("exit", code2);
16630
- } catch {
16631
- }
16632
- throw new NodeExitError(code2);
16633
- }
16634
- this._assignedExitCode = assignProcessExitCode(args[0]);
16692
+ if (this._exitError) throw this._exitError;
16693
+ if (args.length > 0) this._assignedExitCode = assignProcessExitCode(args[0]);
16635
16694
  const code = numericExitCode(this._assignedExitCode);
16636
16695
  this._recordExit(code);
16637
16696
  try {
16638
16697
  this.emit("exit", code);
16639
16698
  } catch {
16640
16699
  }
16641
- throw new NodeExitError(code);
16700
+ this._silenced = true;
16701
+ try {
16702
+ this._onHardExit?.(code);
16703
+ } catch {
16704
+ }
16705
+ this._exitError = hardExitError(this._ctx, code);
16706
+ throw this._exitError;
16642
16707
  }
16643
16708
  _recordExit(code) {
16644
16709
  this._didExit = true;
@@ -16647,8 +16712,9 @@ var Process = class extends EventEmitter {
16647
16712
  this._onExit?.(code);
16648
16713
  }
16649
16714
  };
16650
- function createProcess({ ctx, argv, nextTick, onExit, handles, Buffer: Buffer2 }) {
16715
+ function createProcess({ ctx, argv, nextTick, onExit, onHardExit, handles, Buffer: Buffer2 }) {
16651
16716
  const process2 = new Process({ ctx, argv, nextTick, onExit, handles, Buffer: Buffer2 });
16717
+ process2._onHardExit = onHardExit;
16652
16718
  return {
16653
16719
  process: process2,
16654
16720
  writeStdout: process2._writeStdout,
@@ -16671,11 +16737,12 @@ function Timeout() {
16671
16737
  function Immediate() {
16672
16738
  }
16673
16739
  function createTimers(handles, { onCallbackError } = {}) {
16674
- const nativeSetTimeout = globalThis.setTimeout.bind(globalThis);
16740
+ const nativeSetTimeout2 = globalThis.setTimeout.bind(globalThis);
16675
16741
  const nativeClearTimeout = globalThis.clearTimeout.bind(globalThis);
16676
16742
  const nativeSetInterval = globalThis.setInterval.bind(globalThis);
16677
16743
  const nativeClearInterval = globalThis.clearInterval.bind(globalThis);
16678
16744
  const byId = /* @__PURE__ */ new Map();
16745
+ let stopped = false;
16679
16746
  const runMethod = (handle, method, args) => {
16680
16747
  try {
16681
16748
  handle[method](...args);
@@ -16709,6 +16776,9 @@ function createTimers(handles, { onCallbackError } = {}) {
16709
16776
  };
16710
16777
  };
16711
16778
  const makeTimeout = (fn, delay, args, repeating) => {
16779
+ if (stopped) {
16780
+ return repeating ? nativeSetInterval(fn, delay, ...args) : nativeSetTimeout2(fn, delay, ...args);
16781
+ }
16712
16782
  const state = {
16713
16783
  refed: true,
16714
16784
  id: null,
@@ -16718,18 +16788,20 @@ function createTimers(handles, { onCallbackError } = {}) {
16718
16788
  handle._onTimeout = fn;
16719
16789
  attachRefApi(handle, state);
16720
16790
  const fire = () => {
16791
+ if (stopped) return;
16721
16792
  if (!state.repeating) {
16722
16793
  byId.delete(state.id);
16723
16794
  handles.delete(state);
16724
16795
  }
16725
16796
  runMethod(handle, "_onTimeout", args);
16726
16797
  };
16727
- state.id = repeating ? nativeSetInterval(fire, delay ?? 0) : nativeSetTimeout(fire, delay ?? 0);
16798
+ state.id = repeating ? nativeSetInterval(fire, delay ?? 0) : nativeSetTimeout2(fire, delay ?? 0);
16728
16799
  byId.set(state.id, state);
16729
16800
  handles.add(state);
16730
16801
  return handle;
16731
16802
  };
16732
16803
  const makeImmediate = (fn, args) => {
16804
+ if (stopped) return nativeSetTimeout2(fn, 0, ...args);
16733
16805
  const state = {
16734
16806
  refed: true,
16735
16807
  id: null,
@@ -16739,11 +16811,12 @@ function createTimers(handles, { onCallbackError } = {}) {
16739
16811
  handle._onImmediate = fn;
16740
16812
  attachRefApi(handle, state);
16741
16813
  const fire = () => {
16814
+ if (stopped) return;
16742
16815
  byId.delete(state.id);
16743
16816
  handles.delete(state);
16744
16817
  runMethod(handle, "_onImmediate", args);
16745
16818
  };
16746
- state.id = nativeSetTimeout(fire, 0);
16819
+ state.id = nativeSetTimeout2(fire, 0);
16747
16820
  byId.set(state.id, state);
16748
16821
  handles.add(state);
16749
16822
  return handle;
@@ -16759,7 +16832,7 @@ function createTimers(handles, { onCallbackError } = {}) {
16759
16832
  };
16760
16833
  return {
16761
16834
  setTimeout: (fn, delay, ...args) => {
16762
- if (typeof fn !== "function") return nativeSetTimeout(fn, delay, ...args);
16835
+ if (typeof fn !== "function") return nativeSetTimeout2(fn, delay, ...args);
16763
16836
  return makeTimeout(fn, delay, args, false);
16764
16837
  },
16765
16838
  clearTimeout: (handle) => clear(handle, nativeClearTimeout),
@@ -16769,7 +16842,7 @@ function createTimers(handles, { onCallbackError } = {}) {
16769
16842
  },
16770
16843
  clearInterval: (handle) => clear(handle, nativeClearInterval),
16771
16844
  setImmediate: (fn, ...args) => {
16772
- if (typeof fn !== "function") return nativeSetTimeout(fn, 0, ...args);
16845
+ if (typeof fn !== "function") return nativeSetTimeout2(fn, 0, ...args);
16773
16846
  return makeImmediate(fn, args);
16774
16847
  },
16775
16848
  clearImmediate: (handle) => clear(handle, nativeClearTimeout),
@@ -16781,12 +16854,60 @@ function createTimers(handles, { onCallbackError } = {}) {
16781
16854
  }
16782
16855
  byId.clear();
16783
16856
  handles.notify();
16857
+ },
16858
+ /** The program is ending: clear its timers; later ones bypass the table. */
16859
+ stop() {
16860
+ stopped = true;
16861
+ this.clearPending();
16784
16862
  }
16785
16863
  };
16786
16864
  }
16787
16865
 
16788
16866
  // src/runtime/web/fetch.mjs
16789
- function createFetch(ctx) {
16867
+ var BODY_METHODS = ["arrayBuffer", "blob", "bytes", "formData", "json", "text"];
16868
+ function trackBody(response, track) {
16869
+ for (const name of BODY_METHODS) {
16870
+ const method = response[name];
16871
+ if (typeof method !== "function") continue;
16872
+ Object.defineProperty(response, name, {
16873
+ value: function tracked(...args) {
16874
+ return track(method.apply(response, args));
16875
+ },
16876
+ configurable: true,
16877
+ writable: true
16878
+ });
16879
+ }
16880
+ const bodyDesc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(response), "body");
16881
+ if (!bodyDesc?.get) return response;
16882
+ let wrapped;
16883
+ Object.defineProperty(response, "body", {
16884
+ configurable: true,
16885
+ get() {
16886
+ if (wrapped !== void 0) return wrapped;
16887
+ const original = bodyDesc.get.call(response);
16888
+ if (original == null || typeof ReadableStream !== "function") {
16889
+ wrapped = original;
16890
+ return wrapped;
16891
+ }
16892
+ let reader;
16893
+ wrapped = new ReadableStream({
16894
+ async pull(controller) {
16895
+ reader ??= original.getReader();
16896
+ const { value, done } = await track(reader.read());
16897
+ if (done) controller.close();
16898
+ else controller.enqueue(value);
16899
+ },
16900
+ cancel(reason) {
16901
+ return (reader ?? original).cancel(reason);
16902
+ }
16903
+ });
16904
+ return wrapped;
16905
+ }
16906
+ });
16907
+ return response;
16908
+ }
16909
+ function createFetch(ctx, { handles } = {}) {
16910
+ const track = (p) => handles ? trackPromise(handles, p) : p;
16790
16911
  async function fetch(input, init) {
16791
16912
  if (typeof ctx.fetch !== "function") {
16792
16913
  const err = new TypeError("fetch failed");
@@ -16795,7 +16916,13 @@ function createFetch(ctx) {
16795
16916
  });
16796
16917
  throw err;
16797
16918
  }
16798
- return ctx.fetch(input, init);
16919
+ const response = await track(ctx.fetch(input, init));
16920
+ if (!handles || response == null || typeof response !== "object") return response;
16921
+ try {
16922
+ return trackBody(response, track);
16923
+ } catch {
16924
+ return response;
16925
+ }
16799
16926
  }
16800
16927
  return fetch;
16801
16928
  }
@@ -17110,6 +17237,43 @@ function installJshGlobals(bindings) {
17110
17237
  }
17111
17238
  };
17112
17239
  }
17240
+ function trackPlatformAsync(handles) {
17241
+ const undo = [];
17242
+ const wrap = (target, names) => {
17243
+ if (!target) return;
17244
+ for (const name of names) {
17245
+ const original = target[name];
17246
+ if (typeof original !== "function") continue;
17247
+ try {
17248
+ target[name] = function tracked(...args) {
17249
+ return trackPromise(handles, original.apply(this, args));
17250
+ };
17251
+ undo.push(() => {
17252
+ target[name] = original;
17253
+ });
17254
+ } catch {
17255
+ }
17256
+ }
17257
+ };
17258
+ wrap(globalThis.SubtleCrypto?.prototype, [
17259
+ "decrypt",
17260
+ "deriveBits",
17261
+ "deriveKey",
17262
+ "digest",
17263
+ "encrypt",
17264
+ "exportKey",
17265
+ "generateKey",
17266
+ "importKey",
17267
+ "sign",
17268
+ "unwrapKey",
17269
+ "verify",
17270
+ "wrapKey"
17271
+ ]);
17272
+ wrap(globalThis.WebAssembly, ["compile", "compileStreaming", "instantiate", "instantiateStreaming"]);
17273
+ return () => {
17274
+ for (const fn of undo.reverse()) fn();
17275
+ };
17276
+ }
17113
17277
  async function runNode(ctx, options = {}) {
17114
17278
  installStackPrepare();
17115
17279
  const handles = createHandleTable();
@@ -17169,6 +17333,12 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17169
17333
  Buffer: Buffer2,
17170
17334
  onExit: (code) => {
17171
17335
  exitStatus = code;
17336
+ },
17337
+ // process.exit(): nothing the unwinding code schedules may run.
17338
+ onHardExit: () => {
17339
+ timers.stop();
17340
+ nextTick.stop();
17341
+ handles.notify();
17172
17342
  }
17173
17343
  });
17174
17344
  process2.execArgv = parsed.execArgv ? [...parsed.execArgv] : [];
@@ -17177,12 +17347,13 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17177
17347
  lastEvalCode = parsed.code;
17178
17348
  }
17179
17349
  const console2 = createConsole(writeStdout, writeStderr, util2);
17180
- const fetch = createFetch(ctx);
17350
+ const fetch = createFetch(ctx, { handles });
17351
+ const restorePlatform = trackPlatformAsync(handles);
17181
17352
  const WebSocket = createWebSocket(ctx, { handles, trackPromise });
17182
17353
  const timers = createTimers(handles, {
17183
17354
  onCallbackError: (err) => {
17184
- if (err instanceof NodeExitError) {
17185
- exitStatus = err.code;
17355
+ if (isExitError2(err) || getDidExit()) {
17356
+ exitStatus = getDidExit() ? getExitCode() : err.code;
17186
17357
  timers.clearPending();
17187
17358
  try {
17188
17359
  handles.notify();
@@ -17230,16 +17401,16 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17230
17401
  } catch {
17231
17402
  }
17232
17403
  exitStatus = 1;
17233
- timers.clearPending();
17404
+ timers.stop();
17234
17405
  try {
17235
17406
  ctx.exit?.(1);
17236
17407
  } catch {
17237
17408
  }
17238
17409
  };
17239
- const isExit = (err) => err instanceof NodeExitError || err?.name === "NodeExitError" || getDidExit();
17410
+ const isExit = (err) => isExitError2(err) || getDidExit();
17240
17411
  const rejectionHandler = (reason, promise) => {
17241
17412
  if (isExit(reason)) {
17242
- exitStatus = reason instanceof NodeExitError || reason?.name === "NodeExitError" ? Number(reason.code) & 255 : getExitCode();
17413
+ exitStatus = getDidExit() ? getExitCode() : Number(reason.code) & 255;
17243
17414
  timers.clearPending();
17244
17415
  try {
17245
17416
  handles.notify();
@@ -17258,16 +17429,16 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17258
17429
  evalCode: lastEvalCode
17259
17430
  });
17260
17431
  writeStderr(body);
17432
+ exitStatus = 1;
17433
+ timers.stop();
17261
17434
  try {
17262
17435
  ctx.exit?.(1);
17263
17436
  } catch {
17264
17437
  }
17265
- exitStatus = 1;
17266
- timers.clearPending();
17267
17438
  };
17268
17439
  const exceptionHandler = (err) => {
17269
17440
  if (isExit(err)) {
17270
- exitStatus = err instanceof NodeExitError || err?.name === "NodeExitError" ? Number(err.code) & 255 : getExitCode();
17441
+ exitStatus = getDidExit() ? getExitCode() : Number(err.code) & 255;
17271
17442
  timers.clearPending();
17272
17443
  try {
17273
17444
  handles.notify();
@@ -17338,8 +17509,27 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17338
17509
  });
17339
17510
  cjs.setRequireEsmHook((filename) => esm.requireEsm(filename));
17340
17511
  cjs.setImportModuleHook((specifier, parent) => esm.importModule(specifier, parent));
17512
+ let entry = null;
17513
+ const setEntry = (promise, kind) => {
17514
+ const current2 = { kind, pending: true, promise };
17515
+ entry = current2;
17516
+ Promise.resolve(promise).then(
17517
+ () => {
17518
+ current2.pending = false;
17519
+ handles.notify();
17520
+ },
17521
+ (err) => {
17522
+ current2.pending = false;
17523
+ if (kind === "jsh") rejectionHandler(err, promise);
17524
+ else exceptionHandler(err);
17525
+ handles.notify();
17526
+ }
17527
+ );
17528
+ };
17341
17529
  try {
17342
17530
  const rt = {
17531
+ setEntry,
17532
+ track: (promise) => trackPromise(handles, promise),
17343
17533
  process: process2,
17344
17534
  console: console2,
17345
17535
  Buffer: Buffer2,
@@ -17359,7 +17549,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17359
17549
  }
17360
17550
  nextTick.flushSync();
17361
17551
  } catch (err) {
17362
- if (err instanceof NodeExitError) throw err;
17552
+ if (isExitError2(err)) throw err;
17363
17553
  if (process2.listenerCount("uncaughtException") > 0) {
17364
17554
  process2.emit(
17365
17555
  "uncaughtException",
@@ -17407,7 +17597,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17407
17597
  cjs.runMain("[stdin]", source, { setMain: false });
17408
17598
  nextTick.flushSync();
17409
17599
  } catch (err) {
17410
- if (err instanceof NodeExitError) throw err;
17600
+ if (isExitError2(err)) throw err;
17411
17601
  if (process2.listenerCount("uncaughtException") > 0) {
17412
17602
  process2.emit(
17413
17603
  "uncaughtException",
@@ -17429,10 +17619,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17429
17619
  )` : parsed.code,
17430
17620
  "[eval]"
17431
17621
  );
17432
- if (result != null && typeof result.then === "function") {
17433
- trackPromise(handles, result);
17434
- await result;
17435
- }
17622
+ if (result != null && typeof result.then === "function") setEntry(result, "esm");
17436
17623
  nextTick.flushSync();
17437
17624
  } else {
17438
17625
  const evalParent = `${process2.cwd()}/[eval]`;
@@ -17466,7 +17653,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17466
17653
  }
17467
17654
  }
17468
17655
  } catch (err) {
17469
- if (err instanceof NodeExitError) throw err;
17656
+ if (isExitError2(err)) throw err;
17470
17657
  if (process2.listenerCount("uncaughtException") > 0) {
17471
17658
  process2.emit(
17472
17659
  "uncaughtException",
@@ -17494,16 +17681,13 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17494
17681
  const useEsm = esm.isEsmFilename(filePath, source);
17495
17682
  if (useEsm) {
17496
17683
  const result = esm.runMain(filePath, source);
17497
- if (result != null && typeof result.then === "function") {
17498
- trackPromise(handles, result);
17499
- await result;
17500
- }
17684
+ if (result != null && typeof result.then === "function") setEntry(result, "esm");
17501
17685
  } else {
17502
17686
  cjs.runMain(filePath, source);
17503
17687
  }
17504
17688
  nextTick.flushSync();
17505
17689
  } catch (err) {
17506
- if (err instanceof NodeExitError) throw err;
17690
+ if (isExitError2(err)) throw err;
17507
17691
  if (process2.listenerCount("uncaughtException") > 0) {
17508
17692
  process2.emit(
17509
17693
  "uncaughtException",
@@ -17524,8 +17708,17 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17524
17708
  onBeforeExit: () => {
17525
17709
  emitBeforeExit();
17526
17710
  },
17527
- shouldStop: () => getDidExit() || exitStatus !== void 0
17711
+ shouldStop: () => getDidExit() || exitStatus !== void 0,
17712
+ weakPending: () => entry?.pending === true
17528
17713
  });
17714
+ if (entry?.pending && entry.kind === "esm" && exitStatus === void 0 && !getDidExit()) {
17715
+ const where = parsed.mode === "file" ? `file://${process2.argv[1]}` : "[eval1]";
17716
+ writeStderr(`Warning: Detected unsettled top-level await at ${where}
17717
+
17718
+
17719
+ `);
17720
+ exitStatus = 13;
17721
+ }
17529
17722
  for (let i2 = 0; i2 < 3; i2++) {
17530
17723
  if (exitStatus !== void 0 || getDidExit()) break;
17531
17724
  await new Promise((resolve2) => {
@@ -17550,9 +17743,9 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17550
17743
  }
17551
17744
  return code;
17552
17745
  } catch (err) {
17553
- if (err instanceof NodeExitError) {
17746
+ if (isExitError2(err)) {
17554
17747
  timers.clearPending();
17555
- return err.code;
17748
+ return getDidExit() ? getExitCode() : err.code;
17556
17749
  }
17557
17750
  try {
17558
17751
  printUncaught(err);
@@ -17563,7 +17756,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17563
17756
  return 1;
17564
17757
  } finally {
17565
17758
  timers.clearPending();
17566
- for (const remove of removeCtxHooks) {
17759
+ for (const remove of getDidExit() ? [] : removeCtxHooks) {
17567
17760
  try {
17568
17761
  remove?.();
17569
17762
  } catch {
@@ -17571,6 +17764,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17571
17764
  }
17572
17765
  try {
17573
17766
  restoreGlobals();
17767
+ restorePlatform();
17574
17768
  removeJshHandoff();
17575
17769
  } catch {
17576
17770
  }