@ai-ecoverse/slicc-jsh 0.3.4 → 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.4",
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() {
@@ -16513,8 +16550,12 @@ var Process = class extends EventEmitter {
16513
16550
  tls: false,
16514
16551
  cached_builtins: true
16515
16552
  };
16516
- const writeStdout = (value) => ctx.sync.write(1, toBytes2(value));
16517
- 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
+ };
16518
16559
  this._writeStdout = writeStdout;
16519
16560
  this._writeStderr = writeStderr;
16520
16561
  this.stdout = writableStream(1, writeStdout, false);
@@ -16640,24 +16681,29 @@ var Process = class extends EventEmitter {
16640
16681
  }
16641
16682
  this._cwd = this._ctx.resolve(path);
16642
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
+ */
16643
16691
  exit(...args) {
16644
- if (args.length === 0) {
16645
- const code2 = numericExitCode(this._assignedExitCode);
16646
- this._recordExit(code2);
16647
- try {
16648
- this.emit("exit", code2);
16649
- } catch {
16650
- }
16651
- throw new NodeExitError(code2);
16652
- }
16653
- this._assignedExitCode = assignProcessExitCode(args[0]);
16692
+ if (this._exitError) throw this._exitError;
16693
+ if (args.length > 0) this._assignedExitCode = assignProcessExitCode(args[0]);
16654
16694
  const code = numericExitCode(this._assignedExitCode);
16655
16695
  this._recordExit(code);
16656
16696
  try {
16657
16697
  this.emit("exit", code);
16658
16698
  } catch {
16659
16699
  }
16660
- 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;
16661
16707
  }
16662
16708
  _recordExit(code) {
16663
16709
  this._didExit = true;
@@ -16666,8 +16712,9 @@ var Process = class extends EventEmitter {
16666
16712
  this._onExit?.(code);
16667
16713
  }
16668
16714
  };
16669
- function createProcess({ ctx, argv, nextTick, onExit, handles, Buffer: Buffer2 }) {
16715
+ function createProcess({ ctx, argv, nextTick, onExit, onHardExit, handles, Buffer: Buffer2 }) {
16670
16716
  const process2 = new Process({ ctx, argv, nextTick, onExit, handles, Buffer: Buffer2 });
16717
+ process2._onHardExit = onHardExit;
16671
16718
  return {
16672
16719
  process: process2,
16673
16720
  writeStdout: process2._writeStdout,
@@ -16690,11 +16737,12 @@ function Timeout() {
16690
16737
  function Immediate() {
16691
16738
  }
16692
16739
  function createTimers(handles, { onCallbackError } = {}) {
16693
- const nativeSetTimeout = globalThis.setTimeout.bind(globalThis);
16740
+ const nativeSetTimeout2 = globalThis.setTimeout.bind(globalThis);
16694
16741
  const nativeClearTimeout = globalThis.clearTimeout.bind(globalThis);
16695
16742
  const nativeSetInterval = globalThis.setInterval.bind(globalThis);
16696
16743
  const nativeClearInterval = globalThis.clearInterval.bind(globalThis);
16697
16744
  const byId = /* @__PURE__ */ new Map();
16745
+ let stopped = false;
16698
16746
  const runMethod = (handle, method, args) => {
16699
16747
  try {
16700
16748
  handle[method](...args);
@@ -16728,6 +16776,9 @@ function createTimers(handles, { onCallbackError } = {}) {
16728
16776
  };
16729
16777
  };
16730
16778
  const makeTimeout = (fn, delay, args, repeating) => {
16779
+ if (stopped) {
16780
+ return repeating ? nativeSetInterval(fn, delay, ...args) : nativeSetTimeout2(fn, delay, ...args);
16781
+ }
16731
16782
  const state = {
16732
16783
  refed: true,
16733
16784
  id: null,
@@ -16737,18 +16788,20 @@ function createTimers(handles, { onCallbackError } = {}) {
16737
16788
  handle._onTimeout = fn;
16738
16789
  attachRefApi(handle, state);
16739
16790
  const fire = () => {
16791
+ if (stopped) return;
16740
16792
  if (!state.repeating) {
16741
16793
  byId.delete(state.id);
16742
16794
  handles.delete(state);
16743
16795
  }
16744
16796
  runMethod(handle, "_onTimeout", args);
16745
16797
  };
16746
- state.id = repeating ? nativeSetInterval(fire, delay ?? 0) : nativeSetTimeout(fire, delay ?? 0);
16798
+ state.id = repeating ? nativeSetInterval(fire, delay ?? 0) : nativeSetTimeout2(fire, delay ?? 0);
16747
16799
  byId.set(state.id, state);
16748
16800
  handles.add(state);
16749
16801
  return handle;
16750
16802
  };
16751
16803
  const makeImmediate = (fn, args) => {
16804
+ if (stopped) return nativeSetTimeout2(fn, 0, ...args);
16752
16805
  const state = {
16753
16806
  refed: true,
16754
16807
  id: null,
@@ -16758,11 +16811,12 @@ function createTimers(handles, { onCallbackError } = {}) {
16758
16811
  handle._onImmediate = fn;
16759
16812
  attachRefApi(handle, state);
16760
16813
  const fire = () => {
16814
+ if (stopped) return;
16761
16815
  byId.delete(state.id);
16762
16816
  handles.delete(state);
16763
16817
  runMethod(handle, "_onImmediate", args);
16764
16818
  };
16765
- state.id = nativeSetTimeout(fire, 0);
16819
+ state.id = nativeSetTimeout2(fire, 0);
16766
16820
  byId.set(state.id, state);
16767
16821
  handles.add(state);
16768
16822
  return handle;
@@ -16778,7 +16832,7 @@ function createTimers(handles, { onCallbackError } = {}) {
16778
16832
  };
16779
16833
  return {
16780
16834
  setTimeout: (fn, delay, ...args) => {
16781
- if (typeof fn !== "function") return nativeSetTimeout(fn, delay, ...args);
16835
+ if (typeof fn !== "function") return nativeSetTimeout2(fn, delay, ...args);
16782
16836
  return makeTimeout(fn, delay, args, false);
16783
16837
  },
16784
16838
  clearTimeout: (handle) => clear(handle, nativeClearTimeout),
@@ -16788,7 +16842,7 @@ function createTimers(handles, { onCallbackError } = {}) {
16788
16842
  },
16789
16843
  clearInterval: (handle) => clear(handle, nativeClearInterval),
16790
16844
  setImmediate: (fn, ...args) => {
16791
- if (typeof fn !== "function") return nativeSetTimeout(fn, 0, ...args);
16845
+ if (typeof fn !== "function") return nativeSetTimeout2(fn, 0, ...args);
16792
16846
  return makeImmediate(fn, args);
16793
16847
  },
16794
16848
  clearImmediate: (handle) => clear(handle, nativeClearTimeout),
@@ -16800,12 +16854,60 @@ function createTimers(handles, { onCallbackError } = {}) {
16800
16854
  }
16801
16855
  byId.clear();
16802
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();
16803
16862
  }
16804
16863
  };
16805
16864
  }
16806
16865
 
16807
16866
  // src/runtime/web/fetch.mjs
16808
- 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;
16809
16911
  async function fetch(input, init) {
16810
16912
  if (typeof ctx.fetch !== "function") {
16811
16913
  const err = new TypeError("fetch failed");
@@ -16814,7 +16916,13 @@ function createFetch(ctx) {
16814
16916
  });
16815
16917
  throw err;
16816
16918
  }
16817
- 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
+ }
16818
16926
  }
16819
16927
  return fetch;
16820
16928
  }
@@ -17129,6 +17237,43 @@ function installJshGlobals(bindings) {
17129
17237
  }
17130
17238
  };
17131
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
+ }
17132
17277
  async function runNode(ctx, options = {}) {
17133
17278
  installStackPrepare();
17134
17279
  const handles = createHandleTable();
@@ -17188,6 +17333,12 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17188
17333
  Buffer: Buffer2,
17189
17334
  onExit: (code) => {
17190
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();
17191
17342
  }
17192
17343
  });
17193
17344
  process2.execArgv = parsed.execArgv ? [...parsed.execArgv] : [];
@@ -17196,12 +17347,13 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17196
17347
  lastEvalCode = parsed.code;
17197
17348
  }
17198
17349
  const console2 = createConsole(writeStdout, writeStderr, util2);
17199
- const fetch = createFetch(ctx);
17350
+ const fetch = createFetch(ctx, { handles });
17351
+ const restorePlatform = trackPlatformAsync(handles);
17200
17352
  const WebSocket = createWebSocket(ctx, { handles, trackPromise });
17201
17353
  const timers = createTimers(handles, {
17202
17354
  onCallbackError: (err) => {
17203
- if (err instanceof NodeExitError) {
17204
- exitStatus = err.code;
17355
+ if (isExitError2(err) || getDidExit()) {
17356
+ exitStatus = getDidExit() ? getExitCode() : err.code;
17205
17357
  timers.clearPending();
17206
17358
  try {
17207
17359
  handles.notify();
@@ -17249,16 +17401,16 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17249
17401
  } catch {
17250
17402
  }
17251
17403
  exitStatus = 1;
17252
- timers.clearPending();
17404
+ timers.stop();
17253
17405
  try {
17254
17406
  ctx.exit?.(1);
17255
17407
  } catch {
17256
17408
  }
17257
17409
  };
17258
- const isExit = (err) => err instanceof NodeExitError || err?.name === "NodeExitError" || getDidExit();
17410
+ const isExit = (err) => isExitError2(err) || getDidExit();
17259
17411
  const rejectionHandler = (reason, promise) => {
17260
17412
  if (isExit(reason)) {
17261
- exitStatus = reason instanceof NodeExitError || reason?.name === "NodeExitError" ? Number(reason.code) & 255 : getExitCode();
17413
+ exitStatus = getDidExit() ? getExitCode() : Number(reason.code) & 255;
17262
17414
  timers.clearPending();
17263
17415
  try {
17264
17416
  handles.notify();
@@ -17277,16 +17429,16 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17277
17429
  evalCode: lastEvalCode
17278
17430
  });
17279
17431
  writeStderr(body);
17432
+ exitStatus = 1;
17433
+ timers.stop();
17280
17434
  try {
17281
17435
  ctx.exit?.(1);
17282
17436
  } catch {
17283
17437
  }
17284
- exitStatus = 1;
17285
- timers.clearPending();
17286
17438
  };
17287
17439
  const exceptionHandler = (err) => {
17288
17440
  if (isExit(err)) {
17289
- exitStatus = err instanceof NodeExitError || err?.name === "NodeExitError" ? Number(err.code) & 255 : getExitCode();
17441
+ exitStatus = getDidExit() ? getExitCode() : Number(err.code) & 255;
17290
17442
  timers.clearPending();
17291
17443
  try {
17292
17444
  handles.notify();
@@ -17357,8 +17509,27 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17357
17509
  });
17358
17510
  cjs.setRequireEsmHook((filename) => esm.requireEsm(filename));
17359
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
+ };
17360
17529
  try {
17361
17530
  const rt = {
17531
+ setEntry,
17532
+ track: (promise) => trackPromise(handles, promise),
17362
17533
  process: process2,
17363
17534
  console: console2,
17364
17535
  Buffer: Buffer2,
@@ -17378,7 +17549,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17378
17549
  }
17379
17550
  nextTick.flushSync();
17380
17551
  } catch (err) {
17381
- if (err instanceof NodeExitError) throw err;
17552
+ if (isExitError2(err)) throw err;
17382
17553
  if (process2.listenerCount("uncaughtException") > 0) {
17383
17554
  process2.emit(
17384
17555
  "uncaughtException",
@@ -17426,7 +17597,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17426
17597
  cjs.runMain("[stdin]", source, { setMain: false });
17427
17598
  nextTick.flushSync();
17428
17599
  } catch (err) {
17429
- if (err instanceof NodeExitError) throw err;
17600
+ if (isExitError2(err)) throw err;
17430
17601
  if (process2.listenerCount("uncaughtException") > 0) {
17431
17602
  process2.emit(
17432
17603
  "uncaughtException",
@@ -17448,10 +17619,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17448
17619
  )` : parsed.code,
17449
17620
  "[eval]"
17450
17621
  );
17451
- if (result != null && typeof result.then === "function") {
17452
- trackPromise(handles, result);
17453
- await result;
17454
- }
17622
+ if (result != null && typeof result.then === "function") setEntry(result, "esm");
17455
17623
  nextTick.flushSync();
17456
17624
  } else {
17457
17625
  const evalParent = `${process2.cwd()}/[eval]`;
@@ -17485,7 +17653,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17485
17653
  }
17486
17654
  }
17487
17655
  } catch (err) {
17488
- if (err instanceof NodeExitError) throw err;
17656
+ if (isExitError2(err)) throw err;
17489
17657
  if (process2.listenerCount("uncaughtException") > 0) {
17490
17658
  process2.emit(
17491
17659
  "uncaughtException",
@@ -17513,16 +17681,13 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17513
17681
  const useEsm = esm.isEsmFilename(filePath, source);
17514
17682
  if (useEsm) {
17515
17683
  const result = esm.runMain(filePath, source);
17516
- if (result != null && typeof result.then === "function") {
17517
- trackPromise(handles, result);
17518
- await result;
17519
- }
17684
+ if (result != null && typeof result.then === "function") setEntry(result, "esm");
17520
17685
  } else {
17521
17686
  cjs.runMain(filePath, source);
17522
17687
  }
17523
17688
  nextTick.flushSync();
17524
17689
  } catch (err) {
17525
- if (err instanceof NodeExitError) throw err;
17690
+ if (isExitError2(err)) throw err;
17526
17691
  if (process2.listenerCount("uncaughtException") > 0) {
17527
17692
  process2.emit(
17528
17693
  "uncaughtException",
@@ -17543,8 +17708,17 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17543
17708
  onBeforeExit: () => {
17544
17709
  emitBeforeExit();
17545
17710
  },
17546
- shouldStop: () => getDidExit() || exitStatus !== void 0
17711
+ shouldStop: () => getDidExit() || exitStatus !== void 0,
17712
+ weakPending: () => entry?.pending === true
17547
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
+ }
17548
17722
  for (let i2 = 0; i2 < 3; i2++) {
17549
17723
  if (exitStatus !== void 0 || getDidExit()) break;
17550
17724
  await new Promise((resolve2) => {
@@ -17569,9 +17743,9 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17569
17743
  }
17570
17744
  return code;
17571
17745
  } catch (err) {
17572
- if (err instanceof NodeExitError) {
17746
+ if (isExitError2(err)) {
17573
17747
  timers.clearPending();
17574
- return err.code;
17748
+ return getDidExit() ? getExitCode() : err.code;
17575
17749
  }
17576
17750
  try {
17577
17751
  printUncaught(err);
@@ -17582,7 +17756,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17582
17756
  return 1;
17583
17757
  } finally {
17584
17758
  timers.clearPending();
17585
- for (const remove of removeCtxHooks) {
17759
+ for (const remove of getDidExit() ? [] : removeCtxHooks) {
17586
17760
  try {
17587
17761
  remove?.();
17588
17762
  } catch {
@@ -17590,6 +17764,7 @@ slicc-jsh ${NODE_SHIM_VERSION} (Node-compatible, abi: js)
17590
17764
  }
17591
17765
  try {
17592
17766
  restoreGlobals();
17767
+ restorePlatform();
17593
17768
  removeJshHandoff();
17594
17769
  } catch {
17595
17770
  }