@camstack/system 1.2.216 → 1.2.218

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 +9 -6
  2. package/dist/addon-runner.mjs +9 -6
  3. package/dist/addon-utils.js +1 -1
  4. package/dist/addon-utils.mjs +1 -1
  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 +1 -1
  28. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  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/native-metrics.addon.d.ts +0 -7
  32. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -8
  33. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -8
  34. package/dist/builtins/platform-probe/index.js +1 -1
  35. package/dist/builtins/platform-probe/index.mjs +1 -1
  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 +1 -1
  41. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  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/{custom-action-registry-jY0NOZK8.js → custom-action-registry-BDwM5qAK.js} +19 -0
  51. package/dist/{custom-action-registry-F__gp_VX.mjs → custom-action-registry-CsONUlhC.mjs} +19 -0
  52. package/dist/{dist-DYWqXngV.js → dist-BOlMCOeT.js} +157 -5
  53. package/dist/{dist-MtqqwJVI.mjs → dist-DigmGsQS.mjs} +152 -6
  54. package/dist/index.d.ts +3 -1
  55. package/dist/index.js +11 -3
  56. package/dist/index.mjs +4 -4
  57. package/dist/kernel/array-buffer-census.d.ts +122 -0
  58. package/dist/kernel/custom-action-registry.d.ts +10 -1
  59. package/dist/kernel/heap-watch.d.ts +15 -0
  60. package/dist/kernel/transport/child-cap-protocol.d.ts +15 -1
  61. package/dist/kernel/transport/local-child-client.d.ts +18 -2
  62. package/dist/{manifest-system-deps-DvY1bY_n.js → manifest-system-deps-Bo92lg5u.js} +350 -14
  63. package/dist/{manifest-system-deps-726RBOX7.mjs → manifest-system-deps-D--wyMD9.mjs} +303 -15
  64. package/dist/{retired-settings-keys-BBrgMHDy.mjs → retired-settings-keys-vK_U-CG2.mjs} +1 -1
  65. package/dist/{retired-settings-keys-CXLIB19R.js → retired-settings-keys-xEAlYnv7.js} +1 -1
  66. package/package.json +1 -1
@@ -0,0 +1,122 @@
1
+ /** One power-of-two bucket of the live set: every buffer with `byteLength <= upToBytes`
2
+ * and above the previous bucket. */
3
+ export interface ArrayBufferSizeBucket {
4
+ readonly upToBytes: number;
5
+ readonly count: number;
6
+ readonly bytes: number;
7
+ }
8
+ /** One exact byteLength and how much of the live set it accounts for. */
9
+ export interface ArrayBufferExactSize {
10
+ readonly byteLength: number;
11
+ readonly count: number;
12
+ readonly bytes: number;
13
+ }
14
+ export interface ArrayBufferCensusReport {
15
+ /** Live `ArrayBuffer` objects reachable after the census's own GC. */
16
+ readonly count: number;
17
+ /** Their total `byteLength`. */
18
+ readonly bytes: number;
19
+ /** Buffers whose backing store is gone (`byteLength === 0`, detached). */
20
+ readonly detached: number;
21
+ /** Largest buckets first, by bytes. */
22
+ readonly buckets: readonly ArrayBufferSizeBucket[];
23
+ /** Largest exact sizes first, by bytes. */
24
+ readonly topSizes: readonly ArrayBufferExactSize[];
25
+ }
26
+ /** Take a census. Injectable so the heartbeat's gating is testable without an inspector. */
27
+ export type ArrayBufferCensus = () => Promise<ArrayBufferCensusReport>;
28
+ /**
29
+ * Take the census once `arrayBuffers` has been at or above this for
30
+ * {@link ARRAY_BUFFER_CENSUS_SUSTAIN_MS}.
31
+ *
32
+ * 512 MB. The two 2026-09-10 episodes crossed it 25 and 8 minutes in; the
33
+ * routine reading in six hours of 2-second samples around them was 18–100 MB
34
+ * with single-sample spikes to 479 MB, and the process's floor after every
35
+ * compaction is 12–18 MB. A dead-buffer sawtooth between major GCs (measured
36
+ * up to 3.65 GB on 2026-08-08 when the heap had 4 GB of headroom) cannot reach
37
+ * it while GC runs every few seconds — and if one did, the census would SAY
38
+ * so: it reports the live total after its own GC next to the raw reading.
39
+ */
40
+ export declare const ARRAY_BUFFER_CENSUS_THRESHOLD_MB = 512;
41
+ /**
42
+ * How long the reading must stay above the threshold before a census is taken.
43
+ *
44
+ * 60 s = 30 probes at the 2 s cadence. A burst that a scavenge or the next
45
+ * major GC returns never pays a forced GC; an episode climbing at the slowest
46
+ * rate measured (20 MB/min) is still 20 MB higher by the time it is measured,
47
+ * which is nothing against the threshold.
48
+ */
49
+ export declare const ARRAY_BUFFER_CENSUS_SUSTAIN_MS = 60000;
50
+ /**
51
+ * Minimum spacing between two censuses.
52
+ *
53
+ * 30 minutes: the second episode ran 76 minutes, so it would have produced
54
+ * three readings — enough to see the shape change (or not) as it grew — at a
55
+ * cost the router already pays six times an hour for the reclaim pass.
56
+ */
57
+ export declare const ARRAY_BUFFER_CENSUS_COOLDOWN_MS: number;
58
+ /**
59
+ * A drop of at least this share of the threshold between two consecutive
60
+ * probes, from a reading that had been SUSTAINED above the threshold, is a
61
+ * RELEASE — the boundary both episodes crossed with no line, and the one line
62
+ * that lets the release be correlated with whatever else the process logged
63
+ * that second. Sustained, not merely above: a one-probe spike that the next
64
+ * scavenge sweeps (a 1.3 GB burst in 11 s was measured on 2026-08-29) is not
65
+ * an episode ending, and a WARN for every one of those would bury the line
66
+ * this exists to produce.
67
+ */
68
+ export declare const ARRAY_BUFFER_RELEASE_MIN_DROP_RATIO = 0.5;
69
+ export interface ArrayBufferCensusGateOptions {
70
+ readonly thresholdMb?: number;
71
+ readonly sustainMs?: number;
72
+ readonly cooldownMs?: number;
73
+ }
74
+ /** What one probe reading means to the gate. */
75
+ export type ArrayBufferCensusVerdict = {
76
+ readonly kind: 'hold';
77
+ }
78
+ /** Take a census now. `reason` is printed on the resulting line. */
79
+ | {
80
+ readonly kind: 'take';
81
+ readonly reason: string;
82
+ }
83
+ /** The live set was released between this probe and the previous one. */
84
+ | {
85
+ readonly kind: 'released';
86
+ readonly fromMb: number;
87
+ readonly toMb: number;
88
+ };
89
+ export interface ArrayBufferCensusGate {
90
+ /** Judge one reading. A `take` verdict starts the cooldown. */
91
+ readonly observe: (arrayBuffersMb: number, at: number) => ArrayBufferCensusVerdict;
92
+ }
93
+ /**
94
+ * The pure decision: threshold, sustain, cooldown, release — testable without
95
+ * allocating a gigabyte or forcing a GC.
96
+ */
97
+ export declare function createArrayBufferCensusGate(options?: ArrayBufferCensusGateOptions): ArrayBufferCensusGate;
98
+ /** The inspector answers `unknown`; the report is trusted only once it has this shape. */
99
+ export declare function isArrayBufferCensusReport(value: unknown): value is ArrayBufferCensusReport;
100
+ /**
101
+ * The real census: an in-process inspector session, opened for the call and
102
+ * closed after it, so no session is left listening between censuses.
103
+ *
104
+ * Every remote object it creates is released before the session closes; a
105
+ * failure anywhere still disconnects. The session is in-process — nothing
106
+ * listens on a port, nothing outside this process can reach it.
107
+ */
108
+ export declare function createInspectorArrayBufferCensus(): ArrayBufferCensus;
109
+ /** What a census line needs beyond the report. */
110
+ export interface ArrayBufferCensusContext {
111
+ /** `process.memoryUsage().arrayBuffers` at the probe that triggered it. */
112
+ readonly rawMb: number;
113
+ readonly tookMs: number;
114
+ /** The gate's `take` reason. */
115
+ readonly reason: string;
116
+ }
117
+ /**
118
+ * The census line. `live` is what survived the census's own GC; `raw` is the
119
+ * reading that triggered it — when they disagree by a lot, the growth was dead
120
+ * buffers awaiting a sweep, not a retention, and the line says which.
121
+ */
122
+ export declare function formatArrayBufferCensus(label: string, report: ArrayBufferCensusReport, context: ArrayBufferCensusContext): string;
@@ -1,4 +1,4 @@
1
- import { CustomActionCaller, CustomActionSpec, CustomActionsSpec } from '@camstack/types';
1
+ import { ChildCustomActionCatalogs, CustomActionCaller, CustomActionSpec, CustomActionsSpec } from '@camstack/types';
2
2
  type Handler = (action: string, input: unknown, caller?: CustomActionCaller) => Promise<unknown>;
3
3
  export interface CustomActionEntry {
4
4
  readonly spec: CustomActionSpec;
@@ -19,5 +19,14 @@ export declare class CustomActionRegistry {
19
19
  resolve(addonId: string, action: string): CustomActionEntry | null;
20
20
  listActions(addonId: string): readonly string[];
21
21
  listAddons(): readonly string[];
22
+ /**
23
+ * Every registered catalog with its schemas stripped, keyed by addon id —
24
+ * what a runner puts in its register frame so the hub learns the catalogs
25
+ * from the process that owns them (D444). `hostedAddonIds` are the addons
26
+ * this runner hosts: each is present in the result, with an EMPTY catalog
27
+ * when it registered none, so the parent can say "declares no actions" per
28
+ * addon instead of guessing from an absent key.
29
+ */
30
+ describeAll(hostedAddonIds: readonly string[]): ChildCustomActionCatalogs;
22
31
  }
23
32
  export {};
@@ -1,6 +1,7 @@
1
1
  import { EventPlaneReader } from './event-plane-report.js';
2
2
  import { SocketPlaneReader } from './socket-plane-report.js';
3
3
  import { HeapSpaceReader } from './heap-spaces.js';
4
+ import { ArrayBufferCensus, ArrayBufferCensusGateOptions } from './array-buffer-census.js';
4
5
  /**
5
6
  * What hub-main calls itself in a `[mem]` line.
6
7
  *
@@ -606,6 +607,20 @@ export interface HeapWatchProbes {
606
607
  * from the parent's side. Only hub-main and an agent's main pass one.
607
608
  */
608
609
  readonly socketPlane?: SocketPlaneReader;
610
+ /**
611
+ * The ArrayBuffer census that ARMS ITSELF. No default: it costs a forced
612
+ * full GC when it fires, and only hub-main has an episode on record (two
613
+ * silent linear climbs to 1.3 GB and 5 GB on 2026-09-10, each released in
614
+ * one instant with no line, the second two hours before the OOM). A runner
615
+ * that legitimately holds gigabytes of ArrayBuffers (`hub/stream-broker`,
616
+ * ~900 MB of RTP pre-roll rings) would fire it forever. See
617
+ * `array-buffer-census.ts` for the gate, the cost and what it is NOT.
618
+ */
619
+ readonly arrayBufferCensus?: ArrayBufferCensusProbe;
620
+ }
621
+ /** How the census is wired: the census itself plus the gate's thresholds. */
622
+ export interface ArrayBufferCensusProbe extends ArrayBufferCensusGateOptions {
623
+ readonly census: ArrayBufferCensus;
609
624
  }
610
625
  /**
611
626
  * Start the heartbeat. Returns a stop function.
@@ -1,4 +1,4 @@
1
- import { CustomActionCaller, IReadinessRegistryRecord, LogLevel, LogTags, SystemEvent } from '@camstack/types';
1
+ import { ChildCustomActionCatalogs, CustomActionCaller, IReadinessRegistryRecord, LogLevel, LogTags, SystemEvent } from '@camstack/types';
2
2
  /**
3
3
  * Routing descriptor a child sends so the parent can route cap calls to it.
4
4
  * The provider implementation never crosses the wire — only these keys do.
@@ -35,6 +35,18 @@ export interface RegisterMessage {
35
35
  * `EventSubUpdateMessage` for post-boot updates.
36
36
  */
37
37
  readonly eventPatterns?: readonly string[];
38
+ /**
39
+ * Custom-action catalogs of the addons this child hosts, keyed by addon id,
40
+ * with the Zod schemas stripped — see `CustomActionDescriptor`. Carried IN
41
+ * the register frame for the same reason as `eventPatterns`: the parent
42
+ * learns it race-free, at the post-init re-register, FROM THE PROCESS THAT
43
+ * OWNS THE ADDON. It is never learned by evaluating the addon's bundle in the
44
+ * parent (D444: ten 9 MB evaluations in hub-main, none of which produced a
45
+ * catalog, and every one pinned the evicted graph's module-scope state).
46
+ * OPTIONAL: absent from the pre-init register (the catalogs do not exist yet)
47
+ * and from a legacy child; absent means "not described yet", never "none".
48
+ */
49
+ readonly customActions?: ChildCustomActionCatalogs;
38
50
  }
39
51
  /**
40
52
  * Child → parent, fire-and-forget: the child's category-pattern subscription
@@ -248,6 +260,8 @@ export interface RegisteredChild {
248
260
  * one. See docs/decisions/adr-0188-an-unregister-carries-proof-of-ownership.md.
249
261
  */
250
262
  readonly incarnation: number;
263
+ /** See {@link RegisterMessage.customActions}. Absent = not described yet. */
264
+ readonly customActions?: ChildCustomActionCatalogs;
251
265
  }
252
266
  /** Arguments to route a cap method call (the `cap-call` message minus its discriminant). */
253
267
  export type CapCallInput = Omit<CapCallMessage, 'kind'>;
@@ -1,4 +1,4 @@
1
- import { IReadinessRegistryRecord, SystemEvent } from '@camstack/types';
1
+ import { ChildCustomActionCatalogs, IReadinessRegistryRecord, SystemEvent } from '@camstack/types';
2
2
  import { AddonCallInput, CapCallInput, ChildCapDescriptor, ChildLogMessage } from './child-cap-protocol.js';
3
3
  export interface LocalChildClientOptions {
4
4
  /** Parent node id — selects the UDS endpoint this child connects to. */
@@ -56,6 +56,15 @@ export declare class LocalChildClient {
56
56
  * subscriptions do), the register carries the real union — even if empty.
57
57
  */
58
58
  private hasDeclaredEventPatterns;
59
+ /**
60
+ * The custom-action catalogs of every hosted addon, once the runner's init
61
+ * loop has produced them (`updateCaps(caps, catalogs)` at post-init). `null`
62
+ * until then, and OMITTED from the register frame while null: the parent
63
+ * reads absence as "not described yet", and a pre-init register must never
64
+ * look like "this child declares no actions". Kept on the client so every
65
+ * later re-register (native-cap change, reconnect) re-carries it unchanged.
66
+ */
67
+ private latestCustomActions;
59
68
  /** Events and logs queued while the channel is not yet open. */
60
69
  private readonly pendingEmits;
61
70
  /** Handler for parent→child events. Registered via `onEvent`. */
@@ -138,7 +147,14 @@ export declare class LocalChildClient {
138
147
  * it (device-restore can race ahead of the UDS connect). After `start()`,
139
148
  * the set is sent immediately.
140
149
  */
141
- updateCaps(caps: readonly ChildCapDescriptor[]): Promise<void>;
150
+ updateCaps(caps: readonly ChildCapDescriptor[], customActions?: ChildCustomActionCatalogs): Promise<void>;
151
+ /**
152
+ * The register frame: caps, plus everything a re-register must atomically
153
+ * re-carry so no separate re-sync can be missed — the subscription union
154
+ * (omitted if nothing ever declared, which keeps the fail-open shape) and the
155
+ * custom-action catalogs (omitted until the init loop produced them).
156
+ */
157
+ private registerFrame;
142
158
  /**
143
159
  * Fire-and-forget: send a system event to the parent for forwarding to the
144
160
  * hub event bus. Safe to call before `start()` — events are buffered and