@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.
Files changed (56) hide show
  1. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  2. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  3. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/alerts/alerts.addon.js +1 -1
  6. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  7. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  8. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  9. package/dist/builtins/console-logging/index.js +1 -1
  10. package/dist/builtins/console-logging/index.mjs +1 -1
  11. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  12. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  13. package/dist/builtins/device-manager/device-manager.addon.js +53 -6
  14. package/dist/builtins/device-manager/device-manager.addon.mjs +53 -6
  15. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  16. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  17. package/dist/builtins/hub-forwarder/index.js +1 -1
  18. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  19. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  20. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  21. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  22. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  23. package/dist/builtins/local-network/local-network.addon.js +1 -1
  24. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  25. package/dist/builtins/loki-logging/index.js +1 -1
  26. package/dist/builtins/loki-logging/index.mjs +1 -1
  27. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  28. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  29. package/dist/builtins/platform-probe/index.js +1 -1
  30. package/dist/builtins/platform-probe/index.mjs +1 -1
  31. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  32. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  33. package/dist/builtins/snapshot/index.js +1 -1
  34. package/dist/builtins/snapshot/index.mjs +1 -1
  35. package/dist/builtins/sqlite-storage/analyze-stats.d.ts +41 -0
  36. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  38. package/dist/builtins/sqlite-storage/query-profiler.d.ts +74 -1
  39. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +67 -1
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  41. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  42. package/dist/builtins/sqlite-storage/statement-shape.d.ts +64 -0
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  45. package/dist/builtins/system-config/system-config.addon.js +1 -1
  46. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  47. package/dist/builtins/winston-logging/index.js +1 -1
  48. package/dist/builtins/winston-logging/index.mjs +1 -1
  49. package/dist/{dist-BUEU7B1V.mjs → dist-Bh25kEUH.mjs} +62 -32
  50. package/dist/{dist-DqcaE-k1.js → dist-D-R0SuP-.js} +62 -32
  51. package/dist/index.js +18 -1
  52. package/dist/index.mjs +18 -1
  53. package/dist/kernel/config-manager.d.ts +4 -0
  54. package/dist/{retired-settings-keys-BhPleRL7.mjs → retired-settings-keys-BZbOXqch.mjs} +1 -1
  55. package/dist/{retired-settings-keys-KZnmtfsh.js → retired-settings-keys-CqD6rSQx.js} +1 -1
  56. 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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-KZnmtfsh.js");
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 = slim ? {} : await pctx.settings.readDeviceStore(m.id);
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, {}), pctx.settings.readDeviceStore(deviceId)]);
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, {}), Promise.all(deviceIds.map((id) => pctx.settings.readDeviceStore(id).catch((err) => {
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, {}), pctx.settings.readDeviceStore(deviceId)]);
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-BUEU7B1V.mjs";
2
- import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-BhPleRL7.mjs";
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 = slim ? {} : await pctx.settings.readDeviceStore(m.id);
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, {}), pctx.settings.readDeviceStore(deviceId)]);
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, {}), Promise.all(deviceIds.map((id) => pctx.settings.readDeviceStore(id).catch((err) => {
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, {}), pctx.settings.readDeviceStore(deviceId)]);
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.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-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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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";