@camstack/system 1.2.354 → 1.2.356
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/calendars/calendar-prefs-store.d.ts +7 -0
- package/dist/builtins/calendars/calendars.addon.js +3 -2
- package/dist/builtins/calendars/calendars.addon.mjs +3 -2
- package/dist/builtins/camera-grid/grid-activity-mirror.d.ts +12 -2
- package/dist/builtins/camera-grid/index.js +15 -3
- package/dist/builtins/camera-grid/index.mjs +15 -3
- package/dist/builtins/composer/composer.addon.js +53 -12
- package/dist/builtins/composer/composer.addon.mjs +53 -12
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/block-settings-store.d.ts +5 -0
- package/dist/builtins/core-blocks/core-blocks.addon.js +7 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +7 -2
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/analyze-stats.d.ts +0 -2
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +9 -11
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{child-cap-dispatch-C1x1kNJK.mjs → child-cap-dispatch-BcRHQBKW.mjs} +28 -81
- package/dist/{child-cap-dispatch-CRqYKHAb.js → child-cap-dispatch-wbIQJctP.js} +27 -86
- package/dist/{composition-sources-DzkEFd8q.mjs → composition-sources-BBfqepyT.mjs} +1 -1
- package/dist/{composition-sources-0nuWOdNd.js → composition-sources-CeO0K2cl.js} +1 -1
- package/dist/{dist-DVyXxn41.mjs → dist-B7WRgEZY.mjs} +82 -49
- package/dist/{dist-DePB7uwU.js → dist-CFVOy8VT.js} +87 -48
- package/dist/index.d.ts +1 -1
- package/dist/index.js +18 -46
- package/dist/index.mjs +19 -46
- package/dist/kernel/event-plane-report.d.ts +7 -36
- package/dist/kernel/fs-utils.d.ts +1 -5
- package/dist/kernel/heap-spaces.d.ts +2 -23
- package/dist/kernel/index.d.ts +0 -2
- package/dist/kernel/moleculer/event-bus-core.d.ts +6 -28
- package/dist/kernel/moleculer/process-service.d.ts +2 -5
- package/dist/kernel/moleculer/runner-native-allocator.d.ts +1 -6
- package/dist/kernel/transport/index.d.ts +1 -1
- package/dist/kernel/transport/local-child-registry.d.ts +8 -41
- package/dist/kernel/transport/uds-event-bridge.d.ts +2 -2
- package/dist/{retired-settings-keys-BTKZdPn6.js → retired-settings-keys-CRlTzxaS.js} +1 -1
- package/dist/{retired-settings-keys-DFur4hJF.mjs → retired-settings-keys-DKRjfz0U.mjs} +1 -1
- package/package.json +1 -1
- package/dist/kernel/heap-allocation-sample.d.ts +0 -107
|
@@ -22,27 +22,13 @@
|
|
|
22
22
|
* on that runner also counts page-cache reads and it owns a vector store, so the
|
|
23
23
|
* correlation is not an attribution. `fanoutTop` turns it into one.
|
|
24
24
|
*
|
|
25
|
-
* ##
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* (`
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* The hub runs with `CAMSTACK_MOLECULER_EVENT_FANOUT=shadow` — which computes
|
|
33
|
-
* the drop decision, counts the would-suppresses and **still delivers every
|
|
34
|
-
* event** — and **neither counter has ever had a production caller**: both
|
|
35
|
-
* functions are reachable only from barrel re-exports and unit tests. So the
|
|
36
|
-
* burn-in has no end condition, and the promotion to `filter` never happened
|
|
37
|
-
* because the evidence that would authorise it was never surfaced. This module
|
|
38
|
-
* surfaces it. It changes no default and flips no env: the promotion stays a
|
|
39
|
-
* one-env decision for the operator, and it now has a number behind it.
|
|
40
|
-
*
|
|
41
|
-
* Read the modes with the counts, always. A suppressed count of 0 means
|
|
42
|
-
* "nothing would have been dropped" under `shadow` and "nothing WAS dropped"
|
|
43
|
-
* under `filter`, and those are different claims. A count printed without its
|
|
44
|
-
* regime is unreadable, and the regime is read ONCE at construction — invisible
|
|
45
|
-
* at runtime until now.
|
|
25
|
+
* ## Both planes always filter
|
|
26
|
+
*
|
|
27
|
+
* The cross-node plane ran a `shadow` burn-in (`CAMSTACK_MOLECULER_EVENT_FANOUT`)
|
|
28
|
+
* with no end condition, and the UDS plane carried the same three-mode switch
|
|
29
|
+
* (`CAMSTACK_UDS_EVENT_FANOUT`). Both switches were removed on 2026-10-06: a
|
|
30
|
+
* suppressed count now always means "this many WERE dropped", and the line no
|
|
31
|
+
* longer prints a regime because there is only one.
|
|
46
32
|
*
|
|
47
33
|
* ## The fail-open nobody can see
|
|
48
34
|
*
|
|
@@ -81,16 +67,7 @@
|
|
|
81
67
|
* `fanoutOrphans` counts what was serialised and walked across every child with
|
|
82
68
|
* zero subscribers. A suppressed pair was measured at **255 ns** — 1.84 ms/s of
|
|
83
69
|
* event loop at this rate — so the filter is not the cost; the emit is.
|
|
84
|
-
*
|
|
85
|
-
* ## What this is NOT evidence of
|
|
86
|
-
*
|
|
87
|
-
* `shadow` is the CROSS-NODE plane. The local UDS plane defaults to `filter` and
|
|
88
|
-
* its env is unset, so it is filtering. hub-main's ~44 000 socket syscalls/s are
|
|
89
|
-
* mostly to LOCAL runners, so the shadow mode is a real defect and is **not**
|
|
90
|
-
* established as the source of that load. Do not read these two facts as one.
|
|
91
70
|
*/
|
|
92
|
-
/** Fan-out regime for one plane. Same three values on both. */
|
|
93
|
-
export type EventFanoutMode = 'filter' | 'shadow' | 'broadcast';
|
|
94
71
|
/** One child's fan-out counters, as the registry keeps them (cumulative). */
|
|
95
72
|
export interface ChildFanoutSample {
|
|
96
73
|
readonly childId: string;
|
|
@@ -127,7 +104,6 @@ export interface ChildFanoutRegistry {
|
|
|
127
104
|
readonly listChildren: () => readonly ChildFanoutRegistryChild[];
|
|
128
105
|
readonly getChildEventStats: (childId: string) => ChildFanoutRegistryStats | null;
|
|
129
106
|
readonly undeclaredChildCount: () => number;
|
|
130
|
-
readonly eventFanoutMode: EventFanoutMode;
|
|
131
107
|
readonly categoryFanout: () => readonly CategoryFanoutSample[];
|
|
132
108
|
readonly categoryCensusOverflow: () => number;
|
|
133
109
|
}
|
|
@@ -138,8 +114,6 @@ export interface CrossNodeEventStats {
|
|
|
138
114
|
}
|
|
139
115
|
/** One cumulative reading of both planes. */
|
|
140
116
|
export interface EventPlaneCounters {
|
|
141
|
-
readonly udsMode: EventFanoutMode;
|
|
142
|
-
readonly crossNodeMode: EventFanoutMode;
|
|
143
117
|
readonly children: readonly ChildFanoutSample[];
|
|
144
118
|
readonly childrenConnected: number;
|
|
145
119
|
readonly childrenUndeclared: number;
|
|
@@ -156,7 +130,6 @@ export type EventPlaneReader = () => EventPlaneCounters | undefined;
|
|
|
156
130
|
export interface EventPlaneSources {
|
|
157
131
|
readonly registry: () => ChildFanoutRegistry | null;
|
|
158
132
|
readonly crossNodeStats: () => CrossNodeEventStats | null;
|
|
159
|
-
readonly crossNodeMode: () => EventFanoutMode;
|
|
160
133
|
}
|
|
161
134
|
/**
|
|
162
135
|
* Build a reader over the two registries.
|
|
@@ -183,8 +156,6 @@ export declare function createEventPlaneReader(sources: EventPlaneSources): Even
|
|
|
183
156
|
export declare const EVENT_PLANE_TOP_N = 5;
|
|
184
157
|
/** Both planes over one heartbeat window. */
|
|
185
158
|
export interface EventPlaneWindow {
|
|
186
|
-
readonly udsMode: EventFanoutMode;
|
|
187
|
-
readonly crossNodeMode: EventFanoutMode;
|
|
188
159
|
readonly childrenConnected: number;
|
|
189
160
|
readonly childrenUndeclared: number;
|
|
190
161
|
readonly fanoutSent: number;
|
|
@@ -26,8 +26,7 @@ export declare function copyDirRecursive(src: string, dest: string): Promise<voi
|
|
|
26
26
|
* `addons/` stays node_modules-free, which is what lets the backup tar the whole
|
|
27
27
|
* folder with no exclusion list (see ADR-0027). An addon that genuinely needs an
|
|
28
28
|
* un-bundleable runtime dep declares it explicitly in
|
|
29
|
-
* `camstack.runtimeDependencies
|
|
30
|
-
* `CAMSTACK_INSTALL_FULL_DEPS=1` restores the legacy install-everything path.
|
|
29
|
+
* `camstack.runtimeDependencies`.
|
|
31
30
|
*
|
|
32
31
|
* (Historically this mirrored the build preset's COMMON_NATIVE_DEPS and
|
|
33
32
|
* per-addon-installed node-av/sharp/onnxruntime-node/ssh2/werift/systeminformation
|
|
@@ -49,9 +48,6 @@ export declare const RUNTIME_NATIVE_KEEP: readonly string[];
|
|
|
49
48
|
* `dependencies` so `--omit=peer` installs can't drop them (pipeline's
|
|
50
49
|
* patched `werift`).
|
|
51
50
|
*
|
|
52
|
-
* Escape hatch: `CAMSTACK_INSTALL_FULL_DEPS=1` restores the legacy behaviour
|
|
53
|
-
* (strip only @camstack/*) for debugging a suspected undeclared runtime dep.
|
|
54
|
-
*
|
|
55
51
|
* Returns a new object (immutable).
|
|
56
52
|
*/
|
|
57
53
|
export declare function stripBundledDeps(pkg: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -88,22 +88,6 @@ export declare function selectReportedSpaces(spaces: readonly HeapSpaceUsage[],
|
|
|
88
88
|
* a query someone already wrote.
|
|
89
89
|
*/
|
|
90
90
|
export declare function formatHeapSpaces(spaces: readonly HeapSpaceUsage[], minMb?: number): string;
|
|
91
|
-
/**
|
|
92
|
-
* Env var that authorises a heap snapshot on SIGUSR2.
|
|
93
|
-
*
|
|
94
|
-
* A snapshot is an admin mutation on a production hub: `writeHeapSnapshot`
|
|
95
|
-
* streams a file the size of the heap to `/tmp` and stops the world while it
|
|
96
|
-
* walks it — on the recorder that is a multi-GB file and a stall measured in
|
|
97
|
-
* seconds. The per-space breakdown is ~1.2 µs and changes nothing. Welding them
|
|
98
|
-
* to one signal priced the free answer at the cost of the expensive one.
|
|
99
|
-
*/
|
|
100
|
-
/**
|
|
101
|
-
* Whether the operator has authorised the snapshot half of SIGUSR2.
|
|
102
|
-
*
|
|
103
|
-
* Explicit `'on'` only. Anything else — unset, empty, `'true'`, `'1'` — is NOT
|
|
104
|
-
* authorisation: a multi-GB stop-the-world write must never be reachable by a
|
|
105
|
-
* value someone set for a different purpose.
|
|
106
|
-
*/
|
|
107
91
|
/** What a diagnostic report is ABOUT. */
|
|
108
92
|
export interface HeapDiagnosticRequest {
|
|
109
93
|
/** The runner's nodeId, so the line groups with its `[mem]` heartbeat. */
|
|
@@ -115,19 +99,14 @@ export interface HeapDiagnosticRequest {
|
|
|
115
99
|
export interface HeapDiagnosticDeps {
|
|
116
100
|
readonly readMemory: () => NodeJS.MemoryUsage;
|
|
117
101
|
readonly readSpaces: HeapSpaceReader;
|
|
118
|
-
readonly env: NodeJS.ProcessEnv;
|
|
119
102
|
}
|
|
120
103
|
/**
|
|
121
|
-
* The SIGUSR2 report — memory + the FULL per-space breakdown
|
|
122
|
-
* snapshot
|
|
104
|
+
* The SIGUSR2 report — memory + the FULL per-space breakdown; never a heap
|
|
105
|
+
* snapshot (D718) — see the note in the body.
|
|
123
106
|
*
|
|
124
107
|
* The breakdown here keeps every non-empty space at 0.1 MB, unlike the
|
|
125
108
|
* heartbeat's filtered whole-MB pair: this is a hand-fired diagnostic read once
|
|
126
109
|
* by a human who asked for it, so completeness costs nothing. The heartbeat runs
|
|
127
110
|
* unattended on every runner forever, so it pays for every field it prints.
|
|
128
|
-
*
|
|
129
|
-
* A refused snapshot SAYS SO. A branch that drops work silently reads as "it was
|
|
130
|
-
* never requested", and this one is fired by an operator who is standing there
|
|
131
|
-
* waiting for a file.
|
|
132
111
|
*/
|
|
133
112
|
export declare function emitHeapDiagnosticReport(request: HeapDiagnosticRequest, deps?: HeapDiagnosticDeps): void;
|
package/dist/kernel/index.d.ts
CHANGED
|
@@ -45,8 +45,6 @@ export { createCoreCapService, CORE_CAP_SERVICE_NAME } from './moleculer/core-ca
|
|
|
45
45
|
export type { CoreCapAction, CoreCapCallOrigin, CoreCapServiceOptions, } from './moleculer/core-cap-service.js';
|
|
46
46
|
export { createAddonContext, createUdsAddonContext, setHubConnected, adaptBrokerToCluster, registerEventBusService, setNodeEventInterest, getMoleculerEventStats, subscribePassthrough, getBrokerEventBus, clusterEventTopic, EVENT_TOPIC_PREFIX, } from './moleculer/addon-context-factory.js';
|
|
47
47
|
export type { MoleculerEventStats } from './moleculer/addon-context-factory.js';
|
|
48
|
-
export type { MoleculerEventFanoutMode } from './moleculer/event-bus-core.js';
|
|
49
|
-
export { readMoleculerFanoutMode } from './moleculer/event-bus-core.js';
|
|
50
48
|
export { HubLogForwarder } from './moleculer/hub-log-forwarder.js';
|
|
51
49
|
export type { AddonContextOptions } from './moleculer/addon-context-factory.js';
|
|
52
50
|
export { createHubService } from './moleculer/hub-service.js';
|
|
@@ -142,31 +142,12 @@ export declare const RING_BUFFER_DENY_PATTERNS: readonly string[];
|
|
|
142
142
|
export declare const MAX_RECENT_EVENTS = 1000;
|
|
143
143
|
export declare function isHighFrequencyCategory(category: string): boolean;
|
|
144
144
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
* declared patterns).
|
|
151
|
-
* - `shadow` — compute the drop decision + count would-suppresses, but
|
|
152
|
-
* STILL deliver every event (burn-in: prove zero would-be-starved deliveries
|
|
153
|
-
* before flipping to `filter`).
|
|
154
|
-
* - `broadcast` — ignore the gate entirely (pre-D2 behaviour).
|
|
155
|
-
*
|
|
156
|
-
* ROLLBACK CONTRACT (operators, read this): this env governs ONLY the inter-node
|
|
157
|
-
* (Moleculer) gate. The intra-host UDS fan-out has a SEPARATE, independent
|
|
158
|
-
* kill-switch, `CAMSTACK_UDS_EVENT_FANOUT` (see `local-child-registry.ts`). A
|
|
159
|
-
* FULL rollback to pre-D2 / pre-#44 delivery therefore requires BOTH env vars
|
|
160
|
-
* set to `broadcast` AND a process restart on EVERY node (hub + all agents) —
|
|
161
|
-
* each is read ONCE at registration/construction, so a running process will not
|
|
162
|
-
* pick up a change. Flipping only one leg leaves the other filtering and yields
|
|
163
|
-
* inconsistent behaviour. Recommended first fleet-wide enable: `shadow` on both,
|
|
164
|
-
* watch the suppressed counters (`getMoleculerEventStats` /
|
|
165
|
-
* `getChildEventStats`), then flip to `filter` once burn-in shows zero
|
|
166
|
-
* would-be-starved deliveries.
|
|
145
|
+
* Cross-node (Moleculer) inbound gate: an inbound cross-node event whose
|
|
146
|
+
* category no local subscriber on THIS node wants (the union of its children's
|
|
147
|
+
* declared patterns) is dropped and counted (`suppressed`). It always filters —
|
|
148
|
+
* the `CAMSTACK_MOLECULER_EVENT_FANOUT` shadow/broadcast modes were removed on
|
|
149
|
+
* 2026-10-06; the intra-host analogue is `LocalChildRegistry.childWantsEvent`.
|
|
167
150
|
*/
|
|
168
|
-
export type MoleculerEventFanoutMode = 'filter' | 'shadow' | 'broadcast';
|
|
169
|
-
export declare function readMoleculerFanoutMode(): MoleculerEventFanoutMode;
|
|
170
151
|
/**
|
|
171
152
|
* A node's inbound-interest snapshot used by {@link crossNodeAcceptsCategory}.
|
|
172
153
|
* - `retainRecent` — the receiving bus retains events for `getRecent`/audit
|
|
@@ -185,16 +166,13 @@ export interface CrossNodeInterestSnapshot {
|
|
|
185
166
|
/**
|
|
186
167
|
* Does this node want to accept an inbound cross-node event in `category`?
|
|
187
168
|
* The receiving-side mirror of `LocalChildRegistry.childWantsEvent`:
|
|
188
|
-
* - `broadcast` mode → always (gate disabled).
|
|
189
169
|
* - a retaining bus (hub main) → always (it serves `getRecent` + admin-ui;
|
|
190
170
|
* its interest is genuinely everything).
|
|
191
171
|
* - undeclared interest (`null`) → always (fail-open).
|
|
192
172
|
* - else the declared union must match via `matchesPattern` — the SAME
|
|
193
173
|
* function the local subscriber map-key gate uses, giving delivery parity.
|
|
194
|
-
* `shadow` is handled by the caller (it counts the would-suppress but still
|
|
195
|
-
* delivers), exactly like the UDS fan-out.
|
|
196
174
|
*/
|
|
197
|
-
export declare function crossNodeAcceptsCategory(
|
|
175
|
+
export declare function crossNodeAcceptsCategory(snapshot: CrossNodeInterestSnapshot, category: string): boolean;
|
|
198
176
|
/**
|
|
199
177
|
* Deliver `event` to all matching local subscribers and — ONLY on a bus that
|
|
200
178
|
* opted into retention (`state.retainRecent`, i.e. the hub main process) and
|
|
@@ -95,9 +95,8 @@ export declare const HEAVY_MAX_OLD_MB_DEFAULT = 1024;
|
|
|
95
95
|
* --v8-pool-size=2 9 threads
|
|
96
96
|
* --v8-pool-size=0 18 threads
|
|
97
97
|
*
|
|
98
|
-
* So
|
|
99
|
-
*
|
|
100
|
-
* the tuning off, use `CAMSTACK_RUNNER_HEAP_TUNING=off`.
|
|
98
|
+
* So the flag is only ever passed with a value of at least 1 — the same trap as
|
|
99
|
+
* `MALLOC_ARENA_MAX=0` in `runner-native-allocator.ts`.
|
|
101
100
|
*
|
|
102
101
|
* ## What is deliberately NOT bounded
|
|
103
102
|
*
|
|
@@ -110,8 +109,6 @@ export declare const HEAVY_MAX_OLD_MB_DEFAULT = 1024;
|
|
|
110
109
|
* ~58 more threads for serialized filesystem I/O in runners whose I/O profile
|
|
111
110
|
* has not been measured, on a media system. A thread saving is not worth a
|
|
112
111
|
* media gap.
|
|
113
|
-
*
|
|
114
|
-
* Override: `CAMSTACK_RUNNER_LIGHT_V8_POOL_SIZE`.
|
|
115
112
|
*/
|
|
116
113
|
export declare const LIGHT_V8_POOL_SIZE_DEFAULT = 2;
|
|
117
114
|
interface SpawnedProcess {
|
|
@@ -85,12 +85,7 @@ export interface RunnerNativeAllocatorEnv {
|
|
|
85
85
|
* restores the glibc/sharp defaults. Recoverable without a rebuild.
|
|
86
86
|
* 2. A value the operator already put in the environment (`MALLOC_ARENA_MAX`,
|
|
87
87
|
* `VIPS_CONCURRENCY`) — inherited verbatim, never overwritten.
|
|
88
|
-
* 3.
|
|
89
|
-
* 4. The defaults above.
|
|
90
|
-
*
|
|
91
|
-
* A nonsense override falls back to the default rather than being passed through:
|
|
92
|
-
* glibc reads `MALLOC_ARENA_MAX=0` as "unbounded", which is the very state this
|
|
93
|
-
* exists to leave.
|
|
88
|
+
* 3. The defaults above.
|
|
94
89
|
*/
|
|
95
90
|
export declare function runnerNativeAllocatorEnv(parentEnv: NodeJS.ProcessEnv, platform?: NodeJS.Platform): RunnerNativeAllocatorEnv;
|
|
96
91
|
/**
|
|
@@ -10,7 +10,7 @@ export { PeerAnsweredError } from './peer-answered-error.js';
|
|
|
10
10
|
export { UdsLocalTransportServer, UdsLocalTransportClient } from './uds-local-transport.js';
|
|
11
11
|
export { createLocalTransport } from './create-local-transport.js';
|
|
12
12
|
export type { ChildCapDescriptor, RegisterMessage, ChildLogMessage, ChildEventMessage, ChildToParentRequest, CapCallMessage, CapCallInput, CapCallOutMessage, AddonCallMessage, AddonCallInput, AddonCallTarget, AddonSettingsMethod, ParentToChildRequest, RegisteredChild, SetLogLevelMessage, } from './child-cap-protocol.js';
|
|
13
|
-
export { LocalChildRegistry, afterWorkerOnlineAnnounce, UDS_NO_ROUTE_PREFIX } from './local-child-registry.js';
|
|
13
|
+
export { LocalChildRegistry, afterWorkerOnlineAnnounce, UDS_NO_ROUTE_PREFIX, } from './local-child-registry.js';
|
|
14
14
|
export type { LocalChildRegistryOptions, LocalChildRegistryLogger, ChildLifecycleEvents, } from './local-child-registry.js';
|
|
15
15
|
export type { LocalChildClientOptions, AddonCallHandler } from './local-child-client.js';
|
|
16
16
|
export { LocalChildClient } from './local-child-client.js';
|
|
@@ -29,17 +29,6 @@ export interface ForwardCensus {
|
|
|
29
29
|
* check.
|
|
30
30
|
*/
|
|
31
31
|
export declare const PRE_REGISTER_PEER_ID = "(pre-register)";
|
|
32
|
-
/**
|
|
33
|
-
* Fan-out mode for parent→child event delivery, from the
|
|
34
|
-
* `CAMSTACK_UDS_EVENT_FANOUT` env (read once at registry construction):
|
|
35
|
-
* - `filter` (default) — apply the subscription gate; a child receives a
|
|
36
|
-
* category only if one of its declared patterns matches.
|
|
37
|
-
* - `shadow` — compute the gate decision + count would-suppresses, but
|
|
38
|
-
* STILL send every event (burn-in: prove zero would-be-starved deliveries).
|
|
39
|
-
* - `broadcast` — ignore the gate entirely (today's behaviour); the operator's
|
|
40
|
-
* one-env rollback without redeploying runners.
|
|
41
|
-
*/
|
|
42
|
-
export type UdsEventFanoutMode = 'filter' | 'shadow' | 'broadcast';
|
|
43
32
|
/** Per-child event fan-out counters (sent = delivered, suppressed = gated/would-gate). */
|
|
44
33
|
export interface ChildEventStats {
|
|
45
34
|
sent: number;
|
|
@@ -56,8 +45,7 @@ export interface ChildEventStats {
|
|
|
56
45
|
* sums them concludes the cluster emits an order of magnitude more than it does.
|
|
57
46
|
*
|
|
58
47
|
* `wanted` is the number of (event × child) pairs whose SUBSCRIPTION matched —
|
|
59
|
-
* the gate answer,
|
|
60
|
-
* deliver regardless) still report the truth. `wanted === 0` over a window means
|
|
48
|
+
* the gate answer, which is also the delivery answer. `wanted === 0` over a window means
|
|
61
49
|
* the category was serialised and walked across every child and **nobody asked
|
|
62
50
|
* for it**: pure waste, and the one finding worth acting on.
|
|
63
51
|
*/
|
|
@@ -340,8 +328,6 @@ export declare class LocalChildRegistry {
|
|
|
340
328
|
private readonly capUsageObserver?;
|
|
341
329
|
/** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
|
|
342
330
|
private readonly egressRoutedCaps;
|
|
343
|
-
/** Active event fan-out mode, read once from `CAMSTACK_UDS_EVENT_FANOUT`. */
|
|
344
|
-
private readonly fanoutMode;
|
|
345
331
|
/** Per-child event fan-out counters (sent / suppressed). */
|
|
346
332
|
private readonly childEventStats;
|
|
347
333
|
/** D467: per-category production census (cumulative). See {@link CategoryFanoutSample}. */
|
|
@@ -374,7 +360,7 @@ export declare class LocalChildRegistry {
|
|
|
374
360
|
/**
|
|
375
361
|
* Per-child event fan-out counters (`{ sent, suppressed }`) or `null` if the
|
|
376
362
|
* child has no recorded events yet. Exposed for the starvation-verification
|
|
377
|
-
* surface (
|
|
363
|
+
* surface (operator debug).
|
|
378
364
|
*/
|
|
379
365
|
getChildEventStats(childId: string): ChildEventStats | null;
|
|
380
366
|
/**
|
|
@@ -420,16 +406,6 @@ export declare class LocalChildRegistry {
|
|
|
420
406
|
* `decoded` half of an entry, next to the bytes it carried.
|
|
421
407
|
*/
|
|
422
408
|
readActionCensus(): CapActionReading;
|
|
423
|
-
/**
|
|
424
|
-
* The regime the counters above were produced under, read once from
|
|
425
|
-
* `CAMSTACK_UDS_EVENT_FANOUT` at construction.
|
|
426
|
-
*
|
|
427
|
-
* A suppressed count means "nothing WAS dropped" under `filter` and "nothing
|
|
428
|
-
* WOULD have been dropped" under `shadow`. Those are different claims, and
|
|
429
|
-
* until this getter existed the mode was invisible at runtime — the counters
|
|
430
|
-
* were readable and the regime that produced them was not.
|
|
431
|
-
*/
|
|
432
|
-
get eventFanoutMode(): UdsEventFanoutMode;
|
|
433
409
|
/**
|
|
434
410
|
* Connected children that never declared a subscription pattern set.
|
|
435
411
|
*
|
|
@@ -443,27 +419,18 @@ export declare class LocalChildRegistry {
|
|
|
443
419
|
*/
|
|
444
420
|
undeclaredChildCount(): number;
|
|
445
421
|
/**
|
|
446
|
-
* Does `entry` want to receive an event in `category`?
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
422
|
+
* Does `entry` want to receive an event in `category`? Undeclared patterns
|
|
423
|
+
* (`null`) → always (fail-open, counted by {@link undeclaredChildCount});
|
|
424
|
+
* else the child's declared set must match via `matchesPattern` — the SAME
|
|
425
|
+
* function the child's own `deliverShared` map-key gate uses, giving provable
|
|
426
|
+
* delivery parity. The parent always filters: the `CAMSTACK_UDS_EVENT_FANOUT`
|
|
427
|
+
* shadow/broadcast modes were removed on 2026-10-06.
|
|
452
428
|
*
|
|
453
429
|
* NOTE: this gate must NOT consult `RING_BUFFER_DENY_PATTERNS` /
|
|
454
430
|
* `isHighFrequencyCategory` — those are ring-buffer STORAGE policy; a child
|
|
455
431
|
* that explicitly subscribes to a ring-denied category must still RECEIVE it.
|
|
456
432
|
*/
|
|
457
433
|
private childWantsEvent;
|
|
458
|
-
/**
|
|
459
|
-
* The SUBSCRIPTION answer alone, with no fan-out-mode override.
|
|
460
|
-
*
|
|
461
|
-
* {@link childWantsEvent} answers "will this child be sent the event", which
|
|
462
|
-
* under `broadcast` is `true` for everything and therefore cannot say whether
|
|
463
|
-
* anyone actually asked. The D467 census needs the second question, so the
|
|
464
|
-
* two are separate functions and `broadcast` mode overrides only the first.
|
|
465
|
-
*/
|
|
466
|
-
private childSubscribesTo;
|
|
467
434
|
/**
|
|
468
435
|
* D2: this node's aggregate cross-node event interest — the UNION of every
|
|
469
436
|
* connected child's declared category patterns. Consumed by the parent's
|
|
@@ -7,8 +7,8 @@ import { IEventBus, SystemEvent } from '@camstack/types';
|
|
|
7
7
|
* fans an event only to children whose declared category-pattern set matches
|
|
8
8
|
* `event.category` (mirror of each child's local `SharedBusState.handlers`
|
|
9
9
|
* keys). A child that never declared a set (legacy/undeclared) fails OPEN and
|
|
10
|
-
* receives everything.
|
|
11
|
-
* `
|
|
10
|
+
* receives everything. There is no kill-switch any more (the
|
|
11
|
+
* `CAMSTACK_UDS_EVENT_FANOUT` modes were removed on 2026-10-06). The bridge itself
|
|
12
12
|
* needs no per-event logic change — both fan-out call sites here go through the
|
|
13
13
|
* filtered `broadcastEventToChildren`. `sendEventToChild` (targeted push) is
|
|
14
14
|
* NOT filtered — an explicit single-child send expresses intent.
|
package/package.json
CHANGED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WHERE the bytes come from, without stopping the process.
|
|
3
|
-
*
|
|
4
|
-
* A heap SNAPSHOT answers "what is retained" and costs a stop-the-world walk
|
|
5
|
-
* plus a multi-gigabyte write. On this hub that took the machine down twice;
|
|
6
|
-
* the second attempt did not even finish — it left a 0-byte file and an
|
|
7
|
-
* unresponsive host that had to be rebooted. The remotely-triggerable command
|
|
8
|
-
* is gone (`scripts/check-no-heap-dump-command.ts`).
|
|
9
|
-
*
|
|
10
|
-
* V8's SAMPLING heap profiler answers a cheaper, different question: which
|
|
11
|
-
* allocation SITES the bytes came from, statistically, with no pause and
|
|
12
|
-
* nothing written. Measured locally: 51 ms for a window that allocated 200 000
|
|
13
|
-
* objects.
|
|
14
|
-
*
|
|
15
|
-
* ## What this is NOT
|
|
16
|
-
*
|
|
17
|
-
* It is not retention analysis. It says where bytes were BORN, not what is
|
|
18
|
-
* holding them alive, and a leak is about the second. It is still the right
|
|
19
|
-
* first instrument for the recorder's ~900 MB of large objects that "no
|
|
20
|
-
* allocation site in its tree can produce" — because naming the sites is
|
|
21
|
-
* exactly the claim under test, and if the sites turn out to be ordinary, the
|
|
22
|
-
* retention question is the one that survives.
|
|
23
|
-
*
|
|
24
|
-
* This module is the PURE half: it folds the profile V8 hands back. The
|
|
25
|
-
* sampling belongs to the caller, so the fold is testable without a profiler.
|
|
26
|
-
*/
|
|
27
|
-
/** One frame as the inspector protocol reports it. */
|
|
28
|
-
export interface AllocationCallFrame {
|
|
29
|
-
readonly functionName: string;
|
|
30
|
-
readonly url: string;
|
|
31
|
-
readonly lineNumber: number;
|
|
32
|
-
}
|
|
33
|
-
/** One node of `HeapProfiler.stopSampling`'s profile tree. */
|
|
34
|
-
export interface AllocationProfileNode {
|
|
35
|
-
readonly selfSize: number;
|
|
36
|
-
readonly callFrame: AllocationCallFrame;
|
|
37
|
-
readonly children?: readonly AllocationProfileNode[];
|
|
38
|
-
}
|
|
39
|
-
export interface AllocationSite {
|
|
40
|
-
readonly functionName: string;
|
|
41
|
-
/** `file.js:line` — what a human reads in a log line. */
|
|
42
|
-
readonly site: string;
|
|
43
|
-
readonly bytes: number;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Fold the tree into the biggest allocation sites.
|
|
47
|
-
*
|
|
48
|
-
* Sites are SUMMED across call paths: one site reached from two callers is one
|
|
49
|
-
* site, and reporting it twice at half the size is how a dominant allocator
|
|
50
|
-
* hides in a long tail. Identity is (function, url, line) — the same line of
|
|
51
|
-
* two files is two sites.
|
|
52
|
-
*/
|
|
53
|
-
export declare function summariseAllocationProfile(head: AllocationProfileNode, limit: number): readonly AllocationSite[];
|
|
54
|
-
/**
|
|
55
|
-
* The inspector session slice this needs. Injected so the sampler is testable
|
|
56
|
-
* without an inspector, and so nothing here reaches for a global.
|
|
57
|
-
*/
|
|
58
|
-
export interface HeapProfilerSession {
|
|
59
|
-
connect: () => void;
|
|
60
|
-
disconnect: () => void;
|
|
61
|
-
post: (method: string, paramsOrCb: unknown, maybeCb?: unknown) => void;
|
|
62
|
-
}
|
|
63
|
-
export interface SampleHeapAllocationsInput {
|
|
64
|
-
readonly session: HeapProfilerSession;
|
|
65
|
-
/** How long to sample. Bounded by the caller; this module never loops. */
|
|
66
|
-
readonly durationMs: number;
|
|
67
|
-
readonly limit: number;
|
|
68
|
-
readonly wait: (ms: number) => Promise<void>;
|
|
69
|
-
/** Bytes between samples. Larger = cheaper and coarser. */
|
|
70
|
-
readonly samplingInterval?: number;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Sample allocations for a bounded window and answer with the top sites.
|
|
74
|
-
*
|
|
75
|
-
* Writes NOTHING and pauses nothing. The profiler is stopped and the session
|
|
76
|
-
* disconnected in a `finally`, because a sampler left running is a tax on the
|
|
77
|
-
* process that outlives whoever enabled it — and the failure that made this
|
|
78
|
-
* module necessary was a diagnostic nobody could turn off from outside.
|
|
79
|
-
*/
|
|
80
|
-
export declare function sampleHeapAllocations(input: SampleHeapAllocationsInput): Promise<readonly AllocationSite[]>;
|
|
81
|
-
/**
|
|
82
|
-
* Per-runner opt-in for allocation sampling.
|
|
83
|
-
*
|
|
84
|
-
* Explicit `'on'` only — the same discipline the snapshot flag had. The
|
|
85
|
-
* DIFFERENCE is what it authorises: that flag allowed a stop-the-world walk and
|
|
86
|
-
* a multi-gigabyte write, so leaving it on in production (which is exactly what
|
|
87
|
-
* happened) was an outage waiting for a signal. This one allows ~50 ms of
|
|
88
|
-
* statistical sampling and one log line, so a runner left with it on is simply
|
|
89
|
-
* a runner that reports where its bytes come from.
|
|
90
|
-
*/
|
|
91
|
-
export declare const RUNNER_ALLOC_SAMPLE_ENV = "CAMSTACK_RUNNER_ALLOC_SAMPLE";
|
|
92
|
-
export declare function allocationSamplingEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
93
|
-
/** Sample on every Nth heartbeat — one sample per ~10 minutes at a 60 s beat. */
|
|
94
|
-
export declare const ALLOCATION_SAMPLE_EVERY_N_BEATS = 10;
|
|
95
|
-
/** How long one sample runs. Short enough that two can never overlap. */
|
|
96
|
-
export declare const ALLOCATION_SAMPLE_WINDOW_MS = 5000;
|
|
97
|
-
/** How many sites one log line carries. */
|
|
98
|
-
export declare const ALLOCATION_SAMPLE_TOP_N = 8;
|
|
99
|
-
/**
|
|
100
|
-
* Is this the beat that samples?
|
|
101
|
-
*
|
|
102
|
-
* Beat 0 never samples: a runner that has just booted has allocated nothing
|
|
103
|
-
* worth ranking. A non-positive cadence samples NEVER rather than always — a
|
|
104
|
-
* misconfigured `0` must not turn a diagnostic into a permanent load, which is
|
|
105
|
-
* the failure mode this whole module exists because of.
|
|
106
|
-
*/
|
|
107
|
-
export declare function shouldSampleAllocations(beat: number, everyN: number): boolean;
|