@camstack/system 1.2.240 → 1.2.242

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 (53) 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/adoption-job-engine.d.ts +28 -7
  14. package/dist/builtins/device-manager/device-manager.addon.d.ts +11 -0
  15. package/dist/builtins/device-manager/device-manager.addon.js +20 -6
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +20 -6
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  25. package/dist/builtins/local-network/local-network.addon.js +1 -1
  26. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  27. package/dist/builtins/loki-logging/index.js +1 -1
  28. package/dist/builtins/loki-logging/index.mjs +1 -1
  29. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  30. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  31. package/dist/builtins/platform-probe/index.js +1 -1
  32. package/dist/builtins/platform-probe/index.mjs +1 -1
  33. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  34. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  35. package/dist/builtins/snapshot/index.js +1 -1
  36. package/dist/builtins/snapshot/index.mjs +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  38. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -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-Dze0l7UM.js → dist-BETx_5mH.js} +48 -8
  48. package/dist/{dist-CDDG1zn3.mjs → dist-DkGEz_3L.mjs} +48 -8
  49. package/dist/index.js +1 -1
  50. package/dist/index.mjs +1 -1
  51. package/dist/{retired-settings-keys-Cbt4-K_M.mjs → retired-settings-keys-BSsaf7n4.mjs} +1 -1
  52. package/dist/{retired-settings-keys-1GWw9mup.js → retired-settings-keys-BnTBoLTv.js} +1 -1
  53. 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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, bn as EventCategory, k as addonPagesCapability, qt as errMsg } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, bn as EventCategory, k as addonPagesCapability, qt as errMsg } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, bn as EventCategory, j as addonWidgetsCapability, qt as errMsg } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, bn as EventCategory, j as addonWidgetsCapability, qt as errMsg } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, M as alertsCapability, bn as EventCategory, n as AlertSchema, qt as errMsg, sn as createEvent } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, M as alertsCapability, bn as EventCategory, n as AlertSchema, qt as errMsg, sn as createEvent } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Bt as storageOccupancyCapability, Jt as BaseAddon, P as backupCapability, bn as EventCategory, yt as mayWriteToLocation } from "../../dist-CDDG1zn3.mjs";
1
+ import { Bt as storageOccupancyCapability, Jt as BaseAddon, P as backupCapability, bn as EventCategory, yt as mayWriteToLocation } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, ht as logDestinationCapability } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, ht as logDestinationCapability } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
3
+ const require_dist = require("../../dist-BETx_5mH.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 { B as coreBlockIdFromAddonId, Jt as BaseAddon, V as coreBlocksCapability, c as CORE_BLOCK_ADDON_PREFIX, d as DeclaredDevices, l as CoreBlockSchema, qt as errMsg, s as CORE_BLOCKS_ADDON_ID, z as coreBlockAddonId } from "../../dist-CDDG1zn3.mjs";
1
+ import { B as coreBlockIdFromAddonId, Jt as BaseAddon, V as coreBlocksCapability, c as CORE_BLOCK_ADDON_PREFIX, d as DeclaredDevices, l as CoreBlockSchema, qt as errMsg, s as CORE_BLOCKS_ADDON_ID, z as coreBlockAddonId } from "../../dist-DkGEz_3L.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";
@@ -1,4 +1,5 @@
1
1
  import { AdoptionJob, IScopedLogger } from '@camstack/types';
2
+ import { RemovalFence } from './removal-fence.js';
2
3
  /**
3
4
  * The slice of a `device-adoption` provider this engine drives. Structural on
4
5
  * purpose: the real provider satisfies it, and a spec can exercise the whole
@@ -25,18 +26,38 @@ export interface AdoptionJobProvider {
25
26
  name?: string;
26
27
  hiddenChildIds?: string[];
27
28
  }>;
28
- }): Promise<{
29
- readonly adopted: readonly {
30
- readonly childNativeId: string;
31
- readonly parentDeviceId: number;
32
- readonly accessoryDeviceIds: readonly number[];
33
- }[];
34
- }>;
29
+ }): Promise<AdoptResult>;
30
+ }
31
+ /** What one `adopt` call answers. Named so the per-candidate suspension in
32
+ * {@link AdoptionJobEngine} has a return type to state. */
33
+ export interface AdoptResult {
34
+ readonly adopted: readonly {
35
+ readonly childNativeId: string;
36
+ readonly parentDeviceId: number;
37
+ readonly accessoryDeviceIds: readonly number[];
38
+ }[];
35
39
  }
36
40
  export interface AdoptionJobEngineDeps {
37
41
  /** Resolve the integration's adoption provider for an `addonId` pin. */
38
42
  resolveProvider(addonId: string): Promise<AdoptionJobProvider>;
39
43
  readonly logger: IScopedLogger;
44
+ /**
45
+ * The device-manager's removal fence, so an operator re-adopting hardware
46
+ * they just deleted is not refused for their OWN action.
47
+ *
48
+ * `removal-fence.ts` says a deliberate re-add lifts the fence, and
49
+ * `adoptDevice` does exactly that — but a job never went near it, so every
50
+ * integration driven through this engine refused a re-add for the whole
51
+ * 5-minute TTL. Reported on a Dreame vacuum, 2026-09-16.
52
+ *
53
+ * It has to be suspended HERE and not by the caller: `runUnfenced` is a
54
+ * counter held for the length of an awaited call, while `start()` hands back
55
+ * a jobId immediately and adopts on a detached promise. Wrapping the caller
56
+ * would lower the fence for the microseconds it takes to mint an id.
57
+ *
58
+ * Optional: absent means exactly the previous behaviour.
59
+ */
60
+ readonly removalFence?: RemovalFence;
40
61
  readonly now?: () => number;
41
62
  readonly newId?: () => string;
42
63
  }
@@ -50,6 +50,17 @@ export declare class DeviceManagerAddon extends BaseAddon {
50
50
  private remoteNativeCaps;
51
51
  /** Background adoption jobs — lazily constructed (needs `ctx.logger`). */
52
52
  private adoptionJobEngine;
53
+ /**
54
+ * ONE removal fence for this process, shared by the provider context and the
55
+ * adoption-job engine.
56
+ *
57
+ * It used to be constructed inline into the context, so the job engine had
58
+ * no way to reach it and an operator re-adopting hardware they had just
59
+ * deleted was refused for the whole 5-minute TTL — their own action, denied.
60
+ * Two fences would be worse than one: the engine would suspend a fence that
61
+ * `allocateDeviceId` never consults.
62
+ */
63
+ private readonly removalFence;
53
64
  /** The runtime-state mirror, asserted present (constructed in onInitialize). */
54
65
  private get stateMirror();
55
66
  /** Build the `ProviderHost` the extracted provider-method modules
@@ -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-Dze0l7UM.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-1GWw9mup.js");
6
+ const require_dist = require("../../dist-BETx_5mH.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-BnTBoLTv.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
@@ -228,13 +228,15 @@ var AdoptionJobEngine = class {
228
228
  const startedAt = this.now();
229
229
  try {
230
230
  const per = input.perCandidate?.[childNativeId];
231
- const entry = (await provider.adopt({
231
+ const adoptCandidate = async () => await provider.adopt({
232
232
  integrationId: input.integrationId,
233
233
  childNativeIds: [childNativeId],
234
234
  ...input.filter !== void 0 ? { filter: input.filter } : {},
235
235
  ...input.importLocations !== void 0 ? { importLocations: input.importLocations } : {},
236
236
  ...per !== void 0 ? { perCandidate: { [childNativeId]: per } } : {}
237
- })).adopted[0];
237
+ });
238
+ const fence = this.deps.removalFence;
239
+ const entry = (fence === void 0 ? await adoptCandidate() : await fence.runUnfenced(adoptCandidate)).adopted[0];
238
240
  if (!entry) {
239
241
  job.results.push({
240
242
  childNativeId,
@@ -6749,6 +6751,17 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
6749
6751
  remoteNativeCaps = /* @__PURE__ */ new Map();
6750
6752
  /** Background adoption jobs — lazily constructed (needs `ctx.logger`). */
6751
6753
  adoptionJobEngine = null;
6754
+ /**
6755
+ * ONE removal fence for this process, shared by the provider context and the
6756
+ * adoption-job engine.
6757
+ *
6758
+ * It used to be constructed inline into the context, so the job engine had
6759
+ * no way to reach it and an operator re-adopting hardware they had just
6760
+ * deleted was refused for the whole 5-minute TTL — their own action, denied.
6761
+ * Two fences would be worse than one: the engine would suspend a fence that
6762
+ * `allocateDeviceId` never consults.
6763
+ */
6764
+ removalFence = createRemovalFence();
6752
6765
  /** The runtime-state mirror, asserted present (constructed in onInitialize). */
6753
6766
  get stateMirror() {
6754
6767
  if (!this.stateMirrorImpl) throw new Error("DeviceManagerAddon: state mirror accessed before onInitialize");
@@ -6786,7 +6799,8 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
6786
6799
  get adoptionJobsImpl() {
6787
6800
  if (!this.adoptionJobEngine) this.adoptionJobEngine = new AdoptionJobEngine({
6788
6801
  resolveProvider: async (addonId) => this.requireDeviceAdoptionProvider(addonId),
6789
- logger: this.ctx.logger
6802
+ logger: this.ctx.logger,
6803
+ removalFence: this.removalFence
6790
6804
  });
6791
6805
  return this.adoptionJobEngine;
6792
6806
  }
@@ -6937,7 +6951,7 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
6937
6951
  registry,
6938
6952
  bindingsDeps: this.bindingsDeps,
6939
6953
  migrationGuard: createMigrationGuard(),
6940
- removalFence: createRemovalFence(),
6954
+ removalFence: this.removalFence,
6941
6955
  requireDeviceOps,
6942
6956
  stampIntegrationId: stampIntegrationId$1,
6943
6957
  get provider() {
@@ -1,5 +1,5 @@
1
- import { $t as DeviceRole, G as deviceManagerCapability, Jt as BaseAddon, K as deviceStateCapability, L as buildStreamParamsConfigSchema, Mt as runtimeStatePolicyFor, Qt as DeviceFeature, S as STREAM_PROFILE_META, St as normalizeUnit, X as enumerateItemArrayFields, Z as enumerateSchemaFields, a as CAMERA_SWITCH_ORDER, bn as EventCategory, en as DeviceType, f as DeviceStatusSchema, fn as isDeviceConfigCap, kt as resolveContainerPrimaryChild, o as CAP_NAMES_WITH_STATUS, q as deviceStatusCapability, qt as errMsg, rn as WELL_KNOWN_TAB_MAP, t as ALL_CAPABILITY_DEFINITIONS, wt as parseStreamParamsFormPatch, yn as sleep$1 } from "../../dist-CDDG1zn3.mjs";
2
- import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-Cbt4-K_M.mjs";
1
+ import { $t as DeviceRole, G as deviceManagerCapability, Jt as BaseAddon, K as deviceStateCapability, L as buildStreamParamsConfigSchema, Mt as runtimeStatePolicyFor, Qt as DeviceFeature, S as STREAM_PROFILE_META, St as normalizeUnit, X as enumerateItemArrayFields, Z as enumerateSchemaFields, a as CAMERA_SWITCH_ORDER, bn as EventCategory, en as DeviceType, f as DeviceStatusSchema, fn as isDeviceConfigCap, kt as resolveContainerPrimaryChild, o as CAP_NAMES_WITH_STATUS, q as deviceStatusCapability, qt as errMsg, rn as WELL_KNOWN_TAB_MAP, t as ALL_CAPABILITY_DEFINITIONS, wt as parseStreamParamsFormPatch, yn as sleep$1 } from "../../dist-DkGEz_3L.mjs";
2
+ import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-BSsaf7n4.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
@@ -223,13 +223,15 @@ var AdoptionJobEngine = class {
223
223
  const startedAt = this.now();
224
224
  try {
225
225
  const per = input.perCandidate?.[childNativeId];
226
- const entry = (await provider.adopt({
226
+ const adoptCandidate = async () => await provider.adopt({
227
227
  integrationId: input.integrationId,
228
228
  childNativeIds: [childNativeId],
229
229
  ...input.filter !== void 0 ? { filter: input.filter } : {},
230
230
  ...input.importLocations !== void 0 ? { importLocations: input.importLocations } : {},
231
231
  ...per !== void 0 ? { perCandidate: { [childNativeId]: per } } : {}
232
- })).adopted[0];
232
+ });
233
+ const fence = this.deps.removalFence;
234
+ const entry = (fence === void 0 ? await adoptCandidate() : await fence.runUnfenced(adoptCandidate)).adopted[0];
233
235
  if (!entry) {
234
236
  job.results.push({
235
237
  childNativeId,
@@ -6744,6 +6746,17 @@ var DeviceManagerAddon = class extends BaseAddon {
6744
6746
  remoteNativeCaps = /* @__PURE__ */ new Map();
6745
6747
  /** Background adoption jobs — lazily constructed (needs `ctx.logger`). */
6746
6748
  adoptionJobEngine = null;
6749
+ /**
6750
+ * ONE removal fence for this process, shared by the provider context and the
6751
+ * adoption-job engine.
6752
+ *
6753
+ * It used to be constructed inline into the context, so the job engine had
6754
+ * no way to reach it and an operator re-adopting hardware they had just
6755
+ * deleted was refused for the whole 5-minute TTL — their own action, denied.
6756
+ * Two fences would be worse than one: the engine would suspend a fence that
6757
+ * `allocateDeviceId` never consults.
6758
+ */
6759
+ removalFence = createRemovalFence();
6747
6760
  /** The runtime-state mirror, asserted present (constructed in onInitialize). */
6748
6761
  get stateMirror() {
6749
6762
  if (!this.stateMirrorImpl) throw new Error("DeviceManagerAddon: state mirror accessed before onInitialize");
@@ -6781,7 +6794,8 @@ var DeviceManagerAddon = class extends BaseAddon {
6781
6794
  get adoptionJobsImpl() {
6782
6795
  if (!this.adoptionJobEngine) this.adoptionJobEngine = new AdoptionJobEngine({
6783
6796
  resolveProvider: async (addonId) => this.requireDeviceAdoptionProvider(addonId),
6784
- logger: this.ctx.logger
6797
+ logger: this.ctx.logger,
6798
+ removalFence: this.removalFence
6785
6799
  });
6786
6800
  return this.adoptionJobEngine;
6787
6801
  }
@@ -6932,7 +6946,7 @@ var DeviceManagerAddon = class extends BaseAddon {
6932
6946
  registry,
6933
6947
  bindingsDeps: this.bindingsDeps,
6934
6948
  migrationGuard: createMigrationGuard(),
6935
- removalFence: createRemovalFence(),
6949
+ removalFence: this.removalFence,
6936
6950
  requireDeviceOps,
6937
6951
  stampIntegrationId: stampIntegrationId$1,
6938
6952
  get provider() {
@@ -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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { F as bareAddonId, J as doorbellCapability, Jt as BaseAddon, Q as evaluateSensorEdge, b as SOURCE_DEVICE_TYPES, bn as EventCategory, ct as isSameAddonId, en as DeviceType, lt as isSourceCap, qt as errMsg, sn as createEvent, y as SOURCE_CAPS } from "../../dist-CDDG1zn3.mjs";
1
+ import { F as bareAddonId, J as doorbellCapability, Jt as BaseAddon, Q as evaluateSensorEdge, b as SOURCE_DEVICE_TYPES, bn as EventCategory, ct as isSameAddonId, en as DeviceType, lt as isSourceCap, qt as errMsg, sn as createEvent, y as SOURCE_CAPS } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, ht as logDestinationCapability } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, ht as logDestinationCapability } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
3
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, bn as EventCategory, qt as errMsg, sn as createEvent, v as RecordingStatusSchema } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, bn as EventCategory, qt as errMsg, sn as createEvent, v as RecordingStatusSchema } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { C as ScopedTokenSchema, Jt as BaseAddon, N as authProviderCapability, O as UserRecordSchema, Ut as userManagementCapability, r as ApiKeyRecordSchema } from "../../dist-CDDG1zn3.mjs";
2
+ import { C as ScopedTokenSchema, Jt as BaseAddon, N as authProviderCapability, O as UserRecordSchema, Ut as userManagementCapability, r as ApiKeyRecordSchema } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
3
+ const require_dist = require("../../dist-BETx_5mH.js");
4
4
  const require_tls = require("../../tls-BFs4PzoW.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 { Jt as BaseAddon, bn as EventCategory, mt as localNetworkCapability } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, bn as EventCategory, mt as localNetworkCapability } from "../../dist-DkGEz_3L.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-2xbgg78V.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, ht as logDestinationCapability } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, ht as logDestinationCapability } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.js");
7
7
  let node_fs_promises = require("node:fs/promises");
8
8
  let node_fs = require("node:fs");
9
9
  node_fs = require_chunk.__toESM(node_fs);
@@ -1,4 +1,4 @@
1
- import { Dt as reducePoints, Jt as BaseAddon, Ot as resolveBucketMs, bn as EventCategory, bt as metricsProviderCapability, nt as foldSnapshotByFunction, qt as errMsg, sn as createEvent } from "../../dist-CDDG1zn3.mjs";
1
+ import { Dt as reducePoints, Jt as BaseAddon, Ot as resolveBucketMs, bn as EventCategory, bt as metricsProviderCapability, nt as foldSnapshotByFunction, qt as errMsg, sn as createEvent } from "../../dist-DkGEz_3L.mjs";
2
2
  import { access, readFile, readdir } from "node:fs/promises";
3
3
  import * as fs from "node:fs";
4
4
  import { constants, readFileSync } from "node:fs";
@@ -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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.js");
7
7
  let node_fs = require("node:fs");
8
8
  node_fs = require_chunk.__toESM(node_fs);
9
9
  let node_child_process = require("node:child_process");
@@ -1,5 +1,5 @@
1
1
  import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
2
- import { Ft as scoreRuntimes, Jt as BaseAddon, Tt as platformProbeCapability, Y as enumerateInferenceDevices, bn as EventCategory, ln as emitReadiness, qt as errMsg } from "../../dist-CDDG1zn3.mjs";
2
+ import { Ft as scoreRuntimes, Jt as BaseAddon, Tt as platformProbeCapability, Y as enumerateInferenceDevices, bn as EventCategory, ln as emitReadiness, qt as errMsg } from "../../dist-DkGEz_3L.mjs";
3
3
  import * as fs from "node:fs";
4
4
  import { execFile } from "node:child_process";
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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, bn as EventCategory } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, bn as EventCategory } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.js");
7
7
  const require_snapshot_courtesy = require("../../snapshot-courtesy-oeTWCXPv.js");
8
8
  let zod = require("zod");
9
9
  let node_crypto = require("node:crypto");
@@ -1,4 +1,4 @@
1
- import { F as bareAddonId, Ht as streamQualityLabel, I as batteryCapability, Jt as BaseAddon, Lt as snapshotCapability, Qt as DeviceFeature, W as deriveBatteryPresence, bn as EventCategory, en as DeviceType, i as BatteryStatusSchema, pn as nodePin, qt as errMsg } from "../../dist-CDDG1zn3.mjs";
1
+ import { F as bareAddonId, Ht as streamQualityLabel, I as batteryCapability, Jt as BaseAddon, Lt as snapshotCapability, Qt as DeviceFeature, W as deriveBatteryPresence, bn as EventCategory, en as DeviceType, i as BatteryStatusSchema, pn as nodePin, qt as errMsg } from "../../dist-DkGEz_3L.mjs";
2
2
  import { i as renderCourtesyOverlayJpeg, n as courtesyCacheKey, r as renderCourtesyJpeg } from "../../snapshot-courtesy-LoJNgHHZ.mjs";
3
3
  import { z } from "zod";
4
4
  import { randomUUID } from "node:crypto";
@@ -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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, Vt as storageProviderCapability, tt as filesystemBrowseCapability } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, Vt as storageProviderCapability, tt as filesystemBrowseCapability } from "../../dist-DkGEz_3L.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";
@@ -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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.js");
7
7
  const require_hub_cap_forward = require("../../hub-cap-forward-DmHNjbB0.js");
8
8
  let zod = require("zod");
9
9
  let node_crypto = require("node:crypto");
@@ -1,4 +1,4 @@
1
- import { $ as evictionPolicyOfLocation, At as resolveLocationMode, D as StorageMigrationJobSchema, E as StorageLocationTypeSchema, It as settingsStoreCapability, Jt as BaseAddon, Kt as withLocationMode, R as collectSecretConfigKeys, Rt as storageCapability, T as StorageLocationModeSchema, bn as EventCategory, ft as legacyModeOf, g as REDACTED_SECRET, m as LegacyStorageLocationDefaultSchema, mn as parseJsonObject, ot as isLocationEnabled, rt as gbToBytes, vt as mayReadLocation, w as StorageCleanupJobSchema, xt as modeMayWrite, yt as mayWriteToLocation, zt as storageMigrationCapability } from "../../dist-CDDG1zn3.mjs";
1
+ import { $ as evictionPolicyOfLocation, At as resolveLocationMode, D as StorageMigrationJobSchema, E as StorageLocationTypeSchema, It as settingsStoreCapability, Jt as BaseAddon, Kt as withLocationMode, R as collectSecretConfigKeys, Rt as storageCapability, T as StorageLocationModeSchema, bn as EventCategory, ft as legacyModeOf, g as REDACTED_SECRET, m as LegacyStorageLocationDefaultSchema, mn as parseJsonObject, ot as isLocationEnabled, rt as gbToBytes, vt as mayReadLocation, w as StorageCleanupJobSchema, xt as modeMayWrite, yt as mayWriteToLocation, zt as storageMigrationCapability } from "../../dist-DkGEz_3L.mjs";
2
2
  import { t as HUB_CAP_FWD_ACTION } from "../../hub-cap-forward-BdT320dq.mjs";
3
3
  import { z } from "zod";
4
4
  import { randomUUID } from "node:crypto";
@@ -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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, dn as hydrateSchema, qt as errMsg } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, dn as hydrateSchema, qt as errMsg } from "../../dist-DkGEz_3L.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-Dze0l7UM.js");
6
+ const require_dist = require("../../dist-BETx_5mH.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 { Jt as BaseAddon, ht as logDestinationCapability } from "../../dist-CDDG1zn3.mjs";
1
+ import { Jt as BaseAddon, ht as logDestinationCapability } from "../../dist-DkGEz_3L.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";
@@ -18579,13 +18579,26 @@ var TrackAudioLabelSchema = zod.z.object({
18579
18579
  * - `audio` — an audio event on the camera itself that was anomalous for
18580
18580
  * THAT camera, loud, and heard while nothing visual was happening (D62).
18581
18581
  *
18582
+ * - `onboard` — the CAMERA's own firmware, paired with a decoded frame in
18583
+ * that frame's pixel space. A real root detector and a SPATIAL one: its
18584
+ * boxes are the same kind of fact `pipeline`'s are, produced by a different
18585
+ * detector.
18586
+ *
18587
+ * `onboard` was missing here while `DetectionSourceSchema` already had it, so
18588
+ * a persisted onboard track failed `safeParse` on read and came back with NO
18589
+ * source at all — which `isSpatialTrack` then admitted by accident, through the
18590
+ * `undefined` arm rather than by anybody's decision, and which `excludeSources`
18591
+ * could not name.
18592
+ *
18582
18593
  * The spatial subsystems (tracker association, occupancy count, re-id /
18583
18594
  * embedding, resurrection) MUST skip every synthetic source. Test for that
18584
- * with `isSpatialTrack`, which allow-lists `pipeline` — a `!== 'sensor'`
18585
- * check silently readmits every source added after it was written.
18595
+ * with `isSpatialTrack`, which allow-lists the spatial sources explicitly — a
18596
+ * `!== 'sensor'` check silently readmits every source added after it was
18597
+ * written.
18586
18598
  */
18587
18599
  var TrackSourceSchema = zod.z.enum([
18588
18600
  "pipeline",
18601
+ "onboard",
18589
18602
  "sensor",
18590
18603
  "audio"
18591
18604
  ]);
@@ -19181,6 +19194,7 @@ var MediaFileKindEnum = zod.z.enum([
19181
19194
  "keyFrame",
19182
19195
  "keyFrameSmall",
19183
19196
  "thumbnailSmall",
19197
+ "confirmationCrop",
19184
19198
  "sceneFrame"
19185
19199
  ]);
19186
19200
  /**
@@ -21322,13 +21336,39 @@ var MotionSourceEnum = zod.z.enum([
21322
21336
  */
21323
21337
  var MotionSourcesSchema = zod.z.array(MotionSourceEnum);
21324
21338
  /**
21325
- * Which root detectors a camera runs. Deliberately the SAME vocabulary
21326
- * post-analysis already tags every detection with (`DetectionSource`) rather
21327
- * than a second spelling of the same two ideas — the value an operator picks
21328
- * here is the value that comes back on the track, the overlay and the debug
21329
- * row.
21339
+ * Which root detector a camera runs — EXACTLY ONE.
21340
+ *
21341
+ * Deliberately the SAME vocabulary post-analysis already tags every detection
21342
+ * with (`DetectionSource`) rather than a second spelling of the same two
21343
+ * ideas: the value an operator picks here is the value that comes back on the
21344
+ * track, the overlay and the debug row.
21345
+ *
21346
+ * ## Why one, and why it is still an array
21347
+ *
21348
+ * Two roots on one camera is a capability nobody asked for and the operator has
21349
+ * since ruled out. It was never free: both planes feed the SAME per-device
21350
+ * stationary registry, both can promote the same parked object, and the two
21351
+ * detectors disagree about the same box by construction — which is the
21352
+ * disagreement D505 had to arbitrate. Removing the case removes the arbitration.
21353
+ *
21354
+ * The ARRAY shape survives because the stored settings and the attach payload
21355
+ * already speak it on every camera of every fleet, and a cap input that
21356
+ * suddenly refuses a stored value makes the camera un-attachable — a fail-closed
21357
+ * in the one direction that costs an operator their cameras. So the wire stays
21358
+ * tolerant and the TYPE is exact: a longer list is truncated to its first
21359
+ * element rather than refused, and `max(1)` is what every consumer can then
21360
+ * rely on.
21361
+ *
21362
+ * AT MOST one, not exactly one. The EMPTY list is a legal, deliberate pick —
21363
+ * a camera an operator left with no root detector — and `planDetectionSources`
21364
+ * has always said so: inventing a root for them is how a default acts without
21365
+ * anybody choosing it. Tightening this to `length(1)` broke that, and the
21366
+ * suite caught it.
21367
+ *
21368
+ * Measured before tightening (2026-09-15, this fleet, 6 h of attaches): 3327
21369
+ * `["pipeline"]` and 2 `["onboard"]`. Not one camera had two.
21330
21370
  */
21331
- var DetectionSourcesSchema = zod.z.array(DetectionSourceSchema);
21371
+ var DetectionSourcesSchema = zod.z.preprocess((value) => Array.isArray(value) && value.length > 1 ? value.slice(0, 1) : value, zod.z.array(DetectionSourceSchema).max(1));
21332
21372
  /**
21333
21373
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
21334
21374
  * so cap-side consumers (the orchestrator forward, the runner addon's
@@ -18579,13 +18579,26 @@ var TrackAudioLabelSchema = z.object({
18579
18579
  * - `audio` — an audio event on the camera itself that was anomalous for
18580
18580
  * THAT camera, loud, and heard while nothing visual was happening (D62).
18581
18581
  *
18582
+ * - `onboard` — the CAMERA's own firmware, paired with a decoded frame in
18583
+ * that frame's pixel space. A real root detector and a SPATIAL one: its
18584
+ * boxes are the same kind of fact `pipeline`'s are, produced by a different
18585
+ * detector.
18586
+ *
18587
+ * `onboard` was missing here while `DetectionSourceSchema` already had it, so
18588
+ * a persisted onboard track failed `safeParse` on read and came back with NO
18589
+ * source at all — which `isSpatialTrack` then admitted by accident, through the
18590
+ * `undefined` arm rather than by anybody's decision, and which `excludeSources`
18591
+ * could not name.
18592
+ *
18582
18593
  * The spatial subsystems (tracker association, occupancy count, re-id /
18583
18594
  * embedding, resurrection) MUST skip every synthetic source. Test for that
18584
- * with `isSpatialTrack`, which allow-lists `pipeline` — a `!== 'sensor'`
18585
- * check silently readmits every source added after it was written.
18595
+ * with `isSpatialTrack`, which allow-lists the spatial sources explicitly — a
18596
+ * `!== 'sensor'` check silently readmits every source added after it was
18597
+ * written.
18586
18598
  */
18587
18599
  var TrackSourceSchema = z.enum([
18588
18600
  "pipeline",
18601
+ "onboard",
18589
18602
  "sensor",
18590
18603
  "audio"
18591
18604
  ]);
@@ -19181,6 +19194,7 @@ var MediaFileKindEnum = z.enum([
19181
19194
  "keyFrame",
19182
19195
  "keyFrameSmall",
19183
19196
  "thumbnailSmall",
19197
+ "confirmationCrop",
19184
19198
  "sceneFrame"
19185
19199
  ]);
19186
19200
  /**
@@ -21322,13 +21336,39 @@ var MotionSourceEnum = z.enum([
21322
21336
  */
21323
21337
  var MotionSourcesSchema = z.array(MotionSourceEnum);
21324
21338
  /**
21325
- * Which root detectors a camera runs. Deliberately the SAME vocabulary
21326
- * post-analysis already tags every detection with (`DetectionSource`) rather
21327
- * than a second spelling of the same two ideas — the value an operator picks
21328
- * here is the value that comes back on the track, the overlay and the debug
21329
- * row.
21339
+ * Which root detector a camera runs — EXACTLY ONE.
21340
+ *
21341
+ * Deliberately the SAME vocabulary post-analysis already tags every detection
21342
+ * with (`DetectionSource`) rather than a second spelling of the same two
21343
+ * ideas: the value an operator picks here is the value that comes back on the
21344
+ * track, the overlay and the debug row.
21345
+ *
21346
+ * ## Why one, and why it is still an array
21347
+ *
21348
+ * Two roots on one camera is a capability nobody asked for and the operator has
21349
+ * since ruled out. It was never free: both planes feed the SAME per-device
21350
+ * stationary registry, both can promote the same parked object, and the two
21351
+ * detectors disagree about the same box by construction — which is the
21352
+ * disagreement D505 had to arbitrate. Removing the case removes the arbitration.
21353
+ *
21354
+ * The ARRAY shape survives because the stored settings and the attach payload
21355
+ * already speak it on every camera of every fleet, and a cap input that
21356
+ * suddenly refuses a stored value makes the camera un-attachable — a fail-closed
21357
+ * in the one direction that costs an operator their cameras. So the wire stays
21358
+ * tolerant and the TYPE is exact: a longer list is truncated to its first
21359
+ * element rather than refused, and `max(1)` is what every consumer can then
21360
+ * rely on.
21361
+ *
21362
+ * AT MOST one, not exactly one. The EMPTY list is a legal, deliberate pick —
21363
+ * a camera an operator left with no root detector — and `planDetectionSources`
21364
+ * has always said so: inventing a root for them is how a default acts without
21365
+ * anybody choosing it. Tightening this to `length(1)` broke that, and the
21366
+ * suite caught it.
21367
+ *
21368
+ * Measured before tightening (2026-09-15, this fleet, 6 h of attaches): 3327
21369
+ * `["pipeline"]` and 2 `["onboard"]`. Not one camera had two.
21330
21370
  */
21331
- var DetectionSourcesSchema = z.array(DetectionSourceSchema);
21371
+ var DetectionSourcesSchema = z.preprocess((value) => Array.isArray(value) && value.length > 1 ? value.slice(0, 1) : value, z.array(DetectionSourceSchema).max(1));
21332
21372
  /**
21333
21373
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
21334
21374
  * so cap-side consumers (the orchestrator forward, the runner addon's
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-Dze0l7UM.js");
3
+ const require_dist = require("./dist-BETx_5mH.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");
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 { A as addonSettingsCapability, Ct as objectInputDeclaresAddonId, Et as procedureAuthKey, Nt as scopesAllowAddon, Pt as scopesAllowDeviceCap, Xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Yt as DATAPLANE_SECRET_HEADER$1, Zt as DEVICE_STATUS_METHOD, _ as RUNTIME_DEFAULTS, _n as resolveCapMount, _t as looseSchema, an as asNumber, at as isCollectionArrayMethod, bn as EventCategory$1, cn as emitDownForOwnedCaps, dt as kebabToCamel, et as extractNestedAddonId, gn as readinessKey, gt as logLevelAtMost, h as METHOD_ACCESS_MAP, hn as parseJsonUnknown, in as asJsonObject$1, it as isArrayOutputSchema, jt as resolveMethodAuth, mn as parseJsonObject, nn as ReadinessTimeoutError, on as asString$1, p as LOG_LEVEL_RANK, pt as lifecycleJobSchema, qt as errMsg$1, sn as createEvent, st as isObjectInput, t as ALL_CAPABILITY_DEFINITIONS, tn as ReadinessRegistry, un as expandCapMethods, ut as isVoidInput, vn as scopeKey } from "./dist-CDDG1zn3.mjs";
2
+ import { A as addonSettingsCapability, Ct as objectInputDeclaresAddonId, Et as procedureAuthKey, Nt as scopesAllowAddon, Pt as scopesAllowDeviceCap, Xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Yt as DATAPLANE_SECRET_HEADER$1, Zt as DEVICE_STATUS_METHOD, _ as RUNTIME_DEFAULTS, _n as resolveCapMount, _t as looseSchema, an as asNumber, at as isCollectionArrayMethod, bn as EventCategory$1, cn as emitDownForOwnedCaps, dt as kebabToCamel, et as extractNestedAddonId, gn as readinessKey, gt as logLevelAtMost, h as METHOD_ACCESS_MAP, hn as parseJsonUnknown, in as asJsonObject$1, it as isArrayOutputSchema, jt as resolveMethodAuth, mn as parseJsonObject, nn as ReadinessTimeoutError, on as asString$1, p as LOG_LEVEL_RANK, pt as lifecycleJobSchema, qt as errMsg$1, sn as createEvent, st as isObjectInput, t as ALL_CAPABILITY_DEFINITIONS, tn as ReadinessRegistry, un as expandCapMethods, ut as isVoidInput, vn as scopeKey } from "./dist-DkGEz_3L.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";
@@ -1,4 +1,4 @@
1
- import { in as asJsonObject } from "./dist-CDDG1zn3.mjs";
1
+ import { in as asJsonObject } from "./dist-DkGEz_3L.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-Dze0l7UM.js");
1
+ const require_dist = require("./dist-BETx_5mH.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?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.240",
3
+ "version": "1.2.242",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",