@volter/tabnode 0.5.7 → 0.5.9

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.
@@ -6771,6 +6771,11 @@ function __recordRun(token, run) {
6771
6771
  if (runs.get(token) === run) runs.delete(token);
6772
6772
  };
6773
6773
  }
6774
+ const terminations = /* @__PURE__ */ new Map();
6775
+ function __recordTermination(process2, signal) {
6776
+ const token = tokensByProcess.get(process2);
6777
+ if (token !== void 0) terminations.set(token, signal);
6778
+ }
6774
6779
  function __runFor(token) {
6775
6780
  return runs.get(token);
6776
6781
  }
@@ -9324,7 +9329,16 @@ const osBinding = {
9324
9329
  /** Node's `os.type()`, `release()` and `version()`, in that order. */
9325
9330
  getOSInformation: () => [type$1(), release(), version$2()],
9326
9331
  getHostname: () => hostname(),
9327
- getHomeDirectory: () => homedir(),
9332
+ /**
9333
+ * Node's `os.homedir()` is libuv's: `HOME` when the environment sets it,
9334
+ * the account's directory otherwise. `userInfo().homedir` stays the
9335
+ * account's, as it is in Node.
9336
+ */
9337
+ getHomeDirectory: () => {
9338
+ var _a3, _b3;
9339
+ const home = (_b3 = (_a3 = globalThis.process) == null ? void 0 : _a3.env) == null ? void 0 : _b3.HOME;
9340
+ return home && home.length > 0 ? home : homedir();
9341
+ },
9328
9342
  getUptime: () => uptime(),
9329
9343
  getTotalMem: () => totalmem(),
9330
9344
  getFreeMem: () => freemem(),
@@ -26816,6 +26830,7 @@ function createProcess(options) {
26816
26830
  return true;
26817
26831
  }
26818
26832
  if (__substrateIgnoredSignals.has(name)) return true;
26833
+ __recordTermination(proc, name);
26819
26834
  proc.exit(128 + __substrateSignals[name]);
26820
26835
  return true;
26821
26836
  },
@@ -70826,6 +70841,7 @@ function startChildRun(request) {
70826
70841
  let finished = false;
70827
70842
  let started = false;
70828
70843
  let killedBy = null;
70844
+ let hosted = false;
70829
70845
  const initialStdin = [];
70830
70846
  let flushingInput;
70831
70847
  const flushStdin = () => {
@@ -70906,6 +70922,7 @@ function startChildRun(request) {
70906
70922
  let outcome;
70907
70923
  try {
70908
70924
  const processHost = admittedNode ? nodeProcessHostFor(token) : void 0;
70925
+ hosted = processHost !== void 0;
70909
70926
  const env = { ...request.env };
70910
70927
  delete env[PROCESS_TOKEN_ENV];
70911
70928
  outcome = processHost ? await runHostedNode(processHost, {
@@ -70934,7 +70951,7 @@ function startChildRun(request) {
70934
70951
  }
70935
70952
  if (outcome.stdout.length > streamedOut) (_a4 = request.stdout) == null ? void 0 : _a4.call(request, outcome.stdout.slice(streamedOut));
70936
70953
  if (outcome.stderr.length > streamedErr) (_b3 = request.stderr) == null ? void 0 : _b3.call(request, outcome.stderr.slice(streamedErr));
70937
- end(outcome.exitCode, null);
70954
+ end(outcome.exitCode, outcome.signal ?? null);
70938
70955
  })();
70939
70956
  };
70940
70957
  _activeForkedChildren += 1;
@@ -70945,6 +70962,7 @@ function startChildRun(request) {
70945
70962
  pid,
70946
70963
  kill(signal) {
70947
70964
  if (finished) return UV_ESRCH;
70965
+ if (hosted && signal !== "SIGKILL" && signal !== "SIGSTOP" && signalPid(pid, signal)) return 0;
70948
70966
  killedBy = signal;
70949
70967
  controller.abort(signal);
70950
70968
  __releaseOwnedServers(token, false);
@@ -73926,7 +73944,10 @@ function __substrateScopeGlobalCalls(code2) {
73926
73944
  }
73927
73945
  const positions = [];
73928
73946
  walkAst(ast, (node) => {
73929
- if (node.type === "NewExpression" && node.callee.type === "Identifier") positions.push([node.callee.start, node.callee.end, "(__substrateGuestConstructor(" + code2.slice(node.callee.start, node.callee.end) + ",$process))"]);
73947
+ if (node.type === "NewExpression" && node.callee.type === "Identifier") {
73948
+ const callee = code2.slice(node.callee.start, node.callee.end);
73949
+ positions.push([node.callee.start, node.callee.end, "(typeof __substrateGuestConstructor==='function'?__substrateGuestConstructor(" + callee + ",$process):" + callee + ")"]);
73950
+ }
73930
73951
  const called = node.type === "CallExpression" ? node.callee : node.type === "TaggedTemplateExpression" ? node.tag : void 0;
73931
73952
  if ((called == null ? void 0 : called.type) === "Identifier" && (called.name === "fetch" || called.name === "Promise")) positions.push([called.start, called.end, "(0," + code2.slice(called.start, called.end) + ")"]);
73932
73953
  });
package/dist/index.d.ts CHANGED
@@ -57,6 +57,8 @@ export interface RunResult {
57
57
  stdout: string;
58
58
  stderr: string;
59
59
  exitCode: number;
60
+ /** The signal whose default action ended the run's guest, as Node reports a process a signal ended. */
61
+ signal?: string;
60
62
  }
61
63
  export interface RunOptions {
62
64
  cwd?: string;
package/dist/index.mjs CHANGED
@@ -6480,6 +6480,16 @@ function __recordRun(token, run) {
6480
6480
  if (runs.get(token) === run) runs.delete(token);
6481
6481
  };
6482
6482
  }
6483
+ const terminations = /* @__PURE__ */ new Map();
6484
+ function __recordTermination(process2, signal) {
6485
+ const token = tokensByProcess.get(process2);
6486
+ if (token !== void 0) terminations.set(token, signal);
6487
+ }
6488
+ function __takeTermination(token) {
6489
+ const signal = terminations.get(token);
6490
+ terminations.delete(token);
6491
+ return signal;
6492
+ }
6483
6493
  function __tokenForProcess(process2) {
6484
6494
  return tokensByProcess.get(process2) ?? null;
6485
6495
  }
@@ -9487,7 +9497,16 @@ const osBinding = {
9487
9497
  /** Node's `os.type()`, `release()` and `version()`, in that order. */
9488
9498
  getOSInformation: () => [type$1(), release(), version$2()],
9489
9499
  getHostname: () => hostname(),
9490
- getHomeDirectory: () => homedir(),
9500
+ /**
9501
+ * Node's `os.homedir()` is libuv's: `HOME` when the environment sets it,
9502
+ * the account's directory otherwise. `userInfo().homedir` stays the
9503
+ * account's, as it is in Node.
9504
+ */
9505
+ getHomeDirectory: () => {
9506
+ var _a2, _b2;
9507
+ const home = (_b2 = (_a2 = globalThis.process) == null ? void 0 : _a2.env) == null ? void 0 : _b2.HOME;
9508
+ return home && home.length > 0 ? home : homedir();
9509
+ },
9491
9510
  getUptime: () => uptime(),
9492
9511
  getTotalMem: () => totalmem(),
9493
9512
  getFreeMem: () => freemem(),
@@ -26999,6 +27018,7 @@ function createProcess(options) {
26999
27018
  return true;
27000
27019
  }
27001
27020
  if (__substrateIgnoredSignals.has(name)) return true;
27021
+ __recordTermination(proc, name);
27002
27022
  proc.exit(128 + __substrateSignals[name]);
27003
27023
  return true;
27004
27024
  },
@@ -30518,6 +30538,7 @@ function startChildRun(request) {
30518
30538
  let finished = false;
30519
30539
  let started2 = false;
30520
30540
  let killedBy = null;
30541
+ let hosted = false;
30521
30542
  const initialStdin = [];
30522
30543
  let flushingInput;
30523
30544
  const flushStdin = () => {
@@ -30598,6 +30619,7 @@ function startChildRun(request) {
30598
30619
  let outcome;
30599
30620
  try {
30600
30621
  const processHost = admittedNode ? nodeProcessHostFor(token) : void 0;
30622
+ hosted = processHost !== void 0;
30601
30623
  const env = { ...request.env };
30602
30624
  delete env[PROCESS_TOKEN_ENV];
30603
30625
  outcome = processHost ? await runHostedNode(processHost, {
@@ -30626,7 +30648,7 @@ function startChildRun(request) {
30626
30648
  }
30627
30649
  if (outcome.stdout.length > streamedOut) (_a3 = request.stdout) == null ? void 0 : _a3.call(request, outcome.stdout.slice(streamedOut));
30628
30650
  if (outcome.stderr.length > streamedErr) (_b2 = request.stderr) == null ? void 0 : _b2.call(request, outcome.stderr.slice(streamedErr));
30629
- end(outcome.exitCode, null);
30651
+ end(outcome.exitCode, outcome.signal ?? null);
30630
30652
  })();
30631
30653
  };
30632
30654
  _activeForkedChildren += 1;
@@ -30637,6 +30659,7 @@ function startChildRun(request) {
30637
30659
  pid,
30638
30660
  kill(signal) {
30639
30661
  if (finished) return UV_ESRCH;
30662
+ if (hosted && signal !== "SIGKILL" && signal !== "SIGSTOP" && signalPid(pid, signal)) return 0;
30640
30663
  killedBy = signal;
30641
30664
  controller.abort(signal);
30642
30665
  __releaseOwnedServers(token, false);
@@ -33619,7 +33642,10 @@ function __substrateScopeGlobalCalls(code2) {
33619
33642
  }
33620
33643
  const positions = [];
33621
33644
  walkAst(ast, (node) => {
33622
- if (node.type === "NewExpression" && node.callee.type === "Identifier") positions.push([node.callee.start, node.callee.end, "(__substrateGuestConstructor(" + code2.slice(node.callee.start, node.callee.end) + ",$process))"]);
33645
+ if (node.type === "NewExpression" && node.callee.type === "Identifier") {
33646
+ const callee = code2.slice(node.callee.start, node.callee.end);
33647
+ positions.push([node.callee.start, node.callee.end, "(typeof __substrateGuestConstructor==='function'?__substrateGuestConstructor(" + callee + ",$process):" + callee + ")"]);
33648
+ }
33623
33649
  const called = node.type === "CallExpression" ? node.callee : node.type === "TaggedTemplateExpression" ? node.tag : void 0;
33624
33650
  if ((called == null ? void 0 : called.type) === "Identifier" && (called.name === "fetch" || called.name === "Promise")) positions.push([called.start, called.end, "(0," + code2.slice(called.start, called.end) + ")"]);
33625
33651
  });
@@ -35683,7 +35709,7 @@ class WorkerRuntime {
35683
35709
  this.worker = new Worker(
35684
35710
  new URL(
35685
35711
  /* @vite-ignore */
35686
- "/assets/runtime-worker-CZQ5Vxoj.js",
35712
+ "/assets/runtime-worker-CezP_cM0.js",
35687
35713
  import.meta.url
35688
35714
  ),
35689
35715
  { type: "module" }
@@ -38150,7 +38176,7 @@ class NativeStreamScope {
38150
38176
  const handle = entry.handle;
38151
38177
  switch (operation.operation) {
38152
38178
  case "duplicate": {
38153
- if (!handle.peer || handle.listening) return { status: UV_ENOTSUP };
38179
+ if (handle.listening) return { status: UV_ENOTSUP };
38154
38180
  if (this.entries.size >= this.limits.maxHandles) return { status: UV_EMFILE };
38155
38181
  const copy2 = handle.duplicate();
38156
38182
  const descriptor = this.claim(copy2);
@@ -38310,7 +38336,7 @@ class NativeStreamScope {
38310
38336
  if (this.entries.size >= this.limits.maxHandles) return { status: UV_EMFILE };
38311
38337
  const handle = (_a2 = source.entry(id)) == null ? void 0 : _a2.handle;
38312
38338
  if (!handle) return { status: UV_EBADF };
38313
- if (handle.listening || !handle.peer) return { status: UV_ENOTSUP };
38339
+ if (handle.listening) return { status: UV_ENOTSUP };
38314
38340
  const copy2 = handle.duplicate();
38315
38341
  const descriptor = this.claim(copy2);
38316
38342
  if (!descriptor) {
@@ -38389,10 +38415,12 @@ function createContainer(options) {
38389
38415
  runCommand(command, { cwd: runOptions == null ? void 0 : runOptions.cwd, env: runOptions == null ? void 0 : runOptions.env, stdin: typeof (runOptions == null ? void 0 : runOptions.stdin) === "string" ? runOptions.stdin : void 0, processToken, vfs: vfs2 }, (error, stdout, stderr) => {
38390
38416
  var _a3;
38391
38417
  releaseRunStreams(processToken);
38418
+ const terminatedBy = __takeTermination(processToken);
38392
38419
  resolve2({
38393
38420
  stdout: String(stdout),
38394
38421
  stderr: String(stderr),
38395
- exitCode: ((_a3 = runOptions == null ? void 0 : runOptions.signal) == null ? void 0 : _a3.aborted) ? 143 : error ? error.code ?? 1 : 0
38422
+ exitCode: ((_a3 = runOptions == null ? void 0 : runOptions.signal) == null ? void 0 : _a3.aborted) ? 143 : error ? error.code ?? 1 : 0,
38423
+ ...terminatedBy ? { signal: terminatedBy } : {}
38396
38424
  });
38397
38425
  });
38398
38426
  });
@@ -3,6 +3,11 @@ export declare const osBinding: {
3
3
  /** Node's `os.type()`, `release()` and `version()`, in that order. */
4
4
  getOSInformation: () => string[];
5
5
  getHostname: () => string;
6
+ /**
7
+ * Node's `os.homedir()` is libuv's: `HOME` when the environment sets it,
8
+ * the account's directory otherwise. `userInfo().homedir` stays the
9
+ * account's, as it is in Node.
10
+ */
6
11
  getHomeDirectory: () => string;
7
12
  getUptime: () => number;
8
13
  getTotalMem: () => number;
@@ -21,10 +21,12 @@ export interface NodeProcessLaunch {
21
21
  }[];
22
22
  }
23
23
  export interface NodeProcessHost {
24
+ /** `signal` names the signal whose default action ended the process, as Node's exit event does. */
24
25
  run(launch: NodeProcessLaunch): Promise<{
25
26
  stdout: string;
26
27
  stderr: string;
27
28
  exitCode: number;
29
+ signal?: string;
28
30
  }>;
29
31
  }
30
32
  export declare function nodeProcessHostInstalled(): boolean;
@@ -44,6 +44,8 @@ export declare function enterRun<T>(token: ProcessToken, fn: () => T): T;
44
44
  * releasing twice is harmless, as a run ends once.
45
45
  */
46
46
  export declare function __recordRun(token: ProcessToken, run: OwnedRun): () => void;
47
+ export declare function __recordTermination(process: Process, signal: string): void;
48
+ export declare function __takeTermination(token: ProcessToken): string | undefined;
47
49
  /** Bound guest globals retain their actual process across native await turns. */
48
50
  export declare function __tokenForProcess(process: Process): ProcessToken | null;
49
51
  /** The run recorded under this name, while it lasts. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/tabnode",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "Node's own library, in a browser tab.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -58,7 +58,7 @@ import { __adoptHandle, ownerOf, type OwnedHandle } from './node-lib/binding/han
58
58
  import { listenerOnPort } from './node-lib/binding/tcp_wrap';
59
59
  import { nativeStreamOwnerPid } from './native-stream-owner';
60
60
 
61
- import { __currentProcessToken, __runFor, __signalOwnedProcess, __stopOwnedProcess, runPid, processByPid } from './process-tokens';
61
+ import { __currentProcessToken, __runFor, __signalOwnedProcess, __takeTermination, __stopOwnedProcess, runPid, processByPid } from './process-tokens';
62
62
  export { runPid, processByPid };
63
63
  export { createProcessRegistryScope, installProcessRegistry, ownerProcessRegistryScope, ownerProcessTable } from './process-tokens';
64
64
  export { installNodeProcessHost, nodeProcessHostInstalled } from './node-process-host';
@@ -72,6 +72,8 @@ export interface RunResult {
72
72
  stdout: string;
73
73
  stderr: string;
74
74
  exitCode: number;
75
+ /** The signal whose default action ended the run's guest, as Node reports a process a signal ended. */
76
+ signal?: string;
75
77
  }
76
78
 
77
79
  export interface RunOptions {
@@ -198,10 +200,12 @@ export function createContainer(options?: ContainerOptions): {
198
200
  // piped, as it does in a Node shell.
199
201
  runCommand(command, { cwd: runOptions?.cwd, env: runOptions?.env, stdin: typeof runOptions?.stdin === 'string' ? runOptions.stdin : undefined, processToken, vfs }, (error, stdout, stderr) => {
200
202
  releaseRunStreams(processToken);
203
+ const terminatedBy = __takeTermination(processToken);
201
204
  resolve({
202
205
  stdout: String(stdout),
203
206
  stderr: String(stderr),
204
207
  exitCode: runOptions?.signal?.aborted ? 143 : error ? (error.code ?? 1) : 0,
208
+ ...(terminatedBy ? { signal: terminatedBy } : {}),
205
209
  });
206
210
  });
207
211
  });
@@ -142,7 +142,9 @@ export class NativeStreamScope {
142
142
  const handle = entry.handle;
143
143
  switch (operation.operation) {
144
144
  case 'duplicate': {
145
- if (!handle.peer || handle.listening) return { status: UV_ENOTSUP };
145
+ // A connection is duplicated whether or not its other end is still
146
+ // there (the copy reads its EOF); a listening server is not one.
147
+ if (handle.listening) return { status: UV_ENOTSUP };
146
148
  if (this.entries.size >= this.limits.maxHandles) return { status: UV_EMFILE };
147
149
  const copy = handle.duplicate();
148
150
  const descriptor = this.claim(copy);
@@ -289,7 +291,7 @@ export class NativeStreamScope {
289
291
  if (this.entries.size >= this.limits.maxHandles) return { status: UV_EMFILE };
290
292
  const handle = source.entry(id)?.handle;
291
293
  if (!handle) return { status: UV_EBADF };
292
- if (handle.listening || !handle.peer) return { status: UV_ENOTSUP };
294
+ if (handle.listening) return { status: UV_ENOTSUP };
293
295
  const copy = handle.duplicate();
294
296
  const descriptor = this.claim(copy);
295
297
  if (!descriptor) { copy.close(); return { status: UV_EMFILE }; }
@@ -81,7 +81,15 @@ export const osBinding = {
81
81
  /** Node's `os.type()`, `release()` and `version()`, in that order. */
82
82
  getOSInformation: (): string[] => [osShim.type(), osShim.release(), osShim.version()],
83
83
  getHostname: (): string => osShim.hostname(),
84
- getHomeDirectory: (): string => osShim.homedir(),
84
+ /**
85
+ * Node's `os.homedir()` is libuv's: `HOME` when the environment sets it,
86
+ * the account's directory otherwise. `userInfo().homedir` stays the
87
+ * account's, as it is in Node.
88
+ */
89
+ getHomeDirectory: (): string => {
90
+ const home = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.HOME;
91
+ return home && home.length > 0 ? home : osShim.homedir();
92
+ },
85
93
  getUptime: (): number => osShim.uptime(),
86
94
  getTotalMem: (): number => osShim.totalmem(),
87
95
  getFreeMem: (): number => osShim.freemem(),
@@ -20,7 +20,8 @@ export interface NodeProcessLaunch {
20
20
  }
21
21
 
22
22
  export interface NodeProcessHost {
23
- run(launch: NodeProcessLaunch): Promise<{ stdout: string; stderr: string; exitCode: number }>;
23
+ /** `signal` names the signal whose default action ended the process, as Node's exit event does. */
24
+ run(launch: NodeProcessLaunch): Promise<{ stdout: string; stderr: string; exitCode: number; signal?: string }>;
24
25
  }
25
26
 
26
27
  let host: NodeProcessHost | undefined;
@@ -78,6 +78,22 @@ export function __recordRun(token: ProcessToken, run: OwnedRun): () => void {
78
78
  };
79
79
  }
80
80
 
81
+ /**
82
+ * The signal whose default action ended a run's guest, kept under the run's
83
+ * name until the run reports its result: Node reports such a process as ended
84
+ * by that signal, not by the exit code its default action implies.
85
+ */
86
+ const terminations = new Map<ProcessToken, string>();
87
+ export function __recordTermination(process: Process, signal: string): void {
88
+ const token = tokensByProcess.get(process);
89
+ if (token !== undefined) terminations.set(token, signal);
90
+ }
91
+ export function __takeTermination(token: ProcessToken): string | undefined {
92
+ const signal = terminations.get(token);
93
+ terminations.delete(token);
94
+ return signal;
95
+ }
96
+
81
97
  /** Bound guest globals retain their actual process across native await turns. */
82
98
  export function __tokenForProcess(process: Process): ProcessToken | null {
83
99
  return tokensByProcess.get(process) ?? null;
package/src/runtime.ts CHANGED
@@ -142,7 +142,13 @@ function __substrateScopeGlobalCalls(code: string): string {
142
142
  catch { return code; }
143
143
  const positions: Array<[number, number, string]> = [];
144
144
  walkAst(ast, node => {
145
- 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
+ // A function's source is also data: a program sends `String(fn)` to be
146
+ // run elsewhere (a browser page, a worker), where the module wrapper's
147
+ // names do not exist. The rewrite is the original `new` there.
148
+ if (node.type === "NewExpression" && node.callee.type === "Identifier") {
149
+ const callee = code.slice(node.callee.start, node.callee.end);
150
+ positions.push([node.callee.start, node.callee.end, "(typeof __substrateGuestConstructor==='function'?__substrateGuestConstructor(" + callee + ",$process):" + callee + ")"]);
151
+ }
146
152
  // The narrow with-scope below keeps global replacements dynamic.
147
153
  // Remove its object receiver for ordinary calls (including local
148
154
  // bindings, whose bare-call receiver was already undefined).
@@ -60,7 +60,7 @@ import { __substrateExecPath, __substrateProgramName, __substrateLineFor, __subs
60
60
 
61
61
  import { __substrateChildren, __onUncaughtException, __reportUncaughtException } from './process';
62
62
 
63
- import { PROCESS_TOKEN_ENV, __recordRun, __runFor, __currentProcessToken, __lastLaunchedToken, __setLastLaunchedToken, __stopOwnedProcess, enterRun, mintPid, setRunPid, runPid, forgetRunPid, type ProcessToken } from '../process-tokens';
63
+ import { PROCESS_TOKEN_ENV, __recordRun, __runFor, __currentProcessToken, __lastLaunchedToken, __setLastLaunchedToken, __stopOwnedProcess, enterRun, mintPid, setRunPid, runPid, forgetRunPid, signalPid, type ProcessToken } from '../process-tokens';
64
64
  /** The host's own `process`, where it has one that emits, taken as the shim loads and before any guest's takes the global name. */
65
65
  const __hostProcess: { on(event: string, listener: (reason: unknown) => void): unknown; off(event: string, listener: (reason: unknown) => void): unknown } | null =
66
66
  typeof process !== 'undefined' && process !== null && typeof (process as { on?: unknown }).on === 'function' && typeof (process as { off?: unknown }).off === 'function'
@@ -1399,6 +1399,7 @@ interface CommandOutcome {
1399
1399
  stdout: string;
1400
1400
  stderr: string;
1401
1401
  exitCode: number;
1402
+ signal?: string;
1402
1403
  }
1403
1404
 
1404
1405
  /** What a caller gives one run of a command line. */
@@ -1726,6 +1727,8 @@ function startChildRun(request: RunRequest): StartedRun {
1726
1727
  let finished = false;
1727
1728
  let started = false;
1728
1729
  let killedBy: string | null = null;
1730
+ // Whether the child runs on the process host, in a realm of its own.
1731
+ let hosted = false;
1729
1732
  /** What the parent wrote to the child's fd 0 before the command began. */
1730
1733
  const initialStdin: Uint8Array[] = [];
1731
1734
 
@@ -1812,6 +1815,7 @@ function startChildRun(request: RunRequest): StartedRun {
1812
1815
  let outcome: CommandOutcome;
1813
1816
  try {
1814
1817
  const processHost = admittedNode ? nodeProcessHostFor(token) : undefined;
1818
+ hosted = processHost !== undefined;
1815
1819
  const env = { ...request.env };
1816
1820
  delete env[PROCESS_TOKEN_ENV];
1817
1821
  outcome = processHost ? await runHostedNode(processHost, {
@@ -1837,7 +1841,7 @@ function startChildRun(request: RunRequest): StartedRun {
1837
1841
  // its own as it went, and only what it has not already sent is left.
1838
1842
  if (outcome.stdout.length > streamedOut) request.stdout?.(outcome.stdout.slice(streamedOut));
1839
1843
  if (outcome.stderr.length > streamedErr) request.stderr?.(outcome.stderr.slice(streamedErr));
1840
- end(outcome.exitCode, null);
1844
+ end(outcome.exitCode, outcome.signal ?? null);
1841
1845
  })();
1842
1846
  };
1843
1847
 
@@ -1850,6 +1854,11 @@ function startChildRun(request: RunRequest): StartedRun {
1850
1854
  pid,
1851
1855
  kill(signal: string): number {
1852
1856
  if (finished) return UV_ESRCH;
1857
+ // A child in a realm of its own takes a catchable signal as a machine's
1858
+ // process does: its listeners run, else its default action ends it, and
1859
+ // it ends by its own outcome. Only when nothing there receives it does
1860
+ // the parent end it here.
1861
+ if (hosted && signal !== 'SIGKILL' && signal !== 'SIGSTOP' && signalPid(pid, signal)) return 0;
1853
1862
  killedBy = signal;
1854
1863
  controller.abort(signal);
1855
1864
  __releaseOwnedServers(token, false);
@@ -10,7 +10,7 @@ import { Readable } from '../node-lib/stream-module';
10
10
  import { loadNodeLibFor } from '../node-lib/load';
11
11
  import { constantsBinding } from './constants';
12
12
  import ttyWrapBinding from '../node-lib/binding/tty_wrap';
13
- import { mintPid, pidIsLive, signalPid } from '../process-tokens';
13
+ import { mintPid, pidIsLive, signalPid, __recordTermination } from '../process-tokens';
14
14
  import { NODE_LTS_VERSION, nodeVersions } from '../node-lib/node-versions';
15
15
  import { freemem as osFreemem } from './os';
16
16
 
@@ -584,6 +584,7 @@ export function createProcess(options?: {
584
584
  return true;
585
585
  }
586
586
  if (__substrateIgnoredSignals.has(name)) return true;
587
+ __recordTermination(proc as never, name);
587
588
  proc.exit(128 + __substrateSignals[name]);
588
589
  return true;
589
590
  },