@camstack/system 1.2.133 → 1.2.135
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/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 +53 -6
- package/dist/builtins/device-manager/device-manager.addon.mjs +53 -6
- 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/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 +41 -0
- 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/query-profiler.d.ts +74 -1
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +67 -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/sqlite-storage/statement-shape.d.ts +64 -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/{dist-BUEU7B1V.mjs → dist-Bh25kEUH.mjs} +62 -32
- package/dist/{dist-DqcaE-k1.js → dist-D-R0SuP-.js} +62 -32
- package/dist/index.js +18 -1
- package/dist/index.mjs +18 -1
- package/dist/kernel/config-manager.d.ts +4 -0
- package/dist/{retired-settings-keys-BhPleRL7.mjs → retired-settings-keys-BZbOXqch.mjs} +1 -1
- package/dist/{retired-settings-keys-KZnmtfsh.js → retired-settings-keys-CqD6rSQx.js} +1 -1
- package/package.json +1 -1
|
@@ -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-D-R0SuP-.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 { Gt as EventCategory, v as addonPagesCapability, vt as errMsg, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { Gt as EventCategory, v as addonPagesCapability, vt as errMsg, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { Gt as EventCategory, b as addonWidgetsCapability, vt as errMsg, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { Gt as EventCategory, b as addonWidgetsCapability, vt as errMsg, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { Gt as EventCategory, Mt as createEvent, n as AlertSchema, vt as errMsg, x as alertsCapability, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { Gt as EventCategory, Mt as createEvent, n as AlertSchema, vt as errMsg, x as alertsCapability, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { C as backupCapability, Gt as EventCategory, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { C as backupCapability, Gt as EventCategory, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { X as logDestinationCapability, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { D as coreBlockAddonId, O as coreBlockIdFromAddonId, c as CoreBlockSchema, k as coreBlocksCapability, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX, vt as errMsg, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { D as coreBlockAddonId, O as coreBlockIdFromAddonId, c as CoreBlockSchema, k as coreBlocksCapability, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX, vt as errMsg, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.js");
|
|
7
|
+
const require_retired_settings_keys = require("../../retired-settings-keys-CqD6rSQx.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
|
|
@@ -1280,6 +1280,32 @@ async function listPersistedByAddon(pctx, input) {
|
|
|
1280
1280
|
parentDeviceId: m.parentDeviceId
|
|
1281
1281
|
}));
|
|
1282
1282
|
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Every requested device's persisted config, in as few store round trips as the
|
|
1285
|
+
* settings view allows.
|
|
1286
|
+
*
|
|
1287
|
+
* One call when the view can batch (the in-process door, which keys
|
|
1288
|
+
* `addon-device-settings` by `<addonId>:<deviceId>.` and answers a whole addon
|
|
1289
|
+
* with one indexed range scan). Otherwise the per-device form, unchanged — a
|
|
1290
|
+
* fallback and not a silent downgrade: `readDeviceStoreBatch` is optional
|
|
1291
|
+
* precisely because a forked addon's view has nothing to batch, and refusing
|
|
1292
|
+
* would break the only implementation that cannot comply.
|
|
1293
|
+
*
|
|
1294
|
+
* A read that THROWS yields `{}` for that device rather than failing the whole
|
|
1295
|
+
* listing: one unreadable settings row must not make the fleet unlistable.
|
|
1296
|
+
*/
|
|
1297
|
+
async function readDeviceConfigs(pctx, deviceIds) {
|
|
1298
|
+
if (deviceIds.length === 0) return /* @__PURE__ */ new Map();
|
|
1299
|
+
const batch = pctx.settings.readDeviceStoreBatch;
|
|
1300
|
+
if (batch !== void 0) return batch.call(pctx.settings, deviceIds);
|
|
1301
|
+
const out = /* @__PURE__ */ new Map();
|
|
1302
|
+
for (const id of deviceIds) try {
|
|
1303
|
+
out.set(id, await pctx.settings.readDeviceStore(id));
|
|
1304
|
+
} catch {
|
|
1305
|
+
out.set(id, {});
|
|
1306
|
+
}
|
|
1307
|
+
return out;
|
|
1308
|
+
}
|
|
1283
1309
|
async function listAll(pctx, input) {
|
|
1284
1310
|
const ownerFilter = Reflect.get(input, "addonId");
|
|
1285
1311
|
if (ownerFilter !== void 0 && (typeof ownerFilter !== "string" || ownerFilter.length === 0)) throw new Error(`deviceManager.listAll: addonId must be a non-empty string or be omitted — got ${JSON.stringify(ownerFilter)}. An owner filter that is present but empty is never widened to every device. On an addon context the id is \`ctx.id\`; there is no \`ctx.addonId\`.`);
|
|
@@ -1311,6 +1337,7 @@ async function listAll(pctx, input) {
|
|
|
1311
1337
|
} : info);
|
|
1312
1338
|
}
|
|
1313
1339
|
}
|
|
1340
|
+
const configs = await readDeviceConfigs(pctx, slim ? [] : fleet.filter((row) => !seen.has(String(row.meta.id))).filter((row) => idFilter === null || idFilter.has(row.meta.id)).filter((row) => !camerasOnly || row.meta.type === require_dist.DeviceType.Camera).map((row) => row.meta.id));
|
|
1314
1341
|
for (const row of fleet) {
|
|
1315
1342
|
const m = row.meta;
|
|
1316
1343
|
const aid = m.addonId;
|
|
@@ -1319,7 +1346,7 @@ async function listAll(pctx, input) {
|
|
|
1319
1346
|
if (idFilter !== null && !idFilter.has(m.id)) continue;
|
|
1320
1347
|
const persistedType = m.type;
|
|
1321
1348
|
if (camerasOnly && persistedType !== require_dist.DeviceType.Camera) continue;
|
|
1322
|
-
const persistedConfig =
|
|
1349
|
+
const persistedConfig = configs.get(m.id) ?? {};
|
|
1323
1350
|
const metadata = slim ? null : row.metadata;
|
|
1324
1351
|
results.push({
|
|
1325
1352
|
id: m.id,
|
|
@@ -1848,6 +1875,26 @@ function resolveTrackedEventDeviceIds(config, linkedIds) {
|
|
|
1848
1875
|
return linkedIds.filter((id) => picked.has(id));
|
|
1849
1876
|
}
|
|
1850
1877
|
/**
|
|
1878
|
+
* The fleet listing every function here needs, and the ONLY projection any of
|
|
1879
|
+
* them may ask for.
|
|
1880
|
+
*
|
|
1881
|
+
* Linked-device policy reads five fields off a candidate — `id`,
|
|
1882
|
+
* `parentDeviceId`, `location`, `name`, `features` — and `slim` carries all
|
|
1883
|
+
* five. What `slim` drops is `config`, and `config` is not a column: `listAll`
|
|
1884
|
+
* materialises it with ONE `readDeviceStore` per device, sequentially, on
|
|
1885
|
+
* device-manager's event loop. This module asked for the full projection three
|
|
1886
|
+
* times, so every linked-devices read swept the whole fleet's settings rows to
|
|
1887
|
+
* use none of them.
|
|
1888
|
+
*
|
|
1889
|
+
* Measured on the live hub 2026-08-25: `query addon-device-settings` ran
|
|
1890
|
+
* 36 814 times a minute against a 967-device fleet — ~38 full-fleet sweeps a
|
|
1891
|
+
* minute, ~31 of them the `pipeline-analytics` reverse index rebuilding itself
|
|
1892
|
+
* one camera at a time through `getLinkedDevices`. The per-camera `config`
|
|
1893
|
+
* this query DOES need is the separate `readDeviceStore(deviceId)` below, and
|
|
1894
|
+
* it is one row, not the fleet.
|
|
1895
|
+
*/
|
|
1896
|
+
var LINK_CANDIDATE_PROJECTION = { projection: "slim" };
|
|
1897
|
+
/**
|
|
1851
1898
|
* Resolve ONE camera's linked set against an ALREADY-FETCHED fleet.
|
|
1852
1899
|
*
|
|
1853
1900
|
* The fleet is a parameter, not a fetch, because it is the entire cost of this
|
|
@@ -1884,7 +1931,7 @@ function resolveFor(deviceId, all, byId, blob) {
|
|
|
1884
1931
|
/** Cap implementation of `getLinkedDevices`. */
|
|
1885
1932
|
async function getLinkedDevices(pctx, input) {
|
|
1886
1933
|
const { deviceId } = input;
|
|
1887
|
-
const [all, blob] = await Promise.all([listAll(pctx,
|
|
1934
|
+
const [all, blob] = await Promise.all([listAll(pctx, LINK_CANDIDATE_PROJECTION), pctx.settings.readDeviceStore(deviceId)]);
|
|
1888
1935
|
return resolveFor(deviceId, all, new Map(all.map((d) => [d.id, d])), blob);
|
|
1889
1936
|
}
|
|
1890
1937
|
/**
|
|
@@ -1903,7 +1950,7 @@ async function getLinkedDevices(pctx, input) {
|
|
|
1903
1950
|
async function getLinkedDevicesBatch(pctx, input) {
|
|
1904
1951
|
const deviceIds = [...new Set(input.deviceIds)];
|
|
1905
1952
|
if (deviceIds.length === 0) return [];
|
|
1906
|
-
const [all, blobs] = await Promise.all([listAll(pctx,
|
|
1953
|
+
const [all, blobs] = await Promise.all([listAll(pctx, LINK_CANDIDATE_PROJECTION), Promise.all(deviceIds.map((id) => pctx.settings.readDeviceStore(id).catch((err) => {
|
|
1907
1954
|
pctx.host.ctx.logger.warn("getLinkedDevicesBatch: settings read failed — children only", {
|
|
1908
1955
|
tags: { deviceId: id },
|
|
1909
1956
|
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
@@ -1925,7 +1972,7 @@ async function getLinkedDevicesBatch(pctx, input) {
|
|
|
1925
1972
|
async function buildLinkedDevicesContribution(pctx, deviceId) {
|
|
1926
1973
|
const persisted = await pctx.metaStore.resolvePersistedById(deviceId);
|
|
1927
1974
|
if (!persisted || persisted.meta.type !== require_dist.DeviceType.Camera) return null;
|
|
1928
|
-
const [all, blob] = await Promise.all([listAll(pctx,
|
|
1975
|
+
const [all, blob] = await Promise.all([listAll(pctx, LINK_CANDIDATE_PROJECTION), pctx.settings.readDeviceStore(deviceId)]);
|
|
1929
1976
|
const config = parseLinkedDevicesConfig(blob);
|
|
1930
1977
|
const options = all.filter((d) => d.id !== deviceId).map((d) => ({
|
|
1931
1978
|
value: String(d.id),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Ct as DeviceFeature, E as buildStreamParamsConfigSchema, F as deviceStatusCapability, Gt as EventCategory, Lt as isDeviceConfigCap, N as deviceManagerCapability, Ot as WELL_KNOWN_TAB_MAP, P as deviceStateCapability, R as enumerateItemArrayFields, Tt as DeviceType, Wt as sleep, a as CAP_NAMES_WITH_STATUS, at as runtimeStatePolicyFor, et as normalizeUnit, nt as parseStreamParamsFormPatch, p as STREAM_PROFILE_META, t as ALL_CAPABILITY_DEFINITIONS, u as DeviceStatusSchema, vt as errMsg, wt as DeviceRole, yt as BaseAddon, z as enumerateSchemaFields } from "../../dist-
|
|
2
|
-
import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-
|
|
1
|
+
import { Ct as DeviceFeature, E as buildStreamParamsConfigSchema, F as deviceStatusCapability, Gt as EventCategory, Lt as isDeviceConfigCap, N as deviceManagerCapability, Ot as WELL_KNOWN_TAB_MAP, P as deviceStateCapability, R as enumerateItemArrayFields, Tt as DeviceType, Wt as sleep, a as CAP_NAMES_WITH_STATUS, at as runtimeStatePolicyFor, et as normalizeUnit, nt as parseStreamParamsFormPatch, p as STREAM_PROFILE_META, t as ALL_CAPABILITY_DEFINITIONS, u as DeviceStatusSchema, vt as errMsg, wt as DeviceRole, yt as BaseAddon, z as enumerateSchemaFields } from "../../dist-Bh25kEUH.mjs";
|
|
2
|
+
import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-BZbOXqch.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
|
|
@@ -1275,6 +1275,32 @@ async function listPersistedByAddon(pctx, input) {
|
|
|
1275
1275
|
parentDeviceId: m.parentDeviceId
|
|
1276
1276
|
}));
|
|
1277
1277
|
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Every requested device's persisted config, in as few store round trips as the
|
|
1280
|
+
* settings view allows.
|
|
1281
|
+
*
|
|
1282
|
+
* One call when the view can batch (the in-process door, which keys
|
|
1283
|
+
* `addon-device-settings` by `<addonId>:<deviceId>.` and answers a whole addon
|
|
1284
|
+
* with one indexed range scan). Otherwise the per-device form, unchanged — a
|
|
1285
|
+
* fallback and not a silent downgrade: `readDeviceStoreBatch` is optional
|
|
1286
|
+
* precisely because a forked addon's view has nothing to batch, and refusing
|
|
1287
|
+
* would break the only implementation that cannot comply.
|
|
1288
|
+
*
|
|
1289
|
+
* A read that THROWS yields `{}` for that device rather than failing the whole
|
|
1290
|
+
* listing: one unreadable settings row must not make the fleet unlistable.
|
|
1291
|
+
*/
|
|
1292
|
+
async function readDeviceConfigs(pctx, deviceIds) {
|
|
1293
|
+
if (deviceIds.length === 0) return /* @__PURE__ */ new Map();
|
|
1294
|
+
const batch = pctx.settings.readDeviceStoreBatch;
|
|
1295
|
+
if (batch !== void 0) return batch.call(pctx.settings, deviceIds);
|
|
1296
|
+
const out = /* @__PURE__ */ new Map();
|
|
1297
|
+
for (const id of deviceIds) try {
|
|
1298
|
+
out.set(id, await pctx.settings.readDeviceStore(id));
|
|
1299
|
+
} catch {
|
|
1300
|
+
out.set(id, {});
|
|
1301
|
+
}
|
|
1302
|
+
return out;
|
|
1303
|
+
}
|
|
1278
1304
|
async function listAll(pctx, input) {
|
|
1279
1305
|
const ownerFilter = Reflect.get(input, "addonId");
|
|
1280
1306
|
if (ownerFilter !== void 0 && (typeof ownerFilter !== "string" || ownerFilter.length === 0)) throw new Error(`deviceManager.listAll: addonId must be a non-empty string or be omitted — got ${JSON.stringify(ownerFilter)}. An owner filter that is present but empty is never widened to every device. On an addon context the id is \`ctx.id\`; there is no \`ctx.addonId\`.`);
|
|
@@ -1306,6 +1332,7 @@ async function listAll(pctx, input) {
|
|
|
1306
1332
|
} : info);
|
|
1307
1333
|
}
|
|
1308
1334
|
}
|
|
1335
|
+
const configs = await readDeviceConfigs(pctx, slim ? [] : fleet.filter((row) => !seen.has(String(row.meta.id))).filter((row) => idFilter === null || idFilter.has(row.meta.id)).filter((row) => !camerasOnly || row.meta.type === DeviceType.Camera).map((row) => row.meta.id));
|
|
1309
1336
|
for (const row of fleet) {
|
|
1310
1337
|
const m = row.meta;
|
|
1311
1338
|
const aid = m.addonId;
|
|
@@ -1314,7 +1341,7 @@ async function listAll(pctx, input) {
|
|
|
1314
1341
|
if (idFilter !== null && !idFilter.has(m.id)) continue;
|
|
1315
1342
|
const persistedType = m.type;
|
|
1316
1343
|
if (camerasOnly && persistedType !== DeviceType.Camera) continue;
|
|
1317
|
-
const persistedConfig =
|
|
1344
|
+
const persistedConfig = configs.get(m.id) ?? {};
|
|
1318
1345
|
const metadata = slim ? null : row.metadata;
|
|
1319
1346
|
results.push({
|
|
1320
1347
|
id: m.id,
|
|
@@ -1843,6 +1870,26 @@ function resolveTrackedEventDeviceIds(config, linkedIds) {
|
|
|
1843
1870
|
return linkedIds.filter((id) => picked.has(id));
|
|
1844
1871
|
}
|
|
1845
1872
|
/**
|
|
1873
|
+
* The fleet listing every function here needs, and the ONLY projection any of
|
|
1874
|
+
* them may ask for.
|
|
1875
|
+
*
|
|
1876
|
+
* Linked-device policy reads five fields off a candidate — `id`,
|
|
1877
|
+
* `parentDeviceId`, `location`, `name`, `features` — and `slim` carries all
|
|
1878
|
+
* five. What `slim` drops is `config`, and `config` is not a column: `listAll`
|
|
1879
|
+
* materialises it with ONE `readDeviceStore` per device, sequentially, on
|
|
1880
|
+
* device-manager's event loop. This module asked for the full projection three
|
|
1881
|
+
* times, so every linked-devices read swept the whole fleet's settings rows to
|
|
1882
|
+
* use none of them.
|
|
1883
|
+
*
|
|
1884
|
+
* Measured on the live hub 2026-08-25: `query addon-device-settings` ran
|
|
1885
|
+
* 36 814 times a minute against a 967-device fleet — ~38 full-fleet sweeps a
|
|
1886
|
+
* minute, ~31 of them the `pipeline-analytics` reverse index rebuilding itself
|
|
1887
|
+
* one camera at a time through `getLinkedDevices`. The per-camera `config`
|
|
1888
|
+
* this query DOES need is the separate `readDeviceStore(deviceId)` below, and
|
|
1889
|
+
* it is one row, not the fleet.
|
|
1890
|
+
*/
|
|
1891
|
+
var LINK_CANDIDATE_PROJECTION = { projection: "slim" };
|
|
1892
|
+
/**
|
|
1846
1893
|
* Resolve ONE camera's linked set against an ALREADY-FETCHED fleet.
|
|
1847
1894
|
*
|
|
1848
1895
|
* The fleet is a parameter, not a fetch, because it is the entire cost of this
|
|
@@ -1879,7 +1926,7 @@ function resolveFor(deviceId, all, byId, blob) {
|
|
|
1879
1926
|
/** Cap implementation of `getLinkedDevices`. */
|
|
1880
1927
|
async function getLinkedDevices(pctx, input) {
|
|
1881
1928
|
const { deviceId } = input;
|
|
1882
|
-
const [all, blob] = await Promise.all([listAll(pctx,
|
|
1929
|
+
const [all, blob] = await Promise.all([listAll(pctx, LINK_CANDIDATE_PROJECTION), pctx.settings.readDeviceStore(deviceId)]);
|
|
1883
1930
|
return resolveFor(deviceId, all, new Map(all.map((d) => [d.id, d])), blob);
|
|
1884
1931
|
}
|
|
1885
1932
|
/**
|
|
@@ -1898,7 +1945,7 @@ async function getLinkedDevices(pctx, input) {
|
|
|
1898
1945
|
async function getLinkedDevicesBatch(pctx, input) {
|
|
1899
1946
|
const deviceIds = [...new Set(input.deviceIds)];
|
|
1900
1947
|
if (deviceIds.length === 0) return [];
|
|
1901
|
-
const [all, blobs] = await Promise.all([listAll(pctx,
|
|
1948
|
+
const [all, blobs] = await Promise.all([listAll(pctx, LINK_CANDIDATE_PROJECTION), Promise.all(deviceIds.map((id) => pctx.settings.readDeviceStore(id).catch((err) => {
|
|
1902
1949
|
pctx.host.ctx.logger.warn("getLinkedDevicesBatch: settings read failed — children only", {
|
|
1903
1950
|
tags: { deviceId: id },
|
|
1904
1951
|
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
@@ -1920,7 +1967,7 @@ async function getLinkedDevicesBatch(pctx, input) {
|
|
|
1920
1967
|
async function buildLinkedDevicesContribution(pctx, deviceId) {
|
|
1921
1968
|
const persisted = await pctx.metaStore.resolvePersistedById(deviceId);
|
|
1922
1969
|
if (!persisted || persisted.meta.type !== DeviceType.Camera) return null;
|
|
1923
|
-
const [all, blob] = await Promise.all([listAll(pctx,
|
|
1970
|
+
const [all, blob] = await Promise.all([listAll(pctx, LINK_CANDIDATE_PROJECTION), pctx.settings.readDeviceStore(deviceId)]);
|
|
1924
1971
|
const config = parseLinkedDevicesConfig(blob);
|
|
1925
1972
|
const options = all.filter((d) => d.id !== deviceId).map((d) => ({
|
|
1926
1973
|
value: String(d.id),
|
|
@@ -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-D-R0SuP-.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 { G as isSameAddonId, Gt as EventCategory, I as doorbellCapability, Mt as createEvent, Tt as DeviceType, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { G as isSameAddonId, Gt as EventCategory, I as doorbellCapability, Mt as createEvent, Tt as DeviceType, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { X as logDestinationCapability, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { Gt as EventCategory, Mt as createEvent, vt as errMsg, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { Gt as EventCategory, Mt as createEvent, vt as errMsg, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { S as authProviderCapability, _ as UserRecordSchema, ht as userManagementCapability, m as ScopedTokenSchema, r as ApiKeyRecordSchema, yt as BaseAddon } from "../../dist-
|
|
2
|
+
import { S as authProviderCapability, _ as UserRecordSchema, ht as userManagementCapability, m as ScopedTokenSchema, r as ApiKeyRecordSchema, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { Gt as EventCategory, Y as localNetworkCapability, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { Gt as EventCategory, Y as localNetworkCapability, yt as BaseAddon } from "../../dist-Bh25kEUH.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-D-R0SuP-.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 { X as logDestinationCapability, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { X as logDestinationCapability, yt as BaseAddon } from "../../dist-Bh25kEUH.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
|
|
@@ -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-D-R0SuP-.js");
|
|
7
7
|
let node_child_process = require("node:child_process");
|
|
8
8
|
let node_util = require("node:util");
|
|
9
9
|
let node_os = require("node:os");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as metricsProviderCapability, Gt as EventCategory, Mt as createEvent, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { $ as metricsProviderCapability, Gt as EventCategory, Mt as createEvent, yt as BaseAddon } from "../../dist-Bh25kEUH.mjs";
|
|
2
2
|
import { execFile, execFileSync } from "node:child_process";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import * as os from "node:os";
|
|
@@ -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-D-R0SuP-.js");
|
|
7
7
|
let node_child_process = require("node:child_process");
|
|
8
8
|
let node_util = require("node:util");
|
|
9
9
|
let node_os = require("node:os");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import { Gt as EventCategory, L as enumerateInferenceDevices, Pt as emitReadiness, ct as scoreRuntimes, rt as platformProbeCapability, vt as errMsg, yt as BaseAddon } from "../../dist-
|
|
2
|
+
import { Gt as EventCategory, L as enumerateInferenceDevices, Pt as emitReadiness, ct as scoreRuntimes, rt as platformProbeCapability, vt as errMsg, yt as BaseAddon } from "../../dist-Bh25kEUH.mjs";
|
|
3
3
|
import { execFile } from "node:child_process";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import * as os from "node:os";
|
|
@@ -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-D-R0SuP-.js");
|
|
7
7
|
//#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
|
|
8
8
|
/**
|
|
9
9
|
* Reconcile the durable `enabledProviders` set against authoritative
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Gt as EventCategory, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { Gt as EventCategory, yt as BaseAddon } from "../../dist-Bh25kEUH.mjs";
|
|
2
2
|
//#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
|
|
3
3
|
/**
|
|
4
4
|
* Reconcile the durable `enabledProviders` set against authoritative
|
|
@@ -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-D-R0SuP-.js");
|
|
7
7
|
let zod = require("zod");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let _camstack_types_node = require("@camstack/types/node");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ct as DeviceFeature, Gt as EventCategory, M as deriveBatteryPresence, Rt as nodePin, T as batteryCapability, Tt as DeviceType, i as BatteryStatusSchema, mt as streamQualityLabel, ut as snapshotCapability, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { Ct as DeviceFeature, Gt as EventCategory, M as deriveBatteryPresence, Rt as nodePin, T as batteryCapability, Tt as DeviceType, i as BatteryStatusSchema, mt as streamQualityLabel, ut as snapshotCapability, vt as errMsg, w as bareAddonId, yt as BaseAddon } from "../../dist-Bh25kEUH.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { signExpiringUrl, verifyExpiringUrl } from "@camstack/types/node";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Database } from 'better-sqlite3';
|
|
2
|
+
/**
|
|
3
|
+
* Delay before the one-shot `ANALYZE`, in ms.
|
|
4
|
+
*
|
|
5
|
+
* Boot is itself the busiest window this runner has (`ensureTable` ×9, the
|
|
6
|
+
* retired-key purge, the vector registry), and adding a 14 s statement to it
|
|
7
|
+
* would turn a slow boot into one an operator reads as a hang. Long enough that
|
|
8
|
+
* the cluster is serving before the engine goes quiet.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ANALYZE_DELAY_MS = 120000;
|
|
11
|
+
/** Env var that disables the one-shot analysis. `off` is the only value read. */
|
|
12
|
+
export declare const ANALYZE_ENV_VAR = "CAMSTACK_SQLITE_ANALYZE";
|
|
13
|
+
/** What {@link runAnalyzeIfMissing} did, for the caller to log. */
|
|
14
|
+
export type AnalyzeOutcome = {
|
|
15
|
+
readonly kind: 'already-present';
|
|
16
|
+
} | {
|
|
17
|
+
readonly kind: 'analyzed';
|
|
18
|
+
readonly tookMs: number;
|
|
19
|
+
readonly indexesAnalyzed: number;
|
|
20
|
+
} | {
|
|
21
|
+
readonly kind: 'failed';
|
|
22
|
+
readonly tookMs: number;
|
|
23
|
+
readonly error: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* True when the database has no `sqlite_stat1` at all.
|
|
27
|
+
*
|
|
28
|
+
* Deliberately "none", not "old": a stale row still tells the planner the
|
|
29
|
+
* relative selectivity of two indexes, which is the entire question being
|
|
30
|
+
* asked. Re-analysis on a staleness heuristic would put a 14 s statement on a
|
|
31
|
+
* timer, and this runner cannot afford one.
|
|
32
|
+
*/
|
|
33
|
+
export declare function hasIndexStatistics(db: Database): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* `ANALYZE` the database, but only if it has never been analysed.
|
|
36
|
+
*
|
|
37
|
+
* Synchronous and long — see the module doc. Never throws: a database that
|
|
38
|
+
* refuses to be analysed is a missing optimisation, not a reason to take the
|
|
39
|
+
* settings engine down, and the outcome says so rather than going quiet.
|
|
40
|
+
*/
|
|
41
|
+
export declare function runAnalyzeIfMissing(db: Database, now?: () => number): AnalyzeOutcome;
|
|
@@ -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-D-R0SuP-.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as filesystemBrowseCapability, pt as storageProviderCapability, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { V as filesystemBrowseCapability, pt as storageProviderCapability, yt as BaseAddon } from "../../dist-Bh25kEUH.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
|
|
4
4
|
import * as path$1 from "node:path";
|