@camstack/system 1.2.145 → 1.2.147
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 +2 -1
- package/dist/addon-runner.mjs +2 -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/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- 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/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- 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/load-series-config.d.ts +74 -0
- package/dist/builtins/native-metrics/load-series-reader.d.ts +37 -0
- package/dist/builtins/native-metrics/load-series-store.d.ts +232 -0
- package/dist/builtins/native-metrics/native-metrics.addon.d.ts +118 -35
- package/dist/builtins/native-metrics/native-metrics.addon.js +1463 -199
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1463 -199
- package/dist/builtins/native-metrics/node-load-ring.d.ts +214 -0
- package/dist/builtins/native-metrics/process-classification.d.ts +51 -0
- package/dist/builtins/native-metrics/thread-cpu-sampler.d.ts +116 -0
- 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/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 +25 -1
- 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 +2 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +2 -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/{dist-BVU5JADq.js → dist-Dl6MFXPr.js} +496 -35
- package/dist/{dist-CG7kwIZp.mjs → dist-DrBc-7Y3.mjs} +479 -36
- package/dist/index.d.ts +2 -2
- package/dist/index.js +45 -5
- package/dist/index.mjs +37 -6
- package/dist/kernel/heap-watch.d.ts +209 -1
- package/dist/{manifest-python-deps-BRyNCnnG.mjs → manifest-python-deps-DhT0oFOZ.mjs} +200 -8
- package/dist/{manifest-python-deps-GjlyPjm0.js → manifest-python-deps-FYZBHc3v.js} +253 -7
- package/dist/{retired-settings-keys-_PLI9w0k.js → retired-settings-keys-6w_JOqBg.js} +1 -1
- package/dist/{retired-settings-keys-Dm1z4mO4.mjs → retired-settings-keys-CF5r4YKq.mjs} +1 -1
- package/package.json +1 -1
package/dist/addon-runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
2
|
+
const require_manifest_python_deps = require("./manifest-python-deps-FYZBHc3v.js");
|
|
3
3
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -692,6 +692,7 @@ async function main() {
|
|
|
692
692
|
const stopHeapWatch = require_manifest_python_deps.startRunnerHeapWatch({
|
|
693
693
|
heapProfile: process.env["CAMSTACK_RUNNER_HEAP_PROFILE"],
|
|
694
694
|
reclaimSwitch: process.env["CAMSTACK_RUNNER_HEAP_RECLAIM"],
|
|
695
|
+
rssBudgetMb: process.env[require_manifest_python_deps.RUNNER_RSS_BUDGET_ENV],
|
|
695
696
|
label: nodeId,
|
|
696
697
|
sink: {
|
|
697
698
|
info: (line) => {
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { F as createUdsLoggerWithControl, I as LocalChildClient, Nt as
|
|
1
|
+
import { F as createUdsLoggerWithControl, Ht as startRunnerHeapWatch, I as LocalChildClient, Nt as RUNNER_RSS_BUDGET_ENV, bt as resolveAddonClass, i as createUdsAddonContext, it as setWorkerNativeCapsChangeListener, nt as getWorkerNativeCapSnapshot, ot as validateProviderRegistrations, t as installManifestPythonDeps, tt as getWorkerNativeCapProvider, yt as installManifestNativeDeps } from "./manifest-python-deps-DhT0oFOZ.mjs";
|
|
2
2
|
import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
|
|
3
3
|
import { register } from "node:module";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -688,6 +688,7 @@ async function main() {
|
|
|
688
688
|
const stopHeapWatch = startRunnerHeapWatch({
|
|
689
689
|
heapProfile: process.env["CAMSTACK_RUNNER_HEAP_PROFILE"],
|
|
690
690
|
reclaimSwitch: process.env["CAMSTACK_RUNNER_HEAP_RECLAIM"],
|
|
691
|
+
rssBudgetMb: process.env[RUNNER_RSS_BUDGET_ENV],
|
|
691
692
|
label: nodeId,
|
|
692
693
|
sink: {
|
|
693
694
|
info: (line) => {
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ot as errMsg, S as addonPagesCapability, kt as BaseAddon, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ot as errMsg, kt as BaseAddon, tn as EventCategory, w as addonWidgetsCapability } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
//#region src/builtins/alerts/prune-policy.ts
|
|
8
8
|
/**
|
|
9
9
|
* Ids older than `cutoffMs`, oldest first.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ht as createEvent, Ot as errMsg, T as alertsCapability, kt as BaseAddon, n as AlertSchema, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
//#region src/builtins/alerts/prune-policy.ts
|
|
3
3
|
/**
|
|
4
4
|
* Ids older than `cutoffMs`, oldest first.
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let buffer = require("buffer");
|
|
9
9
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as backupCapability,
|
|
1
|
+
import { D as backupCapability, kt as BaseAddon, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
3
3
|
import { Buffer as Buffer$1 } from "buffer";
|
|
4
4
|
import * as fsp from "node:fs/promises";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
//#region src/builtins/console-logging/console-destination.ts
|
|
9
9
|
var LEVEL_RANK = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { kt as BaseAddon, rt as logDestinationCapability } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
//#region src/builtins/console-logging/console-destination.ts
|
|
4
4
|
var LEVEL_RANK = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
3
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
6
6
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { M as coreBlockIdFromAddonId, N as coreBlocksCapability, Ot as errMsg, c as CoreBlockSchema, j as coreBlockAddonId, kt as BaseAddon, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX, u as DeclaredDevices } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
7
|
-
const require_retired_settings_keys = require("../../retired-settings-keys-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
|
+
const require_retired_settings_keys = require("../../retired-settings-keys-6w_JOqBg.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let _camstack_types_node = require("@camstack/types/node");
|
|
10
10
|
//#region src/builtins/device-manager/adoption-job-engine.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as buildStreamParamsConfigSchema,
|
|
2
|
-
import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-
|
|
1
|
+
import { A as buildStreamParamsConfigSchema, Ft as DeviceType, H as enumerateItemArrayFields, L as deviceManagerCapability, Nt as DeviceFeature, Ot as errMsg, Pt as DeviceRole, R as deviceStateCapability, Rt as WELL_KNOWN_TAB_MAP, U as enumerateSchemaFields, _ as STREAM_PROFILE_META, a as CAP_NAMES_WITH_STATUS, d as DeviceStatusSchema, en as sleep, ht as runtimeStatePolicyFor, kt as BaseAddon, lt as parseStreamParamsFormPatch, qt as isDeviceConfigCap, st as normalizeUnit, t as ALL_CAPABILITY_DEFINITIONS, tn as EventCategory, z as deviceStatusCapability } from "../../dist-DrBc-7Y3.mjs";
|
|
2
|
+
import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-CF5r4YKq.mjs";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { canonicalDeviceFingerprint } from "@camstack/types/node";
|
|
5
5
|
//#region src/builtins/device-manager/adoption-job-engine.ts
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
//#region src/builtins/doorbell/trigger-engine.ts
|
|
8
8
|
/**
|
|
9
9
|
* Pure trigger logic for the virtual-doorbell builtin — edge detection over
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as doorbellCapability,
|
|
1
|
+
import { B as doorbellCapability, Ft as DeviceType, Ht as createEvent, O as bareAddonId, Ot as errMsg, Q as isSourceCap, W as evaluateSensorEdge, Z as isSameAddonId, g as SOURCE_DEVICE_TYPES, h as SOURCE_CAPS, kt as BaseAddon, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
//#region src/builtins/doorbell/trigger-engine.ts
|
|
3
3
|
/**
|
|
4
4
|
* Pure trigger logic for the virtual-doorbell builtin — edge detection over
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
//#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
|
|
9
9
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { kt as BaseAddon, rt as logDestinationCapability } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
//#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
|
|
4
4
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
3
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
4
4
|
//#region src/builtins/liveness-monitor/liveness-checks.ts
|
|
5
5
|
var NO_DEVICES = "liveness:no-devices";
|
|
6
6
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ht as createEvent, Ot as errMsg, kt as BaseAddon, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
//#region src/builtins/liveness-monitor/liveness-checks.ts
|
|
3
3
|
var NO_DEVICES = "liveness:no-devices";
|
|
4
4
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
9
9
|
let crypto$1 = require("crypto");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as __require, o as __toESM, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import { E as authProviderCapability,
|
|
2
|
+
import { E as authProviderCapability, Tt as userManagementCapability, kt as BaseAddon, r as ApiKeyRecordSchema, v as ScopedTokenSchema, x as UserRecordSchema } from "../../dist-DrBc-7Y3.mjs";
|
|
3
3
|
import * as crypto$2 from "node:crypto";
|
|
4
4
|
import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
|
|
5
5
|
import nodeCrypto from "crypto";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
3
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
4
4
|
const require_tls = require("../../tls-u8QCJCFE.js");
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
6
6
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { kt as BaseAddon, nt as localNetworkCapability, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
import { S as readLanHttpState, _ as DEFAULT_LAN_HTTP_PORT, a as writeTlsMode, i as writeExtraSans, l as reissueTlsLeaf, n as readTlsAccessStatus, o as validateUploadedTls, r as readTlsMode, s as ensureTlsCert, t as readExtraSans, y as applyLanHttp } from "../../tls-CQhPGSJm.mjs";
|
|
3
3
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-Dl6MFXPr.js");
|
|
7
7
|
//#region src/builtins/loki-logging/loki-payload.ts
|
|
8
8
|
/**
|
|
9
9
|
* Loki rejects a label name that is not a valid Prometheus label
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { kt as BaseAddon, rt as logDestinationCapability } from "../../dist-DrBc-7Y3.mjs";
|
|
2
2
|
//#region src/builtins/loki-logging/loki-payload.ts
|
|
3
3
|
/**
|
|
4
4
|
* Loki rejects a label name that is not a valid Prometheus label
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two knobs of the durable load series, and the arithmetic that makes them
|
|
3
|
+
* honest.
|
|
4
|
+
*
|
|
5
|
+
* ## Where they live, and why there
|
|
6
|
+
*
|
|
7
|
+
* In `native-metrics`'s OWN global settings document — the one that already
|
|
8
|
+
* exists and already carries `samplingIntervalMs`. Fields on a document, never
|
|
9
|
+
* a method per knob: `system.getLoggingSettings` / `setLoggingSettings` set
|
|
10
|
+
* that precedent and it holds here.
|
|
11
|
+
*
|
|
12
|
+
* They are NOT in the logging document, and that is a decision rather than an
|
|
13
|
+
* omission. That document is about levels and diagnostic windows; a metrics
|
|
14
|
+
* cadence and a table's retention are neither. Two documents that both claim a
|
|
15
|
+
* knob is how this repo has already shipped a switch nobody read.
|
|
16
|
+
*
|
|
17
|
+
* They are cluster-wide, not per-node. Every node emits on the same cadence or
|
|
18
|
+
* the fleet's series cannot be laid over each other, and the table is single
|
|
19
|
+
* and hub-resident, so a per-node retention would be a promise nothing could
|
|
20
|
+
* keep.
|
|
21
|
+
*
|
|
22
|
+
* ## Refused, not clamped
|
|
23
|
+
*
|
|
24
|
+
* A cadence outside 5-60 s is REFUSED. Clamping would silently store 10 when
|
|
25
|
+
* the operator typed 2 and then report 10 back as though it had been accepted
|
|
26
|
+
* — the failure mode where a knob and its readback agree on a value nobody
|
|
27
|
+
* chose. The schema advertises the bounds; this refuses anything else.
|
|
28
|
+
*/
|
|
29
|
+
/** The resolved, in-force configuration. */
|
|
30
|
+
export interface LoadSeriesConfig {
|
|
31
|
+
readonly cadenceSec: number;
|
|
32
|
+
readonly retentionHours: number;
|
|
33
|
+
readonly maxRows: number;
|
|
34
|
+
}
|
|
35
|
+
/** Why a value was refused — the message an operator is shown verbatim. */
|
|
36
|
+
export declare class LoadSeriesConfigError extends Error {
|
|
37
|
+
constructor(message: string);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the configuration, REFUSING anything out of range.
|
|
41
|
+
*
|
|
42
|
+
* An ABSENT field takes its default — that is not a refusal, it is a document
|
|
43
|
+
* that has never been written. A PRESENT field outside its bounds throws.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveLoadSeriesConfig(raw: {
|
|
46
|
+
readonly loadSeriesCadenceSec?: unknown;
|
|
47
|
+
readonly loadSeriesRetentionHours?: unknown;
|
|
48
|
+
}): LoadSeriesConfig;
|
|
49
|
+
/** What a configuration is projected to cost, from OBSERVED counts. */
|
|
50
|
+
export interface LoadSeriesProjection {
|
|
51
|
+
/** Rows the retention window alone would hold. */
|
|
52
|
+
readonly intendedRows: number;
|
|
53
|
+
/** Rows actually allowed — `min(intendedRows, maxRows)`. */
|
|
54
|
+
readonly boundedRows: number;
|
|
55
|
+
readonly estimatedBytes: number;
|
|
56
|
+
/** Does the row cap bite before the retention window is full? */
|
|
57
|
+
readonly capBites: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Project the cost of a configuration from the numbers the cluster is actually
|
|
61
|
+
* reporting — nodes and processes OBSERVED, never a constant.
|
|
62
|
+
*
|
|
63
|
+
* This is what makes the knob honest: an operator raising retention to three
|
|
64
|
+
* days sees the row count and the megabytes BEFORE applying it, rather than
|
|
65
|
+
* discovering them afterwards. `MEASURED_BYTES_PER_ROW` is measured, not
|
|
66
|
+
* guessed — see `load-series-store.ts`.
|
|
67
|
+
*/
|
|
68
|
+
export declare function projectLoadSeriesCost(input: {
|
|
69
|
+
readonly config: LoadSeriesConfig;
|
|
70
|
+
/** Process rows observed across the fleet in the most recent snapshots. */
|
|
71
|
+
readonly observedProcessRows: number;
|
|
72
|
+
}): LoadSeriesProjection;
|
|
73
|
+
/** Human-readable one-liner for the settings form. */
|
|
74
|
+
export declare function describeLoadSeriesCost(projection: LoadSeriesProjection): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LoadPoint } from '@camstack/types';
|
|
2
|
+
import { RetainedSample } from './load-series-store.js';
|
|
3
|
+
/** One function's assembled series, before it is shaped for the wire. */
|
|
4
|
+
export interface FoldedSeries {
|
|
5
|
+
readonly key: string;
|
|
6
|
+
readonly kind: 'addon' | 'root' | 'unattributed';
|
|
7
|
+
readonly points: readonly LoadPoint[];
|
|
8
|
+
}
|
|
9
|
+
export interface MergeLoadSeriesInput {
|
|
10
|
+
/** Cold samples, oldest-first. May overlap `hot` — that is expected. */
|
|
11
|
+
readonly cold: readonly RetainedSample[];
|
|
12
|
+
/** Hot samples, oldest-first. Wins over a cold sample at the same `atMs`. */
|
|
13
|
+
readonly hot: readonly RetainedSample[];
|
|
14
|
+
readonly cadenceMs: number;
|
|
15
|
+
/** Absent ⇒ no reduction. */
|
|
16
|
+
readonly maxPoints?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface MergedLoadSeries {
|
|
19
|
+
readonly series: readonly FoldedSeries[];
|
|
20
|
+
readonly bucketMs: number;
|
|
21
|
+
readonly retainedSamples: number;
|
|
22
|
+
readonly oldestAtMs: number | null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Merge the two tiers into one deduped, oldest-first list of samples.
|
|
26
|
+
*
|
|
27
|
+
* Exported because the dedup is the property worth testing on its own: a
|
|
28
|
+
* doubled point is invisible in a total and obvious only as a chart that reads
|
|
29
|
+
* twice as loud as the machine.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mergeSamples(cold: readonly RetainedSample[], hot: readonly RetainedSample[]): readonly RetainedSample[];
|
|
32
|
+
/**
|
|
33
|
+
* Merge, fold and reduce. The whole read path in one pure function, so every
|
|
34
|
+
* property that matters — dedup, peak survival, an empty bucket staying empty
|
|
35
|
+
* — is testable without a database or a ring.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mergeLoadSeries(input: MergeLoadSeriesInput): MergedLoadSeries;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { IScopedLogger, SettingsStoreClient } from '@camstack/types';
|
|
2
|
+
/**
|
|
3
|
+
* @durable class=audit owner=metrics-native
|
|
4
|
+
* write="one row per process per sample, appended in ONE transaction per
|
|
5
|
+
* sample (`settingsStore.insertMany`) by the HUB's `native-metrics`, off its
|
|
6
|
+
* subscription to `metrics.node-processes-snapshot`. Emission is
|
|
7
|
+
* fixed-cadence, so the write rate is deterministic: nodes x processes /
|
|
8
|
+
* cadence, 7.6 rows/s on the live fleet at the 10 s default. Only a sample
|
|
9
|
+
* the in-memory ring ACCEPTED is written, which is what makes the append
|
|
10
|
+
* idempotent without a unique key."
|
|
11
|
+
* retention="TWO bounds, swept together at most once a minute. By AGE, the
|
|
12
|
+
* operator's `loadSeriesRetentionHours` (default 6, the intention); by ROWS,
|
|
13
|
+
* DEFAULT_MAX_ROWS (the guarantee, which bites regardless of the age knob).
|
|
14
|
+
* Both prune oldest-first through a bounded page — never a full scan — and
|
|
15
|
+
* the row cap logs when it bites. Losing the table loses the cold window
|
|
16
|
+
* only: the ring keeps serving the last hour and the charts keep drawing."
|
|
17
|
+
*/
|
|
18
|
+
export declare const LOAD_SERIES_COLLECTION = "metrics:node-load-samples";
|
|
19
|
+
/**
|
|
20
|
+
* Bytes one stored row costs on disk, MEASURED — table plus index, after a
|
|
21
|
+
* truncating checkpoint. Used to project the cost of a configuration for the
|
|
22
|
+
* operator BEFORE they apply it, so the knob is honest.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MEASURED_BYTES_PER_ROW = 87;
|
|
25
|
+
/**
|
|
26
|
+
* Sampling cadence bounds, in seconds. Outside this range a cadence is
|
|
27
|
+
* REFUSED — see {@link resolveLoadSeriesConfig}.
|
|
28
|
+
*/
|
|
29
|
+
export declare const MIN_CADENCE_SEC = 5;
|
|
30
|
+
export declare const MAX_CADENCE_SEC = 60;
|
|
31
|
+
export declare const DEFAULT_CADENCE_SEC = 10;
|
|
32
|
+
/** Retention the operator asked for, in hours. Six is the shipped default. */
|
|
33
|
+
export declare const DEFAULT_RETENTION_HOURS = 6;
|
|
34
|
+
export declare const MIN_RETENTION_HOURS = 1;
|
|
35
|
+
export declare const MAX_RETENTION_HOURS = 72;
|
|
36
|
+
/**
|
|
37
|
+
* Hard ceiling on the table, in ROWS.
|
|
38
|
+
*
|
|
39
|
+
* The guarantee behind the retention knob. Sized against the shipped default
|
|
40
|
+
* and against the worst configuration the knob can express:
|
|
41
|
+
*
|
|
42
|
+
* | cadence | retention | rows (3 nodes, 76 processes) |
|
|
43
|
+
* | --- | --- | --- |
|
|
44
|
+
* | 10 s | 6 h (default) | 164 160 |
|
|
45
|
+
* | 5 s | 6 h | 328 320 |
|
|
46
|
+
* | 5 s | 72 h | 3 939 840 — capped here |
|
|
47
|
+
*
|
|
48
|
+
* 500 000 rows x the measured 87 B = **41.5 MiB**, roughly 3x what the shipped
|
|
49
|
+
* default needs and far below the 2 M rows a three-day retention would reach.
|
|
50
|
+
* It is deliberately NOT a knob: the point of a guarantee is that it is not
|
|
51
|
+
* subject to the same hand that raised the intention. This is the discipline
|
|
52
|
+
* the in-memory ring already adopted (`DEFAULT_MAX_TOTAL_PROCESS_ROWS`) and
|
|
53
|
+
* the one the RTP pre-roll rings still lack — a maximum per instance and no
|
|
54
|
+
* budget at all for the whole, which reached 898 MB across 47 rings
|
|
55
|
+
* (`docs/architecture/load-ledger.md` #5).
|
|
56
|
+
*/
|
|
57
|
+
export declare const DEFAULT_MAX_ROWS = 500000;
|
|
58
|
+
/**
|
|
59
|
+
* Rows a single prune pass may remove.
|
|
60
|
+
*
|
|
61
|
+
* The prune is BOUNDED, never a full scan. It reads at most this many keys
|
|
62
|
+
* oldest-first through `idx_load_samples_node_at`, takes the last one's `atMs`
|
|
63
|
+
* as the effective cutoff and issues ONE `deleteWhere` up to it. A backlog
|
|
64
|
+
* larger than a page is worked off across passes rather than in one stall —
|
|
65
|
+
* which is the defect corrected in the recorder the same week, where
|
|
66
|
+
* `accountingForLocations` visited 6.7 M rows twice a minute.
|
|
67
|
+
*/
|
|
68
|
+
export declare const PRUNE_PAGE_ROWS = 20000;
|
|
69
|
+
/** How often a prune pass may run. A bound, not a deadline. */
|
|
70
|
+
export declare const PRUNE_INTERVAL_MS = 60000;
|
|
71
|
+
export declare const LOAD_SERIES_COLUMNS: readonly [{
|
|
72
|
+
readonly name: "id";
|
|
73
|
+
readonly type: "INTEGER";
|
|
74
|
+
readonly primaryKey: true;
|
|
75
|
+
readonly notNull: true;
|
|
76
|
+
}, {
|
|
77
|
+
readonly name: "nodeId";
|
|
78
|
+
readonly type: "TEXT";
|
|
79
|
+
readonly notNull: true;
|
|
80
|
+
}, {
|
|
81
|
+
readonly name: "atMs";
|
|
82
|
+
readonly type: "INTEGER";
|
|
83
|
+
readonly notNull: true;
|
|
84
|
+
}, {
|
|
85
|
+
readonly name: "pid";
|
|
86
|
+
readonly type: "INTEGER";
|
|
87
|
+
readonly notNull: true;
|
|
88
|
+
}, {
|
|
89
|
+
readonly name: "addonId";
|
|
90
|
+
readonly type: "TEXT";
|
|
91
|
+
}, {
|
|
92
|
+
readonly name: "classification";
|
|
93
|
+
readonly type: "TEXT";
|
|
94
|
+
readonly notNull: true;
|
|
95
|
+
}, {
|
|
96
|
+
readonly name: "cpuDeci";
|
|
97
|
+
readonly type: "INTEGER";
|
|
98
|
+
readonly notNull: true;
|
|
99
|
+
}, {
|
|
100
|
+
readonly name: "rssMib";
|
|
101
|
+
readonly type: "INTEGER";
|
|
102
|
+
readonly notNull: true;
|
|
103
|
+
}, {
|
|
104
|
+
readonly name: "cpuMainDeci";
|
|
105
|
+
readonly type: "INTEGER";
|
|
106
|
+
}, {
|
|
107
|
+
readonly name: "cpuGcDeci";
|
|
108
|
+
readonly type: "INTEGER";
|
|
109
|
+
}];
|
|
110
|
+
export declare const LOAD_SERIES_INDEXES: readonly [{
|
|
111
|
+
readonly name: "idx_load_samples_node_at";
|
|
112
|
+
readonly columns: readonly ["nodeId", "atMs"];
|
|
113
|
+
}];
|
|
114
|
+
/** One stored process row, in the units the table stores them in. */
|
|
115
|
+
export interface LoadSeriesRow {
|
|
116
|
+
readonly nodeId: string;
|
|
117
|
+
readonly atMs: number;
|
|
118
|
+
readonly pid: number;
|
|
119
|
+
readonly addonId: string | null;
|
|
120
|
+
readonly classification: string;
|
|
121
|
+
readonly cpuDeci: number;
|
|
122
|
+
readonly rssMib: number;
|
|
123
|
+
readonly cpuMainDeci: number | null;
|
|
124
|
+
readonly cpuGcDeci: number | null;
|
|
125
|
+
}
|
|
126
|
+
/** The process shape both tiers hand back — the series' own row, not `ps`'s. */
|
|
127
|
+
export interface RetainedProcess {
|
|
128
|
+
readonly pid: number;
|
|
129
|
+
readonly addonId: string | null;
|
|
130
|
+
readonly classification: string;
|
|
131
|
+
readonly cpuPercent: number;
|
|
132
|
+
readonly memoryRssBytes: number;
|
|
133
|
+
readonly cpuMainPercent: number | null;
|
|
134
|
+
readonly cpuGcPercent: number | null;
|
|
135
|
+
}
|
|
136
|
+
/** One retained sample: when it was taken, and the processes in it. */
|
|
137
|
+
export interface RetainedSample {
|
|
138
|
+
readonly atMs: number;
|
|
139
|
+
readonly processes: readonly RetainedProcess[];
|
|
140
|
+
}
|
|
141
|
+
/** Storage row → the shape a reader gets. The ONE decode. */
|
|
142
|
+
export declare function rowToProcess(row: LoadSeriesRow): RetainedProcess;
|
|
143
|
+
/** The shape a reader gets → the storage row. The ONE encode. */
|
|
144
|
+
export declare function processToRow(nodeId: string, atMs: number, process: RetainedProcess): LoadSeriesRow;
|
|
145
|
+
/** Group flat rows into samples, oldest-first. A sample is one `atMs`. */
|
|
146
|
+
export declare function rowsToSamples(rows: readonly LoadSeriesRow[]): readonly RetainedSample[];
|
|
147
|
+
/** The two bounds in force. */
|
|
148
|
+
export interface LoadSeriesRetention {
|
|
149
|
+
readonly retentionHours: number;
|
|
150
|
+
readonly maxRows: number;
|
|
151
|
+
}
|
|
152
|
+
export interface LoadSeriesStoreDeps {
|
|
153
|
+
readonly store: SettingsStoreClient;
|
|
154
|
+
readonly logger: IScopedLogger;
|
|
155
|
+
readonly now?: () => number;
|
|
156
|
+
readonly prunePageRows?: number;
|
|
157
|
+
readonly pruneIntervalMs?: number;
|
|
158
|
+
}
|
|
159
|
+
/** What one prune pass did. Returned so a test can assert the bound held. */
|
|
160
|
+
export interface PruneOutcome {
|
|
161
|
+
readonly deletedByAge: number;
|
|
162
|
+
readonly deletedByCap: number;
|
|
163
|
+
/** Rows read to find the cutoffs — the number that must stay bounded. */
|
|
164
|
+
readonly rowsExamined: number;
|
|
165
|
+
readonly capBit: boolean;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The cold tier. Append-only, bounded, and never the authority on anything the
|
|
169
|
+
* hot ring can answer.
|
|
170
|
+
*
|
|
171
|
+
* Every method is best-effort and says so in the log rather than throwing at
|
|
172
|
+
* the emitter: a storage hiccup must cost a gap in a chart, never a dropped
|
|
173
|
+
* snapshot on the bus.
|
|
174
|
+
*/
|
|
175
|
+
export declare class LoadSeriesStore {
|
|
176
|
+
private declared;
|
|
177
|
+
private lastPruneAtMs;
|
|
178
|
+
private readonly store;
|
|
179
|
+
private readonly logger;
|
|
180
|
+
private readonly nowFn;
|
|
181
|
+
private readonly prunePageRows;
|
|
182
|
+
private readonly pruneIntervalMs;
|
|
183
|
+
constructor(deps: LoadSeriesStoreDeps);
|
|
184
|
+
/** Idempotently declare the collection. `false` when the store refused. */
|
|
185
|
+
declare(): Promise<boolean>;
|
|
186
|
+
/**
|
|
187
|
+
* Append ONE sample — every process row of it — in ONE transaction.
|
|
188
|
+
*
|
|
189
|
+
* Never a write per row. `insertMany` exists for exactly this: at the 10 s
|
|
190
|
+
* default the fleet produces 7.6 rows/s, and 7.6 separate commits per second
|
|
191
|
+
* on the connection that also serves every cluster-wide configuration read
|
|
192
|
+
* is a constant load nobody asked for.
|
|
193
|
+
*/
|
|
194
|
+
append(nodeId: string, atMs: number, processes: readonly RetainedProcess[]): Promise<number>;
|
|
195
|
+
/**
|
|
196
|
+
* Read one node's cold samples, oldest-first.
|
|
197
|
+
*
|
|
198
|
+
* `sinceMs` is EXCLUSIVE, matching the ring, so a caller passing the newest
|
|
199
|
+
* timestamp it holds gets only what it is missing. `limitRows` bounds the
|
|
200
|
+
* read in ROWS (not samples) because rows are what the query costs.
|
|
201
|
+
*/
|
|
202
|
+
read(nodeId: string, sinceMs: number, limitRows: number): Promise<readonly RetainedSample[]>;
|
|
203
|
+
/**
|
|
204
|
+
* Enforce BOTH bounds, oldest-first, through a bounded page each.
|
|
205
|
+
*
|
|
206
|
+
* Rate-limited to {@link pruneIntervalMs}: a bound is not a deadline, and the
|
|
207
|
+
* append path must not pay a sweep on every sample.
|
|
208
|
+
*/
|
|
209
|
+
prune(nodeIds: readonly string[], retention: LoadSeriesRetention, force?: boolean): Promise<PruneOutcome | null>;
|
|
210
|
+
/** Total rows, or `null` when the store could not answer. */
|
|
211
|
+
count(): Promise<number | null>;
|
|
212
|
+
/**
|
|
213
|
+
* Delete this node's rows older than `cutoff`, at most one page's worth.
|
|
214
|
+
*
|
|
215
|
+
* The page is the whole point. `deleteWhere({ atMs: [0, cutoff] })` on its
|
|
216
|
+
* own is one statement but an UNBOUNDED one — a first pass after a retention
|
|
217
|
+
* change would delete millions of rows inside a single stalling transaction.
|
|
218
|
+
* So the page is read first (keys only, ordered by the index), its last
|
|
219
|
+
* `atMs` becomes the EFFECTIVE cutoff, and the delete is bounded by it.
|
|
220
|
+
*/
|
|
221
|
+
private pruneNodeToCutoff;
|
|
222
|
+
/**
|
|
223
|
+
* Drop the oldest rows across the known nodes until `excess` is covered.
|
|
224
|
+
*
|
|
225
|
+
* Same bounded-page technique, walked per node so the one index serves it.
|
|
226
|
+
* The node holding the oldest rows pays first, which is also the node
|
|
227
|
+
* producing the pressure when a runaway process count is the cause.
|
|
228
|
+
*/
|
|
229
|
+
private pruneOldestRows;
|
|
230
|
+
}
|
|
231
|
+
/** Structural validation on read. A malformed row is skipped, never charted. */
|
|
232
|
+
export declare function recordToRow(data: Record<string, unknown>): LoadSeriesRow | null;
|