@camstack/system 1.2.151 → 1.2.154

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 (66) hide show
  1. package/dist/addon-runner.js +14 -15
  2. package/dist/addon-runner.mjs +14 -14
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  25. package/dist/builtins/local-network/local-network.addon.js +3 -3
  26. package/dist/builtins/local-network/local-network.addon.mjs +3 -3
  27. package/dist/builtins/loki-logging/index.js +1 -1
  28. package/dist/builtins/loki-logging/index.mjs +1 -1
  29. package/dist/builtins/native-metrics/cgroup-memory.d.ts +193 -0
  30. package/dist/builtins/native-metrics/container-memory-series.d.ts +226 -0
  31. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +26 -0
  32. package/dist/builtins/native-metrics/native-metrics.addon.js +1536 -661
  33. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1536 -660
  34. package/dist/builtins/platform-probe/index.js +3 -3
  35. package/dist/builtins/platform-probe/index.mjs +2 -2
  36. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  37. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  38. package/dist/builtins/snapshot/index.js +1 -1
  39. package/dist/builtins/snapshot/index.mjs +1 -1
  40. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +2 -2
  41. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +2 -2
  42. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  43. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  45. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  46. package/dist/builtins/system-config/system-config.addon.js +1 -1
  47. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  48. package/dist/builtins/winston-logging/index.js +1 -1
  49. package/dist/builtins/winston-logging/index.mjs +1 -1
  50. package/dist/{dist-CImxMt5h.js → dist-BPlfW-CG.js} +96 -10
  51. package/dist/{dist-CbRciAbu.mjs → dist-D_NyUV6Y.mjs} +96 -10
  52. package/dist/index.d.ts +6 -2
  53. package/dist/index.js +24 -5
  54. package/dist/index.mjs +5 -5
  55. package/dist/kernel/event-plane-report.d.ts +202 -0
  56. package/dist/kernel/heap-spaces.d.ts +138 -0
  57. package/dist/kernel/heap-watch.d.ts +142 -5
  58. package/dist/kernel/index.d.ts +2 -0
  59. package/dist/kernel/transport/local-child-registry.d.ts +22 -0
  60. package/dist/{manifest-python-deps-DuQ3Uqoq.mjs → manifest-python-deps-BILJm2mI.mjs} +522 -15
  61. package/dist/{manifest-python-deps-BqWrDjSN.js → manifest-python-deps-COeSr7el.js} +636 -15
  62. package/dist/{retired-settings-keys-DhFPXIRD.mjs → retired-settings-keys-Bq1Tb84I.mjs} +1 -1
  63. package/dist/{retired-settings-keys-C7gLUS3x.js → retired-settings-keys-DBY6ebwV.js} +1 -1
  64. package/package.json +1 -1
  65. package/dist/{tls-u8QCJCFE.js → tls-BxQlomxd.js} +1 -1
  66. package/dist/{tls-CQhPGSJm.mjs → tls-DOTmtLCW.mjs} +1 -1
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- require("./dist-CImxMt5h.js");
2
+ require("./dist-BPlfW-CG.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  node_crypto = require_chunk.__toESM(node_crypto);
5
5
  let _camstack_types_node = require("@camstack/types/node");
@@ -8,19 +8,361 @@ let node_path = require("node:path");
8
8
  node_path = require_chunk.__toESM(node_path);
9
9
  let node_child_process = require("node:child_process");
10
10
  let node_util = require("node:util");
11
- let node_os = require("node:os");
12
- node_os = require_chunk.__toESM(node_os);
13
11
  let node_fs = require("node:fs");
14
12
  node_fs = require_chunk.__toESM(node_fs);
13
+ let node_os = require("node:os");
14
+ node_os = require_chunk.__toESM(node_os);
15
15
  let node_http = require("node:http");
16
- let node_perf_hooks = require("node:perf_hooks");
17
16
  let node_v8 = require("node:v8");
18
17
  node_v8 = require_chunk.__toESM(node_v8);
18
+ let node_perf_hooks = require("node:perf_hooks");
19
19
  let node_vm = require("node:vm");
20
20
  node_vm = require_chunk.__toESM(node_vm);
21
21
  let _camstack_types_addon = require("@camstack/types/addon");
22
22
  let node_net = require("node:net");
23
23
  let _trpc_client = require("@trpc/client");
24
+ //#region src/kernel/event-plane-report.ts
25
+ /**
26
+ * Build a reader over the two registries.
27
+ *
28
+ * Returns `undefined` until the child registry exists — the heartbeat starts as
29
+ * the FIRST statement of `bootstrap()` (a process that dies early still leaves
30
+ * samples) and `LocalChildRegistry` is built hundreds of lines later inside
31
+ * `MoleculerService.onModuleInit`. Printing zeros in that window would report a
32
+ * silent plane where there is no plane at all.
33
+ *
34
+ * Wrapped: a registry mid-teardown may throw, and a diagnostic that can crash
35
+ * the process it watches is worse than none.
36
+ */
37
+ function createEventPlaneReader(sources) {
38
+ return () => {
39
+ try {
40
+ const registry = sources.registry();
41
+ if (registry === null) return void 0;
42
+ const children = [];
43
+ const listed = registry.listChildren();
44
+ for (const child of listed) {
45
+ const stats = registry.getChildEventStats(child.childId);
46
+ if (stats === null) continue;
47
+ children.push({
48
+ childId: child.childId,
49
+ sent: stats.sent,
50
+ suppressed: stats.suppressed
51
+ });
52
+ }
53
+ const crossNode = sources.crossNodeStats();
54
+ return {
55
+ udsMode: registry.eventFanoutMode,
56
+ crossNodeMode: sources.crossNodeMode(),
57
+ children,
58
+ childrenConnected: listed.length,
59
+ childrenUndeclared: registry.undeclaredChildCount(),
60
+ crossNodeDelivered: crossNode?.delivered ?? 0,
61
+ crossNodeSuppressed: crossNode?.suppressed ?? 0
62
+ };
63
+ } catch {
64
+ return;
65
+ }
66
+ };
67
+ }
68
+ /**
69
+ * How many children get named on the line.
70
+ *
71
+ * Five, because the question is which peer DOMINATES and the measured
72
+ * distribution is not flat: one peer accounted for 78–82% of outbound bytes and
73
+ * the runner-up for ~6%. Five names the dominant peer, its challenger and enough
74
+ * of the tail to see the shape change; naming all ~38 would put a kilobyte-long
75
+ * line in the hub's shared log every minute, which is how a log stops being read.
76
+ */
77
+ var EVENT_PLANE_TOP_N = 5;
78
+ /** A process that has never read a plane. */
79
+ var EMPTY_EVENT_PLANE_BASELINE = {
80
+ children: /* @__PURE__ */ new Map(),
81
+ crossNodeDelivered: 0,
82
+ crossNodeSuppressed: 0
83
+ };
84
+ /**
85
+ * Subtract the previous cumulative reading from the current one.
86
+ *
87
+ * A child that RESTARTED has counters that went backwards — the registry keys by
88
+ * childId and a respawned runner reconnects under the same id with a fresh
89
+ * entry. Clamping at 0 reports the restart as a quiet window rather than as a
90
+ * negative rate: the window's traffic is genuinely unknown, and a negative
91
+ * number on a rate reads as a broken meter.
92
+ */
93
+ function diffEventPlane(baseline, current, topN = 5) {
94
+ const deltas = [];
95
+ let fanoutSent = 0;
96
+ let fanoutSuppressed = 0;
97
+ for (const sample of current.children) {
98
+ const before = baseline.children.get(sample.childId);
99
+ const sent = Math.max(0, sample.sent - (before?.sent ?? 0));
100
+ const suppressed = Math.max(0, sample.suppressed - (before?.suppressed ?? 0));
101
+ fanoutSent += sent;
102
+ fanoutSuppressed += suppressed;
103
+ if (sent > 0 || suppressed > 0) deltas.push({
104
+ childId: sample.childId,
105
+ sent,
106
+ suppressed
107
+ });
108
+ }
109
+ return {
110
+ udsMode: current.udsMode,
111
+ crossNodeMode: current.crossNodeMode,
112
+ childrenConnected: current.childrenConnected,
113
+ childrenUndeclared: current.childrenUndeclared,
114
+ fanoutSent,
115
+ fanoutSuppressed,
116
+ crossNodeDelivered: Math.max(0, current.crossNodeDelivered - baseline.crossNodeDelivered),
117
+ crossNodeSuppressed: Math.max(0, current.crossNodeSuppressed - baseline.crossNodeSuppressed),
118
+ top: deltas.toSorted((a, b) => b.sent - a.sent || a.childId.localeCompare(b.childId)).slice(0, topN)
119
+ };
120
+ }
121
+ function createEventPlaneMeter(reader, topN = 5) {
122
+ let baseline = EMPTY_EVENT_PLANE_BASELINE;
123
+ return { read: () => {
124
+ const current = reader();
125
+ if (current === void 0) return void 0;
126
+ const window = diffEventPlane(baseline, current, topN);
127
+ baseline = {
128
+ children: new Map(current.children.map((s) => [s.childId, s])),
129
+ crossNodeDelivered: current.crossNodeDelivered,
130
+ crossNodeSuppressed: current.crossNodeSuppressed
131
+ };
132
+ return window;
133
+ } };
134
+ }
135
+ /**
136
+ * The suffix appended to a `[mem]` line — leading space included, empty when
137
+ * this process has no event plane.
138
+ *
139
+ * Only two processes in the cluster have one (hub-main, and an agent's main), so
140
+ * these fields never appear on the ~38 runner lines that share the same log
141
+ * stream. On the two that do, every field is printed on every line INCLUDING at
142
+ * zero: the modes because a suppressed count without its regime is unreadable,
143
+ * `childrenUndeclared` because one undeclared child silently disables both
144
+ * gates, and the deltas because "the plane went quiet for a minute" is a
145
+ * reading, not a blank.
146
+ *
147
+ * `fanoutTop` is the one conditional field — a ranked list of nothing is noise —
148
+ * and it is a single comma-separated value so the field COUNT does not change
149
+ * from line to line: `childId:sent/suppressed`, largest first.
150
+ */
151
+ function formatEventPlane(window) {
152
+ if (window === void 0) return "";
153
+ const top = window.top.map((d) => `${d.childId}:${d.sent}/${d.suppressed}`).join(",");
154
+ return ` fanoutMode=uds:${window.udsMode}/cross-node:${window.crossNodeMode} children=${window.childrenConnected} childrenUndeclared=${window.childrenUndeclared} fanoutSent=${window.fanoutSent} fanoutSuppressed=${window.fanoutSuppressed} crossNodeDelivered=${window.crossNodeDelivered} crossNodeSuppressed=${window.crossNodeSuppressed}` + (top.length === 0 ? "" : ` fanoutTop=${top}`);
155
+ }
156
+ //#endregion
157
+ //#region src/kernel/heap-spaces.ts
158
+ /**
159
+ * heap-spaces — WHERE in the V8 heap the bytes are, on the ordinary heartbeat.
160
+ *
161
+ * ## The question this exists to answer, and why it was unobtainable
162
+ *
163
+ * `hub/recorder` holds ~1.4 GB of live, retained JS heap that nobody can name.
164
+ * That is measured, not inferred: a forced compacting
165
+ * `gc({ flavor: 'last-resort' })` returned 507 MB of RSS and left V8 with
166
+ * 1870 MB committed and 1439 MB of it LIVE forty seconds later. Everything the
167
+ * 2026-08-29 pass could price — index rows 60–67 MB, runner shell ~50 MB, boot
168
+ * parse 35–50 MB transient, write path 0 retained — sums to 115–125 MB, under
169
+ * 9%. The same addon build running as `recorder` on an agent with no cameras
170
+ * and no archive sits at 52 MB.
171
+ *
172
+ * The next question is cheap and binary, and it halves the search:
173
+ *
174
+ * - **`old_space` holds it** ⇒ millions of small objects. The hunt becomes
175
+ * "what allocates ~7 M objects", and the row counters the recorder's index
176
+ * already exposes are the next thing to log.
177
+ * - **`large_object_space` holds it** ⇒ a handful of objects over V8's
178
+ * ~128 KB regular-object ceiling. The hunt becomes "who holds one huge array
179
+ * or string", which is a very short list in any one addon.
180
+ *
181
+ * V8 answers it for free, and this repository has been computing the answer
182
+ * since the SIGUSR2 handler was written — and then throwing it away, because
183
+ * `addon-runner.ts` welded the free read to `v8.writeHeapSnapshot`. One signal,
184
+ * both actions, so the cheap answer could not be had without the expensive one
185
+ * an operator has to authorise on a production hub. {@link emitHeapDiagnosticReport}
186
+ * splits them; this module puts the same breakdown on the periodic `[mem]` line
187
+ * so no signal is needed at all.
188
+ *
189
+ * ## Why bytes and not MB in the model
190
+ *
191
+ * The two consumers want different resolution — the heartbeat wants whole MB
192
+ * next to `heapUsed`, the SIGUSR2 report keeps the 0.1 MB it has always
193
+ * printed — so the reading stays raw and rounding happens at the edge. A model
194
+ * that pre-rounds cannot serve both without lying to one of them.
195
+ */
196
+ /**
197
+ * The two spaces that ANSWER the question, printed always — including at zero.
198
+ *
199
+ * Node 24 reports thirteen spaces (measured on 24.17: `read_only_space`,
200
+ * `new_space`, `old_space`, `code_space`, `shared_space`, `trusted_space`,
201
+ * `shared_trusted_space`, `new_large_object_space`, `large_object_space`,
202
+ * `code_large_object_space`, `shared_large_object_space`,
203
+ * `shared_trusted_large_object_space`, `trusted_large_object_space`). Printing
204
+ * all thirteen once a minute per process would add ~13 fields to a line that
205
+ * already carries eleven, on every runner, forever — and eleven of the thirteen
206
+ * cannot be the answer to a 1.4 GB retained-set question.
207
+ *
208
+ * These two are printed unconditionally because **absence must never be
209
+ * ambiguous**. A threshold-only rule would drop `large_object_space` at 20 MB,
210
+ * and a reader would not be able to tell "small" from "this build does not
211
+ * report it" — which is the same class of mistake as a heartbeat with no
212
+ * destination (D285). `largeObjectSpace=0MB` is a load-bearing reading: it says
213
+ * the retainer is NOT a handful of huge objects.
214
+ */
215
+ var DECISIVE_HEAP_SPACES = ["old_space", "large_object_space"];
216
+ /**
217
+ * A non-decisive space is printed only once it holds at least this many MB.
218
+ *
219
+ * 32 MB, and the number comes from the smallest heap this line is ever asked to
220
+ * explain: the control in the 2026-08-29 pass is an idle `recorder` runner at
221
+ * **52 MB** of `heapUsed`. A threshold below that means no space that could
222
+ * dominate even the smallest watched process is ever hidden, while a quiet
223
+ * process — measured on a bare Node 24.17: `new_space` 0.7 MB, `code_space`
224
+ * 0.25 MB, `trusted_space` 0.9 MB — prints nothing but the decisive pair.
225
+ *
226
+ * What this drops, and why it is right to drop it: `new_space` is the scavenger's
227
+ * semi-space and is bounded by `--max-semi-space-size`, so it can never be a
228
+ * retained set; `code_space` and `read_only_space` are JIT output and V8's own
229
+ * immutable roots, both bounded by the code that exists rather than by the data
230
+ * it touches; the `shared_*` spaces are empty outside a worker-threads
231
+ * deployment, which this cluster does not run. None of them has ever been the
232
+ * answer to "what is this process holding", and each would cost a field on
233
+ * every `[mem]` line in the fleet.
234
+ *
235
+ * They are not censored, though — a space over the threshold prints, whatever it
236
+ * is. If `code_space` ever reaches 32 MB that is itself the finding.
237
+ */
238
+ var HEAP_SPACE_REPORT_MIN_MB = 32;
239
+ var BYTES_PER_MB = 1048576;
240
+ /** Whole MB, matching the rest of the `[mem]` line. */
241
+ function mb(bytes) {
242
+ return Math.round(bytes / BYTES_PER_MB);
243
+ }
244
+ /** Tenths of an MB — the resolution the SIGUSR2 report has always printed. */
245
+ function tenthsMb(bytes) {
246
+ return Math.round(bytes / BYTES_PER_MB * 10) / 10;
247
+ }
248
+ /**
249
+ * Read every space from V8.
250
+ *
251
+ * Wrapped: a diagnostic that can crash the process it watches is worse than
252
+ * none, and this is called from a heartbeat whose whole contract is that it
253
+ * survives whatever it is measuring. An empty reading prints no fields, which
254
+ * is exactly what a heartbeat that could not read the heap should say.
255
+ */
256
+ function readHeapSpaces() {
257
+ try {
258
+ return node_v8.getHeapSpaceStatistics().map((space) => ({
259
+ name: space.space_name,
260
+ usedBytes: space.space_used_size
261
+ }));
262
+ } catch {
263
+ return [];
264
+ }
265
+ }
266
+ /**
267
+ * `old_space` → `oldSpace`. Mechanical and total, so a space V8 adds tomorrow
268
+ * gets a field name without anyone editing a table.
269
+ *
270
+ * camelCase because that is the vocabulary of every other field on this line
271
+ * (`heapUsed`, `heapTotal`, `arrayBuffers`, `rssBudget`, `loopP99`). A line that
272
+ * mixed `heapUsed=` with `old_space=` would be two conventions for one record.
273
+ */
274
+ function heapSpaceField(v8Name) {
275
+ return v8Name.replace(/_([a-z])/g, (_match, letter) => letter.toUpperCase());
276
+ }
277
+ /**
278
+ * The spaces worth a field on this line: the decisive pair (in that order,
279
+ * always), then every other space at or above `minMb`, largest first.
280
+ *
281
+ * Largest-first for the tail because the tail only ever appears when something
282
+ * unexpected is holding memory, and the biggest surprise should be the first
283
+ * thing read. The decisive pair keeps a FIXED position so the two numbers a
284
+ * reader is comparing are always in the same place on every line.
285
+ */
286
+ function selectReportedSpaces(spaces, minMb = 32) {
287
+ const decisive = DECISIVE_HEAP_SPACES.map((name) => spaces.find((space) => space.name === name)).filter((space) => space !== void 0);
288
+ const rest = spaces.filter((space) => !DECISIVE_HEAP_SPACES.includes(space.name)).filter((space) => mb(space.usedBytes) >= minMb).toSorted((a, b) => b.usedBytes - a.usedBytes || a.name.localeCompare(b.name));
289
+ return [...decisive, ...rest];
290
+ }
291
+ /**
292
+ * The suffix appended to a `[mem]` line — leading space included, empty when
293
+ * there is nothing to say.
294
+ *
295
+ * APPENDED, never interleaved: every existing field keeps its name AND its
296
+ * position, so a `hl loki-query` pipeline written against the old line still
297
+ * matches. Prefix stability is the only change to a log line that cannot break
298
+ * a query someone already wrote.
299
+ */
300
+ function formatHeapSpaces(spaces, minMb = 32) {
301
+ const selected = selectReportedSpaces(spaces, minMb);
302
+ if (selected.length === 0) return "";
303
+ return ` ${selected.map((s) => `${heapSpaceField(s.name)}=${mb(s.usedBytes)}MB`).join(" ")}`;
304
+ }
305
+ /**
306
+ * Env var that authorises a heap snapshot on SIGUSR2.
307
+ *
308
+ * A snapshot is an admin mutation on a production hub: `writeHeapSnapshot`
309
+ * streams a file the size of the heap to `/tmp` and stops the world while it
310
+ * walks it — on the recorder that is a multi-GB file and a stall measured in
311
+ * seconds. The per-space breakdown is ~1.2 µs and changes nothing. Welding them
312
+ * to one signal priced the free answer at the cost of the expensive one.
313
+ */
314
+ var RUNNER_HEAP_SNAPSHOT_ENV = "CAMSTACK_RUNNER_HEAP_SNAPSHOT";
315
+ /**
316
+ * Whether the operator has authorised the snapshot half of SIGUSR2.
317
+ *
318
+ * Explicit `'on'` only. Anything else — unset, empty, `'true'`, `'1'` — is NOT
319
+ * authorisation: a multi-GB stop-the-world write must never be reachable by a
320
+ * value someone set for a different purpose.
321
+ */
322
+ function heapSnapshotAuthorised(env = process.env) {
323
+ return env[RUNNER_HEAP_SNAPSHOT_ENV] === "on";
324
+ }
325
+ var defaultDeps = {
326
+ readMemory: () => process.memoryUsage(),
327
+ readSpaces: readHeapSpaces,
328
+ writeSnapshot: (path) => {
329
+ node_v8.writeHeapSnapshot(path);
330
+ },
331
+ env: process.env
332
+ };
333
+ /**
334
+ * The SIGUSR2 report — memory + the FULL per-space breakdown, always; the
335
+ * snapshot only when {@link heapSnapshotAuthorised}.
336
+ *
337
+ * The breakdown here keeps every non-empty space at 0.1 MB, unlike the
338
+ * heartbeat's filtered whole-MB pair: this is a hand-fired diagnostic read once
339
+ * by a human who asked for it, so completeness costs nothing. The heartbeat runs
340
+ * unattended on every runner forever, so it pays for every field it prints.
341
+ *
342
+ * A refused snapshot SAYS SO. A branch that drops work silently reads as "it was
343
+ * never requested", and this one is fired by an operator who is standing there
344
+ * waiting for a file.
345
+ */
346
+ function emitHeapDiagnosticReport(request, deps = defaultDeps) {
347
+ try {
348
+ const mu = deps.readMemory();
349
+ const spaces = deps.readSpaces().filter((space) => space.usedBytes > 0).map((space) => `${space.name}=${tenthsMb(space.usedBytes)}`).join(" ");
350
+ request.sink.info(`[mem] node="${request.label}" addons=[${request.addons.join(",")}] rss=${tenthsMb(mu.rss)} heapUsed=${tenthsMb(mu.heapUsed)} heapTotal=${tenthsMb(mu.heapTotal)} external=${tenthsMb(mu.external)} arrayBuffers=${tenthsMb(mu.arrayBuffers)} | ${spaces}`);
351
+ } catch (error) {
352
+ request.sink.warn(`[mem] node="${request.label}" space report failed: ${error instanceof Error ? error.message : String(error)}`);
353
+ }
354
+ if (!heapSnapshotAuthorised(deps.env)) {
355
+ request.sink.info(`[mem] node="${request.label}" heap snapshot NOT taken — it is an admin mutation (a multi-GB write and a stop-the-world walk of the heap). The per-space breakdown above is the free half and needs no authorisation. Set ${RUNNER_HEAP_SNAPSHOT_ENV}=on for this runner and signal again to take one.`);
356
+ return;
357
+ }
358
+ try {
359
+ deps.writeSnapshot(request.snapshotPath);
360
+ request.sink.info(`[mem] node="${request.label}" heap snapshot written -> ${request.snapshotPath}`);
361
+ } catch (error) {
362
+ request.sink.warn(`[mem] node="${request.label}" snapshot failed: ${error instanceof Error ? error.message : String(error)}`);
363
+ }
364
+ }
365
+ //#endregion
24
366
  //#region src/kernel/heap-watch.ts
25
367
  /**
26
368
  * heap-watch — hub-main's own memory, on the record, and returned to the OS.
@@ -62,6 +404,14 @@ let _trpc_client = require("@trpc/client");
62
404
  * - `heapUsedMb` flat with a sharp jump under load → a burst allocation, and
63
405
  * the timestamp says what was being served.
64
406
  *
407
+ * Since 2026-08-29 the line also says **WHERE in the V8 heap** the bytes are —
408
+ * `oldSpace` and `largeObjectSpace`, appended after everything already on it.
409
+ * `heapUsed` alone cannot separate "millions of small objects" from "a handful
410
+ * of huge ones", and those lead to opposite searches; the recorder's unnamed
411
+ * ~1.4 GB retained set is the case that proved it. See
412
+ * {@link formatHeapSpaces} for which spaces are printed and why the rest are
413
+ * not.
414
+ *
65
415
  * `external`/`arrayBuffers` ride along because they are NOT bounded by
66
416
  * `--max-old-space-size` and are most of the gap between a 1.5GB cap and the
67
417
  * ~2.05GB RSS observed live: a diagnosis that only looks at the JS heap
@@ -203,6 +553,86 @@ var HEAP_RECLAIM_TRIGGER_MB = 1024;
203
553
  * router's time, against a ~1.5GiB peak it removes each pass.
204
554
  */
205
555
  var HEAP_RECLAIM_MIN_INTERVAL_MS = 12e4;
556
+ /**
557
+ * Floor on the pass once it has PROVEN it is steady state, not a rescue.
558
+ *
559
+ * ## Why `stranded` cannot discriminate on hub-main
560
+ *
561
+ * {@link strandedMb} is `rss − heapUsed − external`: everything the process
562
+ * holds that those two numbers do not name. That lumps together two things with
563
+ * opposite fixes —
564
+ *
565
+ * - V8 pages committed at a sawtooth peak, which `gc(last-resort)` RETURNS;
566
+ * - glibc arena memory already freed and never handed back, which **no V8
567
+ * flavor can reach** (nothing in this repository calls `malloc_trim`).
568
+ *
569
+ * {@link HEAP_RECLAIM_TRIGGER_MB} was calibrated against a hub-main whose strand
570
+ * was mostly the first kind, and a pass then took it back under the trigger. Once
571
+ * the second kind grows past 1024 MB the quantity can never fall back under it,
572
+ * and the gate degenerates. Measured on the live hub 2026-08-29, first 25
573
+ * minutes of hub-main telemetry ever collected:
574
+ *
575
+ * - `stranded` sat at **1031–2313 MB for the entire boot**, i.e.
576
+ * {@link shouldReclaim} never once said no. **What is written as a threshold
577
+ * is, on this process, an unconditional 120-second timer.**
578
+ * - Nine minutes out of nine that contained a reclaim show `loopMax` ≈ the
579
+ * reclaim's own duration (555–869 ms). Every minute without one is
580
+ * 107–435 ms. **The largest recurring event-loop stall on the process that
581
+ * mediates every cross-runner call is the memory patch it applies to itself.**
582
+ * - Each pass freed less than the last (1193 → 462 MB) while the post-pass RSS
583
+ * floor ratcheted **1940 → 3510 MB in fourteen minutes**, with `heapUsed`
584
+ * never moving. It is compacting a heap that is not the problem.
585
+ *
586
+ * ## The fix is not a bigger trigger
587
+ *
588
+ * Raising {@link HEAP_RECLAIM_TRIGGER_MB} would move the number at which the same
589
+ * degeneration happens, and it would silence `hub/recorder` — whose single pass
590
+ * in six hours is the only cheap proof anyone has that the recorder's 1.4 GB is
591
+ * RETAINED (a forced compaction freed 507 MB and V8 still held 1.44 GB live).
592
+ * The discriminator is not the level of the strand; it is **whether the strand
593
+ * ever falls back under the trigger between passes**, which is precisely what
594
+ * {@link RECLAIM_STEADY_STATE_PASSES} already counts and used only to talk about.
595
+ *
596
+ * So the counter becomes load-bearing: once the pass has fired at the floor
597
+ * {@link RECLAIM_STEADY_STATE_PASSES} times running, the trigger has demonstrably
598
+ * stopped discriminating on this process, and the cadence falls back to a period
599
+ * chosen for its COST rather than to a threshold pretending to be a gate.
600
+ *
601
+ * ## Why 600_000, and why that is not a regression
602
+ *
603
+ * It is the value {@link HEAP_RECLAIM_MIN_INTERVAL_MS} held before 2026-08-17,
604
+ * and the reason it came down is recorded there: *"the ten-minute floor let a
605
+ * peak that re-formed in seconds stand for ten minutes"*. That argument is about
606
+ * a BURST — and a burst subsides, which resets the run and restores the 120 s
607
+ * floor. It never applied to a process in proven steady state. So the burst
608
+ * bound is untouched and the steady state gets the period the burst argument was
609
+ * never about.
610
+ *
611
+ * ## What each process does after this change
612
+ *
613
+ * - **hub-main**: first six passes at 120 s, unchanged. From the seventh
614
+ * consecutive floor-to-floor pass, every 600 s. Stop-the-world cost on the
615
+ * router falls from ~0.58% of wall clock to ~0.12%. The ArrayBuffer probe
616
+ * survives at six passes an hour — the finding it produced needed ten passes
617
+ * total, not ten in twenty-five minutes.
618
+ * - **`hub/recorder`**: zero change, by construction. `passesAtFloor` only
619
+ * increments when a pass fires within `minIntervalMs * 2` of the previous
620
+ * one; the recorder's strand takes six hours to re-form, so the counter is
621
+ * reset to 1 on every pass and can never reach six. The 507 MB probe is
622
+ * intact.
623
+ * - **Anything that recovers**: the run resets the moment the strand falls back
624
+ * under the trigger, and the 120 s floor returns with it.
625
+ */
626
+ var HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS = 6e5;
627
+ /**
628
+ * The floor in force for the NEXT pass, given how many have fired at the floor.
629
+ *
630
+ * Pure, so the cadence change is testable without stranding a gigabyte to reach
631
+ * it — and so the one place that decides it can be read on its own.
632
+ */
633
+ function reclaimIntervalMs(passesAtFloor, minIntervalMs = HEAP_RECLAIM_MIN_INTERVAL_MS, steadyStateIntervalMs = HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS, steadyStatePasses = 6) {
634
+ return passesAtFloor >= steadyStatePasses ? Math.max(minIntervalMs, steadyStateIntervalMs) : minIntervalMs;
635
+ }
206
636
  /** What a loop with nothing recorded yet reports. */
207
637
  var ZERO_LOOP_DELAY = {
208
638
  p50Ms: 0,
@@ -222,6 +652,37 @@ var ZERO_LOOP_DELAY = {
222
652
  * naively would print `loopMax=9223372036854ms` and be read as a catastrophe on
223
653
  * every boot. `count === 0` short-circuits to {@link ZERO_LOOP_DELAY}.
224
654
  *
655
+ * ## `loopP50=20ms` was the SAMPLER, not the loop (fixed 2026-08-29)
656
+ *
657
+ * `monitorEventLoopDelay` records the whole INTERVAL between its own timer
658
+ * firings, not the excess over the interval it asked for. So on a loop with
659
+ * nothing wrong the histogram reads `resolution`, and every `[mem]` line this
660
+ * process has ever emitted said `loopP50=20ms` — which was read, repeatedly in
661
+ * one session, as "hub-main is chronically 20 ms behind". It is not; 20 was the
662
+ * default `resolutionMs` of this very function.
663
+ *
664
+ * The delay is `interval − resolution`, and that is not a fudge factor — it is
665
+ * the only reading the four resolutions agree on. Measured here, one 120 ms
666
+ * block observed by four histograms at once:
667
+ *
668
+ * | resolution | raw p50 | raw max | max − resolution |
669
+ * | --- | --- | --- | --- |
670
+ * | 20 ms | 20.40 ms | 137.63 ms | 117.6 ms |
671
+ * | 10 ms | 10.22 ms | 123.60 ms | 113.6 ms |
672
+ * | 5 ms | 5.11 ms | 123.60 ms | 118.6 ms |
673
+ * | 1 ms | 1.27 ms | 121.04 ms | 120.0 ms |
674
+ *
675
+ * Raw, the four disagree by 16 ms about the same event and none of them reports
676
+ * the block. Corrected, they agree within 7 ms and all four name it. The
677
+ * subtraction costs nothing and needs no faster sampler — a 1 ms resolution
678
+ * would be 1 000 extra timer wakeups per second on the process that already
679
+ * serves ~44 000 socket operations per second, to buy 2 ms of accuracy on a
680
+ * quantity nobody reads below 100 ms.
681
+ *
682
+ * **Readings from before this change are 20 ms high.** `loopP99=21–28ms` in the
683
+ * 2026-08-29 census is really 1–8 ms; `loopMax=2804ms` is really 2784 ms. Do not
684
+ * compare a pre-fix series with a post-fix one without shifting it.
685
+ *
225
686
  * Returns undefined if the platform declines, so the caller keeps a heartbeat
226
687
  * either way.
227
688
  */
@@ -229,14 +690,15 @@ function createLoopDelayMeter(resolutionMs = 20) {
229
690
  try {
230
691
  const histogram = (0, node_perf_hooks.monitorEventLoopDelay)({ resolution: resolutionMs });
231
692
  histogram.enable();
693
+ const delay = (nanoseconds) => Math.max(0, Math.round(nanoseconds / 1e6) - resolutionMs);
232
694
  return {
233
695
  read: () => {
234
696
  try {
235
697
  if (histogram.count === 0) return ZERO_LOOP_DELAY;
236
698
  const sample = {
237
- p50Ms: Math.round(histogram.percentile(50) / 1e6),
238
- p99Ms: Math.round(histogram.percentile(99) / 1e6),
239
- maxMs: Math.round(histogram.max / 1e6)
699
+ p50Ms: delay(histogram.percentile(50)),
700
+ p99Ms: delay(histogram.percentile(99)),
701
+ maxMs: delay(histogram.max)
240
702
  };
241
703
  histogram.reset();
242
704
  return sample;
@@ -447,10 +909,22 @@ function createV8Reclaimer() {
447
909
  function formatOverBudget(label, b, source) {
448
910
  return `[mem] ${label} OVER RSS BUDGET rss=${b.rssMb}MB budget=${b.budgetMb}MB over=+${b.overMb}MB shape=${b.shape} heapUsed=${b.heapUsedMb}MB(${share(b.heapUsedMb, b.rssMb)}%) external=${b.externalMb}MB(${share(b.externalMb, b.rssMb)}%) nativeResidue=${b.nativeResidueMb}MB(${share(b.nativeResidueMb, b.rssMb)}%) arrayBuffers=${b.arrayBuffersMb}MB budgetFrom="${source}" — ${SHAPE_ADVICE[b.shape]}`;
449
911
  }
450
- function format(label, s, loop, budgetMb) {
912
+ /**
913
+ * The heartbeat line.
914
+ *
915
+ * ## Nothing here may be renamed or moved
916
+ *
917
+ * `heapUsed` says HOW MUCH; the per-space suffix says WHERE, which is the half
918
+ * that names a retained set. The suffix is APPENDED after the loop fields for
919
+ * one reason: every existing field then keeps its name and its position, so the
920
+ * `hl loki-query` pipelines written against this line keep matching. A rename or
921
+ * a reorder is the one change to a log format that silently breaks a query
922
+ * nobody will re-run until they need it.
923
+ */
924
+ function format(label, s, loop, budgetMb, suffix) {
451
925
  const line = `[mem] ${label} rss=${s.rssMb}MB heapUsed=${s.heapUsedMb}MB heapTotal=${s.heapTotalMb}MB heapLimit=${s.heapLimitMb}MB used=${Math.round(s.usedRatio * 100)}% external=${s.externalMb}MB arrayBuffers=${s.arrayBuffersMb}MB` + (budgetMb === void 0 ? "" : ` rssBudget=${budgetMb}MB`);
452
- if (loop === void 0) return line;
453
- return `${line} loopP50=${loop.p50Ms}ms loopP99=${loop.p99Ms}ms loopMax=${loop.maxMs}ms`;
926
+ if (loop === void 0) return `${line}${suffix}`;
927
+ return `${line} loopP50=${loop.p50Ms}ms loopP99=${loop.p99Ms}ms loopMax=${loop.maxMs}ms${suffix}`;
454
928
  }
455
929
  /**
456
930
  * Start the heartbeat. Returns a stop function.
@@ -458,11 +932,14 @@ function format(label, s, loop, budgetMb) {
458
932
  * `unref`ed so it can never hold the process open, and every read is wrapped:
459
933
  * a diagnostic that can crash the process it watches is worse than none.
460
934
  */
461
- function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions, loopDelay = createLoopDelayMeter(), execArgv = process.execArgv, announceCeilingOrigin = true, rssBudget) {
935
+ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions, loopDelay = createLoopDelayMeter(), execArgv = process.execArgv, announceCeilingOrigin = true, rssBudget, probes) {
936
+ const readSpaces = probes?.readSpaces ?? readHeapSpaces;
937
+ const eventPlane = probes?.eventPlane === void 0 ? void 0 : createEventPlaneMeter(probes.eventPlane);
462
938
  const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
463
939
  const now = reclaimOptions?.now ?? (() => Date.now());
464
940
  const triggerMb = reclaimOptions?.triggerMb ?? 1024;
465
941
  const minIntervalMs = reclaimOptions?.minIntervalMs ?? 12e4;
942
+ const steadyStateIntervalMs = reclaimOptions?.steadyStateIntervalMs ?? 6e5;
466
943
  const fastIntervalMs = reclaimOptions?.fastIntervalMs ?? 2e3;
467
944
  const escalateRatio = reclaimOptions?.escalateRatio ?? .7;
468
945
  const deescalateRatio = reclaimOptions?.deescalateRatio ?? .6;
@@ -482,9 +959,10 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
482
959
  steadyStateAnnounced = false;
483
960
  return;
484
961
  }
962
+ const floorMs = reclaimIntervalMs(passesAtFloor, minIntervalMs, steadyStateIntervalMs);
485
963
  const sinceLast = now() - lastReclaimAt;
486
- if (sinceLast < minIntervalMs) return;
487
- passesAtFloor = sinceLast <= minIntervalMs * 2 ? passesAtFloor + 1 : 1;
964
+ if (sinceLast < floorMs) return;
965
+ passesAtFloor = sinceLast <= floorMs * 2 ? passesAtFloor + 1 : 1;
488
966
  lastReclaimAt = now();
489
967
  const startedAt = now();
490
968
  try {
@@ -497,7 +975,8 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
497
975
  sink.info(`[mem] reclaim ${label} stranded=${strandedMb(sample)}MB rss=${sample.rssMb}MB→${after.rssMb}MB freed=${sample.rssMb - after.rssMb}MB arrayBuffers=${sample.arrayBuffersMb}MB→${after.arrayBuffersMb}MB took=${now() - startedAt}ms`);
498
976
  if (passesAtFloor >= 6 && !steadyStateAnnounced) {
499
977
  steadyStateAnnounced = true;
500
- sink.warn(`[mem] reclaim ${label} has run at the floor for ${passesAtFloor} consecutive passes (every ${minIntervalMs}ms) — the stop-the-world is now STEADY STATE, not a rescue. The allocation source is what needs the fix; this pass only bounds its peak.`);
978
+ const nextFloorMs = reclaimIntervalMs(passesAtFloor, minIntervalMs, steadyStateIntervalMs);
979
+ sink.warn(`[mem] reclaim ${label} has run at the floor for ${passesAtFloor} consecutive passes (every ${minIntervalMs}ms) — the stop-the-world is now STEADY STATE, not a rescue: stranded never fell back under ${triggerMb}MB between passes, so the trigger is not discriminating on this process and what is left deciding is the timer. BACKING OFF to every ${nextFloorMs}ms — the pass keeps running (it is still the only measurement of this process's live ArrayBuffer set) at a cost the router can pay. The allocation source is what needs the fix; this pass only bounds its peak.`);
501
980
  }
502
981
  };
503
982
  let mode = "steady";
@@ -560,7 +1039,7 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
560
1039
  const due = at - lastLoggedAt >= intervalMs;
561
1040
  if (mode === "escalated" || due) {
562
1041
  lastLoggedAt = at;
563
- const line = format(label, sample, loopDelay?.read(), budgetMb);
1042
+ const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces())}${formatEventPlane(eventPlane?.read())}`);
564
1043
  if (sample.nearLimit) sink.warn(`${line} — APPROACHING HEAP LIMIT`);
565
1044
  else if (mode === "escalated") sink.warn(`${line} — heap elevated, sampling every ${probeIntervalMs}ms`);
566
1045
  else sink.info(line);
@@ -5479,6 +5958,34 @@ var LocalChildRegistry = class {
5479
5958
  };
5480
5959
  }
5481
5960
  /**
5961
+ * The regime the counters above were produced under, read once from
5962
+ * `CAMSTACK_UDS_EVENT_FANOUT` at construction.
5963
+ *
5964
+ * A suppressed count means "nothing WAS dropped" under `filter` and "nothing
5965
+ * WOULD have been dropped" under `shadow`. Those are different claims, and
5966
+ * until this getter existed the mode was invisible at runtime — the counters
5967
+ * were readable and the regime that produced them was not.
5968
+ */
5969
+ get eventFanoutMode() {
5970
+ return this.fanoutMode;
5971
+ }
5972
+ /**
5973
+ * Connected children that never declared a subscription pattern set.
5974
+ *
5975
+ * Each one is a fail-open on BOTH planes: `childWantsEvent` returns true for
5976
+ * an undeclared child ({@link ChildEntry.eventPatterns} `=== null`), and
5977
+ * `aggregateEventInterest` returns `null` — accept everything — if ANY
5978
+ * connected child is undeclared, which disables the node's inbound cross-node
5979
+ * gate as well. **One legacy runner silently turns off the filtering for the
5980
+ * whole node**, and nothing reported it, so a zero here is as load-bearing as
5981
+ * a non-zero one.
5982
+ */
5983
+ undeclaredChildCount() {
5984
+ let count = 0;
5985
+ for (const entry of this.children.values()) if (entry.eventPatterns === null) count += 1;
5986
+ return count;
5987
+ }
5988
+ /**
5482
5989
  * Does `entry` want to receive an event in `category`? Honours the fan-out
5483
5990
  * mode: `broadcast` → always; undeclared patterns (`null`) → always
5484
5991
  * (fail-open); else the child's declared set must match via `matchesPattern`
@@ -8692,12 +9199,24 @@ Object.defineProperty(exports, "CapabilityUnavailableError", {
8692
9199
  return CapabilityUnavailableError;
8693
9200
  }
8694
9201
  });
9202
+ Object.defineProperty(exports, "DECISIVE_HEAP_SPACES", {
9203
+ enumerable: true,
9204
+ get: function() {
9205
+ return DECISIVE_HEAP_SPACES;
9206
+ }
9207
+ });
8695
9208
  Object.defineProperty(exports, "DeviceRegistry", {
8696
9209
  enumerable: true,
8697
9210
  get: function() {
8698
9211
  return DeviceRegistry;
8699
9212
  }
8700
9213
  });
9214
+ Object.defineProperty(exports, "EVENT_PLANE_TOP_N", {
9215
+ enumerable: true,
9216
+ get: function() {
9217
+ return EVENT_PLANE_TOP_N;
9218
+ }
9219
+ });
8701
9220
  Object.defineProperty(exports, "EVENT_TOPIC_PREFIX", {
8702
9221
  enumerable: true,
8703
9222
  get: function() {
@@ -8716,12 +9235,24 @@ Object.defineProperty(exports, "HEAP_RECLAIM_MIN_INTERVAL_MS", {
8716
9235
  return HEAP_RECLAIM_MIN_INTERVAL_MS;
8717
9236
  }
8718
9237
  });
9238
+ Object.defineProperty(exports, "HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS", {
9239
+ enumerable: true,
9240
+ get: function() {
9241
+ return HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS;
9242
+ }
9243
+ });
8719
9244
  Object.defineProperty(exports, "HEAP_RECLAIM_TRIGGER_MB", {
8720
9245
  enumerable: true,
8721
9246
  get: function() {
8722
9247
  return HEAP_RECLAIM_TRIGGER_MB;
8723
9248
  }
8724
9249
  });
9250
+ Object.defineProperty(exports, "HEAP_SPACE_REPORT_MIN_MB", {
9251
+ enumerable: true,
9252
+ get: function() {
9253
+ return HEAP_SPACE_REPORT_MIN_MB;
9254
+ }
9255
+ });
8725
9256
  Object.defineProperty(exports, "HEAP_WATCH_INTERVAL_MS", {
8726
9257
  enumerable: true,
8727
9258
  get: function() {
@@ -8794,6 +9325,12 @@ Object.defineProperty(exports, "RSS_BUDGET_RELEASE_RATIO", {
8794
9325
  return RSS_BUDGET_RELEASE_RATIO;
8795
9326
  }
8796
9327
  });
9328
+ Object.defineProperty(exports, "RUNNER_HEAP_SNAPSHOT_ENV", {
9329
+ enumerable: true,
9330
+ get: function() {
9331
+ return RUNNER_HEAP_SNAPSHOT_ENV;
9332
+ }
9333
+ });
8797
9334
  Object.defineProperty(exports, "RUNNER_HEAP_WATCH_INTERVAL_MS", {
8798
9335
  enumerable: true,
8799
9336
  get: function() {
@@ -8830,6 +9367,12 @@ Object.defineProperty(exports, "UdsLocalTransportServer", {
8830
9367
  return UdsLocalTransportServer;
8831
9368
  }
8832
9369
  });
9370
+ Object.defineProperty(exports, "ZERO_LOOP_DELAY", {
9371
+ enumerable: true,
9372
+ get: function() {
9373
+ return ZERO_LOOP_DELAY;
9374
+ }
9375
+ });
8833
9376
  Object.defineProperty(exports, "__resetCapUsageRegistryForTests", {
8834
9377
  enumerable: true,
8835
9378
  get: function() {
@@ -8956,6 +9499,18 @@ Object.defineProperty(exports, "createDeferredHeapWatchSink", {
8956
9499
  return createDeferredHeapWatchSink;
8957
9500
  }
8958
9501
  });
9502
+ Object.defineProperty(exports, "createEventPlaneMeter", {
9503
+ enumerable: true,
9504
+ get: function() {
9505
+ return createEventPlaneMeter;
9506
+ }
9507
+ });
9508
+ Object.defineProperty(exports, "createEventPlaneReader", {
9509
+ enumerable: true,
9510
+ get: function() {
9511
+ return createEventPlaneReader;
9512
+ }
9513
+ });
8959
9514
  Object.defineProperty(exports, "createHubCapForwardService", {
8960
9515
  enumerable: true,
8961
9516
  get: function() {
@@ -8974,6 +9529,12 @@ Object.defineProperty(exports, "createLocalTransport", {
8974
9529
  return createLocalTransport;
8975
9530
  }
8976
9531
  });
9532
+ Object.defineProperty(exports, "createLoopDelayMeter", {
9533
+ enumerable: true,
9534
+ get: function() {
9535
+ return createLoopDelayMeter;
9536
+ }
9537
+ });
8977
9538
  Object.defineProperty(exports, "createParentUnownedCallHandler", {
8978
9539
  enumerable: true,
8979
9540
  get: function() {
@@ -9028,12 +9589,36 @@ Object.defineProperty(exports, "deserializeTypedArrays", {
9028
9589
  return deserializeTypedArrays;
9029
9590
  }
9030
9591
  });
9592
+ Object.defineProperty(exports, "diffEventPlane", {
9593
+ enumerable: true,
9594
+ get: function() {
9595
+ return diffEventPlane;
9596
+ }
9597
+ });
9598
+ Object.defineProperty(exports, "emitHeapDiagnosticReport", {
9599
+ enumerable: true,
9600
+ get: function() {
9601
+ return emitHeapDiagnosticReport;
9602
+ }
9603
+ });
9031
9604
  Object.defineProperty(exports, "encodeFrame", {
9032
9605
  enumerable: true,
9033
9606
  get: function() {
9034
9607
  return encodeFrame;
9035
9608
  }
9036
9609
  });
9610
+ Object.defineProperty(exports, "formatEventPlane", {
9611
+ enumerable: true,
9612
+ get: function() {
9613
+ return formatEventPlane;
9614
+ }
9615
+ });
9616
+ Object.defineProperty(exports, "formatHeapSpaces", {
9617
+ enumerable: true,
9618
+ get: function() {
9619
+ return formatHeapSpaces;
9620
+ }
9621
+ });
9037
9622
  Object.defineProperty(exports, "getBrokerEventBus", {
9038
9623
  enumerable: true,
9039
9624
  get: function() {
@@ -9082,6 +9667,18 @@ Object.defineProperty(exports, "getWorkerNativeCapSnapshot", {
9082
9667
  return getWorkerNativeCapSnapshot;
9083
9668
  }
9084
9669
  });
9670
+ Object.defineProperty(exports, "heapSnapshotAuthorised", {
9671
+ enumerable: true,
9672
+ get: function() {
9673
+ return heapSnapshotAuthorised;
9674
+ }
9675
+ });
9676
+ Object.defineProperty(exports, "heapSpaceField", {
9677
+ enumerable: true,
9678
+ get: function() {
9679
+ return heapSpaceField;
9680
+ }
9681
+ });
9085
9682
  Object.defineProperty(exports, "hubMainRssBudget", {
9086
9683
  enumerable: true,
9087
9684
  get: function() {
@@ -9142,6 +9739,24 @@ Object.defineProperty(exports, "parseRssBudgetMb", {
9142
9739
  return parseRssBudgetMb;
9143
9740
  }
9144
9741
  });
9742
+ Object.defineProperty(exports, "readHeapSpaces", {
9743
+ enumerable: true,
9744
+ get: function() {
9745
+ return readHeapSpaces;
9746
+ }
9747
+ });
9748
+ Object.defineProperty(exports, "readMoleculerFanoutMode", {
9749
+ enumerable: true,
9750
+ get: function() {
9751
+ return readMoleculerFanoutMode;
9752
+ }
9753
+ });
9754
+ Object.defineProperty(exports, "reclaimIntervalMs", {
9755
+ enumerable: true,
9756
+ get: function() {
9757
+ return reclaimIntervalMs;
9758
+ }
9759
+ });
9145
9760
  Object.defineProperty(exports, "registerEventBusService", {
9146
9761
  enumerable: true,
9147
9762
  get: function() {
@@ -9172,6 +9787,12 @@ Object.defineProperty(exports, "runNpm", {
9172
9787
  return runNpm;
9173
9788
  }
9174
9789
  });
9790
+ Object.defineProperty(exports, "selectReportedSpaces", {
9791
+ enumerable: true,
9792
+ get: function() {
9793
+ return selectReportedSpaces;
9794
+ }
9795
+ });
9175
9796
  Object.defineProperty(exports, "serializeTypedArrays", {
9176
9797
  enumerable: true,
9177
9798
  get: function() {