@camstack/system 1.2.218 → 1.2.219

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/addon-runner.js +2 -2
  2. package/dist/addon-runner.mjs +2 -2
  3. package/dist/addon-utils.js +2 -2
  4. package/dist/addon-utils.mjs +2 -2
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  9. package/dist/builtins/alerts/alerts.addon.js +1 -1
  10. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  13. package/dist/builtins/console-logging/index.js +1 -1
  14. package/dist/builtins/console-logging/index.mjs +1 -1
  15. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  16. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  17. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  18. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  19. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  20. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  21. package/dist/builtins/hub-forwarder/index.js +1 -1
  22. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  23. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  24. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  25. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  26. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  27. package/dist/builtins/local-network/local-network.addon.js +2 -2
  28. package/dist/builtins/local-network/local-network.addon.mjs +2 -2
  29. package/dist/builtins/loki-logging/index.js +1 -1
  30. package/dist/builtins/loki-logging/index.mjs +1 -1
  31. package/dist/builtins/native-metrics/gpu-probe.d.ts +18 -0
  32. package/dist/builtins/native-metrics/native-metrics-provider.d.ts +1 -1
  33. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +26 -3
  34. package/dist/builtins/native-metrics/native-metrics.addon.js +1320 -1093
  35. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1320 -1096
  36. package/dist/builtins/native-metrics/proc-process-table.d.ts +25 -0
  37. package/dist/builtins/platform-probe/index.js +3 -3
  38. package/dist/builtins/platform-probe/index.mjs +3 -3
  39. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  40. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  41. package/dist/builtins/snapshot/index.js +1 -1
  42. package/dist/builtins/snapshot/index.mjs +1 -1
  43. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  44. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  45. package/dist/builtins/sqlite-storage/sqlite-pragmas.d.ts +23 -0
  46. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +1 -1
  47. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +1 -0
  48. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  49. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  50. package/dist/builtins/sqlite-storage/wal-checkpoint-policy.d.ts +115 -0
  51. package/dist/builtins/sqlite-storage/wal-checkpoint-worker.d.ts +1 -0
  52. package/dist/builtins/sqlite-storage/wal-checkpointer.d.ts +70 -0
  53. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  54. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  55. package/dist/builtins/system-config/system-config.addon.js +1 -1
  56. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  57. package/dist/builtins/winston-logging/index.js +1 -1
  58. package/dist/builtins/winston-logging/index.mjs +1 -1
  59. package/dist/{custom-action-registry-CsONUlhC.mjs → custom-action-registry-B6gOtUWA.mjs} +1 -1
  60. package/dist/{custom-action-registry-BDwM5qAK.js → custom-action-registry-DKWhaWL1.js} +1 -1
  61. package/dist/{dist-BOlMCOeT.js → dist-B17W9ngu.js} +2 -2
  62. package/dist/{dist-DigmGsQS.mjs → dist-Cyz5_i7z.mjs} +2 -2
  63. package/dist/index.d.ts +6 -1
  64. package/dist/index.js +31 -36
  65. package/dist/index.mjs +23 -38
  66. package/dist/kernel/heap-watch.d.ts +24 -1
  67. package/dist/kernel/moleculer/mesh-queue-report.d.ts +51 -0
  68. package/dist/kernel/outbound-queue-watch.d.ts +94 -0
  69. package/dist/kernel/socket-plane-report.d.ts +75 -4
  70. package/dist/kernel/transport/cap-routing-hints.d.ts +21 -0
  71. package/dist/kernel/transport/child-cap-protocol.d.ts +28 -2
  72. package/dist/kernel/transport/frame-codec.d.ts +49 -0
  73. package/dist/kernel/transport/local-child-client.d.ts +7 -0
  74. package/dist/kernel/transport/local-child-registry.d.ts +36 -1
  75. package/dist/kernel/transport/local-transport.d.ts +45 -2
  76. package/dist/kernel/transport/socket-channel.d.ts +19 -1
  77. package/dist/{manifest-system-deps-D--wyMD9.mjs → manifest-system-deps-C7dihwWT.mjs} +1210 -682
  78. package/dist/{manifest-system-deps-Bo92lg5u.js → manifest-system-deps-g_nK0xsF.js} +1252 -664
  79. package/dist/process/proc-stat.d.ts +75 -0
  80. package/dist/process/resource-monitor.d.ts +9 -1
  81. package/dist/{resource-monitor-CdnzxBLP.js → resource-monitor-LVE1BoLs.js} +42 -23
  82. package/dist/{resource-monitor-BWmQ5i-o.mjs → resource-monitor-Vp0bPV3U.mjs} +42 -22
  83. package/dist/{retired-settings-keys-vK_U-CG2.mjs → retired-settings-keys-BCYUrdsA.mjs} +1 -1
  84. package/dist/{retired-settings-keys-xEAlYnv7.js → retired-settings-keys-CjvB7Etx.js} +1 -1
  85. package/dist/wal-checkpoint-policy-CAcg63o-.mjs +92 -0
  86. package/dist/wal-checkpoint-policy-CCJZngds.js +127 -0
  87. package/dist/wal-checkpoint-worker.js +138 -0
  88. package/dist/wal-checkpoint-worker.mjs +137 -0
  89. package/package.json +1 -1
  90. package/dist/{event-loop-stall-monitor-DM9OAzy8.js → event-loop-stall-monitor-CAsHdMwP.js} +1 -1
  91. package/dist/{event-loop-stall-monitor-B3CFd9tM.mjs → event-loop-stall-monitor-GPrVvx14.mjs} +1 -1
  92. package/dist/{tls-DOTmtLCW.mjs → tls-2xbgg78V.mjs} +2 -2
  93. package/dist/{tls-BxQlomxd.js → tls-BFs4PzoW.js} +2 -2
@@ -5,12 +5,12 @@ import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, instal
5
5
  import { unlink } from "node:fs/promises";
6
6
  import * as path$1 from "node:path";
7
7
  import { isAbsolute, join } from "node:path";
8
- import { execFile } from "node:child_process";
9
- import { promisify } from "node:util";
10
8
  import * as fs from "node:fs";
11
9
  import { existsSync } from "node:fs";
10
+ import { execFile } from "node:child_process";
12
11
  import * as os from "node:os";
13
12
  import { tmpdir } from "node:os";
13
+ import { promisify } from "node:util";
14
14
  import { createServer } from "node:http";
15
15
  import * as v8 from "node:v8";
16
16
  import { Session } from "node:inspector/promises";
@@ -308,12 +308,15 @@ function createSocketPlaneReader(sources) {
308
308
  peers.push({
309
309
  peerId: child.childId,
310
310
  tx: traffic.tx,
311
- rx: traffic.rx
311
+ rx: traffic.rx,
312
+ queuedBytes: registry.getChildQueuedBytes(child.childId)
312
313
  });
313
314
  }
315
+ const forward = registry.readForwardCensus?.();
314
316
  return {
315
317
  peers,
316
- peersConnected: listed.length
318
+ peersConnected: listed.length,
319
+ ...forward === void 0 ? {} : { forward }
317
320
  };
318
321
  } catch {
319
322
  return;
@@ -331,8 +334,41 @@ function createSocketPlaneReader(sources) {
331
334
  * stops being read.
332
335
  */
333
336
  var SOCKET_PLANE_TOP_N = 5;
337
+ /** How many queue-holding peers get named. Three: a queue is an exception,
338
+ * and the line already carries five names for traffic. */
339
+ var SOCKET_QUEUE_TOP_N = 3;
340
+ /** The queue reading over the current counters — a level, so no baseline. */
341
+ function readSocketQueues(current) {
342
+ let totalBytes = 0;
343
+ let unmeasured = 0;
344
+ const holding = [];
345
+ for (const peer of current.peers) {
346
+ if (peer.queuedBytes === null) {
347
+ unmeasured += 1;
348
+ continue;
349
+ }
350
+ totalBytes += peer.queuedBytes;
351
+ if (peer.queuedBytes > 0) holding.push({
352
+ peerId: peer.peerId,
353
+ bytes: peer.queuedBytes
354
+ });
355
+ }
356
+ return {
357
+ totalBytes,
358
+ unmeasured,
359
+ top: holding.toSorted((a, b) => b.bytes - a.bytes || a.peerId.localeCompare(b.peerId)).slice(0, 3)
360
+ };
361
+ }
334
362
  /** A process that has never read the plane. */
335
363
  var EMPTY_SOCKET_PLANE_BASELINE = { peers: /* @__PURE__ */ new Map() };
364
+ /** The census over the window; a counter that went backwards reads as quiet. */
365
+ function diffForward(current, before) {
366
+ if (current === void 0) return void 0;
367
+ return {
368
+ raw: Math.max(0, current.raw - (before?.raw ?? 0)),
369
+ decoded: Math.max(0, current.decoded - (before?.decoded ?? 0))
370
+ };
371
+ }
336
372
  function diffDirection(current, before) {
337
373
  const previous = before ?? EMPTY_SOCKET_DIRECTION;
338
374
  return {
@@ -358,6 +394,14 @@ function addDirection(into, add) {
358
394
  function peerMessages(delta) {
359
395
  return socketDirectionMessages(delta.tx) + socketDirectionMessages(delta.rx);
360
396
  }
397
+ /**
398
+ * Total bytes a peer moved in the window, both directions — the OTHER
399
+ * ranking, and the one that names a peer the message ranking structurally
400
+ * cannot see (D454).
401
+ */
402
+ function peerBytes(delta) {
403
+ return socketDirectionBytes(delta.tx) + socketDirectionBytes(delta.rx);
404
+ }
361
405
  /** Subtract the previous cumulative reading from the current one. */
362
406
  function diffSocketPlane(baseline, current, topN = 5) {
363
407
  const deltas = [];
@@ -374,12 +418,16 @@ function diffSocketPlane(baseline, current, topN = 5) {
374
418
  rx = addDirection(rx, delta.rx);
375
419
  if (peerMessages(delta) > 0) deltas.push(delta);
376
420
  }
421
+ const forward = diffForward(current.forward, baseline.forward);
377
422
  return {
378
423
  peersConnected: current.peersConnected,
379
424
  peersMeasured: current.peers.length,
380
425
  tx,
381
426
  rx,
382
- top: deltas.toSorted((a, b) => peerMessages(b) - peerMessages(a) || a.peerId.localeCompare(b.peerId)).slice(0, topN)
427
+ top: deltas.toSorted((a, b) => peerMessages(b) - peerMessages(a) || a.peerId.localeCompare(b.peerId)).slice(0, topN),
428
+ topBytes: deltas.toSorted((a, b) => peerBytes(b) - peerBytes(a) || a.peerId.localeCompare(b.peerId)).slice(0, topN),
429
+ queued: readSocketQueues(current),
430
+ ...forward === void 0 ? {} : { forward }
383
431
  };
384
432
  }
385
433
  function createSocketPlaneMeter(reader, topN = 5) {
@@ -388,24 +436,43 @@ function createSocketPlaneMeter(reader, topN = 5) {
388
436
  const current = reader();
389
437
  if (current === void 0) return void 0;
390
438
  const window = diffSocketPlane(baseline, current, topN);
391
- baseline = { peers: new Map(current.peers.map((p) => [p.peerId, p])) };
439
+ baseline = {
440
+ peers: new Map(current.peers.map((p) => [p.peerId, p])),
441
+ ...current.forward === void 0 ? {} : { forward: current.forward }
442
+ };
392
443
  return window;
393
444
  } };
394
445
  }
395
446
  /** Bytes → whole kB. The plane moves 180–330 MB/min; raw bytes would put
396
447
  * nine-digit numbers on a line that has to stay readable. */
397
- function kb(bytes) {
448
+ function kb$1(bytes) {
398
449
  return Math.round(bytes / 1024);
399
450
  }
400
451
  /** `req:<msgs>/<kB>,res:<msgs>/<kB>,evt:<msgs>/<kB>` — every kind, always,
401
452
  * including at zero: a kind that went quiet is a reading, not a blank. */
402
453
  function formatDirection(sample) {
403
- return `req:${sample.reqMessages}/${kb(sample.reqBytes)}kB,res:${sample.resMessages}/${kb(sample.resBytes)}kB,evt:${sample.evtMessages}/${kb(sample.evtBytes)}kB`;
454
+ return `req:${sample.reqMessages}/${kb$1(sample.reqBytes)}kB,res:${sample.resMessages}/${kb$1(sample.resBytes)}kB,evt:${sample.evtMessages}/${kb$1(sample.evtBytes)}kB`;
404
455
  }
405
- /** `<peer>:tx=<req>/<res>/<evt>:rx=<req>/<res>/<evt>:kB=<tx>/<rx>` — the whole
406
- * peer×kind cross for one peer, which is the question in one token. */
456
+ /** `<req>/<res>/<evt>` in kB — the byte triple, in the same order as the
457
+ * message triple next to it, so the two read as one table. */
458
+ function formatPeerBytes(sample) {
459
+ return `${kb$1(sample.reqBytes)}/${kb$1(sample.resBytes)}/${kb$1(sample.evtBytes)}`;
460
+ }
461
+ /**
462
+ * `<peer>:tx=<req>/<res>/<evt>:rx=…:txkB=<req>/<res>/<evt>:rxkB=…` — the whole
463
+ * peer×kind cross for one peer, messages and bytes, which is the question in
464
+ * one token.
465
+ *
466
+ * The bytes were a per-direction TOTAL until D454, and the total could not
467
+ * answer the question `socket-traffic.ts` says this instrument exists to
468
+ * settle: whether a peer's bytes are RESPONSES (media, and D9/D18 re-opens) or
469
+ * fan-out (`evt`, which scales with runner count and nothing an operator
470
+ * asked for). On 2026-09-11 hub-main wrote 118 MB in one minute to
471
+ * `hub/pipeline-analytics` and the line could only say "118 MB" — separating
472
+ * `res` from `evt` took an hour of arithmetic against the plane-wide totals.
473
+ */
407
474
  function formatPeer(delta) {
408
- return `${delta.peerId}:tx=${delta.tx.reqMessages}/${delta.tx.resMessages}/${delta.tx.evtMessages}:rx=${delta.rx.reqMessages}/${delta.rx.resMessages}/${delta.rx.evtMessages}:kB=${kb(socketDirectionBytes(delta.tx))}/${kb(socketDirectionBytes(delta.rx))}`;
475
+ return `${delta.peerId}:tx=${delta.tx.reqMessages}/${delta.tx.resMessages}/${delta.tx.evtMessages}:rx=${delta.rx.reqMessages}/${delta.rx.resMessages}/${delta.rx.evtMessages}:txkB=${formatPeerBytes(delta.tx)}:rxkB=${formatPeerBytes(delta.rx)}`;
409
476
  }
410
477
  /**
411
478
  * The suffix appended to a `[mem]` line — leading space included, empty when
@@ -418,14 +485,234 @@ function formatPeer(delta) {
418
485
  * is the only way to see an unmeasured channel, and the per-kind splits because
419
486
  * "the plane went quiet for a minute" is a reading.
420
487
  *
421
- * `socketTop` is the one conditional field — a ranked list of nothing is noise —
422
- * and it is a single comma-separated value so the field COUNT does not change
423
- * from line to line.
488
+ * `socketTop` is a conditional field — a ranked list of nothing is noise — and
489
+ * it is a single comma-separated value so the field COUNT does not change from
490
+ * line to line.
491
+ *
492
+ * `socketTopBytes` is the other one, and its PRESENCE is the reading: it is
493
+ * printed only when ranking by bytes names a peer that ranking by messages
494
+ * does not. A line without it says the two rankings agree; a line with it says
495
+ * a peer is moving few, heavy frames and names it (D454).
424
496
  */
425
497
  function formatSocketPlane(window) {
426
498
  if (window === void 0) return "";
427
499
  const top = window.top.map(formatPeer).join(",");
428
- return ` socketPeers=${window.peersMeasured}/${window.peersConnected} socketTx=${formatDirection(window.tx)} socketRx=${formatDirection(window.rx)}` + (top.length === 0 ? "" : ` socketTop=${top}`);
500
+ const named = new Set(window.top.map((p) => p.peerId));
501
+ const topBytes = window.topBytes.filter((p) => !named.has(p.peerId)).map(formatPeer).join(",");
502
+ const queuedTop = window.queued.top.map((p) => `${p.peerId}:${kb$1(p.bytes)}`).join(",");
503
+ return ` socketPeers=${window.peersMeasured}/${window.peersConnected} socketTx=${formatDirection(window.tx)} socketRx=${formatDirection(window.rx)}` + (top.length === 0 ? "" : ` socketTop=${top}`) + (topBytes.length === 0 ? "" : ` socketTopBytes=${topBytes}`) + ` socketQueued=${kb$1(window.queued.totalBytes)}kB` + (window.queued.unmeasured === 0 ? "" : ` socketQueuedUnmeasured=${window.queued.unmeasured}`) + (queuedTop.length === 0 ? "" : ` socketQueuedTop=${queuedTop}`) + (window.forward === void 0 ? "" : ` socketFwd=${window.forward.raw}/${window.forward.decoded}`);
504
+ }
505
+ //#endregion
506
+ //#region src/kernel/moleculer/mesh-queue-report.ts
507
+ function isRecord$1(value) {
508
+ return typeof value === "object" && value !== null;
509
+ }
510
+ /** The shape `TcpWriter` keeps its sockets in. Anything else is not a mesh. */
511
+ function writerSocketsOf(broker) {
512
+ if (!isRecord$1(broker)) return void 0;
513
+ const transit = broker["transit"];
514
+ if (!isRecord$1(transit)) return void 0;
515
+ const transporter = transit["tx"];
516
+ if (!isRecord$1(transporter)) return void 0;
517
+ const writer = transporter["writer"];
518
+ if (!isRecord$1(writer)) return void 0;
519
+ const sockets = writer["sockets"];
520
+ return sockets instanceof Map ? sockets : void 0;
521
+ }
522
+ function readSocket(nodeId, socket) {
523
+ if (typeof nodeId !== "string" || !isRecord$1(socket)) return void 0;
524
+ const queuedBytes = socket["writableLength"];
525
+ const bytesWritten = socket["bytesWritten"];
526
+ if (typeof queuedBytes !== "number" || typeof bytesWritten !== "number") return void 0;
527
+ return {
528
+ nodeId,
529
+ queuedBytes,
530
+ bytesWritten
531
+ };
532
+ }
533
+ /**
534
+ * Build a reader over a lazily-resolved broker. Wrapped: a broker mid-teardown
535
+ * may throw, and a diagnostic that can crash the process it watches is worse
536
+ * than none.
537
+ */
538
+ function createMeshQueueReader(getBroker) {
539
+ return () => {
540
+ try {
541
+ const sockets = writerSocketsOf(getBroker());
542
+ if (sockets === void 0) return void 0;
543
+ const peers = [];
544
+ for (const [nodeId, socket] of sockets) {
545
+ const peer = readSocket(nodeId, socket);
546
+ if (peer !== void 0) peers.push(peer);
547
+ }
548
+ return peers;
549
+ } catch {
550
+ return;
551
+ }
552
+ };
553
+ }
554
+ /** At most this many nodes named. A cluster has a handful. */
555
+ var MESH_QUEUE_TOP_N = 3;
556
+ function kb(bytes) {
557
+ return Math.round(bytes / 1024);
558
+ }
559
+ /**
560
+ * The suffix appended to a `[mem]` line — leading space included, empty when
561
+ * this process has no mesh writer. `meshQueued` is printed always, at zero
562
+ * included: a quiet mesh is a reading. `meshQueuedTop` names only nodes with
563
+ * a queue, largest first — a ranked list of zeros is noise.
564
+ */
565
+ function formatMeshQueue(peers) {
566
+ if (peers === void 0) return "";
567
+ const total = peers.reduce((sum, p) => sum + p.queuedBytes, 0);
568
+ const top = peers.filter((p) => p.queuedBytes > 0).toSorted((a, b) => b.queuedBytes - a.queuedBytes || a.nodeId.localeCompare(b.nodeId)).slice(0, 3).map((p) => `${p.nodeId}:${kb(p.queuedBytes)}`).join(",");
569
+ return ` meshQueued=${kb(total)}kB` + (top.length === 0 ? "" : ` meshQueuedTop=${top}`);
570
+ }
571
+ //#endregion
572
+ //#region src/kernel/outbound-queue-watch.ts
573
+ /**
574
+ * outbound-queue-watch — an outbound socket queue that HOLDS is named, and its
575
+ * release is timestamped (D446).
576
+ *
577
+ * ## The blind spot this closes
578
+ *
579
+ * On 2026-09-10 hub-main's `arrayBuffers` climbed twice at a constant rate
580
+ * (20 MB/min to 1 264 MB; 63 MB/min for 77 min to 4 968 MB), LIVE across a
581
+ * forced compaction, with ~4 % of JS heap alongside, and each time released in
582
+ * one instant with no line from any owner. The investigation excluded "every
583
+ * socket write queue" by summing `writableLength` over
584
+ * `process._getActiveHandles()` — 84 MB, all of it the phone's WebSocket.
585
+ *
586
+ * `_getActiveHandles()` lists only handles that keep the loop alive. An
587
+ * UNREF'D socket is not one of them, and Moleculer's `TcpWriter.connect`
588
+ * unrefs every socket it opens to a peer node (`transporters/tcp/tcp-writer.js`,
589
+ * `socket.unref()`). So the one outbound plane that writes to another MACHINE
590
+ * — where a reader that stops draining is the ordinary failure — was never in
591
+ * the sum. The UDS children were in it, but only as a total, at one instant,
592
+ * by hand.
593
+ *
594
+ * ## What this is
595
+ *
596
+ * A pure gate over per-peer queue depths the heartbeat reads on every probe:
597
+ * the UDS children's `socket.writableLength` (`SocketChannel.queuedBytes`) and
598
+ * the mesh writer sockets' (`mesh-queue-report.ts`). It says three things and
599
+ * nothing else:
600
+ *
601
+ * - a peer whose queue has been at or above {@link OUTBOUND_QUEUE_THRESHOLD_BYTES}
602
+ * for {@link OUTBOUND_QUEUE_SUSTAIN_MS} is NAMED, with its current and peak
603
+ * depth and how long it has held — at most once per
604
+ * {@link OUTBOUND_QUEUE_COOLDOWN_MS};
605
+ * - a named peer whose queue then falls under half the threshold, or that
606
+ * vanishes from the readings (its socket died — which is how a queue is
607
+ * dropped in one instant), is reported as RELEASED with its peak and the
608
+ * hold, so the release the episodes never logged has a line and a peer;
609
+ * - a burst that drains inside the sustain window says nothing. Backpressure
610
+ * measures LIVENESS, not identity (D444): a peer momentarily behind is
611
+ * coming back.
612
+ *
613
+ * ## What it is NOT
614
+ *
615
+ * Not a bound. It terminates nothing: a UDS child whose channel is destroyed
616
+ * loses every in-flight call, and a mesh socket Moleculer reconnects on its
617
+ * own terms. The WS guard (`ws-slow-consumer-guard.ts`) bounds the one plane
618
+ * whose client is expendable. Here the line is the deliverable; what to do
619
+ * about a peer that holds is decided with the peer named, not before.
620
+ */
621
+ /** 64 MiB. Below this a queue is a burst on a busy peer (the orchestrator's
622
+ * channel moves ~1.5 MB/s of audio responses); above it, and held, it is
623
+ * retention with a name. */
624
+ var OUTBOUND_QUEUE_THRESHOLD_BYTES = 64 * 1024 * 1024;
625
+ /** Matches the ArrayBuffer census sustain: a minute above the bound. */
626
+ var OUTBOUND_QUEUE_SUSTAIN_MS = 6e4;
627
+ /** A held queue is re-named every ten minutes, not every probe. */
628
+ var OUTBOUND_QUEUE_COOLDOWN_MS = 10 * 6e4;
629
+ /** A release is a fall under this fraction of the threshold. */
630
+ var RELEASE_RATIO = .5;
631
+ /**
632
+ * The pure decision — threshold, sustain, cooldown, release, gone — testable
633
+ * without a socket.
634
+ */
635
+ function createOutboundQueueGate(options = {}) {
636
+ const thresholdBytes = options.thresholdBytes ?? 67108864;
637
+ const sustainMs = options.sustainMs ?? 6e4;
638
+ const cooldownMs = options.cooldownMs ?? 6e5;
639
+ const tracked = /* @__PURE__ */ new Map();
640
+ const judgeOne = (peerId, bytes, at) => {
641
+ const state = tracked.get(peerId);
642
+ if (bytes >= thresholdBytes) {
643
+ const next = state === void 0 ? {
644
+ aboveSince: at,
645
+ peakBytes: bytes,
646
+ lastNamedAt: null
647
+ } : {
648
+ ...state,
649
+ peakBytes: Math.max(state.peakBytes, bytes)
650
+ };
651
+ const heldForMs = at - next.aboveSince;
652
+ const due = heldForMs >= sustainMs && (next.lastNamedAt === null || at - next.lastNamedAt >= cooldownMs);
653
+ tracked.set(peerId, due ? {
654
+ ...next,
655
+ lastNamedAt: at
656
+ } : next);
657
+ return due ? {
658
+ kind: "sustained",
659
+ peerId,
660
+ bytes,
661
+ peakBytes: next.peakBytes,
662
+ heldForMs
663
+ } : void 0;
664
+ }
665
+ if (state === void 0) return void 0;
666
+ if (bytes >= thresholdBytes * RELEASE_RATIO) return void 0;
667
+ tracked.delete(peerId);
668
+ if (state.lastNamedAt === null) return void 0;
669
+ return {
670
+ kind: "released",
671
+ peerId,
672
+ peakBytes: state.peakBytes,
673
+ toBytes: bytes,
674
+ heldForMs: at - state.aboveSince,
675
+ gone: false
676
+ };
677
+ };
678
+ return { observe(readings, at) {
679
+ const verdicts = [];
680
+ const seen = /* @__PURE__ */ new Set();
681
+ for (const reading of readings) {
682
+ seen.add(reading.peerId);
683
+ const verdict = judgeOne(reading.peerId, reading.bytes, at);
684
+ if (verdict !== void 0) verdicts.push(verdict);
685
+ }
686
+ for (const [peerId, state] of tracked) {
687
+ if (seen.has(peerId)) continue;
688
+ tracked.delete(peerId);
689
+ if (state.lastNamedAt === null) continue;
690
+ verdicts.push({
691
+ kind: "released",
692
+ peerId,
693
+ peakBytes: state.peakBytes,
694
+ toBytes: 0,
695
+ heldForMs: at - state.aboveSince,
696
+ gone: true
697
+ });
698
+ }
699
+ return verdicts;
700
+ } };
701
+ }
702
+ var BYTES_PER_MB$1 = 1048576;
703
+ function mb$2(bytes) {
704
+ return Math.round(bytes / BYTES_PER_MB$1);
705
+ }
706
+ /** `60s` under two minutes, `77m` from there — the hold is read at a glance. */
707
+ function duration(ms) {
708
+ const seconds = Math.round(ms / 1e3);
709
+ return seconds < 120 ? `${seconds}s` : `${Math.round(seconds / 60)}m`;
710
+ }
711
+ /** The line for one verdict. Both carry the peer, the bytes and the hold;
712
+ * the sustained one also says why the older census could not see it. */
713
+ function formatOutboundQueueVerdict(label, verdict) {
714
+ if (verdict.kind === "sustained") return `[mem] ${label} outbound queue to ${verdict.peerId} has held ${mb$2(verdict.bytes)}MB (peak ${mb$2(verdict.peakBytes)}MB) for ${duration(verdict.heldForMs)} — the peer is not draining what this process writes to it. This is socket.writableLength on the channel itself; a sum over _getActiveHandles() does not list an unref'd socket and would miss it.`;
715
+ return `[mem] ${label} outbound queue to ${verdict.peerId} RELEASED — ${mb$2(verdict.peakBytes)}MB at peak, ${mb$2(verdict.toBytes)}MB now, held ${duration(verdict.heldForMs)}` + (verdict.gone ? " (peer gone: the socket closed and dropped its queue)" : " (drained)");
429
716
  }
430
717
  //#endregion
431
718
  //#region src/kernel/heap-spaces.ts
@@ -1413,6 +1700,27 @@ function format(label, s, loop, budgetMb, suffix) {
1413
1700
  return `${line} loopP50=${loop.p50Ms}ms loopP99=${loop.p99Ms}ms loopMax=${loop.maxMs}ms${suffix}`;
1414
1701
  }
1415
1702
  /**
1703
+ * Every outbound queue the heartbeat can reach, as the gate wants them: the
1704
+ * UDS children (only those whose channel keeps a reading — an unmeasured
1705
+ * peer is not a zero) and the mesh writer sockets, each prefixed with its
1706
+ * plane.
1707
+ */
1708
+ function outboundQueueReadings(uds, mesh) {
1709
+ const readings = [];
1710
+ for (const peer of uds?.peers ?? []) {
1711
+ if (peer.queuedBytes === null) continue;
1712
+ readings.push({
1713
+ peerId: `uds:${peer.peerId}`,
1714
+ bytes: peer.queuedBytes
1715
+ });
1716
+ }
1717
+ for (const node of mesh ?? []) readings.push({
1718
+ peerId: `mesh:${node.nodeId}`,
1719
+ bytes: node.queuedBytes
1720
+ });
1721
+ return readings;
1722
+ }
1723
+ /**
1416
1724
  * Start the heartbeat. Returns a stop function.
1417
1725
  *
1418
1726
  * `unref`ed so it can never hold the process open, and every read is wrapped:
@@ -1526,7 +1834,7 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
1526
1834
  const due = at - lastLoggedAt >= intervalMs;
1527
1835
  if (mode === "escalated" || due) {
1528
1836
  lastLoggedAt = at;
1529
- const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces())}${formatEventPlane(eventPlane?.read())}` + formatSocketPlane(socketPlane?.read()));
1837
+ const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces())}${formatEventPlane(eventPlane?.read())}` + formatSocketPlane(socketPlane?.read()) + formatMeshQueue(meshQueue?.()));
1530
1838
  if (sample.nearLimit) sink.warn(`${line} — APPROACHING HEAP LIMIT`);
1531
1839
  else if (mode === "escalated") sink.warn(`${line} — heap elevated, sampling every ${probeIntervalMs}ms`);
1532
1840
  else sink.info(line);
@@ -1535,8 +1843,17 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
1535
1843
  checkRssBudget(sample, at);
1536
1844
  maybeReclaim(sample);
1537
1845
  judgeArrayBuffers(sample, at);
1846
+ judgeOutboundQueues(at);
1538
1847
  } catch {}
1539
1848
  };
1849
+ const meshQueue = probes?.meshQueue;
1850
+ const queueReader = probes?.socketPlane;
1851
+ const queueGate = queueReader === void 0 && meshQueue === void 0 ? void 0 : createOutboundQueueGate(probes?.outboundQueue);
1852
+ const judgeOutboundQueues = (at) => {
1853
+ if (queueGate === void 0) return;
1854
+ const readings = outboundQueueReadings(queueReader?.(), meshQueue?.());
1855
+ for (const verdict of queueGate.observe(readings, at)) sink.warn(formatOutboundQueueVerdict(label, verdict));
1856
+ };
1540
1857
  const censusProbe = probes?.arrayBufferCensus;
1541
1858
  const censusGate = censusProbe === void 0 ? void 0 : createArrayBufferCensusGate(censusProbe);
1542
1859
  let censusInFlight = false;
@@ -5333,6 +5650,74 @@ function encodeFrame(value) {
5333
5650
  Buffer.from(body.buffer, body.byteOffset, body.byteLength).copy(out, 4);
5334
5651
  return out;
5335
5652
  }
5653
+ /** msgpack `fixstr` of {@link PAYLOAD_KEY}: `0xa0 | length`, then the bytes. */
5654
+ var PAYLOAD_KEY_BYTES = Buffer.from([162, ...Buffer.from("pl")]);
5655
+ /** msgpack `bin 32` marker: one byte, then a 4-byte big-endian length. */
5656
+ var BIN32_MARKER = 198;
5657
+ /** msgpack `fixmap` range: `0x80 | count`, count in `0..15`. */
5658
+ var FIXMAP_BASE = 128;
5659
+ var FIXMAP_MAX_COUNT = 15;
5660
+ /**
5661
+ * Encode the HEAD of a frame that carries an opaque payload: the length
5662
+ * prefix, the msgpack envelope with one extra key ({@link PAYLOAD_KEY}), and
5663
+ * the `bin 32` header for the payload — everything but the payload bytes
5664
+ * themselves, which the caller writes straight after it.
5665
+ *
5666
+ * ## Why the payload is the frame's TAIL and not a field
5667
+ *
5668
+ * hub-main routes every sibling↔sibling call. Until this existed it decoded
5669
+ * the whole request (args included), built a new message, and re-encoded it
5670
+ * — walking a 13.5 KB PCM chunk or a 2 000-row settings answer twice on the
5671
+ * one thread that serves every tRPC request, and allocating an `Encoder`
5672
+ * buffer that doubles from 2 KiB up to the body's size on every write
5673
+ * (D441: ~27 % of hub-main's busy time in msgpack decode, ~6 % in encode,
5674
+ * and the churn that fed a 29.5 % GC share).
5675
+ *
5676
+ * With the payload appended as the LAST key of the map, the receiver's
5677
+ * ordinary msgpack decode yields it as a zero-copy VIEW of the frame
5678
+ * (`@msgpack/msgpack` decodes `bin` as `subarray`), the router reads only the
5679
+ * envelope, and forwarding is: encode a ~60-byte head, write it, write the
5680
+ * view. The wire stays plain msgpack — a peer that never heard of payloads
5681
+ * decodes `{ …frame, pl: <bytes> }` and can be told, at register, not to be
5682
+ * sent one.
5683
+ *
5684
+ * ## The one hand-written msgpack in this repository
5685
+ *
5686
+ * `@msgpack/msgpack` has no "encode a map, then append a key" API, so the
5687
+ * envelope is encoded normally and its `fixmap` count byte is bumped by one
5688
+ * before the key and the `bin 32` header are appended. That patch is only
5689
+ * valid for a `fixmap` (≤ 15 keys); a `Frame` has at most four, and anything
5690
+ * else is refused rather than silently corrupted.
5691
+ */
5692
+ function encodeFrameHead(frame, payload) {
5693
+ const envelope = encode(frame, ENCODE_OPTIONS);
5694
+ const first = envelope[0];
5695
+ if (envelope.byteLength === 0 || first === void 0 || first < FIXMAP_BASE || first > 142) throw new Error(`encodeFrameHead: envelope must be a msgpack fixmap with at most ${FIXMAP_MAX_COUNT - 1} keys (got leading byte 0x${(first ?? 0).toString(16)})`);
5696
+ const bodyLength = envelope.byteLength + PAYLOAD_KEY_BYTES.byteLength + 5 + payload.byteLength;
5697
+ const head = Buffer.allocUnsafe(HEADER_BYTES + envelope.byteLength + PAYLOAD_KEY_BYTES.byteLength + 5);
5698
+ head.writeUInt32BE(bodyLength, 0);
5699
+ Buffer.from(envelope.buffer, envelope.byteOffset, envelope.byteLength).copy(head, HEADER_BYTES);
5700
+ head[HEADER_BYTES] = first + 1;
5701
+ let at = HEADER_BYTES + envelope.byteLength;
5702
+ PAYLOAD_KEY_BYTES.copy(head, at);
5703
+ at += PAYLOAD_KEY_BYTES.byteLength;
5704
+ head[at] = BIN32_MARKER;
5705
+ head.writeUInt32BE(payload.byteLength, at + 1);
5706
+ return head;
5707
+ }
5708
+ /**
5709
+ * Serialise a value into the bytes a payload carries. The SAME options as the
5710
+ * envelope codec, so `undefined` properties are omitted rather than turned
5711
+ * into `null` — a `z.void()` cap output must read back as `undefined` on the
5712
+ * far side exactly as it did when it travelled inline.
5713
+ */
5714
+ function packPayload(value) {
5715
+ return encode(value, ENCODE_OPTIONS);
5716
+ }
5717
+ /** Inverse of {@link packPayload}. A `bin` inside decodes as a view of `bytes`. */
5718
+ function unpackPayload(bytes) {
5719
+ return decode(bytes);
5720
+ }
5336
5721
  /** Bytes in the big-endian length prefix that opens every frame. */
5337
5722
  var HEADER_BYTES = 4;
5338
5723
  /**
@@ -5491,6 +5876,25 @@ function localEndpointPath(nodeId) {
5491
5876
  if (process.platform === "win32") return `\\\\.\\pipe\\camstack-${safe}`;
5492
5877
  return join(tmpdir(), `camstack-${safe}.sock`);
5493
5878
  }
5879
+ //#endregion
5880
+ //#region src/kernel/transport/local-transport.ts
5881
+ /**
5882
+ * An answer that carries an opaque payload beside its body.
5883
+ *
5884
+ * A CLASS rather than a shape so the channel can tell it from a provider's
5885
+ * ordinary `{ body, payload }` return value by identity, never by duck-typing:
5886
+ * a cap method is free to return an object with those two keys and it must
5887
+ * travel inline like any other. `request()` resolves with one of these only
5888
+ * when the peer's `res` frame carried a payload.
5889
+ */
5890
+ var PayloadReply = class {
5891
+ body;
5892
+ payload;
5893
+ constructor(body, payload) {
5894
+ this.body = body;
5895
+ this.payload = payload;
5896
+ }
5897
+ };
5494
5898
  var SocketChannel = class {
5495
5899
  socket;
5496
5900
  nextId = 1;
@@ -5547,7 +5951,7 @@ var SocketChannel = class {
5547
5951
  k: "req",
5548
5952
  id,
5549
5953
  body
5550
- });
5954
+ }, opts?.payload);
5551
5955
  });
5552
5956
  }
5553
5957
  emit(body) {
@@ -5587,11 +5991,38 @@ var SocketChannel = class {
5587
5991
  rx: sampleSocketDirection(this.rxCounters)
5588
5992
  };
5589
5993
  }
5590
- send(frame) {
5994
+ /**
5995
+ * Bytes handed to the socket that the kernel has not taken yet — the
5996
+ * `Writable` buffer plus the write in flight. Read LIVE, never cached: this
5997
+ * is the number that says whether the peer is draining what we write, and
5998
+ * it is read on every heartbeat probe (D446). An unref'd socket keeps it
5999
+ * exactly like a ref'd one, which is why it is read here and not summed
6000
+ * over `_getActiveHandles()`.
6001
+ */
6002
+ queuedBytes() {
6003
+ return this.socket.writableLength;
6004
+ }
6005
+ /**
6006
+ * Write one frame. With a payload the head and the tail are two `write`
6007
+ * calls under `cork()` — the kernel sees one `writev`, and the payload bytes
6008
+ * are never copied into the head. A forwarded payload is a view into the
6009
+ * frame it arrived on, and that frame's buffer is never mutated, so handing
6010
+ * the view to the socket is safe.
6011
+ */
6012
+ send(frame, payload) {
5591
6013
  if (this.closed) return;
5592
- const encoded = encodeFrame(frame);
5593
- recordSocketFrame(this.txCounters, frame.k, encoded.byteLength);
5594
- this.socket.write(encoded);
6014
+ if (payload === void 0) {
6015
+ const encoded = encodeFrame(frame);
6016
+ recordSocketFrame(this.txCounters, frame.k, encoded.byteLength);
6017
+ this.socket.write(encoded);
6018
+ return;
6019
+ }
6020
+ const head = encodeFrameHead(frame, payload);
6021
+ recordSocketFrame(this.txCounters, frame.k, head.byteLength + payload.byteLength);
6022
+ this.socket.cork();
6023
+ this.socket.write(head);
6024
+ this.socket.write(payload);
6025
+ this.socket.uncork();
5595
6026
  }
5596
6027
  onData(chunk) {
5597
6028
  const frames = this.decoder.push(chunk);
@@ -5611,8 +6042,14 @@ var SocketChannel = class {
5611
6042
  recordSocketFrame(this.rxCounters, frame.k, wireBytes);
5612
6043
  if (frame.k === "req") {
5613
6044
  try {
5614
- const result = await this.requestHandler(frame.body);
5615
- this.send({
6045
+ const result = await this.requestHandler(frame.body, frame.pl);
6046
+ if (result instanceof PayloadReply) this.send({
6047
+ k: "res",
6048
+ id: frame.id,
6049
+ ok: true,
6050
+ body: result.body
6051
+ }, result.payload);
6052
+ else this.send({
5616
6053
  k: "res",
5617
6054
  id: frame.id,
5618
6055
  ok: true,
@@ -5633,8 +6070,9 @@ var SocketChannel = class {
5633
6070
  if (!p) return;
5634
6071
  this.pending.delete(frame.id);
5635
6072
  if (p.timer !== null) clearTimeout(p.timer);
5636
- if (frame.ok) p.resolve(frame.body);
5637
- else p.reject(new Error(frame.err));
6073
+ if (!frame.ok) p.reject(new Error(frame.err));
6074
+ else if (frame.pl !== void 0) p.resolve(new PayloadReply(frame.body, frame.pl));
6075
+ else p.resolve(frame.body);
5638
6076
  return;
5639
6077
  }
5640
6078
  this.eventHandler(frame.body);
@@ -6185,572 +6623,162 @@ function deliverShared(state, event) {
6185
6623
  }
6186
6624
  }
6187
6625
  //#endregion
6188
- //#region src/kernel/moleculer/resilient-cap-call.ts
6189
- /** Moleculer error `type` values meaning "the service is not (yet) routable". */
6190
- var DISCOVERY_ERROR_TYPES = new Set(["SERVICE_NOT_FOUND", "SERVICE_NOT_AVAILABLE"]);
6191
- /** Default ceiling for the discovery wait — fail-fast past this. */
6192
- var DEFAULT_DISCOVERY_TIMEOUT_MS$1 = 3e4;
6193
- function isDiscoveryError(err) {
6194
- if (typeof err !== "object" || err === null) return false;
6195
- const type = err.type;
6196
- return typeof type === "string" && DISCOVERY_ERROR_TYPES.has(type);
6626
+ //#region src/kernel/transport/cap-routing-hints.ts
6627
+ /** Lift {@link CapRoutingHints} from a call's args. Never throws. */
6628
+ function liftRoutingHints(args) {
6629
+ if (args === null || typeof args !== "object" || Array.isArray(args)) return {};
6630
+ const nodeId = Reflect.get(args, "nodeId");
6631
+ const addonId = Reflect.get(args, "addonId");
6632
+ return {
6633
+ ...typeof nodeId === "string" && nodeId.length > 0 ? { nodeId } : {},
6634
+ ...typeof addonId === "string" && addonId.length > 0 ? { addonId } : {}
6635
+ };
6636
+ }
6637
+ //#endregion
6638
+ //#region src/kernel/transport/local-child-registry.ts
6639
+ function readFanoutMode() {
6640
+ const raw = process.env.CAMSTACK_UDS_EVENT_FANOUT;
6641
+ if (raw === "shadow" || raw === "broadcast") return raw;
6642
+ return "filter";
6197
6643
  }
6198
6644
  /**
6199
- * Call a Moleculer action; on a service-discovery error, wait for the
6200
- * named service to be discovered and retry the call exactly once.
6645
+ * Sentinel prefix used in the no-route error thrown when `cap-call-out` has no
6646
+ * local sibling and no `onUnownedCall` fallback. `ipcParentLink` detects this
6647
+ * prefix to distinguish routing failures (safe to retry via broker) from real
6648
+ * provider errors (must NOT retry to avoid double-executing side effects).
6201
6649
  */
6202
- async function callWithServiceDiscovery(broker, serviceName, action, params, opts, discoveryTimeoutMs = DEFAULT_DISCOVERY_TIMEOUT_MS$1) {
6203
- try {
6204
- return await broker.call(action, params, opts);
6205
- } catch (err) {
6206
- if (!isDiscoveryError(err)) throw err;
6207
- await broker.waitForServices([serviceName], discoveryTimeoutMs);
6208
- return await broker.call(action, params, opts);
6650
+ var UDS_NO_ROUTE_PREFIX = "UDS_NO_ROUTE";
6651
+ /**
6652
+ * Parent-side authority for local addon-runners reachable over a
6653
+ * `LocalTransportServer` (UDS). Children register their cap manifest on
6654
+ * connect; the registry routes `(capName, deviceId?)` cap calls to the
6655
+ * owning child over the channel and drops a child's caps on disconnect.
6656
+ */
6657
+ var LocalChildRegistry = class {
6658
+ children = /* @__PURE__ */ new Map();
6659
+ registeredHandler = () => {};
6660
+ goneHandler = () => {};
6661
+ /** Source of {@link RegisteredChild.incarnation}; one bump per accepted connection. */
6662
+ nextIncarnation = 1;
6663
+ eventHandler = null;
6664
+ logHandler = null;
6665
+ readinessHandler = null;
6666
+ server;
6667
+ onUnownedCall;
6668
+ logger;
6669
+ getActiveSingletonAddonId;
6670
+ resolveChildIdForAddon;
6671
+ /** This node's own Moleculer nodeId (see {@link LocalChildRegistryOptions.ownNodeId}). */
6672
+ ownNodeId;
6673
+ /** See {@link LocalChildRegistryOptions.isAggregatedCollectionMethod}. */
6674
+ isAggregatedCollectionMethod;
6675
+ isAddonPinnedCall;
6676
+ /** See {@link ForwardCensus}. Mutable counters on the hot path, by design. */
6677
+ forwardedRaw = 0;
6678
+ forwardedDecoded = 0;
6679
+ /** See {@link LocalChildRegistryOptions.capTimeoutMs}. */
6680
+ capTimeoutMs;
6681
+ /** See {@link LocalChildRegistryOptions.capUsageObserver}. */
6682
+ capUsageObserver;
6683
+ /** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
6684
+ egressRoutedCaps = /* @__PURE__ */ new Set();
6685
+ /** Active event fan-out mode, read once from `CAMSTACK_UDS_EVENT_FANOUT`. */
6686
+ fanoutMode = readFanoutMode();
6687
+ /** Per-child event fan-out counters (sent / suppressed). */
6688
+ childEventStats = /* @__PURE__ */ new Map();
6689
+ /** Last pattern-set string logged per child, to dedup the INFO line. */
6690
+ loggedPatternSet = /* @__PURE__ */ new Map();
6691
+ /**
6692
+ * Accepts either a plain positional `server` argument (backward-compatible)
6693
+ * or a full `LocalChildRegistryOptions` object.
6694
+ *
6695
+ * Positional overloads (existing call sites are unchanged):
6696
+ * new LocalChildRegistry(server)
6697
+ * new LocalChildRegistry(server, onUnownedCall)
6698
+ *
6699
+ * Options object (new call sites that pass a logger):
6700
+ * new LocalChildRegistry({ server, onUnownedCall, logger })
6701
+ */
6702
+ constructor(serverOrOptions, onUnownedCallArg) {
6703
+ if (serverOrOptions && !("listen" in serverOrOptions)) {
6704
+ const opts = serverOrOptions;
6705
+ this.server = opts.server;
6706
+ this.onUnownedCall = opts.onUnownedCall;
6707
+ this.logger = opts.logger;
6708
+ this.getActiveSingletonAddonId = opts.getActiveSingletonAddonId;
6709
+ this.resolveChildIdForAddon = opts.resolveChildIdForAddon;
6710
+ this.ownNodeId = opts.ownNodeId;
6711
+ this.isAggregatedCollectionMethod = opts.isAggregatedCollectionMethod;
6712
+ this.isAddonPinnedCall = opts.isAddonPinnedCall;
6713
+ this.capTimeoutMs = opts.capTimeoutMs;
6714
+ this.capUsageObserver = opts.capUsageObserver;
6715
+ } else {
6716
+ this.server = serverOrOptions;
6717
+ this.onUnownedCall = onUnownedCallArg;
6718
+ }
6719
+ }
6720
+ async start() {
6721
+ this.logger?.info("UDS event fan-out mode", { mode: this.fanoutMode });
6722
+ this.server.onConnection((channel) => this.onConnection(channel));
6723
+ await this.server.listen();
6209
6724
  }
6210
- }
6211
- //#endregion
6212
- //#region src/kernel/transport/cap-route.ts
6213
- function buildMessage(capName, method, detail) {
6214
- const call = method !== void 0 ? `${capName}.${method}` : capName;
6215
- const target = detail.nodeId !== void 0 ? ` to node ${detail.nodeId}` : "";
6216
- const rejectedStr = detail.rejected.map((r) => `${r.kind}=${r.why}`).join("; ");
6217
- const rejectedClause = rejectedStr.length > 0 ? ` (rejected: ${rejectedStr})` : "";
6218
- return `${call} not routable${target}: ${detail.reason}${rejectedClause}`;
6219
- }
6220
- var CapRouteError = class extends Error {
6221
- reason;
6222
- nodeId;
6223
- rejected;
6224
6725
  /**
6225
- * @param cause Optional original error that triggered this routing failure.
6226
- * Stored as `Error.cause` (TC39 standard option, Node 16.9+).
6227
- * Dispatchers wrapping transport errors MUST pass the original.
6726
+ * Per-child event fan-out counters (`{ sent, suppressed }`) or `null` if the
6727
+ * child has no recorded events yet. Exposed for the starvation-verification
6728
+ * surface (shadow burn-in + operator debug).
6228
6729
  */
6229
- constructor(capName, method, detail, cause) {
6230
- super(buildMessage(capName, method, detail), cause !== void 0 ? { cause } : void 0);
6231
- this.name = "CapRouteError";
6232
- this.reason = detail.reason;
6233
- this.nodeId = detail.nodeId;
6234
- this.rejected = detail.rejected;
6730
+ getChildEventStats(childId) {
6731
+ const s = this.childEventStats.get(childId);
6732
+ return s === void 0 ? null : {
6733
+ sent: s.sent,
6734
+ suppressed: s.suppressed
6735
+ };
6235
6736
  }
6236
- };
6237
- /**
6238
- * Classifies a (capName, opts) pair into a typed CapRoute dispatch descriptor.
6239
- *
6240
- * Precedence (explicit nodeId path):
6241
- * 1. hub-in-process — hub node + hubInProcessProvides
6242
- * 2. hub-local-uds — hub node + hubLocalChildProvides
6243
- * 3. node-offline → CapRouteError{reason:'node-offline'}
6244
- * 4. agent-child-forward — node is an agent AND nodeKnowsCap
6245
- * 5. remote-moleculer — any other online non-agent node
6246
- *
6247
- * Singleton path (no nodeId):
6248
- * 1. hub-in-process (hub provides in-process)
6249
- * 2. hub-local-uds (a hub-local UDS child provides it)
6250
- * 3. remote-moleculer (any online, non-hub node that knows it)
6251
- * 4. → CapRouteError{reason:'no-provider', rejected: all considered routes}
6252
- *
6253
- * PURE: no side effects, no async, no broker/registry imports.
6254
- */
6255
- function classifyCapRoute(capName, opts, snapshot) {
6256
- const rejected = [];
6257
- if (opts.nodeId !== void 0) return classifyExplicitNode(capName, opts.nodeId, opts.deviceId, snapshot, rejected);
6258
- return classifySingleton(capName, opts.deviceId, snapshot, rejected);
6259
- }
6260
- function classifyExplicitNode(capName, nodeId, deviceId, snap, rejected) {
6261
- if (nodeId === snap.hubNodeId) {
6262
- const residentProvides = snap.hubResidentProvides;
6263
- const providesOnHub = residentProvides ?? snap.hubInProcessProvides;
6264
- const getRef = residentProvides !== void 0 ? snap.getHubResidentProviderRef : snap.getInProcessProviderRef;
6265
- if (providesOnHub(capName)) {
6266
- const ref = getRef?.(capName) ?? null;
6267
- if (ref !== null) return {
6268
- kind: "hub-in-process",
6269
- capName,
6270
- ref
6271
- };
6272
- rejected.push({
6273
- kind: "hub-in-process",
6274
- why: "provider ref not available in snapshot"
6275
- });
6276
- throw new CapRouteError(capName, void 0, {
6277
- reason: "no-provider",
6278
- nodeId,
6279
- rejected
6280
- });
6281
- }
6282
- if (snap.hubLocalChildProvides(capName, deviceId)) {
6283
- const childId = snap.getHubLocalChildId?.(capName, deviceId) ?? null;
6284
- if (childId !== null) return {
6285
- kind: "hub-local-uds",
6286
- capName,
6287
- childId
6288
- };
6289
- rejected.push({
6290
- kind: "hub-local-uds",
6291
- why: "child id not resolvable from snapshot"
6292
- });
6293
- throw new CapRouteError(capName, void 0, {
6294
- reason: "no-provider",
6295
- nodeId,
6296
- rejected
6297
- });
6298
- }
6299
- rejected.push({
6300
- kind: "hub-in-process",
6301
- why: "hub does not provide this cap in-process"
6302
- });
6303
- rejected.push({
6304
- kind: "hub-local-uds",
6305
- why: "no hub-local child provides this cap"
6306
- });
6307
- throw new CapRouteError(capName, void 0, {
6308
- reason: "no-provider",
6309
- nodeId,
6310
- rejected
6311
- });
6312
- }
6313
- if (!snap.nodeOnline(nodeId)) {
6314
- rejected.push({
6315
- kind: "remote-moleculer",
6316
- why: `node ${nodeId} is offline`
6317
- });
6318
- throw new CapRouteError(capName, void 0, {
6319
- reason: "node-offline",
6320
- nodeId,
6321
- rejected
6322
- });
6737
+ /**
6738
+ * This child's socket traffic — bytes and messages, both directions, split by
6739
+ * frame kind — or `null` when the child is gone or its channel keeps no
6740
+ * counters (an in-process or test transport).
6741
+ *
6742
+ * The event counters above cover ONE kind of frame and, once surfaced on
6743
+ * 2026-08-29, accounted for 4% of hub-main's ~44 000 socket syscalls/s. This
6744
+ * is the same question asked of every frame the channel moves, and it is the
6745
+ * only per-peer attribution that exists: `/proc` reports one `rchar`/`wchar`
6746
+ * pair for the whole process and has no per-socket breakdown.
6747
+ */
6748
+ getChildSocketTraffic(childId) {
6749
+ const entry = this.children.get(childId);
6750
+ if (entry === void 0) return null;
6751
+ return entry.channel.readTraffic?.() ?? null;
6323
6752
  }
6324
- if (snap.nodeIsAgent(nodeId)) {
6325
- if (snap.nodeKnowsCap(nodeId, capName)) return {
6326
- kind: "agent-child-forward",
6327
- capName,
6328
- agentNodeId: nodeId,
6329
- childId: snap.getAgentChildId?.(nodeId, capName) ?? void 0
6330
- };
6331
- rejected.push({
6332
- kind: "agent-child-forward",
6333
- why: `agent ${nodeId} does not know cap ${capName}`
6334
- });
6335
- throw new CapRouteError(capName, void 0, {
6336
- reason: "no-provider",
6337
- nodeId,
6338
- rejected
6339
- });
6753
+ /**
6754
+ * Bytes this process has written to a child that the child has not yet
6755
+ * taken, live, or `null` when the channel keeps no such reading. Read on
6756
+ * every heartbeat probe (D446) — a child that stops draining is the shape
6757
+ * of an outbound-queue episode, and the number lives on the channel.
6758
+ */
6759
+ getChildQueuedBytes(childId) {
6760
+ const entry = this.children.get(childId);
6761
+ if (entry === void 0) return null;
6762
+ return entry.channel.queuedBytes?.() ?? null;
6340
6763
  }
6341
- return {
6342
- kind: "remote-moleculer",
6343
- capName,
6344
- nodeId
6345
- };
6346
- }
6347
- function classifySingleton(capName, deviceId, snap, rejected) {
6348
- if (snap.hubInProcessProvides(capName)) {
6349
- const ref = snap.getInProcessProviderRef?.(capName) ?? null;
6350
- if (ref !== null) return {
6351
- kind: "hub-in-process",
6352
- capName,
6353
- ref
6354
- };
6355
- rejected.push({
6356
- kind: "hub-in-process",
6357
- why: "provider ref not available in snapshot"
6358
- });
6359
- } else rejected.push({
6360
- kind: "hub-in-process",
6361
- why: "hub does not provide this cap in-process"
6362
- });
6363
- if (snap.hubLocalChildProvides(capName, deviceId)) {
6364
- const childId = snap.getHubLocalChildId?.(capName, deviceId) ?? null;
6365
- if (childId !== null) return {
6366
- kind: "hub-local-uds",
6367
- capName,
6368
- childId
6764
+ /** Cumulative {@link ForwardCensus} of this parent's `cap-call-out` routing. */
6765
+ readForwardCensus() {
6766
+ return {
6767
+ raw: this.forwardedRaw,
6768
+ decoded: this.forwardedDecoded
6369
6769
  };
6370
- rejected.push({
6371
- kind: "hub-local-uds",
6372
- why: "child id not resolvable from snapshot"
6373
- });
6374
- } else rejected.push({
6375
- kind: "hub-local-uds",
6376
- why: "no hub-local child provides this cap"
6377
- });
6378
- const knownNodes = snap.listKnownNodeIds?.() ?? [];
6379
- for (const nodeId of knownNodes) if (nodeId !== snap.hubNodeId && snap.nodeOnline(nodeId) && snap.nodeKnowsCap(nodeId, capName)) return {
6380
- kind: "remote-moleculer",
6381
- capName,
6382
- nodeId
6383
- };
6384
- rejected.push({
6385
- kind: "remote-moleculer",
6386
- why: "no online remote node knows this cap"
6387
- });
6388
- throw new CapRouteError(capName, void 0, {
6389
- reason: "no-provider",
6390
- rejected
6391
- });
6392
- }
6393
- //#endregion
6394
- //#region src/kernel/transport/cap-route-resolver.ts
6395
- /** The Moleculer service name that Task 6's agent registers. */
6396
- var AGENT_CAP_FWD_SERVICE = "$agent-cap-fwd";
6397
- /** The Moleculer action (service.action) for agent cap forwarding. */
6398
- var AGENT_CAP_FWD_ACTION = `${AGENT_CAP_FWD_SERVICE}.forward`;
6399
- /** Default timeout for remote Moleculer cap calls (ms). */
6400
- var REMOTE_CALL_TIMEOUT_MS = 6e4;
6401
- function extractDeviceId(args) {
6402
- if (args === null || typeof args !== "object") return void 0;
6403
- const raw = Reflect.get(args, "deviceId");
6404
- return typeof raw === "number" ? raw : void 0;
6405
- }
6406
- /**
6407
- * Extract an inline `nodeId` string from a cap call's args — the per-call node
6408
- * pin a forked addon expresses by carrying `nodeId` in the input (the SAME way
6409
- * device-scoped caps carry `deviceId`, and the way the generated cap-router on
6410
- * the hub already honours an inline pin). Mirrors {@link extractDeviceId}.
6411
- *
6412
- * This is the routing source for hub→remote-node EXECUTION pinning (e.g. the
6413
- * benchmark addon running a synthetic/decoder workload ON a chosen agent). The
6414
- * out-of-band `nodePin(op.context)` path does NOT survive the forked addon →
6415
- * hub UDS link chain, so `onUnownedCall` reads the inline pin instead. Provider
6416
- * methods that don't declare `nodeId` simply ignore the extra field (they
6417
- * destructure the fields they need); methods that DO declare it (e.g.
6418
- * `getEngineProvisioning({nodeId})`) still receive it unchanged.
6419
- */
6420
- function extractNodeId(args) {
6421
- if (args === null || typeof args !== "object") return void 0;
6422
- const raw = Reflect.get(args, "nodeId");
6423
- return typeof raw === "string" && raw.length > 0 ? raw : void 0;
6424
- }
6425
- /**
6426
- * Merge `callerAddonId` into `args` as an extra field — the SAME "provider
6427
- * destructures what it needs and ignores the rest" convention
6428
- * {@link extractNodeId} already relies on for the inline `nodeId` pin.
6429
- * `undefined` (the overwhelmingly common case: no caller hint, or the census
6430
- * consuming it is disarmed) returns `args` unchanged — no allocation. A
6431
- * non-object `args` (or `null`/array) is returned unchanged too: there is
6432
- * nowhere to attach an extra key without changing the payload's shape, and a
6433
- * provider taking a bare value never reads `callerAddonId` off it anyway.
6434
- */
6435
- function withCallerAddonId(args, callerAddonId) {
6436
- if (callerAddonId === void 0) return args;
6437
- if (args === null || typeof args !== "object" || Array.isArray(args)) return args;
6438
- return {
6439
- ...args,
6440
- callerAddonId
6441
- };
6442
- }
6443
- var CapRouteResolver = class {
6444
- hubNodeId;
6445
- broker;
6446
- hubLocalRegistry;
6447
- nodeAuthority;
6448
- inProcessProviders;
6449
- hubResidentProviders;
6450
- capTimeoutMs;
6451
- snapshot;
6452
- constructor(deps) {
6453
- this.hubNodeId = deps.hubNodeId;
6454
- this.broker = deps.broker;
6455
- this.hubLocalRegistry = deps.hubLocalRegistry;
6456
- this.nodeAuthority = deps.nodeAuthority;
6457
- this.inProcessProviders = deps.inProcessProviders;
6458
- this.hubResidentProviders = deps.hubResidentProviders;
6459
- this.capTimeoutMs = deps.capTimeoutMs;
6460
- this.snapshot = this.buildSnapshot();
6461
- }
6462
- /** Per-call RPC timeout: the cap method's declared override, else the default. */
6463
- callTimeout(capName, method) {
6464
- return this.capTimeoutMs?.(capName, method) ?? REMOTE_CALL_TIMEOUT_MS;
6465
- }
6466
- resolveCapRoute(capName, opts) {
6467
- return classifyCapRoute(capName, opts, this.snapshot);
6468
6770
  }
6469
6771
  /**
6470
- * Resolve the hub-local-uds route for a cap owned by a forked hub-local
6471
- * child, IGNORING any in-hub provider registered for the same cap name.
6472
- *
6473
- * `resolveCapRoute` gives Priority 1 to `hub-in-process`: when an in-hub
6474
- * provider (e.g. a wrapper) is registered for the cap, the route always
6475
- * classifies as `hub-in-process` and the hub-local-uds NATIVE child is never
6476
- * reached. That is correct for the generic dispatch path (the wrapper is the
6477
- * active provider), but WRONG for the native-cap fallback
6478
- * (`setNativeFallback`), whose contract is to reach the NATIVE provider in
6479
- * the forked vendor child so a wrapper can delegate to it. A wrapper cap
6480
- * with a forked native (today: `snapshot`) otherwise resolves to the wrapper
6481
- * itself, the native is never invoked, and the wrapper silently falls
6482
- * through to its secondary strategy.
6772
+ * The regime the counters above were produced under, read once from
6773
+ * `CAMSTACK_UDS_EVENT_FANOUT` at construction.
6483
6774
  *
6484
- * This method consults ONLY the hub-local-child authority
6485
- * (`hubLocalChildProvides` + `getHubLocalChildId`, both deviceId-aware), so
6486
- * it returns the native child route regardless of any in-process shadow.
6487
- * Returns null when no hub-local child owns `(capName, deviceId)` — the
6488
- * caller then falls through to its remote-resolution branch.
6775
+ * A suppressed count means "nothing WAS dropped" under `filter` and "nothing
6776
+ * WOULD have been dropped" under `shadow`. Those are different claims, and
6777
+ * until this getter existed the mode was invisible at runtime — the counters
6778
+ * were readable and the regime that produced them was not.
6489
6779
  */
6490
- resolveHubLocalUdsRoute(capName, deviceId) {
6491
- if (!this.snapshot.hubLocalChildProvides(capName, deviceId)) return null;
6492
- const childId = this.snapshot.getHubLocalChildId?.(capName, deviceId) ?? null;
6493
- if (childId === null) return null;
6494
- return {
6495
- kind: "hub-local-uds",
6496
- capName,
6497
- childId
6498
- };
6499
- }
6500
- /**
6501
- * @param addonId Optional out-of-band PROVIDER-selection hint (Task 7.5a):
6502
- * the addonId of the provider the CALLER already resolved (e.g.
6503
- * `buildCapCallFn`'s `deps.addonId` for a registered grouped-runner
6504
- * provider). Only meaningful for `agent-child-forward` — a `remote-moleculer`
6505
- * route already encodes the provider in its action name
6506
- * (`${addonId}.${cap}.${method}`, via `NodeCapAuthority.getAddonId`), and a
6507
- * `hub-local-uds` caller that already knows the addonId (`buildCapCallFn`)
6508
- * talks to `LocalChildRegistry.callCapOnChild` directly rather than through
6509
- * `dispatch`.
6510
- * @param callerAddonId Optional out-of-band CALLER-identity hint — the
6511
- * addon that ORIGINATED the call, distinct from `addonId` above (which
6512
- * names the resolved PROVIDER, not the caller). Set by
6513
- * `onUnownedCall` from `CapCallInput.callerAddonId`
6514
- * (`LocalChildRegistry` stamped it off the registered `childId`). Only
6515
- * the `hub-in-process` branch consumes it — merged into `args` so a
6516
- * diagnostic tool deep in that provider (e.g. device-manager's
6517
- * fleet-read census) can read it without every provider method changing
6518
- * signature, the same "extra field the provider destructures or
6519
- * ignores" convention `nodeId` already uses on this path.
6520
- */
6521
- async dispatch(route, method, args, addonId, callerAddonId) {
6522
- try {
6523
- return await this.dispatchInner(route, method, args, addonId, callerAddonId);
6524
- } catch (err) {
6525
- if (err instanceof CapRouteError) throw err;
6526
- const nodeId = this.routeNodeId(route);
6527
- const cause = err instanceof Error ? err : new Error(String(err));
6528
- throw new CapRouteError(route.capName, method, {
6529
- reason: "transport-failed",
6530
- nodeId,
6531
- rejected: [{
6532
- kind: route.kind,
6533
- why: cause.message
6534
- }]
6535
- }, cause);
6536
- }
6537
- }
6538
- /**
6539
- * Inner dispatch: may throw CapRouteError (validation failures) or arbitrary
6540
- * transport errors. The outer `dispatch` wraps non-CapRouteErrors.
6541
- */
6542
- async dispatchInner(route, method, args, addonId, callerAddonId) {
6543
- switch (route.kind) {
6544
- case "hub-in-process": return route.ref.invoke(method, withCallerAddonId(args, callerAddonId));
6545
- case "hub-local-uds": {
6546
- const registry = this.hubLocalRegistry;
6547
- if (registry === null) throw new CapRouteError(route.capName, method, {
6548
- reason: "no-provider",
6549
- rejected: [{
6550
- kind: "hub-local-uds",
6551
- why: "UDS registry not available"
6552
- }]
6553
- });
6554
- const deviceId = extractDeviceId(args);
6555
- const input = {
6556
- capName: route.capName,
6557
- method,
6558
- args,
6559
- ...deviceId !== void 0 ? { deviceId } : {}
6560
- };
6561
- return registry.callCapOnChild(route.childId, input);
6562
- }
6563
- case "remote-moleculer": {
6564
- const addonId = this.nodeAuthority.getAddonId(route.nodeId, route.capName);
6565
- if (addonId === null) throw new CapRouteError(route.capName, method, {
6566
- reason: "no-provider",
6567
- nodeId: route.nodeId,
6568
- rejected: [{
6569
- kind: "remote-moleculer",
6570
- why: `no addonId known for ${route.nodeId}/${route.capName}`
6571
- }]
6572
- });
6573
- const deviceId = extractDeviceId(args);
6574
- const isNative = this.nodeAuthority.isNativeCap(route.nodeId, route.capName, deviceId);
6575
- const action = capActionName(addonId, route.capName, method, isNative);
6576
- return callWithServiceDiscovery(this.broker, addonId, action, args, {
6577
- nodeID: route.nodeId,
6578
- timeout: this.callTimeout(route.capName, method)
6579
- });
6580
- }
6581
- case "agent-child-forward": {
6582
- const deviceId = extractDeviceId(args);
6583
- const params = {
6584
- capName: route.capName,
6585
- method,
6586
- args,
6587
- ...route.childId !== void 0 ? { childId: route.childId } : {},
6588
- ...deviceId !== void 0 ? { deviceId } : {},
6589
- ...addonId !== void 0 ? { addonId } : {}
6590
- };
6591
- return callWithServiceDiscovery(this.broker, AGENT_CAP_FWD_SERVICE, AGENT_CAP_FWD_ACTION, params, {
6592
- nodeID: route.agentNodeId,
6593
- timeout: this.callTimeout(route.capName, method)
6594
- });
6595
- }
6596
- }
6597
- }
6598
- buildSnapshot() {
6599
- const hubLocalRegistry = this.hubLocalRegistry;
6600
- const nodeAuthority = this.nodeAuthority;
6601
- const inProcessProviders = this.inProcessProviders;
6602
- const hubResidentProviders = this.hubResidentProviders;
6603
- return {
6604
- hubNodeId: this.hubNodeId,
6605
- hubInProcessProvides: (cap) => inProcessProviders(cap) !== null,
6606
- ...hubResidentProviders !== void 0 ? {
6607
- hubResidentProvides: (cap) => hubResidentProviders(cap) !== null,
6608
- getHubResidentProviderRef: (cap) => hubResidentProviders(cap)
6609
- } : {},
6610
- hubLocalChildProvides: (cap, deviceId) => hubLocalRegistry !== null && hubLocalRegistry.resolveChildId(cap, deviceId) !== null,
6611
- nodeKnowsCap: (nodeId, cap) => nodeAuthority.nodeKnowsCap(nodeId, cap),
6612
- nodeIsAgent: (nodeId) => nodeAuthority.nodeIsAgent(nodeId),
6613
- nodeOnline: (nodeId) => nodeAuthority.nodeOnline(nodeId),
6614
- listKnownNodeIds: () => nodeAuthority.listNodeIds(),
6615
- getInProcessProviderRef: (cap) => inProcessProviders(cap),
6616
- getHubLocalChildId: (cap, deviceId) => hubLocalRegistry !== null ? hubLocalRegistry.resolveChildId(cap, deviceId) : null,
6617
- getAgentChildId: (agentNodeId, cap) => nodeAuthority.getAgentChildId(agentNodeId, cap)
6618
- };
6619
- }
6620
- /** Extract a nodeId string from a route for error reporting, or undefined. */
6621
- routeNodeId(route) {
6622
- switch (route.kind) {
6623
- case "hub-in-process": return this.hubNodeId;
6624
- case "hub-local-uds": return `${this.hubNodeId}/${route.childId}`;
6625
- case "remote-moleculer": return route.nodeId;
6626
- case "agent-child-forward": return route.agentNodeId;
6627
- }
6628
- }
6629
- };
6630
- //#endregion
6631
- //#region src/kernel/transport/local-child-registry.ts
6632
- function readFanoutMode() {
6633
- const raw = process.env.CAMSTACK_UDS_EVENT_FANOUT;
6634
- if (raw === "shadow" || raw === "broadcast") return raw;
6635
- return "filter";
6636
- }
6637
- /**
6638
- * Sentinel prefix used in the no-route error thrown when `cap-call-out` has no
6639
- * local sibling and no `onUnownedCall` fallback. `ipcParentLink` detects this
6640
- * prefix to distinguish routing failures (safe to retry via broker) from real
6641
- * provider errors (must NOT retry to avoid double-executing side effects).
6642
- */
6643
- var UDS_NO_ROUTE_PREFIX = "UDS_NO_ROUTE";
6644
- /**
6645
- * Parent-side authority for local addon-runners reachable over a
6646
- * `LocalTransportServer` (UDS). Children register their cap manifest on
6647
- * connect; the registry routes `(capName, deviceId?)` cap calls to the
6648
- * owning child over the channel and drops a child's caps on disconnect.
6649
- */
6650
- var LocalChildRegistry = class {
6651
- children = /* @__PURE__ */ new Map();
6652
- registeredHandler = () => {};
6653
- goneHandler = () => {};
6654
- /** Source of {@link RegisteredChild.incarnation}; one bump per accepted connection. */
6655
- nextIncarnation = 1;
6656
- eventHandler = null;
6657
- logHandler = null;
6658
- readinessHandler = null;
6659
- server;
6660
- onUnownedCall;
6661
- logger;
6662
- getActiveSingletonAddonId;
6663
- resolveChildIdForAddon;
6664
- /** This node's own Moleculer nodeId (see {@link LocalChildRegistryOptions.ownNodeId}). */
6665
- ownNodeId;
6666
- /** See {@link LocalChildRegistryOptions.isAggregatedCollectionMethod}. */
6667
- isAggregatedCollectionMethod;
6668
- isAddonPinnedCall;
6669
- /** See {@link LocalChildRegistryOptions.capTimeoutMs}. */
6670
- capTimeoutMs;
6671
- /** See {@link LocalChildRegistryOptions.capUsageObserver}. */
6672
- capUsageObserver;
6673
- /** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
6674
- egressRoutedCaps = /* @__PURE__ */ new Set();
6675
- /** Active event fan-out mode, read once from `CAMSTACK_UDS_EVENT_FANOUT`. */
6676
- fanoutMode = readFanoutMode();
6677
- /** Per-child event fan-out counters (sent / suppressed). */
6678
- childEventStats = /* @__PURE__ */ new Map();
6679
- /** Last pattern-set string logged per child, to dedup the INFO line. */
6680
- loggedPatternSet = /* @__PURE__ */ new Map();
6681
- /**
6682
- * Accepts either a plain positional `server` argument (backward-compatible)
6683
- * or a full `LocalChildRegistryOptions` object.
6684
- *
6685
- * Positional overloads (existing call sites are unchanged):
6686
- * new LocalChildRegistry(server)
6687
- * new LocalChildRegistry(server, onUnownedCall)
6688
- *
6689
- * Options object (new call sites that pass a logger):
6690
- * new LocalChildRegistry({ server, onUnownedCall, logger })
6691
- */
6692
- constructor(serverOrOptions, onUnownedCallArg) {
6693
- if (serverOrOptions && !("listen" in serverOrOptions)) {
6694
- const opts = serverOrOptions;
6695
- this.server = opts.server;
6696
- this.onUnownedCall = opts.onUnownedCall;
6697
- this.logger = opts.logger;
6698
- this.getActiveSingletonAddonId = opts.getActiveSingletonAddonId;
6699
- this.resolveChildIdForAddon = opts.resolveChildIdForAddon;
6700
- this.ownNodeId = opts.ownNodeId;
6701
- this.isAggregatedCollectionMethod = opts.isAggregatedCollectionMethod;
6702
- this.isAddonPinnedCall = opts.isAddonPinnedCall;
6703
- this.capTimeoutMs = opts.capTimeoutMs;
6704
- this.capUsageObserver = opts.capUsageObserver;
6705
- } else {
6706
- this.server = serverOrOptions;
6707
- this.onUnownedCall = onUnownedCallArg;
6708
- }
6709
- }
6710
- async start() {
6711
- this.logger?.info("UDS event fan-out mode", { mode: this.fanoutMode });
6712
- this.server.onConnection((channel) => this.onConnection(channel));
6713
- await this.server.listen();
6714
- }
6715
- /**
6716
- * Per-child event fan-out counters (`{ sent, suppressed }`) or `null` if the
6717
- * child has no recorded events yet. Exposed for the starvation-verification
6718
- * surface (shadow burn-in + operator debug).
6719
- */
6720
- getChildEventStats(childId) {
6721
- const s = this.childEventStats.get(childId);
6722
- return s === void 0 ? null : {
6723
- sent: s.sent,
6724
- suppressed: s.suppressed
6725
- };
6726
- }
6727
- /**
6728
- * This child's socket traffic — bytes and messages, both directions, split by
6729
- * frame kind — or `null` when the child is gone or its channel keeps no
6730
- * counters (an in-process or test transport).
6731
- *
6732
- * The event counters above cover ONE kind of frame and, once surfaced on
6733
- * 2026-08-29, accounted for 4% of hub-main's ~44 000 socket syscalls/s. This
6734
- * is the same question asked of every frame the channel moves, and it is the
6735
- * only per-peer attribution that exists: `/proc` reports one `rchar`/`wchar`
6736
- * pair for the whole process and has no per-socket breakdown.
6737
- */
6738
- getChildSocketTraffic(childId) {
6739
- const entry = this.children.get(childId);
6740
- if (entry === void 0) return null;
6741
- return entry.channel.readTraffic?.() ?? null;
6742
- }
6743
- /**
6744
- * The regime the counters above were produced under, read once from
6745
- * `CAMSTACK_UDS_EVENT_FANOUT` at construction.
6746
- *
6747
- * A suppressed count means "nothing WAS dropped" under `filter` and "nothing
6748
- * WOULD have been dropped" under `shadow`. Those are different claims, and
6749
- * until this getter existed the mode was invisible at runtime — the counters
6750
- * were readable and the regime that produced them was not.
6751
- */
6752
- get eventFanoutMode() {
6753
- return this.fanoutMode;
6780
+ get eventFanoutMode() {
6781
+ return this.fanoutMode;
6754
6782
  }
6755
6783
  /**
6756
6784
  * Connected children that never declared a subscription pattern set.
@@ -7118,7 +7146,7 @@ var LocalChildRegistry = class {
7118
7146
  return;
7119
7147
  }
7120
7148
  });
7121
- channel.onRequest(async (body) => {
7149
+ channel.onRequest(async (body, payload) => {
7122
7150
  const msg = body;
7123
7151
  if (msg.kind === "register") {
7124
7152
  if (childId !== null && childId !== msg.childId) throw new Error(`child attempted to change identity from "${childId}" to "${msg.childId}"`);
@@ -7135,7 +7163,8 @@ var LocalChildRegistry = class {
7135
7163
  channel,
7136
7164
  caps: msg.caps,
7137
7165
  eventPatterns,
7138
- incarnation
7166
+ incarnation,
7167
+ rawForward: msg.rawForward === true
7139
7168
  });
7140
7169
  this.logPatternSet(msg.childId, eventPatterns);
7141
7170
  this.registeredHandler({
@@ -7144,23 +7173,28 @@ var LocalChildRegistry = class {
7144
7173
  incarnation,
7145
7174
  ...msg.customActions !== void 0 ? { customActions: msg.customActions } : {}
7146
7175
  });
7147
- return { ok: true };
7148
- }
7176
+ return {
7177
+ ok: true,
7178
+ rawForward: true
7179
+ };
7180
+ }
7149
7181
  if (msg.kind === "cap-call-out") {
7150
7182
  const out = msg;
7151
- const input = {
7183
+ const hints = out.hints ?? liftRoutingHints(out.args);
7184
+ const materialise = () => payload !== void 0 ? unpackPayload(payload) : out.args;
7185
+ const buildInput = () => ({
7152
7186
  capName: out.capName,
7153
7187
  method: out.method,
7154
- args: out.args,
7188
+ args: materialise(),
7155
7189
  ...out.deviceId !== void 0 ? { deviceId: out.deviceId } : {},
7156
7190
  ...out.nodeId !== void 0 ? { nodeId: out.nodeId } : {},
7157
7191
  ...out.native === true ? { native: true } : {},
7158
7192
  ...childId !== null ? { callerAddonId: childId } : {}
7159
- };
7160
- const pinnedNodeId = out.nodeId ?? extractNodeId(out.args);
7193
+ });
7194
+ const pinnedNodeId = out.nodeId ?? hints.nodeId;
7161
7195
  const pinTargetsThisNode = pinnedNodeId !== void 0 && this.ownNodeId !== void 0 && pinnedNodeId === this.ownNodeId;
7162
7196
  const aggregated = pinnedNodeId === void 0 && this.isAggregatedCollectionMethod?.(out.capName, out.method) === true;
7163
- const addonPinned = pinnedNodeId === void 0 && this.isAddonPinnedCall?.(out.capName, out.method, out.args) === true;
7197
+ const addonPinned = pinnedNodeId === void 0 && this.isAddonPinnedCall?.(out.capName, out.method, hints) === true;
7164
7198
  const target = !(out.native === true) && !aggregated && !addonPinned && (pinnedNodeId === void 0 || pinTargetsThisNode) ? this.resolveChildId(out.capName, out.deviceId) : null;
7165
7199
  this.recordCapUsage(childId, target, out.capName, out.method);
7166
7200
  if (target !== null) {
@@ -7168,9 +7202,27 @@ var LocalChildRegistry = class {
7168
7202
  this.egressRoutedCaps.add(out.capName);
7169
7203
  this.logger?.info("routed child egress over UDS", { capName: out.capName });
7170
7204
  }
7171
- return this.callCap(input);
7205
+ const entry = this.children.get(target);
7206
+ if (payload !== void 0 && entry !== void 0 && entry.rawForward) {
7207
+ this.forwardedRaw += 1;
7208
+ const forward = {
7209
+ kind: "cap-call",
7210
+ capName: out.capName,
7211
+ method: out.method,
7212
+ args: void 0,
7213
+ ...out.deviceId !== void 0 ? { deviceId: out.deviceId } : {}
7214
+ };
7215
+ const declared = this.capTimeoutMs?.(out.capName, out.method);
7216
+ return entry.channel.request(forward, {
7217
+ ...typeof declared === "number" ? { timeoutMs: declared } : {},
7218
+ payload
7219
+ });
7220
+ }
7221
+ this.forwardedDecoded += 1;
7222
+ return this.callCap(buildInput());
7172
7223
  }
7173
- if (this.onUnownedCall !== void 0) return this.onUnownedCall(input);
7224
+ this.forwardedDecoded += 1;
7225
+ if (this.onUnownedCall !== void 0) return this.onUnownedCall(buildInput());
7174
7226
  throw new Error(`${UDS_NO_ROUTE_PREFIX}: cap-call-out has no local provider for "${out.capName}" and no fallback`);
7175
7227
  }
7176
7228
  if (msg.kind === "readiness-request") return {
@@ -7200,6 +7252,11 @@ var LocalChildRegistry = class {
7200
7252
  };
7201
7253
  //#endregion
7202
7254
  //#region src/kernel/transport/local-child-client.ts
7255
+ /** Did the parent's `register` answer say it accepts payload-borne args? */
7256
+ function ackAcceptsRawForward(ack) {
7257
+ if (ack === null || typeof ack !== "object") return false;
7258
+ return ack.rawForward === true;
7259
+ }
7203
7260
  /**
7204
7261
  * Child side of the local UDS transport. Connects to its parent (hub or
7205
7262
  * agent), registers its cap manifest, and serves parent→child cap calls by
@@ -7255,6 +7312,13 @@ var LocalChildClient = class {
7255
7312
  latestCustomActions = null;
7256
7313
  /** Events and logs queued while the channel is not yet open. */
7257
7314
  pendingEmits = [];
7315
+ /**
7316
+ * Whether the parent acknowledged raw-forward at `register`. Until it has,
7317
+ * `callOut` sends args inline exactly as every child always did — a legacy
7318
+ * parent would decode a payload-borne call to `args: undefined` and run the
7319
+ * provider on nothing, silently. Re-read on every re-register.
7320
+ */
7321
+ parentRawForward = false;
7258
7322
  /** Handler for parent→child events. Registered via `onEvent`. */
7259
7323
  eventHandler = null;
7260
7324
  /**
@@ -7362,15 +7426,20 @@ var LocalChildClient = class {
7362
7426
  if (this.client !== null) throw new Error("LocalChildClient: already started — call close() first");
7363
7427
  const client = createLocalTransport().createClient(this.options.nodeId);
7364
7428
  const channel = await client.connect();
7365
- channel.onRequest(async (body) => {
7429
+ channel.onRequest(async (body, payload) => {
7366
7430
  const msg = body;
7367
- if (msg.kind === "cap-call") return this.options.dispatch({
7368
- capName: msg.capName,
7369
- method: msg.method,
7370
- args: msg.args,
7371
- ...msg.deviceId !== void 0 ? { deviceId: msg.deviceId } : {},
7372
- ...msg.addonId !== void 0 ? { addonId: msg.addonId } : {}
7373
- });
7431
+ if (msg.kind === "cap-call") {
7432
+ const args = payload !== void 0 ? unpackPayload(payload) : msg.args;
7433
+ const result = await this.options.dispatch({
7434
+ capName: msg.capName,
7435
+ method: msg.method,
7436
+ args,
7437
+ ...msg.deviceId !== void 0 ? { deviceId: msg.deviceId } : {},
7438
+ ...msg.addonId !== void 0 ? { addonId: msg.addonId } : {}
7439
+ });
7440
+ if (payload !== void 0 && result !== void 0) return new PayloadReply(void 0, packPayload(result));
7441
+ return result;
7442
+ }
7374
7443
  if (msg.kind === "addon-call") {
7375
7444
  if (this.addonCallHandler === null) throw new Error(`LocalChildClient: addon-call for "${msg.addonId}" arrived but no onAddonCall handler is registered`);
7376
7445
  return this.addonCallHandler({
@@ -7394,7 +7463,7 @@ var LocalChildClient = class {
7394
7463
  });
7395
7464
  const register = this.registerFrame(this.latestCaps);
7396
7465
  try {
7397
- await channel.request(register);
7466
+ this.parentRawForward = ackAcceptsRawForward(await channel.request(register));
7398
7467
  } catch (err) {
7399
7468
  await client.close();
7400
7469
  throw err;
@@ -7404,105 +7473,564 @@ var LocalChildClient = class {
7404
7473
  this.flushPending(channel);
7405
7474
  for (const cb of this.connectedHandlers) cb();
7406
7475
  }
7407
- /** Flush buffered pre-start emits over the now-open channel. */
7408
- flushPending(channel) {
7409
- for (const item of this.pendingEmits) channel.emit(item.msg);
7410
- this.pendingEmits.length = 0;
7476
+ /** Flush buffered pre-start emits over the now-open channel. */
7477
+ flushPending(channel) {
7478
+ for (const item of this.pendingEmits) channel.emit(item.msg);
7479
+ this.pendingEmits.length = 0;
7480
+ }
7481
+ /**
7482
+ * Re-send the cap manifest to the parent, atomically replacing the child's
7483
+ * registered descriptor set. Call this after device-restore so newly
7484
+ * registered native (device-scoped) caps become routable over UDS.
7485
+ *
7486
+ * Safe to call before `start()`: the new set is buffered and `start()` sends
7487
+ * it (device-restore can race ahead of the UDS connect). After `start()`,
7488
+ * the set is sent immediately.
7489
+ */
7490
+ async updateCaps(caps, customActions) {
7491
+ this.latestCaps = caps;
7492
+ if (customActions !== void 0) this.latestCustomActions = customActions;
7493
+ if (this.channel === null) return;
7494
+ this.parentRawForward = ackAcceptsRawForward(await this.channel.request(this.registerFrame(caps)));
7495
+ }
7496
+ /**
7497
+ * The register frame: caps, plus everything a re-register must atomically
7498
+ * re-carry so no separate re-sync can be missed — the subscription union
7499
+ * (omitted if nothing ever declared, which keeps the fail-open shape) and the
7500
+ * custom-action catalogs (omitted until the init loop produced them).
7501
+ */
7502
+ registerFrame(caps) {
7503
+ return {
7504
+ kind: "register",
7505
+ childId: this.options.childId,
7506
+ caps,
7507
+ ...this.hasDeclaredEventPatterns ? { eventPatterns: this.latestEventPatterns } : {},
7508
+ ...this.latestCustomActions !== null ? { customActions: this.latestCustomActions } : {},
7509
+ rawForward: true
7510
+ };
7511
+ }
7512
+ /**
7513
+ * Fire-and-forget: send a system event to the parent for forwarding to the
7514
+ * hub event bus. Safe to call before `start()` — events are buffered and
7515
+ * flushed on connect.
7516
+ */
7517
+ emitEvent(event) {
7518
+ const msg = {
7519
+ kind: "event",
7520
+ event
7521
+ };
7522
+ if (this.channel !== null) this.channel.emit(msg);
7523
+ else this.pendingEmits.push({
7524
+ kind: "event",
7525
+ msg
7526
+ });
7527
+ }
7528
+ /**
7529
+ * Fire-and-forget: send a structured log entry to the parent. Safe to call
7530
+ * before `start()` — log entries are buffered and flushed on connect.
7531
+ */
7532
+ sendLog(entry) {
7533
+ const msg = {
7534
+ kind: "log",
7535
+ ...entry
7536
+ };
7537
+ if (this.channel !== null) this.channel.emit(msg);
7538
+ else this.pendingEmits.push({
7539
+ kind: "log",
7540
+ msg
7541
+ });
7542
+ }
7543
+ /**
7544
+ * Request the current readiness snapshot from the parent. Returns the
7545
+ * authoritative set of `IReadinessRegistryRecord` entries the hub holds.
7546
+ * Requires `start()` to have been called; throws with a clear message if not.
7547
+ */
7548
+ async requestReadinessSnapshot() {
7549
+ if (this.channel === null) throw new Error("LocalChildClient: requestReadinessSnapshot called before start()");
7550
+ return (await this.channel.request({ kind: "readiness-request" })).records;
7551
+ }
7552
+ /**
7553
+ * Ask the parent to execute a cap call this child does NOT own. The parent
7554
+ * routes to the owning local sibling over UDS, or — if no sibling owns it —
7555
+ * to its `onUnownedCall` fallback (the cluster CapabilityRegistry in
7556
+ * production). Throws if called before `start()`.
7557
+ */
7558
+ async callOut(input) {
7559
+ if (this.channel === null) throw new Error("LocalChildClient: callOut before start");
7560
+ const routing = {
7561
+ ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
7562
+ ...input.nodeId !== void 0 ? { nodeId: input.nodeId } : {},
7563
+ ...input.native === true ? { native: true } : {}
7564
+ };
7565
+ if (this.parentRawForward && input.args !== void 0) {
7566
+ const hints = liftRoutingHints(input.args);
7567
+ const msg = {
7568
+ kind: "cap-call-out",
7569
+ capName: input.capName,
7570
+ method: input.method,
7571
+ ...Object.keys(hints).length > 0 ? { hints } : {},
7572
+ ...routing
7573
+ };
7574
+ const reply = await this.channel.request(msg, { payload: packPayload(input.args) });
7575
+ return reply instanceof PayloadReply ? unpackPayload(reply.payload) : reply;
7576
+ }
7577
+ const msg = {
7578
+ kind: "cap-call-out",
7579
+ capName: input.capName,
7580
+ method: input.method,
7581
+ args: input.args,
7582
+ ...routing
7583
+ };
7584
+ return this.channel.request(msg);
7585
+ }
7586
+ /** Disconnect from the parent. Safe to call before `start()` (no-op) and idempotent. */
7587
+ async close() {
7588
+ await this.client?.close();
7589
+ this.client = null;
7590
+ this.channel = null;
7591
+ }
7592
+ };
7593
+ //#endregion
7594
+ //#region src/kernel/transport/cap-route.ts
7595
+ function buildMessage(capName, method, detail) {
7596
+ const call = method !== void 0 ? `${capName}.${method}` : capName;
7597
+ const target = detail.nodeId !== void 0 ? ` to node ${detail.nodeId}` : "";
7598
+ const rejectedStr = detail.rejected.map((r) => `${r.kind}=${r.why}`).join("; ");
7599
+ const rejectedClause = rejectedStr.length > 0 ? ` (rejected: ${rejectedStr})` : "";
7600
+ return `${call} not routable${target}: ${detail.reason}${rejectedClause}`;
7601
+ }
7602
+ var CapRouteError = class extends Error {
7603
+ reason;
7604
+ nodeId;
7605
+ rejected;
7606
+ /**
7607
+ * @param cause Optional original error that triggered this routing failure.
7608
+ * Stored as `Error.cause` (TC39 standard option, Node 16.9+).
7609
+ * Dispatchers wrapping transport errors MUST pass the original.
7610
+ */
7611
+ constructor(capName, method, detail, cause) {
7612
+ super(buildMessage(capName, method, detail), cause !== void 0 ? { cause } : void 0);
7613
+ this.name = "CapRouteError";
7614
+ this.reason = detail.reason;
7615
+ this.nodeId = detail.nodeId;
7616
+ this.rejected = detail.rejected;
7617
+ }
7618
+ };
7619
+ /**
7620
+ * Classifies a (capName, opts) pair into a typed CapRoute dispatch descriptor.
7621
+ *
7622
+ * Precedence (explicit nodeId path):
7623
+ * 1. hub-in-process — hub node + hubInProcessProvides
7624
+ * 2. hub-local-uds — hub node + hubLocalChildProvides
7625
+ * 3. node-offline → CapRouteError{reason:'node-offline'}
7626
+ * 4. agent-child-forward — node is an agent AND nodeKnowsCap
7627
+ * 5. remote-moleculer — any other online non-agent node
7628
+ *
7629
+ * Singleton path (no nodeId):
7630
+ * 1. hub-in-process (hub provides in-process)
7631
+ * 2. hub-local-uds (a hub-local UDS child provides it)
7632
+ * 3. remote-moleculer (any online, non-hub node that knows it)
7633
+ * 4. → CapRouteError{reason:'no-provider', rejected: all considered routes}
7634
+ *
7635
+ * PURE: no side effects, no async, no broker/registry imports.
7636
+ */
7637
+ function classifyCapRoute(capName, opts, snapshot) {
7638
+ const rejected = [];
7639
+ if (opts.nodeId !== void 0) return classifyExplicitNode(capName, opts.nodeId, opts.deviceId, snapshot, rejected);
7640
+ return classifySingleton(capName, opts.deviceId, snapshot, rejected);
7641
+ }
7642
+ function classifyExplicitNode(capName, nodeId, deviceId, snap, rejected) {
7643
+ if (nodeId === snap.hubNodeId) {
7644
+ const residentProvides = snap.hubResidentProvides;
7645
+ const providesOnHub = residentProvides ?? snap.hubInProcessProvides;
7646
+ const getRef = residentProvides !== void 0 ? snap.getHubResidentProviderRef : snap.getInProcessProviderRef;
7647
+ if (providesOnHub(capName)) {
7648
+ const ref = getRef?.(capName) ?? null;
7649
+ if (ref !== null) return {
7650
+ kind: "hub-in-process",
7651
+ capName,
7652
+ ref
7653
+ };
7654
+ rejected.push({
7655
+ kind: "hub-in-process",
7656
+ why: "provider ref not available in snapshot"
7657
+ });
7658
+ throw new CapRouteError(capName, void 0, {
7659
+ reason: "no-provider",
7660
+ nodeId,
7661
+ rejected
7662
+ });
7663
+ }
7664
+ if (snap.hubLocalChildProvides(capName, deviceId)) {
7665
+ const childId = snap.getHubLocalChildId?.(capName, deviceId) ?? null;
7666
+ if (childId !== null) return {
7667
+ kind: "hub-local-uds",
7668
+ capName,
7669
+ childId
7670
+ };
7671
+ rejected.push({
7672
+ kind: "hub-local-uds",
7673
+ why: "child id not resolvable from snapshot"
7674
+ });
7675
+ throw new CapRouteError(capName, void 0, {
7676
+ reason: "no-provider",
7677
+ nodeId,
7678
+ rejected
7679
+ });
7680
+ }
7681
+ rejected.push({
7682
+ kind: "hub-in-process",
7683
+ why: "hub does not provide this cap in-process"
7684
+ });
7685
+ rejected.push({
7686
+ kind: "hub-local-uds",
7687
+ why: "no hub-local child provides this cap"
7688
+ });
7689
+ throw new CapRouteError(capName, void 0, {
7690
+ reason: "no-provider",
7691
+ nodeId,
7692
+ rejected
7693
+ });
7694
+ }
7695
+ if (!snap.nodeOnline(nodeId)) {
7696
+ rejected.push({
7697
+ kind: "remote-moleculer",
7698
+ why: `node ${nodeId} is offline`
7699
+ });
7700
+ throw new CapRouteError(capName, void 0, {
7701
+ reason: "node-offline",
7702
+ nodeId,
7703
+ rejected
7704
+ });
7705
+ }
7706
+ if (snap.nodeIsAgent(nodeId)) {
7707
+ if (snap.nodeKnowsCap(nodeId, capName)) return {
7708
+ kind: "agent-child-forward",
7709
+ capName,
7710
+ agentNodeId: nodeId,
7711
+ childId: snap.getAgentChildId?.(nodeId, capName) ?? void 0
7712
+ };
7713
+ rejected.push({
7714
+ kind: "agent-child-forward",
7715
+ why: `agent ${nodeId} does not know cap ${capName}`
7716
+ });
7717
+ throw new CapRouteError(capName, void 0, {
7718
+ reason: "no-provider",
7719
+ nodeId,
7720
+ rejected
7721
+ });
7722
+ }
7723
+ return {
7724
+ kind: "remote-moleculer",
7725
+ capName,
7726
+ nodeId
7727
+ };
7728
+ }
7729
+ function classifySingleton(capName, deviceId, snap, rejected) {
7730
+ if (snap.hubInProcessProvides(capName)) {
7731
+ const ref = snap.getInProcessProviderRef?.(capName) ?? null;
7732
+ if (ref !== null) return {
7733
+ kind: "hub-in-process",
7734
+ capName,
7735
+ ref
7736
+ };
7737
+ rejected.push({
7738
+ kind: "hub-in-process",
7739
+ why: "provider ref not available in snapshot"
7740
+ });
7741
+ } else rejected.push({
7742
+ kind: "hub-in-process",
7743
+ why: "hub does not provide this cap in-process"
7744
+ });
7745
+ if (snap.hubLocalChildProvides(capName, deviceId)) {
7746
+ const childId = snap.getHubLocalChildId?.(capName, deviceId) ?? null;
7747
+ if (childId !== null) return {
7748
+ kind: "hub-local-uds",
7749
+ capName,
7750
+ childId
7751
+ };
7752
+ rejected.push({
7753
+ kind: "hub-local-uds",
7754
+ why: "child id not resolvable from snapshot"
7755
+ });
7756
+ } else rejected.push({
7757
+ kind: "hub-local-uds",
7758
+ why: "no hub-local child provides this cap"
7759
+ });
7760
+ const knownNodes = snap.listKnownNodeIds?.() ?? [];
7761
+ for (const nodeId of knownNodes) if (nodeId !== snap.hubNodeId && snap.nodeOnline(nodeId) && snap.nodeKnowsCap(nodeId, capName)) return {
7762
+ kind: "remote-moleculer",
7763
+ capName,
7764
+ nodeId
7765
+ };
7766
+ rejected.push({
7767
+ kind: "remote-moleculer",
7768
+ why: "no online remote node knows this cap"
7769
+ });
7770
+ throw new CapRouteError(capName, void 0, {
7771
+ reason: "no-provider",
7772
+ rejected
7773
+ });
7774
+ }
7775
+ //#endregion
7776
+ //#region src/kernel/moleculer/resilient-cap-call.ts
7777
+ /** Moleculer error `type` values meaning "the service is not (yet) routable". */
7778
+ var DISCOVERY_ERROR_TYPES = new Set(["SERVICE_NOT_FOUND", "SERVICE_NOT_AVAILABLE"]);
7779
+ /** Default ceiling for the discovery wait — fail-fast past this. */
7780
+ var DEFAULT_DISCOVERY_TIMEOUT_MS$1 = 3e4;
7781
+ function isDiscoveryError(err) {
7782
+ if (typeof err !== "object" || err === null) return false;
7783
+ const type = err.type;
7784
+ return typeof type === "string" && DISCOVERY_ERROR_TYPES.has(type);
7785
+ }
7786
+ /**
7787
+ * Call a Moleculer action; on a service-discovery error, wait for the
7788
+ * named service to be discovered and retry the call exactly once.
7789
+ */
7790
+ async function callWithServiceDiscovery(broker, serviceName, action, params, opts, discoveryTimeoutMs = DEFAULT_DISCOVERY_TIMEOUT_MS$1) {
7791
+ try {
7792
+ return await broker.call(action, params, opts);
7793
+ } catch (err) {
7794
+ if (!isDiscoveryError(err)) throw err;
7795
+ await broker.waitForServices([serviceName], discoveryTimeoutMs);
7796
+ return await broker.call(action, params, opts);
7797
+ }
7798
+ }
7799
+ //#endregion
7800
+ //#region src/kernel/transport/cap-route-resolver.ts
7801
+ /** The Moleculer service name that Task 6's agent registers. */
7802
+ var AGENT_CAP_FWD_SERVICE = "$agent-cap-fwd";
7803
+ /** The Moleculer action (service.action) for agent cap forwarding. */
7804
+ var AGENT_CAP_FWD_ACTION = `${AGENT_CAP_FWD_SERVICE}.forward`;
7805
+ /** Default timeout for remote Moleculer cap calls (ms). */
7806
+ var REMOTE_CALL_TIMEOUT_MS = 6e4;
7807
+ function extractDeviceId(args) {
7808
+ if (args === null || typeof args !== "object") return void 0;
7809
+ const raw = Reflect.get(args, "deviceId");
7810
+ return typeof raw === "number" ? raw : void 0;
7811
+ }
7812
+ /**
7813
+ * Extract an inline `nodeId` string from a cap call's args — the per-call node
7814
+ * pin a forked addon expresses by carrying `nodeId` in the input (the SAME way
7815
+ * device-scoped caps carry `deviceId`, and the way the generated cap-router on
7816
+ * the hub already honours an inline pin). Mirrors {@link extractDeviceId}.
7817
+ *
7818
+ * This is the routing source for hub→remote-node EXECUTION pinning (e.g. the
7819
+ * benchmark addon running a synthetic/decoder workload ON a chosen agent). The
7820
+ * out-of-band `nodePin(op.context)` path does NOT survive the forked addon →
7821
+ * hub UDS link chain, so `onUnownedCall` reads the inline pin instead. Provider
7822
+ * methods that don't declare `nodeId` simply ignore the extra field (they
7823
+ * destructure the fields they need); methods that DO declare it (e.g.
7824
+ * `getEngineProvisioning({nodeId})`) still receive it unchanged.
7825
+ */
7826
+ function extractNodeId(args) {
7827
+ if (args === null || typeof args !== "object") return void 0;
7828
+ const raw = Reflect.get(args, "nodeId");
7829
+ return typeof raw === "string" && raw.length > 0 ? raw : void 0;
7830
+ }
7831
+ /**
7832
+ * Merge `callerAddonId` into `args` as an extra field — the SAME "provider
7833
+ * destructures what it needs and ignores the rest" convention
7834
+ * {@link extractNodeId} already relies on for the inline `nodeId` pin.
7835
+ * `undefined` (the overwhelmingly common case: no caller hint, or the census
7836
+ * consuming it is disarmed) returns `args` unchanged — no allocation. A
7837
+ * non-object `args` (or `null`/array) is returned unchanged too: there is
7838
+ * nowhere to attach an extra key without changing the payload's shape, and a
7839
+ * provider taking a bare value never reads `callerAddonId` off it anyway.
7840
+ */
7841
+ function withCallerAddonId(args, callerAddonId) {
7842
+ if (callerAddonId === void 0) return args;
7843
+ if (args === null || typeof args !== "object" || Array.isArray(args)) return args;
7844
+ return {
7845
+ ...args,
7846
+ callerAddonId
7847
+ };
7848
+ }
7849
+ var CapRouteResolver = class {
7850
+ hubNodeId;
7851
+ broker;
7852
+ hubLocalRegistry;
7853
+ nodeAuthority;
7854
+ inProcessProviders;
7855
+ hubResidentProviders;
7856
+ capTimeoutMs;
7857
+ snapshot;
7858
+ constructor(deps) {
7859
+ this.hubNodeId = deps.hubNodeId;
7860
+ this.broker = deps.broker;
7861
+ this.hubLocalRegistry = deps.hubLocalRegistry;
7862
+ this.nodeAuthority = deps.nodeAuthority;
7863
+ this.inProcessProviders = deps.inProcessProviders;
7864
+ this.hubResidentProviders = deps.hubResidentProviders;
7865
+ this.capTimeoutMs = deps.capTimeoutMs;
7866
+ this.snapshot = this.buildSnapshot();
7867
+ }
7868
+ /** Per-call RPC timeout: the cap method's declared override, else the default. */
7869
+ callTimeout(capName, method) {
7870
+ return this.capTimeoutMs?.(capName, method) ?? REMOTE_CALL_TIMEOUT_MS;
7411
7871
  }
7412
- /**
7413
- * Re-send the cap manifest to the parent, atomically replacing the child's
7414
- * registered descriptor set. Call this after device-restore so newly
7415
- * registered native (device-scoped) caps become routable over UDS.
7416
- *
7417
- * Safe to call before `start()`: the new set is buffered and `start()` sends
7418
- * it (device-restore can race ahead of the UDS connect). After `start()`,
7419
- * the set is sent immediately.
7420
- */
7421
- async updateCaps(caps, customActions) {
7422
- this.latestCaps = caps;
7423
- if (customActions !== void 0) this.latestCustomActions = customActions;
7424
- if (this.channel === null) return;
7425
- await this.channel.request(this.registerFrame(caps));
7872
+ resolveCapRoute(capName, opts) {
7873
+ return classifyCapRoute(capName, opts, this.snapshot);
7426
7874
  }
7427
7875
  /**
7428
- * The register frame: caps, plus everything a re-register must atomically
7429
- * re-carry so no separate re-sync can be missed — the subscription union
7430
- * (omitted if nothing ever declared, which keeps the fail-open shape) and the
7431
- * custom-action catalogs (omitted until the init loop produced them).
7876
+ * Resolve the hub-local-uds route for a cap owned by a forked hub-local
7877
+ * child, IGNORING any in-hub provider registered for the same cap name.
7878
+ *
7879
+ * `resolveCapRoute` gives Priority 1 to `hub-in-process`: when an in-hub
7880
+ * provider (e.g. a wrapper) is registered for the cap, the route always
7881
+ * classifies as `hub-in-process` and the hub-local-uds NATIVE child is never
7882
+ * reached. That is correct for the generic dispatch path (the wrapper is the
7883
+ * active provider), but WRONG for the native-cap fallback
7884
+ * (`setNativeFallback`), whose contract is to reach the NATIVE provider in
7885
+ * the forked vendor child so a wrapper can delegate to it. A wrapper cap
7886
+ * with a forked native (today: `snapshot`) otherwise resolves to the wrapper
7887
+ * itself, the native is never invoked, and the wrapper silently falls
7888
+ * through to its secondary strategy.
7889
+ *
7890
+ * This method consults ONLY the hub-local-child authority
7891
+ * (`hubLocalChildProvides` + `getHubLocalChildId`, both deviceId-aware), so
7892
+ * it returns the native child route regardless of any in-process shadow.
7893
+ * Returns null when no hub-local child owns `(capName, deviceId)` — the
7894
+ * caller then falls through to its remote-resolution branch.
7432
7895
  */
7433
- registerFrame(caps) {
7896
+ resolveHubLocalUdsRoute(capName, deviceId) {
7897
+ if (!this.snapshot.hubLocalChildProvides(capName, deviceId)) return null;
7898
+ const childId = this.snapshot.getHubLocalChildId?.(capName, deviceId) ?? null;
7899
+ if (childId === null) return null;
7434
7900
  return {
7435
- kind: "register",
7436
- childId: this.options.childId,
7437
- caps,
7438
- ...this.hasDeclaredEventPatterns ? { eventPatterns: this.latestEventPatterns } : {},
7439
- ...this.latestCustomActions !== null ? { customActions: this.latestCustomActions } : {}
7440
- };
7441
- }
7442
- /**
7443
- * Fire-and-forget: send a system event to the parent for forwarding to the
7444
- * hub event bus. Safe to call before `start()` — events are buffered and
7445
- * flushed on connect.
7446
- */
7447
- emitEvent(event) {
7448
- const msg = {
7449
- kind: "event",
7450
- event
7901
+ kind: "hub-local-uds",
7902
+ capName,
7903
+ childId
7451
7904
  };
7452
- if (this.channel !== null) this.channel.emit(msg);
7453
- else this.pendingEmits.push({
7454
- kind: "event",
7455
- msg
7456
- });
7457
7905
  }
7458
7906
  /**
7459
- * Fire-and-forget: send a structured log entry to the parent. Safe to call
7460
- * before `start()` — log entries are buffered and flushed on connect.
7907
+ * @param addonId Optional out-of-band PROVIDER-selection hint (Task 7.5a):
7908
+ * the addonId of the provider the CALLER already resolved (e.g.
7909
+ * `buildCapCallFn`'s `deps.addonId` for a registered grouped-runner
7910
+ * provider). Only meaningful for `agent-child-forward` — a `remote-moleculer`
7911
+ * route already encodes the provider in its action name
7912
+ * (`${addonId}.${cap}.${method}`, via `NodeCapAuthority.getAddonId`), and a
7913
+ * `hub-local-uds` caller that already knows the addonId (`buildCapCallFn`)
7914
+ * talks to `LocalChildRegistry.callCapOnChild` directly rather than through
7915
+ * `dispatch`.
7916
+ * @param callerAddonId Optional out-of-band CALLER-identity hint — the
7917
+ * addon that ORIGINATED the call, distinct from `addonId` above (which
7918
+ * names the resolved PROVIDER, not the caller). Set by
7919
+ * `onUnownedCall` from `CapCallInput.callerAddonId`
7920
+ * (`LocalChildRegistry` stamped it off the registered `childId`). Only
7921
+ * the `hub-in-process` branch consumes it — merged into `args` so a
7922
+ * diagnostic tool deep in that provider (e.g. device-manager's
7923
+ * fleet-read census) can read it without every provider method changing
7924
+ * signature, the same "extra field the provider destructures or
7925
+ * ignores" convention `nodeId` already uses on this path.
7461
7926
  */
7462
- sendLog(entry) {
7463
- const msg = {
7464
- kind: "log",
7465
- ...entry
7466
- };
7467
- if (this.channel !== null) this.channel.emit(msg);
7468
- else this.pendingEmits.push({
7469
- kind: "log",
7470
- msg
7471
- });
7927
+ async dispatch(route, method, args, addonId, callerAddonId) {
7928
+ try {
7929
+ return await this.dispatchInner(route, method, args, addonId, callerAddonId);
7930
+ } catch (err) {
7931
+ if (err instanceof CapRouteError) throw err;
7932
+ const nodeId = this.routeNodeId(route);
7933
+ const cause = err instanceof Error ? err : new Error(String(err));
7934
+ throw new CapRouteError(route.capName, method, {
7935
+ reason: "transport-failed",
7936
+ nodeId,
7937
+ rejected: [{
7938
+ kind: route.kind,
7939
+ why: cause.message
7940
+ }]
7941
+ }, cause);
7942
+ }
7472
7943
  }
7473
7944
  /**
7474
- * Request the current readiness snapshot from the parent. Returns the
7475
- * authoritative set of `IReadinessRegistryRecord` entries the hub holds.
7476
- * Requires `start()` to have been called; throws with a clear message if not.
7945
+ * Inner dispatch: may throw CapRouteError (validation failures) or arbitrary
7946
+ * transport errors. The outer `dispatch` wraps non-CapRouteErrors.
7477
7947
  */
7478
- async requestReadinessSnapshot() {
7479
- if (this.channel === null) throw new Error("LocalChildClient: requestReadinessSnapshot called before start()");
7480
- return (await this.channel.request({ kind: "readiness-request" })).records;
7948
+ async dispatchInner(route, method, args, addonId, callerAddonId) {
7949
+ switch (route.kind) {
7950
+ case "hub-in-process": return route.ref.invoke(method, withCallerAddonId(args, callerAddonId));
7951
+ case "hub-local-uds": {
7952
+ const registry = this.hubLocalRegistry;
7953
+ if (registry === null) throw new CapRouteError(route.capName, method, {
7954
+ reason: "no-provider",
7955
+ rejected: [{
7956
+ kind: "hub-local-uds",
7957
+ why: "UDS registry not available"
7958
+ }]
7959
+ });
7960
+ const deviceId = extractDeviceId(args);
7961
+ const input = {
7962
+ capName: route.capName,
7963
+ method,
7964
+ args,
7965
+ ...deviceId !== void 0 ? { deviceId } : {}
7966
+ };
7967
+ return registry.callCapOnChild(route.childId, input);
7968
+ }
7969
+ case "remote-moleculer": {
7970
+ const addonId = this.nodeAuthority.getAddonId(route.nodeId, route.capName);
7971
+ if (addonId === null) throw new CapRouteError(route.capName, method, {
7972
+ reason: "no-provider",
7973
+ nodeId: route.nodeId,
7974
+ rejected: [{
7975
+ kind: "remote-moleculer",
7976
+ why: `no addonId known for ${route.nodeId}/${route.capName}`
7977
+ }]
7978
+ });
7979
+ const deviceId = extractDeviceId(args);
7980
+ const isNative = this.nodeAuthority.isNativeCap(route.nodeId, route.capName, deviceId);
7981
+ const action = capActionName(addonId, route.capName, method, isNative);
7982
+ return callWithServiceDiscovery(this.broker, addonId, action, args, {
7983
+ nodeID: route.nodeId,
7984
+ timeout: this.callTimeout(route.capName, method)
7985
+ });
7986
+ }
7987
+ case "agent-child-forward": {
7988
+ const deviceId = extractDeviceId(args);
7989
+ const params = {
7990
+ capName: route.capName,
7991
+ method,
7992
+ args,
7993
+ ...route.childId !== void 0 ? { childId: route.childId } : {},
7994
+ ...deviceId !== void 0 ? { deviceId } : {},
7995
+ ...addonId !== void 0 ? { addonId } : {}
7996
+ };
7997
+ return callWithServiceDiscovery(this.broker, AGENT_CAP_FWD_SERVICE, AGENT_CAP_FWD_ACTION, params, {
7998
+ nodeID: route.agentNodeId,
7999
+ timeout: this.callTimeout(route.capName, method)
8000
+ });
8001
+ }
8002
+ }
7481
8003
  }
7482
- /**
7483
- * Ask the parent to execute a cap call this child does NOT own. The parent
7484
- * routes to the owning local sibling over UDS, or — if no sibling owns it —
7485
- * to its `onUnownedCall` fallback (the cluster CapabilityRegistry in
7486
- * production). Throws if called before `start()`.
7487
- */
7488
- async callOut(input) {
7489
- if (this.channel === null) throw new Error("LocalChildClient: callOut before start");
7490
- const msg = {
7491
- kind: "cap-call-out",
7492
- capName: input.capName,
7493
- method: input.method,
7494
- args: input.args,
7495
- ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
7496
- ...input.nodeId !== void 0 ? { nodeId: input.nodeId } : {},
7497
- ...input.native === true ? { native: true } : {}
8004
+ buildSnapshot() {
8005
+ const hubLocalRegistry = this.hubLocalRegistry;
8006
+ const nodeAuthority = this.nodeAuthority;
8007
+ const inProcessProviders = this.inProcessProviders;
8008
+ const hubResidentProviders = this.hubResidentProviders;
8009
+ return {
8010
+ hubNodeId: this.hubNodeId,
8011
+ hubInProcessProvides: (cap) => inProcessProviders(cap) !== null,
8012
+ ...hubResidentProviders !== void 0 ? {
8013
+ hubResidentProvides: (cap) => hubResidentProviders(cap) !== null,
8014
+ getHubResidentProviderRef: (cap) => hubResidentProviders(cap)
8015
+ } : {},
8016
+ hubLocalChildProvides: (cap, deviceId) => hubLocalRegistry !== null && hubLocalRegistry.resolveChildId(cap, deviceId) !== null,
8017
+ nodeKnowsCap: (nodeId, cap) => nodeAuthority.nodeKnowsCap(nodeId, cap),
8018
+ nodeIsAgent: (nodeId) => nodeAuthority.nodeIsAgent(nodeId),
8019
+ nodeOnline: (nodeId) => nodeAuthority.nodeOnline(nodeId),
8020
+ listKnownNodeIds: () => nodeAuthority.listNodeIds(),
8021
+ getInProcessProviderRef: (cap) => inProcessProviders(cap),
8022
+ getHubLocalChildId: (cap, deviceId) => hubLocalRegistry !== null ? hubLocalRegistry.resolveChildId(cap, deviceId) : null,
8023
+ getAgentChildId: (agentNodeId, cap) => nodeAuthority.getAgentChildId(agentNodeId, cap)
7498
8024
  };
7499
- return this.channel.request(msg);
7500
8025
  }
7501
- /** Disconnect from the parent. Safe to call before `start()` (no-op) and idempotent. */
7502
- async close() {
7503
- await this.client?.close();
7504
- this.client = null;
7505
- this.channel = null;
8026
+ /** Extract a nodeId string from a route for error reporting, or undefined. */
8027
+ routeNodeId(route) {
8028
+ switch (route.kind) {
8029
+ case "hub-in-process": return this.hubNodeId;
8030
+ case "hub-local-uds": return `${this.hubNodeId}/${route.childId}`;
8031
+ case "remote-moleculer": return route.nodeId;
8032
+ case "agent-child-forward": return route.agentNodeId;
8033
+ }
7506
8034
  }
7507
8035
  };
7508
8036
  //#endregion
@@ -10174,4 +10702,4 @@ async function defaultRun(command, args) {
10174
10702
  await execFileAsync(command, [...args], { timeout: INSTALL_TIMEOUT_MS });
10175
10703
  }
10176
10704
  //#endregion
10177
- export { buildUdsNativeCapProxy as $, ARRAY_BUFFER_RELEASE_MIN_DROP_RATIO as $t, createUdsLoggerWithControl as A, HUB_MAIN_RSS_BUDGET_MB as At, readMoleculerFanoutMode as B, createV8Reclaimer as Bt, ipcParentLink as C, EVENT_PLANE_TOP_N as Cn, createAddonDataPlaneFacility as Ct, createUdsEventBus as D, formatEventPlane as Dn, HEAP_WATCH_INTERVAL_MS as Dt, createUdsEventBridge as E, diffEventPlane as En, HEAP_RECLAIM_TRIGGER_MB as Et, AGENT_CAP_FWD_SERVICE as F, RUNNER_RSS_BUDGET_ENV as Ft, createLocalTransport as G, reclaimIntervalMs as Gt, PARENT_ROUTED_PROVIDER_ADDON_ID as H, hubMainRssBudget as Ht, CapRouteResolver as I, ZERO_LOOP_DELAY as It, SocketChannel as J, startRunnerHeapWatch as Jt, UdsLocalTransportClient as K, shouldReclaim as Kt, CapRouteError as L, buildHeapSample as Lt, LocalChildRegistry as M, RSS_BUDGET_REANNOUNCE_MIN_MS as Mt, UDS_NO_ROUTE_PREFIX as N, RSS_BUDGET_RELEASE_RATIO as Nt, udsChildLogToWorkerEntry as O, HEAP_WATCH_WARN_RATIO as Ot, AGENT_CAP_FWD_ACTION as P, RUNNER_HEAP_WATCH_INTERVAL_MS as Pt, buildNativeCapProxy as Q, ARRAY_BUFFER_CENSUS_THRESHOLD_MB as Qt, classifyCapRoute as R, createDeferredHeapWatchSink as Rt, buildLinkChain as S, socketDirectionMessages as Sn, runNpm as St, createParentUnownedCallHandler as T, createEventPlaneReader as Tn, HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS as Tt, __resetCapUsageRegistryForTests as U, nextRssBudgetState as Ut, CapUsageRegistry as V, describeRss as Vt, getCapUsageRegistry as W, parseRssBudgetMb as Wt, FrameDecoder as X, ARRAY_BUFFER_CENSUS_COOLDOWN_MS as Xt, localEndpointPath as Y, strandedMb as Yt, encodeFrame as Z, ARRAY_BUFFER_CENSUS_SUSTAIN_MS as Zt, AddonDepsManager as _, EMPTY_SOCKET_DIRECTION as _n, CapabilityUnavailableError as _t, createUdsAddonContext as a, HEAP_SPACE_REPORT_MIN_MB as an, createAddonService as at, brokerCallForCap as b, sampleSocketDirection as bn, resolveAddonClass as bt, getOrInitReadinessRegistryForClient as c, heapSpaceField as cn, capActionName as ct, clusterEventTopic as d, EMPTY_SOCKET_PLANE_BASELINE as dn, capServiceName as dt, createArrayBufferCensusGate as en, createBrokerDeviceManagerApi as et, getBrokerEventBus as f, SOCKET_PLANE_TOP_N as fn, parseCapAction as ft, subscribePassthrough as g, formatSocketPlane as gn, CapabilityHandle as gt, setNodeEventInterest as h, diffSocketPlane as hn, DeviceRegistry as ht, createAddonContext as i, DECISIVE_HEAP_SPACES as in, setWorkerNativeCapsChangeListener as it, LocalChildClient as j, HUB_RSS_BUDGET_ENV as jt, createUdsLogger as k, HUB_MAIN_HEAP_WATCH_LABEL as kt, setHubConnected as l, readHeapSpaces as ln, capActionSuffix as lt, registerEventBusService as m, createSocketPlaneReader as mn, serializeTypedArrays as mt, installManifestPythonDeps as n, formatArrayBufferCensus as nn, getWorkerNativeCapSnapshot as nt, getWorkerDeviceRegistry as o, emitHeapDiagnosticReport as on, validateProviderRegistrations as ot, getMoleculerEventStats as p, createSocketPlaneMeter as pn, deserializeTypedArrays as pt, UdsLocalTransportServer as q, startHeapWatch as qt, adaptBrokerToCluster as r, isArrayBufferCensusReport as rn, mountNativeCapService as rt, getOrInitReadinessRegistry as s, formatHeapSpaces as sn, NATIVE_PROVIDER_SERVICE_INFIX as st, installManifestSystemDeps as t, createInspectorArrayBufferCensus as tn, getWorkerNativeCapProvider as tt, EVENT_TOPIC_PREFIX as u, selectReportedSpaces as un, capBareAction as ut, createKernelHwAccel as v, createSocketDirectionCounters as vn, copyBundledNativeModules as vt, localProviderLink as w, createEventPlaneMeter as wn, HEAP_RECLAIM_MIN_INTERVAL_MS as wt, brokerTransportLink as x, socketDirectionBytes as xn, resolveNpmInvocation as xt, resolveHwAccel as y, recordSocketFrame as yn, installManifestNativeDeps as yt, callWithServiceDiscovery as z, createLoopDelayMeter as zt };
10705
+ export { buildUdsNativeCapProxy as $, ARRAY_BUFFER_RELEASE_MIN_DROP_RATIO as $t, createUdsLoggerWithControl as A, sampleSocketDirection as An, HUB_MAIN_RSS_BUDGET_MB as At, readMoleculerFanoutMode as B, createV8Reclaimer as Bt, ipcParentLink as C, createSocketPlaneReader as Cn, createAddonDataPlaneFacility as Ct, createUdsEventBus as D, EMPTY_SOCKET_DIRECTION as Dn, HEAP_WATCH_INTERVAL_MS as Dt, createUdsEventBridge as E, readSocketQueues as En, HEAP_RECLAIM_TRIGGER_MB as Et, CapRouteError as F, createEventPlaneReader as Fn, RUNNER_RSS_BUDGET_ENV as Ft, createLocalTransport as G, reclaimIntervalMs as Gt, PARENT_ROUTED_PROVIDER_ADDON_ID as H, hubMainRssBudget as Ht, classifyCapRoute as I, diffEventPlane as In, ZERO_LOOP_DELAY as It, SocketChannel as J, startRunnerHeapWatch as Jt, UdsLocalTransportClient as K, shouldReclaim as Kt, LocalChildClient as L, formatEventPlane as Ln, buildHeapSample as Lt, AGENT_CAP_FWD_SERVICE as M, socketDirectionMessages as Mn, RSS_BUDGET_REANNOUNCE_MIN_MS as Mt, CapRouteResolver as N, EVENT_PLANE_TOP_N as Nn, RSS_BUDGET_RELEASE_RATIO as Nt, udsChildLogToWorkerEntry as O, createSocketDirectionCounters as On, HEAP_WATCH_WARN_RATIO as Ot, callWithServiceDiscovery as P, createEventPlaneMeter as Pn, RUNNER_HEAP_WATCH_INTERVAL_MS as Pt, buildNativeCapProxy as Q, ARRAY_BUFFER_CENSUS_THRESHOLD_MB as Qt, LocalChildRegistry as R, createDeferredHeapWatchSink as Rt, buildLinkChain as S, createSocketPlaneMeter as Sn, runNpm as St, createParentUnownedCallHandler as T, formatSocketPlane as Tn, HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS as Tt, __resetCapUsageRegistryForTests as U, nextRssBudgetState as Ut, CapUsageRegistry as V, describeRss as Vt, getCapUsageRegistry as W, parseRssBudgetMb as Wt, FrameDecoder as X, ARRAY_BUFFER_CENSUS_COOLDOWN_MS as Xt, localEndpointPath as Y, strandedMb as Yt, encodeFrame as Z, ARRAY_BUFFER_CENSUS_SUSTAIN_MS as Zt, AddonDepsManager as _, createMeshQueueReader as _n, CapabilityUnavailableError as _t, createUdsAddonContext as a, HEAP_SPACE_REPORT_MIN_MB as an, createAddonService as at, brokerCallForCap as b, SOCKET_PLANE_TOP_N as bn, resolveAddonClass as bt, getOrInitReadinessRegistryForClient as c, heapSpaceField as cn, capActionName as ct, clusterEventTopic as d, OUTBOUND_QUEUE_COOLDOWN_MS as dn, capServiceName as dt, createArrayBufferCensusGate as en, createBrokerDeviceManagerApi as et, getBrokerEventBus as f, OUTBOUND_QUEUE_SUSTAIN_MS as fn, parseCapAction as ft, subscribePassthrough as g, MESH_QUEUE_TOP_N as gn, CapabilityHandle as gt, setNodeEventInterest as h, formatOutboundQueueVerdict as hn, DeviceRegistry as ht, createAddonContext as i, DECISIVE_HEAP_SPACES as in, setWorkerNativeCapsChangeListener as it, AGENT_CAP_FWD_ACTION as j, socketDirectionBytes as jn, HUB_RSS_BUDGET_ENV as jt, createUdsLogger as k, recordSocketFrame as kn, HUB_MAIN_HEAP_WATCH_LABEL as kt, setHubConnected as l, readHeapSpaces as ln, capActionSuffix as lt, registerEventBusService as m, createOutboundQueueGate as mn, serializeTypedArrays as mt, installManifestPythonDeps as n, formatArrayBufferCensus as nn, getWorkerNativeCapSnapshot as nt, getWorkerDeviceRegistry as o, emitHeapDiagnosticReport as on, validateProviderRegistrations as ot, getMoleculerEventStats as p, OUTBOUND_QUEUE_THRESHOLD_BYTES as pn, deserializeTypedArrays as pt, UdsLocalTransportServer as q, startHeapWatch as qt, adaptBrokerToCluster as r, isArrayBufferCensusReport as rn, mountNativeCapService as rt, getOrInitReadinessRegistry as s, formatHeapSpaces as sn, NATIVE_PROVIDER_SERVICE_INFIX as st, installManifestSystemDeps as t, createInspectorArrayBufferCensus as tn, getWorkerNativeCapProvider as tt, EVENT_TOPIC_PREFIX as u, selectReportedSpaces as un, capBareAction as ut, createKernelHwAccel as v, formatMeshQueue as vn, copyBundledNativeModules as vt, localProviderLink as w, diffSocketPlane as wn, HEAP_RECLAIM_MIN_INTERVAL_MS as wt, brokerTransportLink as x, SOCKET_QUEUE_TOP_N as xn, resolveNpmInvocation as xt, resolveHwAccel as y, EMPTY_SOCKET_PLANE_BASELINE as yn, installManifestNativeDeps as yt, UDS_NO_ROUTE_PREFIX as z, createLoopDelayMeter as zt };