@camstack/system 1.2.134 → 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/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 +39 -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 +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";
|
|
@@ -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";
|
|
@@ -45,6 +45,22 @@ export interface DroppedTable {
|
|
|
45
45
|
export declare function scopeOwnerOf(filter: QueryFilter | undefined): {
|
|
46
46
|
owner?: string;
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Stable identity of a declared schema — every property that changes the DDL
|
|
50
|
+
* or the set of columns a filter can name.
|
|
51
|
+
*
|
|
52
|
+
* Deliberately covers `indexes` too: an added index is as invisible to a
|
|
53
|
+
* name-only memo as an added column, and `CREATE INDEX IF NOT EXISTS` is
|
|
54
|
+
* cheap enough that re-running it costs nothing.
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* A `query` asked to read a column the collection cannot serve. Distinct type
|
|
58
|
+
* so a caller can map it to a 400 — it is always a programming error in the
|
|
59
|
+
* caller, never a condition of the data.
|
|
60
|
+
*/
|
|
61
|
+
export declare class UnprojectableColumnError extends Error {
|
|
62
|
+
constructor(message: string);
|
|
63
|
+
}
|
|
48
64
|
/**
|
|
49
65
|
* SQLite implementation of ISettingsBackend.
|
|
50
66
|
*
|
|
@@ -130,7 +146,7 @@ export declare class SqliteSettingsBackend implements ISettingsBackend {
|
|
|
130
146
|
getEngineInfo(): Promise<DataStoreEngineInfo>;
|
|
131
147
|
get({ namespace, collection, key }: SettingsGetInput): Promise<unknown>;
|
|
132
148
|
set({ namespace, collection, key, value }: SettingsSetInput): Promise<void>;
|
|
133
|
-
query<T extends object = Record<string, unknown>>({ namespace, collection, filter, }: SettingsQueryInput): Promise<readonly SettingsRecord<T>[]>;
|
|
149
|
+
query<T extends object = Record<string, unknown>>({ namespace, collection, filter, columns, }: SettingsQueryInput): Promise<readonly SettingsRecord<T>[]>;
|
|
134
150
|
insert<T extends object = Record<string, unknown>>({ namespace, collection, record, }: SettingsInsertInput<T>): Promise<void>;
|
|
135
151
|
update({ namespace, collection, id, data }: SettingsUpdateInput): Promise<void>;
|
|
136
152
|
delete({ namespace, collection, key }: SettingsDeleteInput): Promise<void>;
|
|
@@ -151,6 +167,28 @@ export declare class SqliteSettingsBackend implements ISettingsBackend {
|
|
|
151
167
|
* uncapped `tableUpdate` would have done.
|
|
152
168
|
*/
|
|
153
169
|
updateWhere({ namespace, collection, filter, data, }: SettingsUpdateWhereInput): Promise<SettingsUpdateWhereResult>;
|
|
170
|
+
/**
|
|
171
|
+
* How many rows match — about the SAME rows {@link query} would return.
|
|
172
|
+
*
|
|
173
|
+
* That agreement is the entire contract, and until now it did not hold. This
|
|
174
|
+
* was the FOURTH hand-rolled copy of the filter logic (after `query`, the
|
|
175
|
+
* bulk mutations and `histogram`) and it compiled only `where`:
|
|
176
|
+
* `whereBetween`, `whereIn` and `whereNot` were dropped silently, so the
|
|
177
|
+
* count was not slow, it was WRONG, and always wrong in the same direction —
|
|
178
|
+
* too big, because every dropped predicate is a predicate that would have
|
|
179
|
+
* excluded rows.
|
|
180
|
+
*
|
|
181
|
+
* Two live callers decided on it. `TrackStore.countStaging({ deviceId,
|
|
182
|
+
* olderThanMs })` sends the cutoff as `whereBetween: { lastSeen: [0, …] }`
|
|
183
|
+
* and got the device's whole staging history instead. The notification-centre
|
|
184
|
+
* artefact gallery pages on `total` from this method while listing through
|
|
185
|
+
* `query`, and its filter is almost entirely `whereIn`/`whereBetween`
|
|
186
|
+
* (visibility, kind, device, time window, expiry) — so `total` counted rows
|
|
187
|
+
* the page could never show, including other users'.
|
|
188
|
+
*
|
|
189
|
+
* `select` mode, deliberately: `count` must be forgiving in exactly the way
|
|
190
|
+
* `query` is, or the two disagree again for a new reason.
|
|
191
|
+
*/
|
|
154
192
|
count({ namespace, collection, filter }: SettingsCountInput): Promise<number>;
|
|
155
193
|
histogram({ namespace, collection, field, bucketSize, origin, filter, }: SettingsHistogramInput): Promise<readonly HistogramBucket[]>;
|
|
156
194
|
isEmpty({ namespace, collection }: SettingsIsEmptyInput): Promise<boolean>;
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dt as storageCapability, ft as storageMigrationCapability, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as settingsStoreCapability, yt as BaseAddon, zt as parseJsonObject } from "../../dist-
|
|
1
|
+
import { dt as storageCapability, ft as storageMigrationCapability, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as settingsStoreCapability, yt as BaseAddon, zt as parseJsonObject } 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,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/system-config/system-config.addon.ts
|
|
8
8
|
/**
|
|
9
9
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { It as hydrateSchema, vt as errMsg, yt as BaseAddon } from "../../dist-
|
|
1
|
+
import { It as hydrateSchema, vt as errMsg, yt as BaseAddon } from "../../dist-Bh25kEUH.mjs";
|
|
2
2
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
3
3
|
/**
|
|
4
4
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -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_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -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
|
import * as path$1 from "node:path";
|
|
4
4
|
import path from "node:path";
|
|
@@ -3704,24 +3704,6 @@ var RecordingRetentionSchema = z.object({
|
|
|
3704
3704
|
maxSizeGb: z.number().min(0).optional()
|
|
3705
3705
|
});
|
|
3706
3706
|
/**
|
|
3707
|
-
* Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
|
|
3708
|
-
* sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
|
|
3709
|
-
* previews at. Five graduated steps; absent on a config = `standard` (the
|
|
3710
|
-
* shipped default, matching `sheet-geometry`/`sheet-composer`).
|
|
3711
|
-
*
|
|
3712
|
-
* Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
|
|
3713
|
-
* Each window's index sidecar carries its own tile dims, so a camera whose
|
|
3714
|
-
* preset changed over time renders every historical window at the dims it was
|
|
3715
|
-
* written with.
|
|
3716
|
-
*/
|
|
3717
|
-
var ScrubThumbnailPresetSchema = z.enum([
|
|
3718
|
-
"minimal",
|
|
3719
|
-
"low",
|
|
3720
|
-
"standard",
|
|
3721
|
-
"high",
|
|
3722
|
-
"max"
|
|
3723
|
-
]);
|
|
3724
|
-
/**
|
|
3725
3707
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
3726
3708
|
*
|
|
3727
3709
|
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
@@ -3729,7 +3711,11 @@ var ScrubThumbnailPresetSchema = z.enum([
|
|
|
3729
3711
|
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
3730
3712
|
*
|
|
3731
3713
|
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
3732
|
-
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30
|
|
3714
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
|
|
3715
|
+
* and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
|
|
3716
|
+
* deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
|
|
3717
|
+
* (D62: a switch that writes a store nobody reads is worse than no switch).
|
|
3718
|
+
* Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
|
|
3733
3719
|
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
3734
3720
|
* persist a band-less config, i.e. silently stop recording the camera.
|
|
3735
3721
|
*/
|
|
@@ -3752,14 +3738,7 @@ var RecordingConfigSchema = z.object({
|
|
|
3752
3738
|
* "off" is the absence of a covering band, never a band value.
|
|
3753
3739
|
*/
|
|
3754
3740
|
bands: z.array(RecordingBandSchema).default([]),
|
|
3755
|
-
retention: RecordingRetentionSchema.optional()
|
|
3756
|
-
/**
|
|
3757
|
-
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
3758
|
-
* timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
|
|
3759
|
-
* windows only — existing sheets are immutable, and each window's index
|
|
3760
|
-
* carries its own tile dims so mixed-preset history renders correctly.
|
|
3761
|
-
*/
|
|
3762
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
3741
|
+
retention: RecordingRetentionSchema.optional()
|
|
3763
3742
|
}).strict();
|
|
3764
3743
|
/**
|
|
3765
3744
|
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
@@ -8060,11 +8039,26 @@ var settingsStoreCapability = {
|
|
|
8060
8039
|
key: z.string(),
|
|
8061
8040
|
value: z.unknown()
|
|
8062
8041
|
}), z.void(), { kind: "mutation" }),
|
|
8063
|
-
/**
|
|
8042
|
+
/**
|
|
8043
|
+
* Rows matching a filter.
|
|
8044
|
+
*
|
|
8045
|
+
* `columns` is a SQL-level projection: the engine SELECTs only those
|
|
8046
|
+
* columns (plus the primary key) instead of the whole row. It is the only
|
|
8047
|
+
* way to stop paying disk for a column that is discarded — a heavy JSON
|
|
8048
|
+
* column dominates the row, and dropping it in JS after the read pays every
|
|
8049
|
+
* byte first. Measured on the live `pipeline-analytics:tracks` table: a
|
|
8050
|
+
* 501-row page is 4.6 MB whole and 0.11 MB projected, same index, same
|
|
8051
|
+
* plan.
|
|
8052
|
+
*
|
|
8053
|
+
* The engine REFUSES a column it cannot serve rather than omitting it —
|
|
8054
|
+
* see `SettingsQueryInput.columns` for why a projection may not be
|
|
8055
|
+
* forgiving the way a predicate is.
|
|
8056
|
+
*/
|
|
8064
8057
|
query: method(z.object({
|
|
8065
8058
|
namespace: z.string().optional(),
|
|
8066
8059
|
collection: z.string(),
|
|
8067
|
-
filter: QueryFilterSchema.optional()
|
|
8060
|
+
filter: QueryFilterSchema.optional(),
|
|
8061
|
+
columns: z.array(z.string()).readonly().optional()
|
|
8068
8062
|
}), z.array(SettingsRecordSchema).readonly()),
|
|
8069
8063
|
/** Insert a new record. */
|
|
8070
8064
|
insert: method(z.object({
|
|
@@ -8229,7 +8223,17 @@ var dataStoreProviderCapability = {
|
|
|
8229
8223
|
query: method(z.object({
|
|
8230
8224
|
namespace: z.string().optional(),
|
|
8231
8225
|
collection: z.string(),
|
|
8232
|
-
filter: QueryFilterSchema.optional()
|
|
8226
|
+
filter: QueryFilterSchema.optional(),
|
|
8227
|
+
/**
|
|
8228
|
+
* SQL-level column projection — MUST mirror `settings-store.query`.
|
|
8229
|
+
*
|
|
8230
|
+
* This is the second schema the same call passes through, and Zod
|
|
8231
|
+
* objects STRIP what they do not declare: a field present on the door
|
|
8232
|
+
* and absent here does not error, it silently disappears one hop before
|
|
8233
|
+
* the engine, and the caller concludes the projection does nothing.
|
|
8234
|
+
* `data-door-schema-parity.spec.ts` is what keeps the two in step.
|
|
8235
|
+
*/
|
|
8236
|
+
columns: z.array(z.string()).readonly().optional()
|
|
8233
8237
|
}), z.array(SettingsRecordSchema).readonly()),
|
|
8234
8238
|
/** Insert a new record. */
|
|
8235
8239
|
insert: method(z.object({
|
|
@@ -22863,7 +22867,27 @@ var faceGalleryCapability = {
|
|
|
22863
22867
|
scope: "system",
|
|
22864
22868
|
mode: "singleton",
|
|
22865
22869
|
methods: {
|
|
22866
|
-
listIdentities: method(z.
|
|
22870
|
+
listIdentities: method(z.object({
|
|
22871
|
+
/**
|
|
22872
|
+
* Inline {@link IdentitySchema.coverBase64} on every row.
|
|
22873
|
+
*
|
|
22874
|
+
* Default `false`, the same inversion `listRecentFaces` and
|
|
22875
|
+
* `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
|
|
22876
|
+
* why the burden belongs on the caller that WANTS the bytes). Measured
|
|
22877
|
+
* on the live hub the same day: four identities cost 40,979 B with the
|
|
22878
|
+
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
22879
|
+
* four times and the viewer holds at `staleTime: 30_000`.
|
|
22880
|
+
*
|
|
22881
|
+
* Nothing loses its avatar: `coverMediaKey` is already on every row and
|
|
22882
|
+
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
22883
|
+
*
|
|
22884
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
22885
|
+
* next train** — the hub router validates cap inputs against its own
|
|
22886
|
+
* compiled Zod and strips a key it does not know. Until then the
|
|
22887
|
+
* provider sees `undefined`, which resolves to `false`: the cheap shape
|
|
22888
|
+
* is what ships, and the opt-in becomes reachable when the train lands.
|
|
22889
|
+
*/
|
|
22890
|
+
includeCrops: z.boolean().optional() }).optional(), z.array(IdentitySchema).readonly()),
|
|
22867
22891
|
createIdentity: method(z.object({ name: z.string().min(1) }), IdentitySchema, {
|
|
22868
22892
|
kind: "mutation",
|
|
22869
22893
|
auth: "admin"
|
|
@@ -26225,7 +26249,13 @@ var plateGalleryCapability = {
|
|
|
26225
26249
|
kind: "mutation",
|
|
26226
26250
|
auth: "admin"
|
|
26227
26251
|
}),
|
|
26228
|
-
listVehicles: method(z.
|
|
26252
|
+
listVehicles: method(z.object({
|
|
26253
|
+
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
26254
|
+
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
26255
|
+
* option; `coverMediaKey` + the `event-media` plane carry the picture.
|
|
26256
|
+
* INPUT field: stripped by the hub router until the train ships, which
|
|
26257
|
+
* resolves to `false` and is exactly the intended default. */
|
|
26258
|
+
includeCrops: z.boolean().optional() }).optional(), z.array(VehicleSchema).readonly()),
|
|
26229
26259
|
createVehicle: method(z.object({ name: z.string().min(1) }), VehicleSchema, {
|
|
26230
26260
|
kind: "mutation",
|
|
26231
26261
|
auth: "admin"
|
|
@@ -3704,24 +3704,6 @@ var RecordingRetentionSchema = zod.z.object({
|
|
|
3704
3704
|
maxSizeGb: zod.z.number().min(0).optional()
|
|
3705
3705
|
});
|
|
3706
3706
|
/**
|
|
3707
|
-
* Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
|
|
3708
|
-
* sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
|
|
3709
|
-
* previews at. Five graduated steps; absent on a config = `standard` (the
|
|
3710
|
-
* shipped default, matching `sheet-geometry`/`sheet-composer`).
|
|
3711
|
-
*
|
|
3712
|
-
* Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
|
|
3713
|
-
* Each window's index sidecar carries its own tile dims, so a camera whose
|
|
3714
|
-
* preset changed over time renders every historical window at the dims it was
|
|
3715
|
-
* written with.
|
|
3716
|
-
*/
|
|
3717
|
-
var ScrubThumbnailPresetSchema = zod.z.enum([
|
|
3718
|
-
"minimal",
|
|
3719
|
-
"low",
|
|
3720
|
-
"standard",
|
|
3721
|
-
"high",
|
|
3722
|
-
"max"
|
|
3723
|
-
]);
|
|
3724
|
-
/**
|
|
3725
3707
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
3726
3708
|
*
|
|
3727
3709
|
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
@@ -3729,7 +3711,11 @@ var ScrubThumbnailPresetSchema = zod.z.enum([
|
|
|
3729
3711
|
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
3730
3712
|
*
|
|
3731
3713
|
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
3732
|
-
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30
|
|
3714
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
|
|
3715
|
+
* and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
|
|
3716
|
+
* deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
|
|
3717
|
+
* (D62: a switch that writes a store nobody reads is worse than no switch).
|
|
3718
|
+
* Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
|
|
3733
3719
|
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
3734
3720
|
* persist a band-less config, i.e. silently stop recording the camera.
|
|
3735
3721
|
*/
|
|
@@ -3752,14 +3738,7 @@ var RecordingConfigSchema = zod.z.object({
|
|
|
3752
3738
|
* "off" is the absence of a covering band, never a band value.
|
|
3753
3739
|
*/
|
|
3754
3740
|
bands: zod.z.array(RecordingBandSchema).default([]),
|
|
3755
|
-
retention: RecordingRetentionSchema.optional()
|
|
3756
|
-
/**
|
|
3757
|
-
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
3758
|
-
* timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
|
|
3759
|
-
* windows only — existing sheets are immutable, and each window's index
|
|
3760
|
-
* carries its own tile dims so mixed-preset history renders correctly.
|
|
3761
|
-
*/
|
|
3762
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
3741
|
+
retention: RecordingRetentionSchema.optional()
|
|
3763
3742
|
}).strict();
|
|
3764
3743
|
/**
|
|
3765
3744
|
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
@@ -8060,11 +8039,26 @@ var settingsStoreCapability = {
|
|
|
8060
8039
|
key: zod.z.string(),
|
|
8061
8040
|
value: zod.z.unknown()
|
|
8062
8041
|
}), zod.z.void(), { kind: "mutation" }),
|
|
8063
|
-
/**
|
|
8042
|
+
/**
|
|
8043
|
+
* Rows matching a filter.
|
|
8044
|
+
*
|
|
8045
|
+
* `columns` is a SQL-level projection: the engine SELECTs only those
|
|
8046
|
+
* columns (plus the primary key) instead of the whole row. It is the only
|
|
8047
|
+
* way to stop paying disk for a column that is discarded — a heavy JSON
|
|
8048
|
+
* column dominates the row, and dropping it in JS after the read pays every
|
|
8049
|
+
* byte first. Measured on the live `pipeline-analytics:tracks` table: a
|
|
8050
|
+
* 501-row page is 4.6 MB whole and 0.11 MB projected, same index, same
|
|
8051
|
+
* plan.
|
|
8052
|
+
*
|
|
8053
|
+
* The engine REFUSES a column it cannot serve rather than omitting it —
|
|
8054
|
+
* see `SettingsQueryInput.columns` for why a projection may not be
|
|
8055
|
+
* forgiving the way a predicate is.
|
|
8056
|
+
*/
|
|
8064
8057
|
query: method(zod.z.object({
|
|
8065
8058
|
namespace: zod.z.string().optional(),
|
|
8066
8059
|
collection: zod.z.string(),
|
|
8067
|
-
filter: QueryFilterSchema.optional()
|
|
8060
|
+
filter: QueryFilterSchema.optional(),
|
|
8061
|
+
columns: zod.z.array(zod.z.string()).readonly().optional()
|
|
8068
8062
|
}), zod.z.array(SettingsRecordSchema).readonly()),
|
|
8069
8063
|
/** Insert a new record. */
|
|
8070
8064
|
insert: method(zod.z.object({
|
|
@@ -8229,7 +8223,17 @@ var dataStoreProviderCapability = {
|
|
|
8229
8223
|
query: method(zod.z.object({
|
|
8230
8224
|
namespace: zod.z.string().optional(),
|
|
8231
8225
|
collection: zod.z.string(),
|
|
8232
|
-
filter: QueryFilterSchema.optional()
|
|
8226
|
+
filter: QueryFilterSchema.optional(),
|
|
8227
|
+
/**
|
|
8228
|
+
* SQL-level column projection — MUST mirror `settings-store.query`.
|
|
8229
|
+
*
|
|
8230
|
+
* This is the second schema the same call passes through, and Zod
|
|
8231
|
+
* objects STRIP what they do not declare: a field present on the door
|
|
8232
|
+
* and absent here does not error, it silently disappears one hop before
|
|
8233
|
+
* the engine, and the caller concludes the projection does nothing.
|
|
8234
|
+
* `data-door-schema-parity.spec.ts` is what keeps the two in step.
|
|
8235
|
+
*/
|
|
8236
|
+
columns: zod.z.array(zod.z.string()).readonly().optional()
|
|
8233
8237
|
}), zod.z.array(SettingsRecordSchema).readonly()),
|
|
8234
8238
|
/** Insert a new record. */
|
|
8235
8239
|
insert: method(zod.z.object({
|
|
@@ -22863,7 +22867,27 @@ var faceGalleryCapability = {
|
|
|
22863
22867
|
scope: "system",
|
|
22864
22868
|
mode: "singleton",
|
|
22865
22869
|
methods: {
|
|
22866
|
-
listIdentities: method(zod.z.
|
|
22870
|
+
listIdentities: method(zod.z.object({
|
|
22871
|
+
/**
|
|
22872
|
+
* Inline {@link IdentitySchema.coverBase64} on every row.
|
|
22873
|
+
*
|
|
22874
|
+
* Default `false`, the same inversion `listRecentFaces` and
|
|
22875
|
+
* `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
|
|
22876
|
+
* why the burden belongs on the caller that WANTS the bytes). Measured
|
|
22877
|
+
* on the live hub the same day: four identities cost 40,979 B with the
|
|
22878
|
+
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
22879
|
+
* four times and the viewer holds at `staleTime: 30_000`.
|
|
22880
|
+
*
|
|
22881
|
+
* Nothing loses its avatar: `coverMediaKey` is already on every row and
|
|
22882
|
+
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
22883
|
+
*
|
|
22884
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
22885
|
+
* next train** — the hub router validates cap inputs against its own
|
|
22886
|
+
* compiled Zod and strips a key it does not know. Until then the
|
|
22887
|
+
* provider sees `undefined`, which resolves to `false`: the cheap shape
|
|
22888
|
+
* is what ships, and the opt-in becomes reachable when the train lands.
|
|
22889
|
+
*/
|
|
22890
|
+
includeCrops: zod.z.boolean().optional() }).optional(), zod.z.array(IdentitySchema).readonly()),
|
|
22867
22891
|
createIdentity: method(zod.z.object({ name: zod.z.string().min(1) }), IdentitySchema, {
|
|
22868
22892
|
kind: "mutation",
|
|
22869
22893
|
auth: "admin"
|
|
@@ -26225,7 +26249,13 @@ var plateGalleryCapability = {
|
|
|
26225
26249
|
kind: "mutation",
|
|
26226
26250
|
auth: "admin"
|
|
26227
26251
|
}),
|
|
26228
|
-
listVehicles: method(zod.z.
|
|
26252
|
+
listVehicles: method(zod.z.object({
|
|
26253
|
+
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
26254
|
+
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
26255
|
+
* option; `coverMediaKey` + the `event-media` plane carry the picture.
|
|
26256
|
+
* INPUT field: stripped by the hub router until the train ships, which
|
|
26257
|
+
* resolves to `false` and is exactly the intended default. */
|
|
26258
|
+
includeCrops: zod.z.boolean().optional() }).optional(), zod.z.array(VehicleSchema).readonly()),
|
|
26229
26259
|
createVehicle: method(zod.z.object({ name: zod.z.string().min(1) }), VehicleSchema, {
|
|
26230
26260
|
kind: "mutation",
|
|
26231
26261
|
auth: "admin"
|
package/dist/index.js
CHANGED
|
@@ -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_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
|
|
5
5
|
require("./builtins/alerts/index.js");
|
|
6
6
|
const require_formatter = require("./formatter-DqAKDlvN.js");
|
|
@@ -6763,6 +6763,23 @@ function createDoorSettingsView(addonId, door, sections) {
|
|
|
6763
6763
|
async readDeviceStore(deviceId) {
|
|
6764
6764
|
return loadPrefixed(door, "addon-device-settings", `${addonId}:${String(deviceId)}.`);
|
|
6765
6765
|
},
|
|
6766
|
+
async readDeviceStoreBatch(deviceIds) {
|
|
6767
|
+
const out = /* @__PURE__ */ new Map();
|
|
6768
|
+
if (deviceIds.length === 0) return out;
|
|
6769
|
+
for (const id of deviceIds) out.set(id, {});
|
|
6770
|
+
const wanted = new Set(deviceIds);
|
|
6771
|
+
const all = await loadPrefixed(door, "addon-device-settings", `${addonId}:`);
|
|
6772
|
+
for (const [suffix, value] of Object.entries(all)) {
|
|
6773
|
+
const dot = suffix.indexOf(".");
|
|
6774
|
+
if (dot <= 0) continue;
|
|
6775
|
+
const deviceId = Number(suffix.slice(0, dot));
|
|
6776
|
+
if (!Number.isInteger(deviceId) || !wanted.has(deviceId)) continue;
|
|
6777
|
+
const blob = out.get(deviceId);
|
|
6778
|
+
if (blob === void 0) continue;
|
|
6779
|
+
blob[suffix.slice(dot + 1)] = value;
|
|
6780
|
+
}
|
|
6781
|
+
return out;
|
|
6782
|
+
},
|
|
6766
6783
|
async writeDeviceStore(deviceId, patch) {
|
|
6767
6784
|
const scope = `${addonId}:${String(deviceId)}.`;
|
|
6768
6785
|
await replacePrefixed(door, "addon-device-settings", scope, {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-
|
|
2
|
+
import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-Bh25kEUH.mjs";
|
|
3
3
|
import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
|
|
4
4
|
import "./builtins/alerts/index.mjs";
|
|
5
5
|
import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
|
|
@@ -6756,6 +6756,23 @@ function createDoorSettingsView(addonId, door, sections) {
|
|
|
6756
6756
|
async readDeviceStore(deviceId) {
|
|
6757
6757
|
return loadPrefixed(door, "addon-device-settings", `${addonId}:${String(deviceId)}.`);
|
|
6758
6758
|
},
|
|
6759
|
+
async readDeviceStoreBatch(deviceIds) {
|
|
6760
|
+
const out = /* @__PURE__ */ new Map();
|
|
6761
|
+
if (deviceIds.length === 0) return out;
|
|
6762
|
+
for (const id of deviceIds) out.set(id, {});
|
|
6763
|
+
const wanted = new Set(deviceIds);
|
|
6764
|
+
const all = await loadPrefixed(door, "addon-device-settings", `${addonId}:`);
|
|
6765
|
+
for (const [suffix, value] of Object.entries(all)) {
|
|
6766
|
+
const dot = suffix.indexOf(".");
|
|
6767
|
+
if (dot <= 0) continue;
|
|
6768
|
+
const deviceId = Number(suffix.slice(0, dot));
|
|
6769
|
+
if (!Number.isInteger(deviceId) || !wanted.has(deviceId)) continue;
|
|
6770
|
+
const blob = out.get(deviceId);
|
|
6771
|
+
if (blob === void 0) continue;
|
|
6772
|
+
blob[suffix.slice(dot + 1)] = value;
|
|
6773
|
+
}
|
|
6774
|
+
return out;
|
|
6775
|
+
},
|
|
6759
6776
|
async writeDeviceStore(deviceId, patch) {
|
|
6760
6777
|
const scope = `${addonId}:${String(deviceId)}.`;
|
|
6761
6778
|
await replacePrefixed(door, "addon-device-settings", scope, {
|
|
@@ -4,6 +4,10 @@ export interface AddonSettingsView {
|
|
|
4
4
|
readAddonStore(): Promise<Record<string, unknown>>;
|
|
5
5
|
writeAddonStore(patch: Record<string, unknown>): Promise<void>;
|
|
6
6
|
readDeviceStore(deviceId: number): Promise<Record<string, unknown>>;
|
|
7
|
+
/** See `IAddonContext['settings'].readDeviceStoreBatch` — optional there and
|
|
8
|
+
* here for the same reason: only the door-backed view can answer it in one
|
|
9
|
+
* range scan, and a caller must fall back rather than refuse. */
|
|
10
|
+
readDeviceStoreBatch?(deviceIds: readonly number[]): Promise<ReadonlyMap<number, Record<string, unknown>>>;
|
|
7
11
|
writeDeviceStore(deviceId: number, patch: Record<string, unknown>): Promise<void>;
|
|
8
12
|
clearDeviceStore(deviceId: number): Promise<void>;
|
|
9
13
|
getSection(section: string): Promise<Record<string, unknown>>;
|