@camstack/system 1.2.134 → 1.2.136

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 (54) 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 +117 -9
  14. package/dist/builtins/device-manager/device-manager.addon.mjs +117 -9
  15. package/dist/builtins/device-manager/device-row-store.d.ts +50 -0
  16. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  18. package/dist/builtins/hub-forwarder/index.js +1 -1
  19. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  20. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  22. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  24. package/dist/builtins/local-network/local-network.addon.js +1 -1
  25. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  26. package/dist/builtins/loki-logging/index.js +1 -1
  27. package/dist/builtins/loki-logging/index.mjs +1 -1
  28. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  29. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  30. package/dist/builtins/platform-probe/index.js +1 -1
  31. package/dist/builtins/platform-probe/index.mjs +1 -1
  32. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  33. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  34. package/dist/builtins/snapshot/index.js +1 -1
  35. package/dist/builtins/snapshot/index.mjs +1 -1
  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/sqlite-settings-backend.d.ts +39 -1
  39. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  41. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  42. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  43. package/dist/builtins/system-config/system-config.addon.js +1 -1
  44. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  45. package/dist/builtins/winston-logging/index.js +1 -1
  46. package/dist/builtins/winston-logging/index.mjs +1 -1
  47. package/dist/{dist-BUEU7B1V.mjs → dist-Bh25kEUH.mjs} +62 -32
  48. package/dist/{dist-DqcaE-k1.js → dist-D-R0SuP-.js} +62 -32
  49. package/dist/index.js +18 -1
  50. package/dist/index.mjs +18 -1
  51. package/dist/kernel/config-manager.d.ts +4 -0
  52. package/dist/{retired-settings-keys-BhPleRL7.mjs → retired-settings-keys-BZbOXqch.mjs} +1 -1
  53. package/dist/{retired-settings-keys-KZnmtfsh.js → retired-settings-keys-CqD6rSQx.js} +1 -1
  54. package/package.json +1 -1
@@ -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";
@@ -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";
@@ -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>;
@@ -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
  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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-BUEU7B1V.mjs";
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-DqcaE-k1.js");
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-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
  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
- /** Get all entries matching an optional filter. */
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.void(), z.array(IdentitySchema).readonly()),
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.void(), z.array(VehicleSchema).readonly()),
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
- /** Get all entries matching an optional filter. */
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.void(), zod.z.array(IdentitySchema).readonly()),
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.void(), zod.z.array(VehicleSchema).readonly()),
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-DqcaE-k1.js");
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-BUEU7B1V.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-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>>;
@@ -1,4 +1,4 @@
1
- import { kt as asJsonObject } from "./dist-BUEU7B1V.mjs";
1
+ import { kt as asJsonObject } from "./dist-Bh25kEUH.mjs";
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DqcaE-k1.js");
1
+ const require_dist = require("./dist-D-R0SuP-.js");
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?