@camstack/system 1.2.142 → 1.2.143

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 (60) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  17. package/dist/builtins/doorbell/trigger-engine.d.ts +7 -81
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.js +29 -109
  19. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +26 -106
  20. package/dist/builtins/hub-forwarder/index.js +1 -1
  21. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  23. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  25. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  26. package/dist/builtins/local-network/local-network.addon.js +1 -1
  27. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  28. package/dist/builtins/loki-logging/index.js +1 -1
  29. package/dist/builtins/loki-logging/index.mjs +1 -1
  30. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  31. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  32. package/dist/builtins/platform-probe/index.js +1 -1
  33. package/dist/builtins/platform-probe/index.mjs +1 -1
  34. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  35. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  36. package/dist/builtins/snapshot/index.js +1 -1
  37. package/dist/builtins/snapshot/index.mjs +1 -1
  38. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  39. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  41. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  42. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  44. package/dist/builtins/system-config/system-config.addon.js +1 -1
  45. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  46. package/dist/builtins/winston-logging/index.js +1 -1
  47. package/dist/builtins/winston-logging/index.mjs +1 -1
  48. package/dist/{dist-jRSrzoXr.js → dist-CQs1b7uh.js} +742 -77
  49. package/dist/{dist-XjWZZYr9.mjs → dist-CVuVKA-O.mjs} +707 -78
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.js +127 -3
  52. package/dist/index.mjs +124 -4
  53. package/dist/logging/log-manager.d.ts +16 -0
  54. package/dist/logging/logging-gate.d.ts +32 -0
  55. package/dist/logging/logging-gate.singleton.d.ts +5 -0
  56. package/dist/{manifest-python-deps-DBQarwp9.js → manifest-python-deps-B_mCU6gz.js} +25 -2
  57. package/dist/{manifest-python-deps-D3zYlMEa.mjs → manifest-python-deps-BuhBXCg0.mjs} +25 -2
  58. package/dist/{retired-settings-keys-C8FeTH36.mjs → retired-settings-keys-DnMYSIEr.mjs} +1 -1
  59. package/dist/{retired-settings-keys-ovd_DQzc.js → retired-settings-keys-Dvei9nhG.js} +1 -1
  60. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_manifest_python_deps = require("./manifest-python-deps-DBQarwp9.js");
2
+ const require_manifest_python_deps = require("./manifest-python-deps-B_mCU6gz.js");
3
3
  const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
4
4
  let node_path = require("node:path");
5
5
  node_path = require_chunk.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { F as createUdsLoggerWithControl, I as LocalChildClient, Nt as startRunnerHeapWatch, bt as resolveAddonClass, i as createUdsAddonContext, it as setWorkerNativeCapsChangeListener, nt as getWorkerNativeCapSnapshot, ot as validateProviderRegistrations, t as installManifestPythonDeps, tt as getWorkerNativeCapProvider, yt as installManifestNativeDeps } from "./manifest-python-deps-D3zYlMEa.mjs";
1
+ import { F as createUdsLoggerWithControl, I as LocalChildClient, Nt as startRunnerHeapWatch, bt as resolveAddonClass, i as createUdsAddonContext, it as setWorkerNativeCapsChangeListener, nt as getWorkerNativeCapSnapshot, ot as validateProviderRegistrations, t as installManifestPythonDeps, tt as getWorkerNativeCapProvider, yt as installManifestNativeDeps } from "./manifest-python-deps-BuhBXCg0.mjs";
2
2
  import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
3
3
  import { register } from "node:module";
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-jRSrzoXr.js");
6
+ const require_dist = require("../../dist-CQs1b7uh.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 { Kt as EventCategory, bt as BaseAddon, v as addonPagesCapability, yt as errMsg } from "../../dist-XjWZZYr9.mjs";
1
+ import { Et as BaseAddon, Qt as EventCategory, S as addonPagesCapability, Tt as errMsg } from "../../dist-CVuVKA-O.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-jRSrzoXr.js");
6
+ const require_dist = require("../../dist-CQs1b7uh.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 { Kt as EventCategory, b as addonWidgetsCapability, bt as BaseAddon, yt as errMsg } from "../../dist-XjWZZYr9.mjs";
1
+ import { Et as BaseAddon, Qt as EventCategory, Tt as errMsg, w as addonWidgetsCapability } from "../../dist-CVuVKA-O.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-jRSrzoXr.js");
6
+ const require_dist = require("../../dist-CQs1b7uh.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 { Kt as EventCategory, Nt as createEvent, bt as BaseAddon, n as AlertSchema, x as alertsCapability, yt as errMsg } from "../../dist-XjWZZYr9.mjs";
1
+ import { Et as BaseAddon, Qt as EventCategory, T as alertsCapability, Tt as errMsg, n as AlertSchema, zt as createEvent } from "../../dist-CVuVKA-O.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-jRSrzoXr.js");
6
+ const require_dist = require("../../dist-CQs1b7uh.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, Kt as EventCategory, bt as BaseAddon } from "../../dist-XjWZZYr9.mjs";
1
+ import { D as backupCapability, Et as BaseAddon, Qt as EventCategory } from "../../dist-CVuVKA-O.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-jRSrzoXr.js");
6
+ const require_dist = require("../../dist-CQs1b7uh.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, bt as BaseAddon } from "../../dist-XjWZZYr9.mjs";
1
+ import { Et as BaseAddon, nt as logDestinationCapability } from "../../dist-CVuVKA-O.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-jRSrzoXr.js");
3
+ const require_dist = require("../../dist-CQs1b7uh.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, bt as BaseAddon, c as CoreBlockSchema, k as coreBlocksCapability, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX, yt as errMsg } from "../../dist-XjWZZYr9.mjs";
1
+ import { Et as BaseAddon, M as coreBlockIdFromAddonId, N as coreBlocksCapability, Tt as errMsg, c as CoreBlockSchema, j as coreBlockAddonId, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX, u as DeclaredDevices } from "../../dist-CVuVKA-O.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-jRSrzoXr.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-ovd_DQzc.js");
6
+ const require_dist = require("../../dist-CQs1b7uh.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-Dvei9nhG.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
@@ -1,5 +1,5 @@
1
- import { E as buildStreamParamsConfigSchema, Et as DeviceType, F as deviceStatusCapability, Gt as sleep, Kt as EventCategory, N as deviceManagerCapability, P as deviceStateCapability, R as enumerateItemArrayFields, Rt as isDeviceConfigCap, Tt as DeviceRole, a as CAP_NAMES_WITH_STATUS, bt as BaseAddon, et as normalizeUnit, kt as WELL_KNOWN_TAB_MAP, nt as parseStreamParamsFormPatch, ot as runtimeStatePolicyFor, p as STREAM_PROFILE_META, t as ALL_CAPABILITY_DEFINITIONS, u as DeviceStatusSchema, wt as DeviceFeature, yt as errMsg, z as enumerateSchemaFields } from "../../dist-XjWZZYr9.mjs";
2
- import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-C8FeTH36.mjs";
1
+ import { A as buildStreamParamsConfigSchema, At as DeviceFeature, Et as BaseAddon, Ft as WELL_KNOWN_TAB_MAP, H as enumerateItemArrayFields, L as deviceManagerCapability, Mt as DeviceType, Qt as EventCategory, R as deviceStateCapability, Tt as errMsg, U as enumerateSchemaFields, Wt as isDeviceConfigCap, Zt as sleep, _ as STREAM_PROFILE_META, a as CAP_NAMES_WITH_STATUS, ct as parseStreamParamsFormPatch, d as DeviceStatusSchema, ft as runtimeStatePolicyFor, jt as DeviceRole, ot as normalizeUnit, t as ALL_CAPABILITY_DEFINITIONS, z as deviceStatusCapability } from "../../dist-CVuVKA-O.mjs";
2
+ import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-DnMYSIEr.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
@@ -1,78 +1,15 @@
1
- /**
2
- * Pure trigger logic for the virtual-doorbell builtin — edge detection over
3
- * runtime-state slices with per-camera debounce. Extracted from the addon
4
- * class so the behaviour is unit-testable without instantiating the addon or
5
- * mocking the event bus.
6
- *
7
- * REACTION MODEL (simplified — operator picks a source, the system reacts
8
- * with a sensible default): a source device rings a camera's doorbell when a
9
- * known binary / switch cap on it RISES to its active state (false→true) — a
10
- * contact opening, a switch turning on, an alarm sensor firing. There is no
11
- * per-source trigger configuration today; the shape stays extensible for a
12
- * future custom-trigger override (see `doorbell-settings.ts`).
13
- */
14
- /**
15
- * Known binary / switch source caps → the boolean slice field whose
16
- * false→true rise rings the doorbell. Every entry is "ring on active".
17
- * Sensors whose "active" reading is not a plain boolean (presence's string
18
- * state, connectivity's connected flag) are deliberately excluded — a
19
- * reconnect is not a doorbell press.
20
- */
21
- export declare const SOURCE_CAP_ACTIVE_FIELD: Readonly<Record<string, string>>;
22
- /**
23
- * The same caps → the slice field carrying the ms-epoch timestamp of the
24
- * last transition. Every source cap MUST appear here (guarded by a spec):
25
- * without a transition timestamp the engine cannot tell a genuine press
26
- * from a boot-time hydration when the FIRST slice it ever sees is already
27
- * active, and errs towards silence — swallowing the press.
28
- *
29
- * These timestamps are UPSTREAM ones, not ingest ones: the Home Assistant
30
- * provider derives them from `state.last_changed`, so they survive our own
31
- * restarts and correctly read as "hours ago" for a state that has been
32
- * active for hours. `motion` names its rise timestamp `lastDetectedAt`.
33
- */
34
- export declare const SOURCE_CAP_CHANGED_AT_FIELD: Readonly<Record<string, string>>;
35
- /** Cap names whose presence in a device's bindings qualify it as a source. */
36
- export declare const SOURCE_CAPS: readonly string[];
37
- /**
38
- * Device `type` values (from `DeviceType`) that can host a binary/switch
39
- * source cap. Used by the camera's `device-multiselect` picker as the
40
- * CLIENT-SIDE filter, alongside `SOURCE_CAPS`.
41
- *
42
- * Why types and not caps alone: the shared picker filters
43
- * `deviceManager.listAll` rows client-side, and those rows carry only the
44
- * device's advertised `features` — NOT its registered cap list. On the live
45
- * cluster binary sensors and switches advertise EMPTY features (features
46
- * mirror only a handful of caps like `motion-trigger`), so a caps-only
47
- * filter matched against `features` would list nothing (the very bug this
48
- * replaced, which relied on the now-empty `getAllBindings`). Matching by
49
- * `type` is the reliable client-side signal; the union with `SOURCE_CAPS`
50
- * still captures any device that DOES advertise a source-cap feature.
51
- * `sensor` covers contact/motion/flood/gas/smoke/CO/vibration/tamper,
52
- * `switch` covers switches, `control` covers generic binary actuators.
53
- */
54
- export declare const SOURCE_DEVICE_TYPES: readonly string[];
55
- /** True when a cap is a recognised binary/switch doorbell source. */
56
- export declare function isSourceCap(capName: string): boolean;
1
+ import { DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, isSourceCap, SOURCE_CAP_ACTIVE_FIELD, SOURCE_CAP_CHANGED_AT_FIELD, SOURCE_CAPS, SOURCE_DEVICE_TYPES, SensorEdgeIgnoreReason } from '@camstack/types';
2
+ export { DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, isSourceCap, SOURCE_CAP_ACTIVE_FIELD, SOURCE_CAP_CHANGED_AT_FIELD, SOURCE_CAPS, SOURCE_DEVICE_TYPES, };
57
3
  /**
58
4
  * Why a slice produced no ring. Every value names a DROPPED evaluation, so
59
5
  * the addon can log the ones that may have cost a real press instead of
60
6
  * returning an empty array that reads as "nothing happened".
7
+ *
8
+ * It is {@link SensorEdgeIgnoreReason} plus ONE value the pure evaluator
9
+ * cannot know: `no-assignment` is a real rise that no camera is wired to, and
10
+ * that is a fact about the doorbell's wiring, not about the sensor.
61
11
  */
62
- export type DoorbellIgnoreReason =
63
- /** Not a recognised binary/switch source cap. */
64
- 'unknown-cap'
65
- /** Recognised cap, but its active field is missing or not a boolean. */
66
- | 'non-boolean-value'
67
- /** First sighting, INACTIVE — nothing can have been lost. */
68
- | 'baseline-seeded-inactive'
69
- /** First sighting, ALREADY ACTIVE, and we could not prove it is a fresh
70
- * transition. A genuine press MAY have been swallowed here. */
71
- | 'baseline-seeded-stale-active'
72
- /** Re-emission carrying the same binary value. */
73
- | 'no-change'
74
- /** The falling edge — switch-off / contact-close never rings. */
75
- | 'falling-edge'
12
+ export type DoorbellIgnoreReason = SensorEdgeIgnoreReason
76
13
  /** A real rise, but no camera is wired to this source. */
77
14
  | 'no-assignment';
78
15
  /**
@@ -87,12 +24,6 @@ export interface DoorbellTriggerResult {
87
24
  /** Set when the slice carried no ring at all; null once a rise was matched. */
88
25
  readonly ignored: DoorbellIgnoreReason | null;
89
26
  }
90
- /**
91
- * How recent a source's own transition timestamp must be for a FIRST
92
- * sighting that is already active to count as a genuine press rather than a
93
- * hydration of long-standing state.
94
- */
95
- export declare const DEFAULT_FIRST_SIGHTING_FRESHNESS_MS = 30000;
96
27
  /**
97
28
  * One camera's virtual-doorbell wiring: a source device that rings it. A
98
29
  * camera with several sources produces several assignments (one per source).
@@ -157,10 +88,5 @@ export declare class DoorbellTriggerEngine {
157
88
  * can ring; re-emissions and the falling edge never do.
158
89
  */
159
90
  onStateSlice(deviceId: number, capName: string, slice: Record<string, unknown>): DoorbellTriggerResult;
160
- /**
161
- * Can this slice PROVE its active state is a transition we would have
162
- * witnessed had we been listening — i.e. recent, and after we started?
163
- */
164
- private roseAfterWeStartedWatching;
165
91
  private matchAndDebounce;
166
92
  }
@@ -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-jRSrzoXr.js");
6
+ const require_dist = require("../../dist-CQs1b7uh.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
@@ -17,95 +17,22 @@ const require_dist = require("../../dist-jRSrzoXr.js");
17
17
  * contact opening, a switch turning on, an alarm sensor firing. There is no
18
18
  * per-source trigger configuration today; the shape stays extensible for a
19
19
  * future custom-trigger override (see `doorbell-settings.ts`).
20
- */
21
- /**
22
- * Known binary / switch source caps → the boolean slice field whose
23
- * false→true rise rings the doorbell. Every entry is "ring on active".
24
- * Sensors whose "active" reading is not a plain boolean (presence's string
25
- * state, connectivity's connected flag) are deliberately excluded — a
26
- * reconnect is not a doorbell press.
27
- */
28
- var SOURCE_CAP_ACTIVE_FIELD = {
29
- contact: "entryOpen",
30
- binary: "on",
31
- switch: "on",
32
- motion: "detected",
33
- flood: "flooded",
34
- gas: "detected",
35
- smoke: "detected",
36
- "carbon-monoxide": "detected",
37
- vibration: "detected",
38
- tamper: "tampered"
39
- };
40
- /**
41
- * The same caps → the slice field carrying the ms-epoch timestamp of the
42
- * last transition. Every source cap MUST appear here (guarded by a spec):
43
- * without a transition timestamp the engine cannot tell a genuine press
44
- * from a boot-time hydration when the FIRST slice it ever sees is already
45
- * active, and errs towards silence — swallowing the press.
46
20
  *
47
- * These timestamps are UPSTREAM ones, not ingest ones: the Home Assistant
48
- * provider derives them from `state.last_changed`, so they survive our own
49
- * restarts and correctly read as "hours ago" for a state that has been
50
- * active for hours. `motion` names its rise timestamp `lastDetectedAt`.
51
- */
52
- var SOURCE_CAP_CHANGED_AT_FIELD = {
53
- contact: "lastChangedAt",
54
- binary: "lastChangedAt",
55
- switch: "lastChangedAt",
56
- motion: "lastDetectedAt",
57
- flood: "lastChangedAt",
58
- gas: "lastChangedAt",
59
- smoke: "lastChangedAt",
60
- "carbon-monoxide": "lastChangedAt",
61
- vibration: "lastChangedAt",
62
- tamper: "lastChangedAt"
63
- };
64
- /** Cap names whose presence in a device's bindings qualify it as a source. */
65
- var SOURCE_CAPS = Object.keys(SOURCE_CAP_ACTIVE_FIELD);
66
- /**
67
- * Device `type` values (from `DeviceType`) that can host a binary/switch
68
- * source cap. Used by the camera's `device-multiselect` picker as the
69
- * CLIENT-SIDE filter, alongside `SOURCE_CAPS`.
21
+ * ## Dove vive il fronte, dal 2026-08-27
70
22
  *
71
- * Why types and not caps alone: the shared picker filters
72
- * `deviceManager.listAll` rows client-side, and those rows carry only the
73
- * device's advertised `features` NOT its registered cap list. On the live
74
- * cluster binary sensors and switches advertise EMPTY features (features
75
- * mirror only a handful of caps like `motion-trigger`), so a caps-only
76
- * filter matched against `features` would list nothing (the very bug this
77
- * replaced, which relied on the now-empty `getAllBindings`). Matching by
78
- * `type` is the reliable client-side signal; the union with `SOURCE_CAPS`
79
- * still captures any device that DOES advertise a source-cap feature.
80
- * `sensor` covers contact/motion/flood/gas/smoke/CO/vibration/tamper,
81
- * `switch` covers switches, `control` covers generic binary actuators.
23
+ * `SOURCE_CAP_ACTIVE_FIELD`, `SOURCE_CAP_CHANGED_AT_FIELD`, i due predicati di
24
+ * slice e il predicato di fronte sono stati SPOSTATI in
25
+ * `@camstack/types` (`catalogs/sensor-active-state.ts`), perché il recorder ne
26
+ * ha bisogno per il trigger `RecordingTriggers.sensorDeviceIds`. Una seconda
27
+ * copia sarebbe divergita alla prima cap aggiunta, e il sintomo — "il sensore
28
+ * fa suonare il campanello ma non registra" è precisamente D62.
29
+ *
30
+ * Questo file ri-esporta i nomi pubblici (i suoi consumatori non cambiano
31
+ * import) e resta l'unico proprietario di ciò che è del CAMPANELLO e di
32
+ * nessun altro: le assegnazioni camera↔sorgente, il debounce per camera e il
33
+ * vocabolario `DoorbellIgnoreReason` che ha un valore in più
34
+ * (`no-assignment`) che il valutatore puro non può conoscere.
82
35
  */
83
- var SOURCE_DEVICE_TYPES = [
84
- "sensor",
85
- "switch",
86
- "control"
87
- ];
88
- /** True when a cap is a recognised binary/switch doorbell source. */
89
- function isSourceCap(capName) {
90
- return Object.prototype.hasOwnProperty.call(SOURCE_CAP_ACTIVE_FIELD, capName);
91
- }
92
- /** Extract the "active" boolean a source cap's slice carries, or null when
93
- * the cap is unknown or the field is missing / non-boolean. */
94
- function sliceActiveValue(capName, slice) {
95
- const field = SOURCE_CAP_ACTIVE_FIELD[capName];
96
- if (field === void 0) return null;
97
- const raw = slice[field];
98
- return typeof raw === "boolean" ? raw : null;
99
- }
100
- /** Ms-epoch transition timestamp a source cap's slice carries, or null when
101
- * it is absent, non-numeric or the zero "never observed" sentinel. */
102
- function sliceChangedAt(capName, slice) {
103
- const field = SOURCE_CAP_CHANGED_AT_FIELD[capName];
104
- if (field === void 0) return null;
105
- const raw = slice[field];
106
- if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return null;
107
- return raw;
108
- }
109
36
  function ignoredResult(reason) {
110
37
  return {
111
38
  fired: [],
@@ -173,29 +100,22 @@ var DoorbellTriggerEngine = class {
173
100
  * can ring; re-emissions and the falling edge never do.
174
101
  */
175
102
  onStateSlice(deviceId, capName, slice) {
176
- const value = sliceActiveValue(capName, slice);
177
- if (value === null) return ignoredResult(isSourceCap(capName) ? "non-boolean-value" : "unknown-cap");
178
103
  const key = `${deviceId}:${capName}`;
179
- const prior = this.lastValues.get(key);
180
- this.lastValues.set(key, value);
181
- if (prior === void 0) {
182
- if (!value) return ignoredResult("baseline-seeded-inactive");
183
- if (!this.roseAfterWeStartedWatching(capName, slice)) return ignoredResult("baseline-seeded-stale-active");
184
- return this.matchAndDebounce(deviceId);
104
+ const verdict = require_dist.evaluateSensorEdge({
105
+ capName,
106
+ slice,
107
+ prior: this.lastValues.get(key),
108
+ startedAtMs: this.startedAt,
109
+ nowMs: this.now(),
110
+ firstSightingFreshnessMs: this.firstSightingFreshnessMs
111
+ });
112
+ if (verdict.edge === "none") {
113
+ if (verdict.value !== null) this.lastValues.set(key, verdict.value);
114
+ return ignoredResult(verdict.reason);
185
115
  }
186
- if (prior === value) return ignoredResult("no-change");
187
- if (!value) return ignoredResult("falling-edge");
116
+ this.lastValues.set(key, true);
188
117
  return this.matchAndDebounce(deviceId);
189
118
  }
190
- /**
191
- * Can this slice PROVE its active state is a transition we would have
192
- * witnessed had we been listening — i.e. recent, and after we started?
193
- */
194
- roseAfterWeStartedWatching(capName, slice) {
195
- const changedAt = sliceChangedAt(capName, slice);
196
- if (changedAt === null) return false;
197
- return changedAt >= Math.max(this.startedAt, this.now() - this.firstSightingFreshnessMs);
198
- }
199
119
  matchAndDebounce(sourceDeviceId) {
200
120
  const now = this.now();
201
121
  const fired = [];
@@ -540,7 +460,7 @@ var VirtualDoorbellAddon = class extends require_dist.BaseAddon {
540
460
  }];
541
461
  }
542
462
  async handleStateChanged(data) {
543
- if (!isSourceCap(data.capName)) return;
463
+ if (!require_dist.isSourceCap(data.capName)) return;
544
464
  await this.ensureAssignments();
545
465
  const result = this.engine.onStateSlice(data.deviceId, data.capName, data.slice);
546
466
  this.logSuppressions(data, result);
@@ -922,8 +842,8 @@ var VirtualDoorbellAddon = class extends require_dist.BaseAddon {
922
842
  label: "Trigger devices",
923
843
  description: "Any of these becoming active rings this camera. Binary sensors ring when they go active; switches ring when they turn on.",
924
844
  deviceFilter: {
925
- caps: SOURCE_CAPS,
926
- types: SOURCE_DEVICE_TYPES,
845
+ caps: require_dist.SOURCE_CAPS,
846
+ types: require_dist.SOURCE_DEVICE_TYPES,
927
847
  excludeDeviceId: deviceId
928
848
  },
929
849
  value: sources.map((s) => String(s.deviceId))
@@ -1,4 +1,4 @@
1
- import { Et as DeviceType, G as isSameAddonId, I as doorbellCapability, Kt as EventCategory, Nt as createEvent, bt as BaseAddon, w as bareAddonId, yt as errMsg } from "../../dist-XjWZZYr9.mjs";
1
+ import { B as doorbellCapability, Et as BaseAddon, Mt as DeviceType, O as bareAddonId, Qt as EventCategory, Tt as errMsg, W as evaluateSensorEdge, X as isSameAddonId, Z as isSourceCap, g as SOURCE_DEVICE_TYPES, h as SOURCE_CAPS, zt as createEvent } from "../../dist-CVuVKA-O.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
@@ -12,95 +12,22 @@ import { Et as DeviceType, G as isSameAddonId, I as doorbellCapability, Kt as Ev
12
12
  * contact opening, a switch turning on, an alarm sensor firing. There is no
13
13
  * per-source trigger configuration today; the shape stays extensible for a
14
14
  * future custom-trigger override (see `doorbell-settings.ts`).
15
- */
16
- /**
17
- * Known binary / switch source caps → the boolean slice field whose
18
- * false→true rise rings the doorbell. Every entry is "ring on active".
19
- * Sensors whose "active" reading is not a plain boolean (presence's string
20
- * state, connectivity's connected flag) are deliberately excluded — a
21
- * reconnect is not a doorbell press.
22
- */
23
- var SOURCE_CAP_ACTIVE_FIELD = {
24
- contact: "entryOpen",
25
- binary: "on",
26
- switch: "on",
27
- motion: "detected",
28
- flood: "flooded",
29
- gas: "detected",
30
- smoke: "detected",
31
- "carbon-monoxide": "detected",
32
- vibration: "detected",
33
- tamper: "tampered"
34
- };
35
- /**
36
- * The same caps → the slice field carrying the ms-epoch timestamp of the
37
- * last transition. Every source cap MUST appear here (guarded by a spec):
38
- * without a transition timestamp the engine cannot tell a genuine press
39
- * from a boot-time hydration when the FIRST slice it ever sees is already
40
- * active, and errs towards silence — swallowing the press.
41
15
  *
42
- * These timestamps are UPSTREAM ones, not ingest ones: the Home Assistant
43
- * provider derives them from `state.last_changed`, so they survive our own
44
- * restarts and correctly read as "hours ago" for a state that has been
45
- * active for hours. `motion` names its rise timestamp `lastDetectedAt`.
46
- */
47
- var SOURCE_CAP_CHANGED_AT_FIELD = {
48
- contact: "lastChangedAt",
49
- binary: "lastChangedAt",
50
- switch: "lastChangedAt",
51
- motion: "lastDetectedAt",
52
- flood: "lastChangedAt",
53
- gas: "lastChangedAt",
54
- smoke: "lastChangedAt",
55
- "carbon-monoxide": "lastChangedAt",
56
- vibration: "lastChangedAt",
57
- tamper: "lastChangedAt"
58
- };
59
- /** Cap names whose presence in a device's bindings qualify it as a source. */
60
- var SOURCE_CAPS = Object.keys(SOURCE_CAP_ACTIVE_FIELD);
61
- /**
62
- * Device `type` values (from `DeviceType`) that can host a binary/switch
63
- * source cap. Used by the camera's `device-multiselect` picker as the
64
- * CLIENT-SIDE filter, alongside `SOURCE_CAPS`.
16
+ * ## Dove vive il fronte, dal 2026-08-27
65
17
  *
66
- * Why types and not caps alone: the shared picker filters
67
- * `deviceManager.listAll` rows client-side, and those rows carry only the
68
- * device's advertised `features` NOT its registered cap list. On the live
69
- * cluster binary sensors and switches advertise EMPTY features (features
70
- * mirror only a handful of caps like `motion-trigger`), so a caps-only
71
- * filter matched against `features` would list nothing (the very bug this
72
- * replaced, which relied on the now-empty `getAllBindings`). Matching by
73
- * `type` is the reliable client-side signal; the union with `SOURCE_CAPS`
74
- * still captures any device that DOES advertise a source-cap feature.
75
- * `sensor` covers contact/motion/flood/gas/smoke/CO/vibration/tamper,
76
- * `switch` covers switches, `control` covers generic binary actuators.
18
+ * `SOURCE_CAP_ACTIVE_FIELD`, `SOURCE_CAP_CHANGED_AT_FIELD`, i due predicati di
19
+ * slice e il predicato di fronte sono stati SPOSTATI in
20
+ * `@camstack/types` (`catalogs/sensor-active-state.ts`), perché il recorder ne
21
+ * ha bisogno per il trigger `RecordingTriggers.sensorDeviceIds`. Una seconda
22
+ * copia sarebbe divergita alla prima cap aggiunta, e il sintomo — "il sensore
23
+ * fa suonare il campanello ma non registra" è precisamente D62.
24
+ *
25
+ * Questo file ri-esporta i nomi pubblici (i suoi consumatori non cambiano
26
+ * import) e resta l'unico proprietario di ciò che è del CAMPANELLO e di
27
+ * nessun altro: le assegnazioni camera↔sorgente, il debounce per camera e il
28
+ * vocabolario `DoorbellIgnoreReason` che ha un valore in più
29
+ * (`no-assignment`) che il valutatore puro non può conoscere.
77
30
  */
78
- var SOURCE_DEVICE_TYPES = [
79
- "sensor",
80
- "switch",
81
- "control"
82
- ];
83
- /** True when a cap is a recognised binary/switch doorbell source. */
84
- function isSourceCap(capName) {
85
- return Object.prototype.hasOwnProperty.call(SOURCE_CAP_ACTIVE_FIELD, capName);
86
- }
87
- /** Extract the "active" boolean a source cap's slice carries, or null when
88
- * the cap is unknown or the field is missing / non-boolean. */
89
- function sliceActiveValue(capName, slice) {
90
- const field = SOURCE_CAP_ACTIVE_FIELD[capName];
91
- if (field === void 0) return null;
92
- const raw = slice[field];
93
- return typeof raw === "boolean" ? raw : null;
94
- }
95
- /** Ms-epoch transition timestamp a source cap's slice carries, or null when
96
- * it is absent, non-numeric or the zero "never observed" sentinel. */
97
- function sliceChangedAt(capName, slice) {
98
- const field = SOURCE_CAP_CHANGED_AT_FIELD[capName];
99
- if (field === void 0) return null;
100
- const raw = slice[field];
101
- if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return null;
102
- return raw;
103
- }
104
31
  function ignoredResult(reason) {
105
32
  return {
106
33
  fired: [],
@@ -168,29 +95,22 @@ var DoorbellTriggerEngine = class {
168
95
  * can ring; re-emissions and the falling edge never do.
169
96
  */
170
97
  onStateSlice(deviceId, capName, slice) {
171
- const value = sliceActiveValue(capName, slice);
172
- if (value === null) return ignoredResult(isSourceCap(capName) ? "non-boolean-value" : "unknown-cap");
173
98
  const key = `${deviceId}:${capName}`;
174
- const prior = this.lastValues.get(key);
175
- this.lastValues.set(key, value);
176
- if (prior === void 0) {
177
- if (!value) return ignoredResult("baseline-seeded-inactive");
178
- if (!this.roseAfterWeStartedWatching(capName, slice)) return ignoredResult("baseline-seeded-stale-active");
179
- return this.matchAndDebounce(deviceId);
99
+ const verdict = evaluateSensorEdge({
100
+ capName,
101
+ slice,
102
+ prior: this.lastValues.get(key),
103
+ startedAtMs: this.startedAt,
104
+ nowMs: this.now(),
105
+ firstSightingFreshnessMs: this.firstSightingFreshnessMs
106
+ });
107
+ if (verdict.edge === "none") {
108
+ if (verdict.value !== null) this.lastValues.set(key, verdict.value);
109
+ return ignoredResult(verdict.reason);
180
110
  }
181
- if (prior === value) return ignoredResult("no-change");
182
- if (!value) return ignoredResult("falling-edge");
111
+ this.lastValues.set(key, true);
183
112
  return this.matchAndDebounce(deviceId);
184
113
  }
185
- /**
186
- * Can this slice PROVE its active state is a transition we would have
187
- * witnessed had we been listening — i.e. recent, and after we started?
188
- */
189
- roseAfterWeStartedWatching(capName, slice) {
190
- const changedAt = sliceChangedAt(capName, slice);
191
- if (changedAt === null) return false;
192
- return changedAt >= Math.max(this.startedAt, this.now() - this.firstSightingFreshnessMs);
193
- }
194
114
  matchAndDebounce(sourceDeviceId) {
195
115
  const now = this.now();
196
116
  const fired = [];
@@ -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-jRSrzoXr.js");
6
+ const require_dist = require("../../dist-CQs1b7uh.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, bt as BaseAddon } from "../../dist-XjWZZYr9.mjs";
1
+ import { Et as BaseAddon, nt as logDestinationCapability } from "../../dist-CVuVKA-O.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-jRSrzoXr.js");
3
+ const require_dist = require("../../dist-CQs1b7uh.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 { Kt as EventCategory, Nt as createEvent, bt as BaseAddon, yt as errMsg } from "../../dist-XjWZZYr9.mjs";
1
+ import { Et as BaseAddon, Qt as EventCategory, Tt as errMsg, zt as createEvent } from "../../dist-CVuVKA-O.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";