@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
@@ -0,0 +1,226 @@
1
+ import { ContainerMemoryPoint, ContainerMemorySnapshot, IScopedLogger, SettingsStoreClient } from '@camstack/types';
2
+ import { LoadSeriesRetention } from './load-series-store.js';
3
+ /**
4
+ * @durable class=audit owner=metrics-native
5
+ * write="one row per NODE per sample, appended by the HUB's `native-metrics`
6
+ * off its subscription to `metrics.node-processes-snapshot` — the same
7
+ * subscription, the same accepted-sample gate and the same timestamps as
8
+ * `metrics:node-load-samples`, so a memory row and the process rows of the
9
+ * same instant share an `atMs`. A node with no cgroup writes NOTHING; it
10
+ * never writes a zeroed row."
11
+ * retention="The operator's `loadSeriesRetentionHours` by age and
12
+ * CONTAINER_MEMORY_MAX_ROWS by count, swept in the same pass as the process
13
+ * table and through the same bounded page. Losing the table loses the cold
14
+ * window only: the ring keeps serving the last hour."
15
+ */
16
+ export declare const CONTAINER_MEMORY_COLLECTION = "metrics:node-memory-samples";
17
+ /**
18
+ * Per-node ceiling on the HOT ring, in samples.
19
+ *
20
+ * Deliberately the same 180 as the process ring — one hour at the 20 s cadence,
21
+ * six at the 10 s default's own reckoning — because the two series are read
22
+ * together and a memory window shorter than the process window would silently
23
+ * truncate the comparison the pair exists to support.
24
+ */
25
+ export declare const CONTAINER_MEMORY_SAMPLES_PER_NODE = 180;
26
+ /**
27
+ * Fleet ceiling on the hot ring, in READINGS.
28
+ *
29
+ * One reading per node per sample, so this is simply the per-node ceiling times
30
+ * the partition ceiling the process ring already declares (16). 2 880 readings
31
+ * of ten numbers each is well under a megabyte — the bound exists so a runaway
32
+ * node id space costs a fixed amount, not because the number is large.
33
+ */
34
+ export declare const CONTAINER_MEMORY_MAX_TOTAL_ROWS: number;
35
+ /**
36
+ * Hard ceiling on the durable table, in ROWS. The guarantee behind the
37
+ * retention intention, exactly as `DEFAULT_MAX_ROWS` is for the process table.
38
+ *
39
+ * | cadence | retention | rows (3 nodes) |
40
+ * | --- | --- | --- |
41
+ * | 10 s | 6 h (default) | 6 480 |
42
+ * | 5 s | 6 h | 12 960 |
43
+ * | 5 s | 72 h, 16 nodes | 829 440 — capped here |
44
+ *
45
+ * 50 000 rows is 7.7x the shipped default. This row is strictly narrower than
46
+ * a `metrics:node-load-samples` row — fewer columns, one index, every value an
47
+ * integer varint — and that one was MEASURED at 87 B/row, so 50 000 rows is
48
+ * **under 4.2 MiB** with the real figure lower still. It is not a knob: a
49
+ * guarantee that moves with the hand that raised the intention is not one.
50
+ */
51
+ export declare const CONTAINER_MEMORY_MAX_ROWS = 50000;
52
+ /** Rows one prune pass may remove. Bounded, never a full scan. */
53
+ export declare const CONTAINER_MEMORY_PRUNE_PAGE_ROWS = 20000;
54
+ export declare const CONTAINER_MEMORY_COLUMNS: readonly [{
55
+ readonly name: "id";
56
+ readonly type: "INTEGER";
57
+ readonly primaryKey: true;
58
+ readonly notNull: true;
59
+ }, {
60
+ readonly name: "nodeId";
61
+ readonly type: "TEXT";
62
+ readonly notNull: true;
63
+ }, {
64
+ readonly name: "atMs";
65
+ readonly type: "INTEGER";
66
+ readonly notNull: true;
67
+ }, {
68
+ readonly name: "source";
69
+ readonly type: "TEXT";
70
+ readonly notNull: true;
71
+ }, {
72
+ readonly name: "currentMib";
73
+ readonly type: "INTEGER";
74
+ readonly notNull: true;
75
+ }, {
76
+ readonly name: "limitMib";
77
+ readonly type: "INTEGER";
78
+ }, {
79
+ readonly name: "anonMib";
80
+ readonly type: "INTEGER";
81
+ }, {
82
+ readonly name: "fileMib";
83
+ readonly type: "INTEGER";
84
+ }, {
85
+ readonly name: "shmemMib";
86
+ readonly type: "INTEGER";
87
+ }, {
88
+ readonly name: "slabMib";
89
+ readonly type: "INTEGER";
90
+ }, {
91
+ readonly name: "gpuShmemMib";
92
+ readonly type: "INTEGER";
93
+ }];
94
+ export declare const CONTAINER_MEMORY_INDEXES: readonly [{
95
+ readonly name: "idx_node_memory_node_at";
96
+ readonly columns: readonly ["nodeId", "atMs"];
97
+ }];
98
+ /** One stored row, in the units the table stores them in. */
99
+ export interface ContainerMemoryRow {
100
+ readonly nodeId: string;
101
+ readonly atMs: number;
102
+ readonly source: string;
103
+ readonly currentMib: number;
104
+ readonly limitMib: number | null;
105
+ readonly anonMib: number | null;
106
+ readonly fileMib: number | null;
107
+ readonly shmemMib: number | null;
108
+ readonly slabMib: number | null;
109
+ readonly gpuShmemMib: number | null;
110
+ }
111
+ /** The ONE encode. */
112
+ export declare function snapshotToRow(nodeId: string, atMs: number, snapshot: ContainerMemorySnapshot): ContainerMemoryRow;
113
+ /**
114
+ * The ONE decode. A row whose `source` is not a hierarchy this build knows is
115
+ * skipped rather than coerced — a stored string that no longer means anything
116
+ * must not be charted as though it did.
117
+ */
118
+ export declare function rowToPoint(row: ContainerMemoryRow): ContainerMemoryPoint | null;
119
+ /** Structural validation on read. A malformed row is skipped, never charted. */
120
+ export declare function recordToMemoryRow(data: Record<string, unknown>): ContainerMemoryRow | null;
121
+ export interface ContainerMemoryRingOptions {
122
+ readonly samplesPerNode?: number;
123
+ /**
124
+ * Injectable clock, forwarded to the ring's idle-partition sweep. Tests
125
+ * drive eviction without sleeping for an hour; production uses `Date.now`.
126
+ */
127
+ readonly now?: () => number;
128
+ }
129
+ /**
130
+ * The HOT tier — a naming adapter over {@link NodeLoadRing}, not a second ring.
131
+ *
132
+ * One reading per sample, so the ring's "rows" and its samples are the same
133
+ * count and its fleet budget is a sample budget. Every bound, the idle sweep
134
+ * and the monotonic replay gate come from there unchanged.
135
+ */
136
+ export declare class ContainerMemoryRing {
137
+ private readonly ring;
138
+ constructor(options?: ContainerMemoryRingOptions);
139
+ /** Retain one reading. `false` = a timestamp this node already delivered. */
140
+ record(nodeId: string, atMs: number, snapshot: ContainerMemorySnapshot): boolean;
141
+ /**
142
+ * Read one node's retained readings, oldest-first. `sinceMs` is EXCLUSIVE,
143
+ * matching every other reader in this subsystem.
144
+ *
145
+ * A node nobody has recorded answers EMPTY — which is what "this node has no
146
+ * cgroup" looks like, and it must stay distinguishable from a zero.
147
+ */
148
+ read(nodeId: string, sinceMs?: number): readonly ContainerMemoryPoint[];
149
+ }
150
+ /**
151
+ * Merge the two tiers and reduce, oldest-first.
152
+ *
153
+ * Dedupe is on `atMs` with the HOT copy winning, exactly as the process reader
154
+ * does: the ring holds the reading as it arrived, the table holds it after the
155
+ * MiB encode.
156
+ *
157
+ * Reduction keeps, for each bucket, the reading with the largest
158
+ * `currentBytes` — WHOLE, every field from that one sample. A per-field
159
+ * maximum would synthesise a row whose parts never coexisted (an `anon` peak
160
+ * and a `file` peak minutes apart, summed into a total that never happened),
161
+ * and a mean would smear away the spike this series exists to find. `atMs`
162
+ * becomes the bucket START so the points lie on the same x-axis as the folded
163
+ * process series, which is the only reason both travel in one answer.
164
+ *
165
+ * An empty bucket stays ABSENT — never zero, never carried forward.
166
+ */
167
+ export declare function reduceContainerMemory(points: readonly ContainerMemoryPoint[], bucketMs: number, origin: number): readonly ContainerMemoryPoint[];
168
+ /** Merge cold + hot on `atMs`, hot wins. Exported because dedup is the
169
+ * property worth testing on its own. */
170
+ export declare function mergeContainerMemory(cold: readonly ContainerMemoryPoint[], hot: readonly ContainerMemoryPoint[]): readonly ContainerMemoryPoint[];
171
+ export interface ContainerMemoryStoreDeps {
172
+ readonly store: SettingsStoreClient;
173
+ readonly logger: IScopedLogger;
174
+ readonly now?: () => number;
175
+ readonly prunePageRows?: number;
176
+ }
177
+ /** What one prune pass did. Returned so a test can assert the bound held. */
178
+ export interface ContainerMemoryPruneOutcome {
179
+ readonly deletedByAge: number;
180
+ readonly deletedByCap: number;
181
+ readonly rowsExamined: number;
182
+ readonly capBit: boolean;
183
+ }
184
+ /**
185
+ * The COLD tier. Append-only, bounded, and never the authority on anything the
186
+ * hot ring can answer.
187
+ *
188
+ * Every method is best-effort and says so in the log rather than throwing at
189
+ * the emitter: a storage hiccup must cost a gap in a chart, never a dropped
190
+ * snapshot on the bus.
191
+ */
192
+ export declare class ContainerMemoryStore {
193
+ private declared;
194
+ private readonly store;
195
+ private readonly logger;
196
+ private readonly nowFn;
197
+ private readonly prunePageRows;
198
+ constructor(deps: ContainerMemoryStoreDeps);
199
+ /** Idempotently declare the collection. `false` when the store refused. */
200
+ declare(): Promise<boolean>;
201
+ /** Append ONE reading. */
202
+ append(nodeId: string, atMs: number, snapshot: ContainerMemorySnapshot): Promise<number>;
203
+ /** Read one node's cold readings, oldest-first. `sinceMs` is EXCLUSIVE. */
204
+ read(nodeId: string, sinceMs: number, limitRows: number): Promise<readonly ContainerMemoryPoint[]>;
205
+ /**
206
+ * Enforce BOTH bounds, oldest-first, through a bounded page each.
207
+ *
208
+ * Not rate-limited here: it is driven by the process store's own prune
209
+ * cadence, so it runs at most once a minute by construction and a second
210
+ * timer would be a second thing to get wrong.
211
+ */
212
+ prune(nodeIds: readonly string[], retention: LoadSeriesRetention): Promise<ContainerMemoryPruneOutcome | null>;
213
+ /** Total rows, or `null` when the store could not answer. */
214
+ count(): Promise<number | null>;
215
+ /**
216
+ * Delete this node's oldest rows, at most one page's worth.
217
+ *
218
+ * `cutoff === null` means "the oldest rows, whatever their age" — the
219
+ * row-cap path, which is bounded by `limitRows` instead. Either way the page
220
+ * is READ FIRST, ordered by the one index, and its last `atMs` becomes the
221
+ * effective cutoff for a single bounded delete. An unbounded `deleteWhere`
222
+ * would be one statement and one stalling transaction the first time a
223
+ * retention is lowered.
224
+ */
225
+ private deleteOldestPage;
226
+ }
@@ -48,6 +48,20 @@ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
48
48
  * per sample, to reach that very same table.
49
49
  */
50
50
  private loadStore;
51
+ /**
52
+ * The container's OWN memory, sampled on the process-snapshot tick.
53
+ *
54
+ * It rides that tick rather than a timer of its own so a memory reading and
55
+ * the process rows it must be compared against carry the SAME timestamp —
56
+ * the whole question is a subtraction, and two clocks make it an estimate.
57
+ * Constructed in `onInitialize`, where the logger exists; it resolves the
58
+ * cgroup once and latches.
59
+ */
60
+ private memoryProbe;
61
+ /** Hot tier for the container reading. Bounds in `container-memory-series.ts`. */
62
+ private readonly memoryRing;
63
+ /** Cold tier, HUB only — same reasoning as `loadStore`. */
64
+ private memoryStore;
51
65
  /** The resolved knobs. Re-resolved on every settings write. */
52
66
  private loadConfig;
53
67
  /**
@@ -97,6 +111,18 @@ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
97
111
  * cost this subsystem exists to avoid.
98
112
  */
99
113
  private readLoadSeries;
114
+ /**
115
+ * The container's memory over the same window, on the same x-axis.
116
+ *
117
+ * Both tiers, merged and deduped on `atMs` like the process series, then
118
+ * reduced against the SAME `bucketMs` and the SAME origin — otherwise the
119
+ * two series in one answer would sit on two different axes and the
120
+ * subtraction they exist for would be an eyeball.
121
+ *
122
+ * An EMPTY answer means the node has no cgroup, or nothing has been retained
123
+ * for it yet. It never means zero.
124
+ */
125
+ private readContainerMemory;
100
126
  /**
101
127
  * Re-resolve the knobs and restate the fixed cadence.
102
128
  *