@camstack/system 1.2.92 → 1.2.93

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 (51) 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 +1 -1
  14. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  15. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  16. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  17. package/dist/builtins/hub-forwarder/index.js +1 -1
  18. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  19. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  20. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  21. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  22. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  23. package/dist/builtins/local-network/local-network.addon.js +1 -1
  24. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  25. package/dist/builtins/loki-logging/index.js +1 -1
  26. package/dist/builtins/loki-logging/index.mjs +1 -1
  27. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  28. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  29. package/dist/builtins/platform-probe/index.js +1 -1
  30. package/dist/builtins/platform-probe/index.mjs +1 -1
  31. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  32. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  33. package/dist/builtins/snapshot/index.js +27 -6
  34. package/dist/builtins/snapshot/index.mjs +27 -6
  35. package/dist/builtins/snapshot/snapshot-courtesy.d.ts +12 -2
  36. package/dist/builtins/snapshot/snapshot.addon.d.ts +11 -0
  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 +1 -1
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  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-BH2tZ9ZN.js → dist-BMus2E5R.js} +99 -2
  48. package/dist/{dist-DXDvrBi0.mjs → dist-F1XDQDE1.mjs} +94 -3
  49. package/dist/index.js +1 -1
  50. package/dist/index.mjs +1 -1
  51. 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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { Ut as EventCategory, _t as BaseAddon, gt as errMsg, v as addonPagesCapability } from "../../dist-DXDvrBi0.mjs";
1
+ import { Wt as EventCategory, _t as errMsg, v as addonPagesCapability, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { Ut as EventCategory, _t as BaseAddon, b as addonWidgetsCapability, gt as errMsg } from "../../dist-DXDvrBi0.mjs";
1
+ import { Wt as EventCategory, _t as errMsg, b as addonWidgetsCapability, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { At as createEvent, Ut as EventCategory, _t as BaseAddon, gt as errMsg, n as AlertSchema, x as alertsCapability } from "../../dist-DXDvrBi0.mjs";
1
+ import { Wt as EventCategory, _t as errMsg, jt as createEvent, n as AlertSchema, vt as BaseAddon, x as alertsCapability } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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, Ut as EventCategory, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
1
+ import { C as backupCapability, Wt as EventCategory, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
1
+ import { Y as logDestinationCapability, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
3
+ const require_dist = require("../../dist-BMus2E5R.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 coreBlockIdFromAddonId, E as coreBlockAddonId, O as coreBlocksCapability, _t as BaseAddon, c as CoreBlockSchema, gt as errMsg, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX } from "../../dist-DXDvrBi0.mjs";
1
+ import { D as coreBlockIdFromAddonId, E as coreBlockAddonId, O as coreBlocksCapability, _t as errMsg, c as CoreBlockSchema, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let _camstack_types_node = require("@camstack/types/node");
9
9
  //#region src/builtins/device-manager/adoption-job-engine.ts
@@ -1,4 +1,4 @@
1
- import { Ct as DeviceType, Et as WELL_KNOWN_TAB_MAP, Ft as isDeviceConfigCap, Ht as sleep, I as enumerateItemArrayFields, L as enumerateSchemaFields, M as deviceStateCapability, N as deviceStatusCapability, Q as normalizeUnit, St as DeviceRole, T as buildStreamParamsConfigSchema, Ut as EventCategory, _t as BaseAddon, a as CAP_NAMES_WITH_STATUS, et as parseStreamParamsFormPatch, gt as errMsg, j as deviceManagerCapability, p as STREAM_PROFILE_META, rt as runtimeStatePolicyFor, t as ALL_CAPABILITY_DEFINITIONS, u as DeviceStatusSchema, xt as DeviceFeature } from "../../dist-DXDvrBi0.mjs";
1
+ import { $ as normalizeUnit, Ct as DeviceRole, Dt as WELL_KNOWN_TAB_MAP, It as isDeviceConfigCap, L as enumerateItemArrayFields, M as deviceManagerCapability, N as deviceStateCapability, P as deviceStatusCapability, R as enumerateSchemaFields, St as DeviceFeature, T as buildStreamParamsConfigSchema, Ut as sleep, Wt as EventCategory, _t as errMsg, a as CAP_NAMES_WITH_STATUS, it as runtimeStatePolicyFor, p as STREAM_PROFILE_META, t as ALL_CAPABILITY_DEFINITIONS, tt as parseStreamParamsFormPatch, u as DeviceStatusSchema, vt as BaseAddon, wt as DeviceType } from "../../dist-F1XDQDE1.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { canonicalDeviceFingerprint } from "@camstack/types/node";
4
4
  //#region src/builtins/device-manager/adoption-job-engine.ts
@@ -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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { At as createEvent, Ct as DeviceType, P as doorbellCapability, U as isSameAddonId, Ut as EventCategory, _t as BaseAddon, gt as errMsg, w as bareAddonId } from "../../dist-DXDvrBi0.mjs";
1
+ import { F as doorbellCapability, W as isSameAddonId, Wt as EventCategory, _t as errMsg, jt as createEvent, vt as BaseAddon, w as bareAddonId, wt as DeviceType } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
1
+ import { Y as logDestinationCapability, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
3
+ const require_dist = require("../../dist-BMus2E5R.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 { At as createEvent, Ut as EventCategory, _t as BaseAddon, gt as errMsg } from "../../dist-DXDvrBi0.mjs";
1
+ import { Wt as EventCategory, _t as errMsg, jt as createEvent, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  node_crypto = require_chunk.__toESM(node_crypto);
9
9
  let crypto$1 = require("crypto");
@@ -1,5 +1,5 @@
1
1
  import { i as __require, o as __toESM, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
2
- import { S as authProviderCapability, _ as UserRecordSchema, _t as BaseAddon, m as ScopedTokenSchema, pt as userManagementCapability, r as ApiKeyRecordSchema } from "../../dist-DXDvrBi0.mjs";
2
+ import { S as authProviderCapability, _ as UserRecordSchema, m as ScopedTokenSchema, mt as userManagementCapability, r as ApiKeyRecordSchema, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
3
+ const require_dist = require("../../dist-BMus2E5R.js");
4
4
  let node_os = require("node:os");
5
5
  node_os = require_chunk.__toESM(node_os);
6
6
  //#region src/builtins/local-network/local-network.addon.ts
@@ -1,4 +1,4 @@
1
- import { Ut as EventCategory, _t as BaseAddon, q as localNetworkCapability } from "../../dist-DXDvrBi0.mjs";
1
+ import { J as localNetworkCapability, Wt as EventCategory, vt as BaseAddon } from "../../dist-F1XDQDE1.mjs";
2
2
  import * as os from "node:os";
3
3
  //#region src/builtins/local-network/local-network.addon.ts
4
4
  /**
@@ -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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
1
+ import { Y as logDestinationCapability, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { At as createEvent, Ut as EventCategory, Z as metricsProviderCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
1
+ import { Q as metricsProviderCapability, Wt as EventCategory, jt as createEvent, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { F as enumerateInferenceDevices, Mt as emitReadiness, Ut as EventCategory, _t as BaseAddon, gt as errMsg, ot as scoreRuntimes, tt as platformProbeCapability } from "../../dist-DXDvrBi0.mjs";
2
+ import { I as enumerateInferenceDevices, Nt as emitReadiness, Wt as EventCategory, _t as errMsg, nt as platformProbeCapability, st as scoreRuntimes, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { Ut as EventCategory, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
1
+ import { Wt as EventCategory, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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");
@@ -299,6 +299,7 @@ function courtesyLabel(reason) {
299
299
  case "disabled": return "Disabled";
300
300
  case "offline": return "Offline";
301
301
  case "sleeping": return "Sleeping";
302
+ case "unreachable": return "Unreachable";
302
303
  }
303
304
  }
304
305
  /**
@@ -310,6 +311,7 @@ function courtesyBackground(reason) {
310
311
  case "disabled": return "#2b2b31";
311
312
  case "offline": return "#3a2b2b";
312
313
  case "sleeping": return "#232b3a";
314
+ case "unreachable": return "#3a2b2b";
313
315
  }
314
316
  }
315
317
  /** XML escaping for text placed inside an SVG `<text>` node. */
@@ -1355,16 +1357,18 @@ var SnapshotAddon = class SnapshotAddon extends require_dist.BaseAddon {
1355
1357
  });
1356
1358
  return hit ? hit.data : null;
1357
1359
  }
1358
- if (!force && isBatteryDevice && await this.isDeviceSleeping(deviceId)) {
1359
- log.debug("snapshot: sleeping battery cam and no force serving cache, not capturing", {
1360
+ const presence = isBatteryDevice ? await this.readBatteryPresence(deviceId) : "awake";
1361
+ if (!force && presence !== "awake") {
1362
+ log.debug("snapshot: battery cam not awake and no force — serving cache, not capturing", {
1360
1363
  tags: { deviceId },
1361
1364
  meta: {
1365
+ presence,
1362
1366
  hasCache: hit !== void 0,
1363
1367
  ageMs: hit ? now - hit.ts : null
1364
1368
  }
1365
1369
  });
1366
1370
  if (hit) return hit.data;
1367
- return await this.courtesyImage(deviceId, "sleeping", deviceName);
1371
+ return await this.courtesyImage(deviceId, presence, deviceName);
1368
1372
  }
1369
1373
  const flightKey = `${deviceId}:${effectiveStreamId ?? "auto"}`;
1370
1374
  const flight = this.captureFlight.run(flightKey, () => this.captureFresh({
@@ -1727,18 +1731,35 @@ var SnapshotAddon = class SnapshotAddon extends require_dist.BaseAddon {
1727
1731
  * cache hit returns before we get here.
1728
1732
  */
1729
1733
  async isDeviceSleeping(deviceId) {
1734
+ return await this.readBatteryPresence(deviceId) !== "awake";
1735
+ }
1736
+ /**
1737
+ * The device's three-valued battery presence (D173) — `awake`, `sleeping`,
1738
+ * or `unreachable`. Same mirror read as the sleep gate, one derivation
1739
+ * (`deriveBatteryPresence`) so this layer cannot disagree with the badge or
1740
+ * the stream error about what a camera is doing.
1741
+ *
1742
+ * A failed read answers `awake`: unknown must never become a fault badge,
1743
+ * and "assume awake" is the pre-existing, deliberately conservative failure
1744
+ * direction of the gate this replaces.
1745
+ */
1746
+ async readBatteryPresence(deviceId) {
1730
1747
  try {
1731
1748
  const handle = (await this.ctx.fetchDevice(deviceId)).state.battery;
1732
1749
  await handle.refresh();
1733
1750
  const raw = handle.value;
1734
1751
  const parsed = require_dist.BatteryStatusSchema.safeParse(raw);
1735
- return parsed.success && parsed.data.sleeping;
1752
+ if (!parsed.success) return "awake";
1753
+ return require_dist.deriveBatteryPresence({
1754
+ status: parsed.data,
1755
+ nowMs: Date.now()
1756
+ });
1736
1757
  } catch (err) {
1737
1758
  this.ctx.logger.warn("snapshot: battery mirror read failed — assuming awake", {
1738
1759
  tags: { deviceId },
1739
1760
  meta: { error: require_dist.errMsg(err) }
1740
1761
  });
1741
- return false;
1762
+ return "awake";
1742
1763
  }
1743
1764
  }
1744
1765
  /**
@@ -1,4 +1,4 @@
1
- import { Ct as DeviceType, It as nodePin, Ut as EventCategory, _t as BaseAddon, ct as snapshotCapability, ft as streamQualityLabel, gt as errMsg, i as BatteryStatusSchema, w as bareAddonId, xt as DeviceFeature } from "../../dist-DXDvrBi0.mjs";
1
+ import { Lt as nodePin, St as DeviceFeature, Wt as EventCategory, _t as errMsg, i as BatteryStatusSchema, j as deriveBatteryPresence, lt as snapshotCapability, pt as streamQualityLabel, vt as BaseAddon, w as bareAddonId, wt as DeviceType } from "../../dist-F1XDQDE1.mjs";
2
2
  import { z } from "zod";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { signExpiringUrl, verifyExpiringUrl } from "@camstack/types/node";
@@ -293,6 +293,7 @@ function courtesyLabel(reason) {
293
293
  case "disabled": return "Disabled";
294
294
  case "offline": return "Offline";
295
295
  case "sleeping": return "Sleeping";
296
+ case "unreachable": return "Unreachable";
296
297
  }
297
298
  }
298
299
  /**
@@ -304,6 +305,7 @@ function courtesyBackground(reason) {
304
305
  case "disabled": return "#2b2b31";
305
306
  case "offline": return "#3a2b2b";
306
307
  case "sleeping": return "#232b3a";
308
+ case "unreachable": return "#3a2b2b";
307
309
  }
308
310
  }
309
311
  /** XML escaping for text placed inside an SVG `<text>` node. */
@@ -1349,16 +1351,18 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
1349
1351
  });
1350
1352
  return hit ? hit.data : null;
1351
1353
  }
1352
- if (!force && isBatteryDevice && await this.isDeviceSleeping(deviceId)) {
1353
- log.debug("snapshot: sleeping battery cam and no force serving cache, not capturing", {
1354
+ const presence = isBatteryDevice ? await this.readBatteryPresence(deviceId) : "awake";
1355
+ if (!force && presence !== "awake") {
1356
+ log.debug("snapshot: battery cam not awake and no force — serving cache, not capturing", {
1354
1357
  tags: { deviceId },
1355
1358
  meta: {
1359
+ presence,
1356
1360
  hasCache: hit !== void 0,
1357
1361
  ageMs: hit ? now - hit.ts : null
1358
1362
  }
1359
1363
  });
1360
1364
  if (hit) return hit.data;
1361
- return await this.courtesyImage(deviceId, "sleeping", deviceName);
1365
+ return await this.courtesyImage(deviceId, presence, deviceName);
1362
1366
  }
1363
1367
  const flightKey = `${deviceId}:${effectiveStreamId ?? "auto"}`;
1364
1368
  const flight = this.captureFlight.run(flightKey, () => this.captureFresh({
@@ -1721,18 +1725,35 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
1721
1725
  * cache hit returns before we get here.
1722
1726
  */
1723
1727
  async isDeviceSleeping(deviceId) {
1728
+ return await this.readBatteryPresence(deviceId) !== "awake";
1729
+ }
1730
+ /**
1731
+ * The device's three-valued battery presence (D173) — `awake`, `sleeping`,
1732
+ * or `unreachable`. Same mirror read as the sleep gate, one derivation
1733
+ * (`deriveBatteryPresence`) so this layer cannot disagree with the badge or
1734
+ * the stream error about what a camera is doing.
1735
+ *
1736
+ * A failed read answers `awake`: unknown must never become a fault badge,
1737
+ * and "assume awake" is the pre-existing, deliberately conservative failure
1738
+ * direction of the gate this replaces.
1739
+ */
1740
+ async readBatteryPresence(deviceId) {
1724
1741
  try {
1725
1742
  const handle = (await this.ctx.fetchDevice(deviceId)).state.battery;
1726
1743
  await handle.refresh();
1727
1744
  const raw = handle.value;
1728
1745
  const parsed = BatteryStatusSchema.safeParse(raw);
1729
- return parsed.success && parsed.data.sleeping;
1746
+ if (!parsed.success) return "awake";
1747
+ return deriveBatteryPresence({
1748
+ status: parsed.data,
1749
+ nowMs: Date.now()
1750
+ });
1730
1751
  } catch (err) {
1731
1752
  this.ctx.logger.warn("snapshot: battery mirror read failed — assuming awake", {
1732
1753
  tags: { deviceId },
1733
1754
  meta: { error: errMsg(err) }
1734
1755
  });
1735
- return false;
1756
+ return "awake";
1736
1757
  }
1737
1758
  }
1738
1759
  /**
@@ -1,5 +1,15 @@
1
- /** Why a camera cannot produce a frame right now. */
2
- export type CourtesyReason = 'disabled' | 'offline' | 'sleeping';
1
+ /**
2
+ * Why a camera cannot produce a frame right now.
3
+ *
4
+ * `sleeping` and `unreachable` are deliberately two reasons and not one. A
5
+ * battery camera in low-power mode is WORKING — that tile must not read as a
6
+ * fault, which is D62's rule in the third state — while a battery camera
7
+ * nothing has been heard from for hours is a genuine fault the operator has to
8
+ * see (a flat battery, or a camera off the LAN). Painting the second as the
9
+ * first is how a dead camera stayed green for 30 hours. The two are separated
10
+ * by `deriveBatteryPresence`, never by a caller's own guess.
11
+ */
12
+ export type CourtesyReason = 'disabled' | 'offline' | 'sleeping' | 'unreachable';
3
13
  /** Default tile size when the caller asks for no particular width. */
4
14
  export declare const COURTESY_DEFAULT_WIDTH = 640;
5
15
  /** The word the frame carries. Deliberately the operator's vocabulary. */
@@ -374,6 +374,17 @@ export declare class SnapshotAddon extends BaseAddon<SnapshotAddonConfig> {
374
374
  * cache hit returns before we get here.
375
375
  */
376
376
  private isDeviceSleeping;
377
+ /**
378
+ * The device's three-valued battery presence (D173) — `awake`, `sleeping`,
379
+ * or `unreachable`. Same mirror read as the sleep gate, one derivation
380
+ * (`deriveBatteryPresence`) so this layer cannot disagree with the badge or
381
+ * the stream error about what a camera is doing.
382
+ *
383
+ * A failed read answers `awake`: unknown must never become a fault badge,
384
+ * and "assume awake" is the pre-existing, deliberately conservative failure
385
+ * direction of the gate this replaces.
386
+ */
387
+ private readBatteryPresence;
377
388
  /**
378
389
  * True when at least one of the device's brokers is actively
379
390
  * streaming (status === 'streaming'). Used by the battery-cam guard
@@ -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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { _t as BaseAddon, dt as storageProviderCapability, z as filesystemBrowseCapability } from "../../dist-DXDvrBi0.mjs";
1
+ import { B as filesystemBrowseCapability, ft as storageProviderCapability, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs = require("node:fs");
9
9
  let node_module = require("node:module");
@@ -1,4 +1,4 @@
1
- import { A as decodeVectorBase64, Dt as asJsonObject, Rt as parseJsonUnknown, _t as BaseAddon, f as RUNTIME_DEFAULTS, gt as errMsg, ht as vectorStoreCapability, k as dataStoreProviderCapability, mt as vectorDimFromBase64, w as bareAddonId } from "../../dist-DXDvrBi0.mjs";
1
+ import { A as decodeVectorBase64, Ot as asJsonObject, _t as errMsg, f as RUNTIME_DEFAULTS, gt as vectorStoreCapability, ht as vectorDimFromBase64, k as dataStoreProviderCapability, vt as BaseAddon, w as bareAddonId, zt as parseJsonUnknown } from "../../dist-F1XDQDE1.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { statSync } 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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { Lt as parseJsonObject, _t as BaseAddon, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, lt as storageCapability, st as settingsStoreCapability, ut as storageMigrationCapability } from "../../dist-DXDvrBi0.mjs";
1
+ import { Rt as parseJsonObject, ct as settingsStoreCapability, dt as storageMigrationCapability, g as StorageMigrationJobSchema, h as StorageLocationTypeSchema, ut as storageCapability, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { Pt as hydrateSchema, _t as BaseAddon, gt as errMsg } from "../../dist-DXDvrBi0.mjs";
1
+ import { Ft as hydrateSchema, _t as errMsg, vt as BaseAddon } from "../../dist-F1XDQDE1.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-BH2tZ9ZN.js");
6
+ const require_dist = require("../../dist-BMus2E5R.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 { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
1
+ import { Y as logDestinationCapability, vt as BaseAddon } from "../../dist-F1XDQDE1.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";
@@ -20825,6 +20825,25 @@ var BatteryStatusSchema = zod.z.object({
20825
20825
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
20826
20826
  lastUpdated: zod.z.number(),
20827
20827
  /**
20828
+ * Ms epoch of the last time the device PROVED it was reachable — a
20829
+ * completed firmware round-trip, an observed wake, or an inbound push
20830
+ * (firmware event, email). `0`/absent = never since this slice was born.
20831
+ *
20832
+ * This is the ONLY input that separates "asleep" from "gone", and it is
20833
+ * fed exclusively by PASSIVE signals: nothing may write it by reaching
20834
+ * for the radio, because a poll that confirms reachability is the same
20835
+ * poll that drains the battery. See {@link deriveBatteryPresence} — the
20836
+ * single derivation every consumer must use; no surface computes its own.
20837
+ *
20838
+ * It is deliberately NOT a clock in the
20839
+ * `scripts/check-runtime-state-durability.ts` sense: it is the
20840
+ * observation itself, and it is the only thing a 30-hour silence is
20841
+ * visible in. Writers quantise it (see `CONTACT_WRITE_QUANTUM_MS` in the
20842
+ * Reolink provider) so a value that means "recently" cannot cost a
20843
+ * SQLite commit per round-trip.
20844
+ */
20845
+ lastContactAt: zod.z.number().optional(),
20846
+ /**
20828
20847
  * True when the source is a BINARY low-battery indicator (HA
20829
20848
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
20830
20849
  * charge level — `percentage` is then a coarse stand-in (100 = normal,
@@ -27507,13 +27526,63 @@ var CamStreamDescriptorSchema = zod.z.object({
27507
27526
  * set of stream descriptors it can offer for the device, synchronously, so the
27508
27527
  * broker can reconcile its registry against the authoritative provider state.
27509
27528
  */
27529
+ /**
27530
+ * The catalog as a DURABLE fact rather than a live answer.
27531
+ *
27532
+ * A battery camera's descriptors are profile-stable — they change when the
27533
+ * operator rewrites an encoder profile, not minute to minute — but building
27534
+ * them costs a Baichuan login, which on a sleeping Argus IS a wake. So the
27535
+ * provider is allowed to build them exactly once per profile and must serve
27536
+ * every later pull from a cache.
27537
+ *
27538
+ * Holding that cache only in RAM is what turned a restart into an outage. The
27539
+ * runner comes back with the camera asleep, `buildStreamCatalogUncached`
27540
+ * correctly refuses to wake it, the pull answers `[]`, the broker has no
27541
+ * cam-stream entry to build a broker from, and `webrtcSession.handleOffer`
27542
+ * fails with a flat "No broker for stream" — for as long as the camera sleeps,
27543
+ * which on a battery cam is most of the day. The camera was fine. The stream
27544
+ * was unreachable because the process had forgotten what the camera offers.
27545
+ *
27546
+ * Declaring it here puts it in `device-runtime-state`, the kernel's canonical
27547
+ * declared collection, with the same `restored` durability `battery` uses for
27548
+ * the same reason: the last known value is the only value there is while the
27549
+ * device is asleep. The broker's brokers are therefore always DEFINABLE — it
27550
+ * is the DIAL that wakes a camera, never the catalog (D173).
27551
+ */
27552
+ var StreamCatalogStateSchema = zod.z.object({
27553
+ /** The descriptors as last built from a real camera response. Never a guess:
27554
+ * a failed or refused build writes NOTHING, so a restored catalog is always
27555
+ * one the camera itself once produced. */
27556
+ descriptors: zod.z.array(CamStreamDescriptorSchema),
27557
+ /** Ms epoch of the build that produced {@link descriptors}. Lets the wake
27558
+ * path decide whether the camera's own awake window is worth spending on a
27559
+ * re-read. */
27560
+ lastFetchedAt: zod.z.number()
27561
+ });
27510
27562
  var streamCatalogCapability = {
27511
27563
  name: "stream-catalog",
27512
27564
  scope: "device",
27513
27565
  deviceNative: true,
27514
27566
  mode: "singleton",
27515
27567
  deviceTypes: [DeviceType.Camera],
27516
- methods: { getCatalog: method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.array(CamStreamDescriptorSchema).readonly()) }
27568
+ methods: { getCatalog: method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.array(CamStreamDescriptorSchema).readonly()) },
27569
+ runtimeState: StreamCatalogStateSchema,
27570
+ /**
27571
+ * Runtime-state durability: **restored** — see the schema doc. A cold
27572
+ * catalog on a sleeping battery camera is not a slow first frame, it is a
27573
+ * camera that cannot be watched at all until it happens to wake.
27574
+ *
27575
+ * Churn is nil by construction: the slice is written only by a SUCCESSFUL
27576
+ * build, and a build only runs when there is no cached copy (or the copy is
27577
+ * a day old and the camera is awake anyway).
27578
+ *
27579
+ * See `RuntimeStateDurability`. Enforced by
27580
+ * `scripts/check-runtime-state-durability.ts`.
27581
+ */
27582
+ durability: "restored",
27583
+ /** Clock field: written, but excluded from the compare that decides whether
27584
+ * persisting is worth a SQLite commit — the descriptors are the value. */
27585
+ volatileStateFields: ["lastFetchedAt"]
27517
27586
  };
27518
27587
  /** One of the camera's stream profiles. */
27519
27588
  var StreamProfileSchema = zod.z.enum([
@@ -29510,6 +29579,24 @@ var DeclaredDevices = class {
29510
29579
  DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
29511
29580
  new Set(Object.values(DeviceType));
29512
29581
  DeviceFeature.BatteryOperated;
29582
+ /**
29583
+ * THE derivation. One crop rectangle, one presence verdict — see D52 for why
29584
+ * this repo insists a derived value has exactly one implementation.
29585
+ *
29586
+ * `undefined` status ⇒ `sleeping`. A device with no slice has made no claim,
29587
+ * and the caller decides separately whether it is even battery-operated
29588
+ * (`DeviceFeature.BatteryOperated`); this function never answers that
29589
+ * question, only what a battery device is doing.
29590
+ */
29591
+ function deriveBatteryPresence(input) {
29592
+ const status = input.status;
29593
+ if (!status) return "sleeping";
29594
+ if (status.sleeping !== true) return "awake";
29595
+ const lastContactAt = status.lastContactAt;
29596
+ if (typeof lastContactAt !== "number" || lastContactAt <= 0) return "sleeping";
29597
+ const budget = input.unreachableAfterMs ?? 216e5;
29598
+ return input.nowMs - lastContactAt > budget ? "unreachable" : "sleeping";
29599
+ }
29513
29600
  /** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
29514
29601
  * Zod v4 exposes `.unwrap()` on all three wrapper classes. */
29515
29602
  function unwrap(schema) {
@@ -37123,7 +37210,7 @@ Object.freeze({
37123
37210
  });
37124
37211
  /**
37125
37212
  * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
37126
- * `runtimeState`. 63 caps: 33 `restored`, 30 `session`.
37213
+ * `runtimeState`. 64 caps: 34 `restored`, 30 `session`.
37127
37214
  *
37128
37215
  * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
37129
37216
  * with `durability: 'session'` has one and has decided not to keep it.
@@ -37329,6 +37416,10 @@ var RUNTIME_STATE_POLICY = {
37329
37416
  durability: "restored",
37330
37417
  volatileFields: ["lastChangedAt"]
37331
37418
  },
37419
+ "stream-catalog": {
37420
+ durability: "restored",
37421
+ volatileFields: ["lastFetchedAt"]
37422
+ },
37332
37423
  "stream-params": {
37333
37424
  durability: "restored",
37334
37425
  volatileFields: ["lastFetchedAt"]
@@ -38204,6 +38295,12 @@ Object.defineProperty(exports, "decodeVectorBase64", {
38204
38295
  return decodeVectorBase64;
38205
38296
  }
38206
38297
  });
38298
+ Object.defineProperty(exports, "deriveBatteryPresence", {
38299
+ enumerable: true,
38300
+ get: function() {
38301
+ return deriveBatteryPresence;
38302
+ }
38303
+ });
38207
38304
  Object.defineProperty(exports, "deviceManagerCapability", {
38208
38305
  enumerable: true,
38209
38306
  get: function() {
@@ -20825,6 +20825,25 @@ var BatteryStatusSchema = z.object({
20825
20825
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
20826
20826
  lastUpdated: z.number(),
20827
20827
  /**
20828
+ * Ms epoch of the last time the device PROVED it was reachable — a
20829
+ * completed firmware round-trip, an observed wake, or an inbound push
20830
+ * (firmware event, email). `0`/absent = never since this slice was born.
20831
+ *
20832
+ * This is the ONLY input that separates "asleep" from "gone", and it is
20833
+ * fed exclusively by PASSIVE signals: nothing may write it by reaching
20834
+ * for the radio, because a poll that confirms reachability is the same
20835
+ * poll that drains the battery. See {@link deriveBatteryPresence} — the
20836
+ * single derivation every consumer must use; no surface computes its own.
20837
+ *
20838
+ * It is deliberately NOT a clock in the
20839
+ * `scripts/check-runtime-state-durability.ts` sense: it is the
20840
+ * observation itself, and it is the only thing a 30-hour silence is
20841
+ * visible in. Writers quantise it (see `CONTACT_WRITE_QUANTUM_MS` in the
20842
+ * Reolink provider) so a value that means "recently" cannot cost a
20843
+ * SQLite commit per round-trip.
20844
+ */
20845
+ lastContactAt: z.number().optional(),
20846
+ /**
20828
20847
  * True when the source is a BINARY low-battery indicator (HA
20829
20848
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
20830
20849
  * charge level — `percentage` is then a coarse stand-in (100 = normal,
@@ -27507,13 +27526,63 @@ var CamStreamDescriptorSchema = z.object({
27507
27526
  * set of stream descriptors it can offer for the device, synchronously, so the
27508
27527
  * broker can reconcile its registry against the authoritative provider state.
27509
27528
  */
27529
+ /**
27530
+ * The catalog as a DURABLE fact rather than a live answer.
27531
+ *
27532
+ * A battery camera's descriptors are profile-stable — they change when the
27533
+ * operator rewrites an encoder profile, not minute to minute — but building
27534
+ * them costs a Baichuan login, which on a sleeping Argus IS a wake. So the
27535
+ * provider is allowed to build them exactly once per profile and must serve
27536
+ * every later pull from a cache.
27537
+ *
27538
+ * Holding that cache only in RAM is what turned a restart into an outage. The
27539
+ * runner comes back with the camera asleep, `buildStreamCatalogUncached`
27540
+ * correctly refuses to wake it, the pull answers `[]`, the broker has no
27541
+ * cam-stream entry to build a broker from, and `webrtcSession.handleOffer`
27542
+ * fails with a flat "No broker for stream" — for as long as the camera sleeps,
27543
+ * which on a battery cam is most of the day. The camera was fine. The stream
27544
+ * was unreachable because the process had forgotten what the camera offers.
27545
+ *
27546
+ * Declaring it here puts it in `device-runtime-state`, the kernel's canonical
27547
+ * declared collection, with the same `restored` durability `battery` uses for
27548
+ * the same reason: the last known value is the only value there is while the
27549
+ * device is asleep. The broker's brokers are therefore always DEFINABLE — it
27550
+ * is the DIAL that wakes a camera, never the catalog (D173).
27551
+ */
27552
+ var StreamCatalogStateSchema = z.object({
27553
+ /** The descriptors as last built from a real camera response. Never a guess:
27554
+ * a failed or refused build writes NOTHING, so a restored catalog is always
27555
+ * one the camera itself once produced. */
27556
+ descriptors: z.array(CamStreamDescriptorSchema),
27557
+ /** Ms epoch of the build that produced {@link descriptors}. Lets the wake
27558
+ * path decide whether the camera's own awake window is worth spending on a
27559
+ * re-read. */
27560
+ lastFetchedAt: z.number()
27561
+ });
27510
27562
  var streamCatalogCapability = {
27511
27563
  name: "stream-catalog",
27512
27564
  scope: "device",
27513
27565
  deviceNative: true,
27514
27566
  mode: "singleton",
27515
27567
  deviceTypes: [DeviceType.Camera],
27516
- methods: { getCatalog: method(z.object({ deviceId: z.number().int().nonnegative() }), z.array(CamStreamDescriptorSchema).readonly()) }
27568
+ methods: { getCatalog: method(z.object({ deviceId: z.number().int().nonnegative() }), z.array(CamStreamDescriptorSchema).readonly()) },
27569
+ runtimeState: StreamCatalogStateSchema,
27570
+ /**
27571
+ * Runtime-state durability: **restored** — see the schema doc. A cold
27572
+ * catalog on a sleeping battery camera is not a slow first frame, it is a
27573
+ * camera that cannot be watched at all until it happens to wake.
27574
+ *
27575
+ * Churn is nil by construction: the slice is written only by a SUCCESSFUL
27576
+ * build, and a build only runs when there is no cached copy (or the copy is
27577
+ * a day old and the camera is awake anyway).
27578
+ *
27579
+ * See `RuntimeStateDurability`. Enforced by
27580
+ * `scripts/check-runtime-state-durability.ts`.
27581
+ */
27582
+ durability: "restored",
27583
+ /** Clock field: written, but excluded from the compare that decides whether
27584
+ * persisting is worth a SQLite commit — the descriptors are the value. */
27585
+ volatileStateFields: ["lastFetchedAt"]
27517
27586
  };
27518
27587
  /** One of the camera's stream profiles. */
27519
27588
  var StreamProfileSchema = z.enum([
@@ -29510,6 +29579,24 @@ var DeclaredDevices = class {
29510
29579
  DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
29511
29580
  new Set(Object.values(DeviceType));
29512
29581
  DeviceFeature.BatteryOperated;
29582
+ /**
29583
+ * THE derivation. One crop rectangle, one presence verdict — see D52 for why
29584
+ * this repo insists a derived value has exactly one implementation.
29585
+ *
29586
+ * `undefined` status ⇒ `sleeping`. A device with no slice has made no claim,
29587
+ * and the caller decides separately whether it is even battery-operated
29588
+ * (`DeviceFeature.BatteryOperated`); this function never answers that
29589
+ * question, only what a battery device is doing.
29590
+ */
29591
+ function deriveBatteryPresence(input) {
29592
+ const status = input.status;
29593
+ if (!status) return "sleeping";
29594
+ if (status.sleeping !== true) return "awake";
29595
+ const lastContactAt = status.lastContactAt;
29596
+ if (typeof lastContactAt !== "number" || lastContactAt <= 0) return "sleeping";
29597
+ const budget = input.unreachableAfterMs ?? 216e5;
29598
+ return input.nowMs - lastContactAt > budget ? "unreachable" : "sleeping";
29599
+ }
29513
29600
  /** Unwrap ZodNullable / ZodOptional / ZodDefault wrappers to reach the inner type.
29514
29601
  * Zod v4 exposes `.unwrap()` on all three wrapper classes. */
29515
29602
  function unwrap(schema) {
@@ -37123,7 +37210,7 @@ Object.freeze({
37123
37210
  });
37124
37211
  /**
37125
37212
  * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
37126
- * `runtimeState`. 63 caps: 33 `restored`, 30 `session`.
37213
+ * `runtimeState`. 64 caps: 34 `restored`, 30 `session`.
37127
37214
  *
37128
37215
  * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
37129
37216
  * with `durability: 'session'` has one and has decided not to keep it.
@@ -37329,6 +37416,10 @@ var RUNTIME_STATE_POLICY = {
37329
37416
  durability: "restored",
37330
37417
  volatileFields: ["lastChangedAt"]
37331
37418
  },
37419
+ "stream-catalog": {
37420
+ durability: "restored",
37421
+ volatileFields: ["lastFetchedAt"]
37422
+ },
37332
37423
  "stream-params": {
37333
37424
  durability: "restored",
37334
37425
  volatileFields: ["lastFetchedAt"]
@@ -37934,4 +38025,4 @@ function enumerateInferenceDevices(hw) {
37934
38025
  return out;
37935
38026
  }
37936
38027
  //#endregion
37937
- export { objectInputDeclaresAddonId as $, decodeVectorBase64 as A, createEvent as At, isArrayOutputSchema as B, resolveCapMount as Bt, backupCapability as C, DeviceType as Ct, coreBlockIdFromAddonId as D, asJsonObject as Dt, coreBlockAddonId as E, WELL_KNOWN_TAB_MAP as Et, enumerateInferenceDevices as F, isDeviceConfigCap as Ft, kebabToCamel as G, isObjectInput as H, sleep as Ht, enumerateItemArrayFields as I, nodePin as It, logDestinationCapability as J, lifecycleJobSchema as K, enumerateSchemaFields as L, parseJsonObject as Lt, deviceStateCapability as M, emitReadiness as Mt, deviceStatusCapability as N, expandCapMethods as Nt, coreBlocksCapability as O, asNumber as Ot, doorbellCapability as P, hydrateSchema as Pt, normalizeUnit as Q, extractNestedAddonId as R, parseJsonUnknown as Rt, authProviderCapability as S, DeviceRole as St, buildStreamParamsConfigSchema as T, ReadinessTimeoutError as Tt, isSameAddonId as U, EventCategory as Ut, isCollectionArrayMethod as V, scopeKey as Vt, isVoidInput as W, looseSchema as X, logLevelAtMost as Y, metricsProviderCapability as Z, UserRecordSchema as _, BaseAddon as _t, CAP_NAMES_WITH_STATUS as a, scopesAllowDeviceCap as at, addonWidgetsCapability as b, DEVICE_STATUS_METHOD as bt, CoreBlockSchema as c, snapshotCapability as ct, METHOD_ACCESS_MAP as d, storageProviderCapability as dt, parseStreamParamsFormPatch as et, RUNTIME_DEFAULTS as f, streamQualityLabel as ft, StorageMigrationJobSchema as g, errMsg as gt, StorageLocationTypeSchema as h, vectorStoreCapability as ht, BatteryStatusSchema as i, scopesAllowAddon as it, deviceManagerCapability as j, emitDownForOwnedCaps as jt, dataStoreProviderCapability as k, asString as kt, DeclaredDevices as l, storageCapability as lt, ScopedTokenSchema as m, vectorDimFromBase64 as mt, AlertSchema as n, procedureAuthKey as nt, CORE_BLOCKS_ADDON_ID as o, scoreRuntimes as ot, STREAM_PROFILE_META as p, userManagementCapability as pt, localNetworkCapability as q, ApiKeyRecordSchema as r, runtimeStatePolicyFor as rt, CORE_BLOCK_ADDON_PREFIX as s, settingsStoreCapability as st, ALL_CAPABILITY_DEFINITIONS as t, platformProbeCapability as tt, DeviceStatusSchema as u, storageMigrationCapability as ut, addonPagesCapability as v, DATAPLANE_SECRET_HEADER as vt, bareAddonId as w, ReadinessRegistry as wt, alertsCapability as x, DeviceFeature as xt, addonSettingsCapability as y, DEVICE_SETTINGS_CONTRIBUTION_METHODS as yt, filesystemBrowseCapability as z, readinessKey as zt };
38028
+ export { normalizeUnit as $, decodeVectorBase64 as A, asString as At, filesystemBrowseCapability as B, readinessKey as Bt, backupCapability as C, DeviceRole as Ct, coreBlockIdFromAddonId as D, WELL_KNOWN_TAB_MAP as Dt, coreBlockAddonId as E, ReadinessTimeoutError as Et, doorbellCapability as F, hydrateSchema as Ft, isVoidInput as G, isCollectionArrayMethod as H, scopeKey as Ht, enumerateInferenceDevices as I, isDeviceConfigCap as It, localNetworkCapability as J, kebabToCamel as K, enumerateItemArrayFields as L, nodePin as Lt, deviceManagerCapability as M, emitDownForOwnedCaps as Mt, deviceStateCapability as N, emitReadiness as Nt, coreBlocksCapability as O, asJsonObject as Ot, deviceStatusCapability as P, expandCapMethods as Pt, metricsProviderCapability as Q, enumerateSchemaFields as R, parseJsonObject as Rt, authProviderCapability as S, DeviceFeature as St, buildStreamParamsConfigSchema as T, ReadinessRegistry as Tt, isObjectInput as U, sleep as Ut, isArrayOutputSchema as V, resolveCapMount as Vt, isSameAddonId as W, EventCategory as Wt, logLevelAtMost as X, logDestinationCapability as Y, looseSchema as Z, UserRecordSchema as _, errMsg as _t, CAP_NAMES_WITH_STATUS as a, scopesAllowAddon as at, addonWidgetsCapability as b, DEVICE_SETTINGS_CONTRIBUTION_METHODS as bt, CoreBlockSchema as c, settingsStoreCapability as ct, METHOD_ACCESS_MAP as d, storageMigrationCapability as dt, objectInputDeclaresAddonId as et, RUNTIME_DEFAULTS as f, storageProviderCapability as ft, StorageMigrationJobSchema as g, vectorStoreCapability as gt, StorageLocationTypeSchema as h, vectorDimFromBase64 as ht, BatteryStatusSchema as i, runtimeStatePolicyFor as it, deriveBatteryPresence as j, createEvent as jt, dataStoreProviderCapability as k, asNumber as kt, DeclaredDevices as l, snapshotCapability as lt, ScopedTokenSchema as m, userManagementCapability as mt, AlertSchema as n, platformProbeCapability as nt, CORE_BLOCKS_ADDON_ID as o, scopesAllowDeviceCap as ot, STREAM_PROFILE_META as p, streamQualityLabel as pt, lifecycleJobSchema as q, ApiKeyRecordSchema as r, procedureAuthKey as rt, CORE_BLOCK_ADDON_PREFIX as s, scoreRuntimes as st, ALL_CAPABILITY_DEFINITIONS as t, parseStreamParamsFormPatch as tt, DeviceStatusSchema as u, storageCapability as ut, addonPagesCapability as v, BaseAddon as vt, bareAddonId as w, DeviceType as wt, alertsCapability as x, DEVICE_STATUS_METHOD as xt, addonSettingsCapability as y, DATAPLANE_SECRET_HEADER as yt, extractNestedAddonId as z, parseJsonUnknown as zt };
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-BH2tZ9ZN.js");
3
+ const require_dist = require("./dist-BMus2E5R.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 { $ as objectInputDeclaresAddonId, At as createEvent, B as isArrayOutputSchema, Bt as resolveCapMount, Dt as asJsonObject$1, G as kebabToCamel, H as isObjectInput, K as lifecycleJobSchema, Lt as parseJsonObject, Nt as expandCapMethods, Ot as asNumber, R as extractNestedAddonId, Rt as parseJsonUnknown$1, Tt as ReadinessTimeoutError, Ut as EventCategory$1, V as isCollectionArrayMethod, Vt as scopeKey, W as isVoidInput, X as looseSchema, Y as logLevelAtMost, at as scopesAllowDeviceCap, bt as DEVICE_STATUS_METHOD, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, gt as errMsg$1, it as scopesAllowAddon, jt as emitDownForOwnedCaps, kt as asString$1, nt as procedureAuthKey, t as ALL_CAPABILITY_DEFINITIONS, vt as DATAPLANE_SECRET_HEADER$1, wt as ReadinessRegistry, y as addonSettingsCapability, yt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, zt as readinessKey } from "./dist-DXDvrBi0.mjs";
2
+ import { At as asString$1, Bt as readinessKey, Et as ReadinessTimeoutError, G as isVoidInput, H as isCollectionArrayMethod, Ht as scopeKey, K as kebabToCamel, Mt as emitDownForOwnedCaps, Ot as asJsonObject$1, Pt as expandCapMethods, Rt as parseJsonObject, Tt as ReadinessRegistry, U as isObjectInput, V as isArrayOutputSchema, Vt as resolveCapMount, Wt as EventCategory$1, X as logLevelAtMost, Z as looseSchema, _t as errMsg$1, at as scopesAllowAddon, bt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, d as METHOD_ACCESS_MAP, et as objectInputDeclaresAddonId, f as RUNTIME_DEFAULTS, jt as createEvent, kt as asNumber, ot as scopesAllowDeviceCap, q as lifecycleJobSchema, rt as procedureAuthKey, t as ALL_CAPABILITY_DEFINITIONS, xt as DEVICE_STATUS_METHOD, y as addonSettingsCapability, yt as DATAPLANE_SECRET_HEADER$1, z as extractNestedAddonId, zt as parseJsonUnknown$1 } from "./dist-F1XDQDE1.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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.92",
3
+ "version": "1.2.93",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",