@camstack/system 1.2.330 → 1.2.331

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 (78) 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/autotrack/index.js +3 -3
  10. package/dist/builtins/autotrack/index.mjs +3 -3
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  13. package/dist/builtins/camera-grid/index.js +1 -1
  14. package/dist/builtins/camera-grid/index.mjs +1 -1
  15. package/dist/builtins/composer/composer.addon.js +27 -8
  16. package/dist/builtins/composer/composer.addon.mjs +21 -3
  17. package/dist/builtins/console-logging/index.js +1 -1
  18. package/dist/builtins/console-logging/index.mjs +1 -1
  19. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  20. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  21. package/dist/builtins/device-manager/device-bindings-store.d.ts +7 -0
  22. package/dist/builtins/device-manager/device-manager.addon.d.ts +3 -0
  23. package/dist/builtins/device-manager/device-manager.addon.js +130 -3
  24. package/dist/builtins/device-manager/device-manager.addon.mjs +130 -3
  25. package/dist/builtins/device-manager/stale-wrapper-activations.d.ts +26 -0
  26. package/dist/builtins/hub-forwarder/index.js +1 -1
  27. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  28. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  29. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  30. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  31. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  32. package/dist/builtins/local-network/local-network.addon.js +1 -1
  33. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  34. package/dist/builtins/loki-logging/index.js +1 -1
  35. package/dist/builtins/loki-logging/index.mjs +1 -1
  36. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  37. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  38. package/dist/builtins/platform-probe/index.js +1 -1
  39. package/dist/builtins/platform-probe/index.mjs +1 -1
  40. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  41. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  42. package/dist/builtins/shared/device-state-changed.d.ts +3 -4
  43. package/dist/builtins/snapshot/index.js +1 -1
  44. package/dist/builtins/snapshot/index.mjs +1 -1
  45. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  46. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  47. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  48. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  49. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  50. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  51. package/dist/builtins/system-config/system-config.addon.js +1 -1
  52. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  53. package/dist/builtins/winston-logging/index.js +1 -1
  54. package/dist/builtins/winston-logging/index.mjs +1 -1
  55. package/dist/{child-cap-dispatch-C8uts1P4.js → child-cap-dispatch-93MfsaZL.js} +1 -0
  56. package/dist/{child-cap-dispatch-C2VINHu1.mjs → child-cap-dispatch-kLIiU1CG.mjs} +1 -0
  57. package/dist/{composition-sources-2XxNEet3.js → composition-sources-BXZorHDO.js} +1 -1
  58. package/dist/{composition-sources-Wj2kWund.mjs → composition-sources-aEEer5gE.mjs} +1 -1
  59. package/dist/{dist-Dp043AI0.mjs → dist-CoG8lY6H.mjs} +222 -374
  60. package/dist/{dist-Bx4zxM9N.js → dist-DRUzy1SF.js} +221 -421
  61. package/dist/index.js +2 -2
  62. package/dist/index.mjs +2 -2
  63. package/dist/{retired-settings-keys-DR2WMe5d.js → retired-settings-keys-BY9H1I2b.js} +1 -1
  64. package/dist/{retired-settings-keys-Dxf9vELs.mjs → retired-settings-keys-BcJDpASY.mjs} +1 -1
  65. package/package.json +1 -16
  66. package/dist/builtins/doorbell/binding-mirror.d.ts +0 -110
  67. package/dist/builtins/doorbell/doorbell-composition-migration.d.ts +0 -47
  68. package/dist/builtins/doorbell/doorbell-extension-slot.d.ts +0 -67
  69. package/dist/builtins/doorbell/doorbell-settings.d.ts +0 -58
  70. package/dist/builtins/doorbell/index.d.ts +0 -2
  71. package/dist/builtins/doorbell/index.js +0 -8
  72. package/dist/builtins/doorbell/index.mjs +0 -2
  73. package/dist/builtins/doorbell/trigger-engine.d.ts +0 -92
  74. package/dist/builtins/doorbell/virtual-doorbell.addon.d.ts +0 -218
  75. package/dist/builtins/doorbell/virtual-doorbell.addon.js +0 -1413
  76. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +0 -1407
  77. package/dist/device-state-changed-Bk7cvTnz.js +0 -31
  78. package/dist/device-state-changed-DoBbkyEI.mjs +0 -20
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_child_cap_dispatch = require("./child-cap-dispatch-C8uts1P4.js");
2
+ const require_child_cap_dispatch = require("./child-cap-dispatch-93MfsaZL.js");
3
3
  const require_custom_action_registry = require("./custom-action-registry-acBY3mHA.js");
4
4
  let node_path = require("node:path");
5
5
  node_path = require_chunk.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { $t as RUNNER_RSS_BUDGET_ENV, Ft as resolveAddonClass, H as createUdsLoggerWithControl, Pt as installManifestNativeDeps, U as LocalChildClient, _t as getWorkerNativeCapSnapshot, f as installManifestSystemDeps, fn as startRunnerHeapWatch, g as createUdsAddonContext, gt as getWorkerNativeCapProvider, i as killOwnRunnerGroupAfterParentLoss, n as createChildCapDispatch, p as installManifestPythonDeps, u as startRunnerParentDeathWatchdog, wn as emitHeapDiagnosticReport, xt as validateProviderRegistrations, yt as setWorkerNativeCapsChangeListener } from "./child-cap-dispatch-C2VINHu1.mjs";
1
+ import { $t as RUNNER_RSS_BUDGET_ENV, Ft as resolveAddonClass, H as createUdsLoggerWithControl, Pt as installManifestNativeDeps, U as LocalChildClient, _t as getWorkerNativeCapSnapshot, f as installManifestSystemDeps, fn as startRunnerHeapWatch, g as createUdsAddonContext, gt as getWorkerNativeCapProvider, i as killOwnRunnerGroupAfterParentLoss, n as createChildCapDispatch, p as installManifestPythonDeps, u as startRunnerParentDeathWatchdog, wn as emitHeapDiagnosticReport, xt as validateProviderRegistrations, yt as setWorkerNativeCapsChangeListener } from "./child-cap-dispatch-kLIiU1CG.mjs";
2
2
  import { t as CustomActionRegistry } from "./custom-action-registry-B4Cf4O_X.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-Bx4zxM9N.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.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 { Sr as EventCategory, V as addonPagesCapability, Xn as errMsg, Zn as BaseAddon } from "../../dist-Dp043AI0.mjs";
1
+ import { Hn as errMsg, Un as BaseAddon, V as addonPagesCapability, mr as EventCategory } from "../../dist-CoG8lY6H.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-Bx4zxM9N.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.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 { Sr as EventCategory, U as addonWidgetsCapability, Xn as errMsg, Zn as BaseAddon } from "../../dist-Dp043AI0.mjs";
1
+ import { Hn as errMsg, U as addonWidgetsCapability, Un as BaseAddon, mr as EventCategory } from "../../dist-CoG8lY6H.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-Bx4zxM9N.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.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 { Sr as EventCategory, W as alertsCapability, Xn as errMsg, Zn as BaseAddon, n as AlertSchema, sr as createEvent } from "../../dist-Dp043AI0.mjs";
1
+ import { $n as createEvent, Hn as errMsg, Un as BaseAddon, W as alertsCapability, mr as EventCategory, n as AlertSchema } from "../../dist-CoG8lY6H.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
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Bx4zxM9N.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.js");
7
7
  //#region src/builtins/autotrack/autotrack-config.ts
8
8
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
9
9
  deadZoneFraction: .5,
@@ -33,8 +33,8 @@ var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
33
33
  *
34
34
  * ## One switch, not two (D62, D520)
35
35
  *
36
- * Binding this wrapper to a camera chooses the IMPLEMENTATION — the same act as
37
- * binding `virtual-doorbell`. `setEnabled` is the switch for the function, and
36
+ * Binding this wrapper to a camera chooses the IMPLEMENTATION.
37
+ * `setEnabled` is the switch for the function, and
38
38
  * it is the cap's own switch: a camera with firmware autotrack uses its native
39
39
  * provider for exactly the same method, so the operator never sees two
40
40
  * controls that can disagree.
@@ -1,4 +1,4 @@
1
- import { Sr as EventCategory, Xn as errMsg, Zn as BaseAddon, b as FIRST_LEVEL_MACRO_CLASSES, pr as isEvent, q as bareAddonId, sn as ptzAutotrackCapability } from "../../dist-Dp043AI0.mjs";
1
+ import { Hn as errMsg, Un as BaseAddon, ar as isEvent, b as FIRST_LEVEL_MACRO_CLASSES, mr as EventCategory, q as bareAddonId, rn as ptzAutotrackCapability } from "../../dist-CoG8lY6H.mjs";
2
2
  //#region src/builtins/autotrack/autotrack-config.ts
3
3
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
4
4
  deadZoneFraction: .5,
@@ -28,8 +28,8 @@ var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
28
28
  *
29
29
  * ## One switch, not two (D62, D520)
30
30
  *
31
- * Binding this wrapper to a camera chooses the IMPLEMENTATION — the same act as
32
- * binding `virtual-doorbell`. `setEnabled` is the switch for the function, and
31
+ * Binding this wrapper to a camera chooses the IMPLEMENTATION.
32
+ * `setEnabled` is the switch for the function, and
33
33
  * it is the cap's own switch: a camera with firmware autotrack uses its native
34
34
  * provider for exactly the same method, so the operator never sees two
35
35
  * controls that can disagree.
@@ -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-Bx4zxM9N.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.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 { K as backupCapability, Sn as storageOccupancyCapability, Sr as EventCategory, Yt as mayWriteToLocation, Zn as BaseAddon, m as DATABASE_SNAPSHOT_SUFFIX, mr as nodePin, xr as toNodeId } from "../../dist-Dp043AI0.mjs";
1
+ import { Gt as mayWriteToLocation, K as backupCapability, Un as BaseAddon, m as DATABASE_SNAPSHOT_SUFFIX, mr as EventCategory, or as nodePin, pr as toNodeId, vn as storageOccupancyCapability } from "../../dist-CoG8lY6H.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-Bx4zxM9N.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.js");
7
7
  let zod = require("zod");
8
8
  let _camstack_types_node = require("@camstack/types/node");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { $t as motionCapability, Fn as buildFfmpegArgs, O as MOTION_CLOSE_AFTER_MS, Q as cameraGridLayoutCapability, Sr as EventCategory, Xn as errMsg, Xt as memoizePinnedFfmpeg, Yn as DeviceType, Zn as BaseAddon, _ as DERIVED_CAMERA_SILENCED_CAP_NAMES, dr as hydrateSchema, dt as declarationOwnerNodeId, i as BaseDevice, qn as DeviceFeature, sr as createEvent, v as DeclaredDevices, wn as streamCatalogCapability, yn as snapshotCapability } from "../../dist-Dp043AI0.mjs";
1
+ import { $n as createEvent, Hn as errMsg, Kt as memoizePinnedFfmpeg, O as MOTION_CLOSE_AFTER_MS, Un as BaseAddon, Vn as DeviceType, Yt as motionCapability, Z as cameraGridLayoutCapability, _ as DERIVED_CAMERA_SILENCED_CAP_NAMES, bn as streamCatalogCapability, hn as snapshotCapability, i as BaseDevice, kn as buildFfmpegArgs, mr as EventCategory, rr as hydrateSchema, ut as declarationOwnerNodeId, v as DeclaredDevices, zn as DeviceFeature } from "../../dist-CoG8lY6H.mjs";
2
2
  import { z } from "zod";
3
3
  import { FfmpegProcess } from "@camstack/types/node";
4
4
  import { join } from "node:path";
@@ -3,9 +3,28 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Bx4zxM9N.js");
7
- const require_device_state_changed = require("../../device-state-changed-Bk7cvTnz.js");
8
- const require_composition_sources = require("../../composition-sources-2XxNEet3.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.js");
7
+ const require_composition_sources = require("../../composition-sources-BXZorHDO.js");
8
+ let zod = require("zod");
9
+ //#region src/builtins/shared/device-state-changed.ts
10
+ /** Structural narrowing helper for untrusted bus payloads. */
11
+ function isRecord$2(value) {
12
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13
+ }
14
+ function parseDeviceStateChanged(data) {
15
+ if (!isRecord$2(data)) return null;
16
+ const deviceId = data["deviceId"];
17
+ const capName = data["capName"];
18
+ const slice = data["slice"];
19
+ if (typeof deviceId !== "number" || typeof capName !== "string") return null;
20
+ if (!isRecord$2(slice)) return null;
21
+ return {
22
+ deviceId,
23
+ capName,
24
+ slice
25
+ };
26
+ }
27
+ //#endregion
9
28
  //#region src/builtins/composer/composed-device.ts
10
29
  /**
11
30
  * A composed device: an ordinary `BaseDevice` whose caps are served by the
@@ -29,7 +48,7 @@ const require_composition_sources = require("../../composition-sources-2XxNEet3.
29
48
  * `deviceMeta`: a failed meta read builds a device as `generic`, and the
30
49
  * declaration is the authority for what this device is.
31
50
  */
32
- var COMPOSED_DEVICE_CONFIG_SCHEMA = require("zod").z.object({});
51
+ var COMPOSED_DEVICE_CONFIG_SCHEMA = zod.z.object({});
33
52
  var ComposedDevice = class extends require_dist.BaseDevice {
34
53
  features = [];
35
54
  constructor(ctx, type, caps) {
@@ -3310,7 +3329,7 @@ function entriesOf(request) {
3310
3329
  }))];
3311
3330
  }
3312
3331
  function valueAtPath(slice, path) {
3313
- return path.split(".").reduce((node, segment) => require_device_state_changed.isRecord(node) ? node[segment] : void 0, slice);
3332
+ return path.split(".").reduce((node, segment) => isRecord$2(node) ? node[segment] : void 0, slice);
3314
3333
  }
3315
3334
  function onlineOf(slice) {
3316
3335
  const online = slice["online"];
@@ -3975,12 +3994,12 @@ var SourceTracker = class {
3975
3994
  var DECLARED_INTEGRATION_NAME_UNUSED = "Blocks";
3976
3995
  /** The owner-only shadow payload is not in the typed catalog: narrowed at the boundary, like `device.state-changed`. */
3977
3996
  function parseNativeShadowChanged(data) {
3978
- if (!require_device_state_changed.isRecord(data)) return null;
3997
+ if (!isRecord$2(data)) return null;
3979
3998
  const deviceId = data["deviceId"];
3980
3999
  const capName = data["capName"];
3981
4000
  const native = data["native"];
3982
4001
  if (typeof deviceId !== "number" || typeof capName !== "string") return null;
3983
- if (!require_device_state_changed.isRecord(native)) return null;
4002
+ if (!isRecord$2(native)) return null;
3984
4003
  return {
3985
4004
  deviceId,
3986
4005
  capName,
@@ -4127,7 +4146,7 @@ var ComposerAddon = class extends require_dist.BaseAddon {
4127
4146
  newTimer: () => new NodeDeadlineTimer(() => Date.now())
4128
4147
  });
4129
4148
  this.subscribe({ category: require_dist.EventCategory.DeviceStateChanged }, (event) => {
4130
- const data = require_device_state_changed.parseDeviceStateChanged(event.data);
4149
+ const data = parseDeviceStateChanged(event.data);
4131
4150
  if (data !== null) this.composer?.onStateChanged(data).catch((err) => {
4132
4151
  this.logEventFailure("device.state-changed", data.deviceId, err);
4133
4152
  });
@@ -1,7 +1,25 @@
1
- import { Bn as compositionItemFieldPath, Hn as compositionSourceKey, In as cloneStatefulExpressionMemory, Kn as toExpressionValue, Ln as composedDeviceRef, Mn as COMPOSER_ADDON_ID, Rn as composedDeviceStableId, Sr as EventCategory, Tt as evaluateCompositionField, Un as createStatefulExpressionMemory, Vn as compositionSliceKey, Xn as errMsg, Y as buildCapabilityLookup, Yn as DeviceType, Zn as BaseAddon, c as COMPOSED_ITEM_FIXED_FIELDS, et as composerCapability, i as BaseDevice, in as planComposition, sr as createEvent, t as ALL_CAPABILITY_DEFINITIONS, tt as compositionFieldKey, v as DeclaredDevices, zn as compositionFeatureEnabled } from "../../dist-Dp043AI0.mjs";
2
- import { n as parseDeviceStateChanged, t as isRecord$2 } from "../../device-state-changed-DoBbkyEI.mjs";
3
- import { n as normalizedNativeOwner } from "../../composition-sources-Wj2kWund.mjs";
1
+ import { $ as composerCapability, $n as createEvent, An as cloneStatefulExpressionMemory, Fn as compositionSliceKey, Hn as errMsg, In as compositionSourceKey, Ln as createStatefulExpressionMemory, Mn as composedDeviceStableId, Nn as compositionFeatureEnabled, On as COMPOSER_ADDON_ID, Pn as compositionItemFieldPath, Rn as toExpressionValue, St as evaluateCompositionField, Un as BaseAddon, Vn as DeviceType, Y as buildCapabilityLookup, c as COMPOSED_ITEM_FIXED_FIELDS, en as planComposition, et as compositionFieldKey, i as BaseDevice, jn as composedDeviceRef, mr as EventCategory, t as ALL_CAPABILITY_DEFINITIONS, v as DeclaredDevices } from "../../dist-CoG8lY6H.mjs";
2
+ import { n as normalizedNativeOwner } from "../../composition-sources-aEEer5gE.mjs";
4
3
  import { z } from "zod";
4
+ //#region src/builtins/shared/device-state-changed.ts
5
+ /** Structural narrowing helper for untrusted bus payloads. */
6
+ function isRecord$2(value) {
7
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8
+ }
9
+ function parseDeviceStateChanged(data) {
10
+ if (!isRecord$2(data)) return null;
11
+ const deviceId = data["deviceId"];
12
+ const capName = data["capName"];
13
+ const slice = data["slice"];
14
+ if (typeof deviceId !== "number" || typeof capName !== "string") return null;
15
+ if (!isRecord$2(slice)) return null;
16
+ return {
17
+ deviceId,
18
+ capName,
19
+ slice
20
+ };
21
+ }
22
+ //#endregion
5
23
  //#region src/builtins/composer/composed-device.ts
6
24
  /**
7
25
  * A composed device: an ordinary `BaseDevice` whose caps are served by the
@@ -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-Bx4zxM9N.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.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 { Gt as logDestinationCapability, Zn as BaseAddon } from "../../dist-Dp043AI0.mjs";
1
+ import { Un as BaseAddon, Vt as logDestinationCapability } from "../../dist-CoG8lY6H.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,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-Bx4zxM9N.js");
4
- const require_composition_sources = require("../../composition-sources-2XxNEet3.js");
3
+ const require_dist = require("../../dist-DRUzy1SF.js");
4
+ const require_composition_sources = require("../../composition-sources-BXZorHDO.js");
5
5
  let node_crypto = require("node:crypto");
6
6
  let _camstack_types_node = require("@camstack/types/node");
7
7
  let node_fs_promises = require("node:fs/promises");
@@ -1,5 +1,5 @@
1
- import { Dn as validateComposition, Hn as compositionSourceKey, Ln as composedDeviceRef, Xn as errMsg, Y as buildCapabilityLookup, Zn as BaseAddon, at as coreBlockIdFromAddonId, d as CORE_BLOCK_ADDON_PREFIX, f as CoreBlockSchema, ht as describeComposableCaps, in as planComposition, it as coreBlockComposition, l as COMPOSER_RUNNER_ID, ln as replacedFieldKeys, nt as compositionSourceRefs, ot as coreBlockSourceKind, rt as coreBlockAddonId, st as coreBlocksCapability, t as ALL_CAPABILITY_DEFINITIONS, u as CORE_BLOCKS_ADDON_ID, v as DeclaredDevices } from "../../dist-Dp043AI0.mjs";
2
- import { t as describeCompositionSources } from "../../composition-sources-Wj2kWund.mjs";
1
+ import { Cn as validateComposition, Hn as errMsg, In as compositionSourceKey, Un as BaseAddon, Y as buildCapabilityLookup, an as replacedFieldKeys, at as coreBlockSourceKind, d as CORE_BLOCK_ADDON_PREFIX, en as planComposition, f as CoreBlockSchema, it as coreBlockIdFromAddonId, jn as composedDeviceRef, l as COMPOSER_RUNNER_ID, mt as describeComposableCaps, nt as coreBlockAddonId, ot as coreBlocksCapability, rt as coreBlockComposition, t as ALL_CAPABILITY_DEFINITIONS, tt as compositionSourceRefs, u as CORE_BLOCKS_ADDON_ID, v as DeclaredDevices } from "../../dist-CoG8lY6H.mjs";
2
+ import { t as describeCompositionSources } from "../../composition-sources-aEEer5gE.mjs";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { customizationBlockName } from "@camstack/types/node";
5
5
  import * as fs from "node:fs/promises";
@@ -1,6 +1,7 @@
1
1
  import { AddonContext, CapabilityDefinition, DeviceBindingEntry, ICapabilityRegistry } from '@camstack/types';
2
2
  import { DeviceBindingsStore } from './device-meta-types.js';
3
3
  import { DeviceRow, DeviceRowStore } from './device-row-store.js';
4
+ import { StaleWrapperActivations } from './stale-wrapper-activations.js';
4
5
  import { WriteLock } from './write-lock.js';
5
6
  /** Push-fed remote native-cap cache shape (numeric deviceId → capName → owner). */
6
7
  export type RemoteNativeCaps = Map<number, Map<string, {
@@ -40,6 +41,12 @@ export interface BindingsDeps {
40
41
  * whatever toggle happens to be in flight.
41
42
  */
42
43
  readonly withAddonStoreWriteLock: WriteLock;
44
+ /**
45
+ * The per-process memory of stored activations that name a RETIRED wrapper
46
+ * (a cap with no `kind: 'wrapper'` any more): each is ignored by step 1 and
47
+ * said once (task 17 review M1, `stale-wrapper-activations.ts`).
48
+ */
49
+ readonly staleWrapperActivations: StaleWrapperActivations;
43
50
  }
44
51
  /**
45
52
  * Wire the push-fed cross-process native-cap cache (`remoteNativeCaps`).
@@ -122,6 +122,9 @@ export declare class DeviceManagerAddon extends BaseAddon {
122
122
  * one key range is the same defect one level up. Handed to both.
123
123
  */
124
124
  private readonly addonStoreWriteLock;
125
+ /** Stored activations of RETIRED wrappers, said once per process (task 17 review M1). */
126
+ private staleWrapperActivationsImpl;
127
+ private get staleWrapperActivations();
125
128
  /** Build the dependency context the extracted binding resolvers consume. */
126
129
  private get bindingsDeps();
127
130
  getBindings(input: {
@@ -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-Bx4zxM9N.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-DR2WMe5d.js");
6
+ const require_dist = require("../../dist-DRUzy1SF.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-BY9H1I2b.js");
8
8
  let zod = require("zod");
9
9
  let node_crypto = require("node:crypto");
10
10
  let _camstack_types_node = require("@camstack/types/node");
@@ -1025,6 +1025,118 @@ function mergeAggregates(parts) {
1025
1025
  return out;
1026
1026
  }
1027
1027
  //#endregion
1028
+ //#region src/builtins/device-manager/stale-wrapper-activations.ts
1029
+ /**
1030
+ * A stored wrapper activation that names a cap with NO wrapper any more.
1031
+ *
1032
+ * `deviceBindings[device][cap].wrapperAddonId` is the operator's choice of a
1033
+ * wrapper. When a wrapper is RETIRED (the `virtual-doorbell` on `doorbell`,
1034
+ * slice 6, D671), its rows outlive it: nothing deletes them (spec S1 — the
1035
+ * cluster is not written by code), and the admin UI no longer offers a toggle
1036
+ * for a cap that is not a wrapper cap. Routed as before, such a row shadows
1037
+ * the device's native (a composed doorbell) behind an addon that no longer
1038
+ * exists, keeps the cap advertised to HA / HAP / Alexa, and refuses every
1039
+ * call — without a line (task 17 review M1, D391).
1040
+ *
1041
+ * So the row is judged against the cap's DECLARED definition — static at boot,
1042
+ * never the live registry, because a wrapper runner that is still starting must
1043
+ * not read as stale. A string `wrapperAddonId` on a cap that is declared and is
1044
+ * not `kind: 'wrapper'` is treated as ABSENT: the cap resolves to its native
1045
+ * (or to nothing), exactly as if the row were not there. That loses no
1046
+ * doorbell: with a native, the native serves it; without one, the retired
1047
+ * addon could not serve it either. A cap this build does not declare is NOT
1048
+ * judged (unknown is not stale).
1049
+ *
1050
+ * It is said once per (device, cap) per process, by name, with the call that
1051
+ * clears the row. The whole store is checked once per process, read-only, so a
1052
+ * device nobody asks about is still named; a read that fails changes nothing,
1053
+ * says it could not check, and the next answered read checks instead (D49).
1054
+ * Generic on purpose: the next wrapper retirement gets the same backstop.
1055
+ */
1056
+ var STALE_MESSAGE = "bindings: a stored wrapper activation names a cap with no wrapper — ignored, the cap resolves to its native";
1057
+ var UNCHECKED_MESSAGE = "bindings: could not read the stored wrapper activations — retired-wrapper rows not checked";
1058
+ var RECOVERY = "deviceManager.setWrapperActive({ deviceId, capName, wrapperAddonId, active: false })";
1059
+ /**
1060
+ * Every cap this build declares that is NOT a wrapper cap — built once from
1061
+ * the static table: `getAllBindings` is a scheduled hot path, and step 1 asks
1062
+ * this for every stored string activation (re-review N2).
1063
+ */
1064
+ var DECLARED_NON_WRAPPER_CAPS = new Set(require_dist.ALL_CAPABILITY_DEFINITIONS.filter((cap) => cap.kind !== "wrapper").map((cap) => cap.name));
1065
+ /** True when `capName` is declared by this build and is NOT a wrapper cap. */
1066
+ function isDeclaredNonWrapperCap(capName) {
1067
+ return DECLARED_NON_WRAPPER_CAPS.has(capName);
1068
+ }
1069
+ function isRecord$1(value) {
1070
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1071
+ }
1072
+ /** A persisted activation of a wrapper on a cap that has none (see module docblock). */
1073
+ function isRetiredWrapperActivation(capName, wrapperAddonId) {
1074
+ return typeof wrapperAddonId === "string" && isDeclaredNonWrapperCap(capName);
1075
+ }
1076
+ /**
1077
+ * The per-process memory: which (device, cap) rows have been said, and whether
1078
+ * the whole store has been checked once. Owned by the device-manager instance.
1079
+ */
1080
+ var StaleWrapperActivations = class {
1081
+ logger;
1082
+ said = /* @__PURE__ */ new Set();
1083
+ checked = false;
1084
+ constructor(logger) {
1085
+ this.logger = logger;
1086
+ }
1087
+ /** Say one row, once per process. */
1088
+ report(deviceId, capName, wrapperAddonId) {
1089
+ const key = `${deviceId}\u0000${capName}`;
1090
+ if (this.said.has(key)) return;
1091
+ this.said.add(key);
1092
+ this.logger.warn(STALE_MESSAGE, {
1093
+ tags: { deviceId },
1094
+ meta: {
1095
+ capName,
1096
+ wrapperAddonId,
1097
+ recovery: RECOVERY
1098
+ }
1099
+ });
1100
+ }
1101
+ /**
1102
+ * Check a store that was already READ (by a bindings pass) — once per
1103
+ * process. It never throws: it runs inside every bindings pass and under the
1104
+ * boot `void` promise, so a corrupt entry (a null device or row, a hand edit,
1105
+ * a partial write) is skipped — a row it cannot read is not one it can judge
1106
+ * (re-review N1).
1107
+ */
1108
+ checkStore(store) {
1109
+ if (this.checked) return;
1110
+ this.checked = true;
1111
+ const devices = store.deviceBindings;
1112
+ if (!isRecord$1(devices)) return;
1113
+ for (const [deviceKey, perDevice] of Object.entries(devices)) {
1114
+ const deviceId = Number(deviceKey);
1115
+ if (!Number.isInteger(deviceId) || !isRecord$1(perDevice)) continue;
1116
+ for (const [capName, row] of Object.entries(perDevice)) {
1117
+ const wrapperAddonId = isRecord$1(row) ? row["wrapperAddonId"] : void 0;
1118
+ if (typeof wrapperAddonId === "string" && isDeclaredNonWrapperCap(capName)) this.report(deviceId, capName, wrapperAddonId);
1119
+ }
1120
+ }
1121
+ }
1122
+ /** Read the store (read-only) and check it; a failed read changes nothing. */
1123
+ async checkOnce(read) {
1124
+ if (this.checked) return;
1125
+ let store;
1126
+ try {
1127
+ store = await read();
1128
+ } catch (err) {
1129
+ this.logger.warn(UNCHECKED_MESSAGE, { meta: { error: err instanceof Error ? err.message : String(err) } });
1130
+ return;
1131
+ }
1132
+ try {
1133
+ this.checkStore(store);
1134
+ } catch (err) {
1135
+ this.logger.warn(UNCHECKED_MESSAGE, { meta: { error: err instanceof Error ? err.message : String(err) } });
1136
+ }
1137
+ }
1138
+ };
1139
+ //#endregion
1028
1140
  //#region src/builtins/device-manager/device-bindings-store.ts
1029
1141
  /**
1030
1142
  * Wire the push-fed cross-process native-cap cache (`remoteNativeCaps`).
@@ -1265,6 +1377,7 @@ function collectionBindings(deps, deviceId, deviceType) {
1265
1377
  }
1266
1378
  async function getBindings(deps, input) {
1267
1379
  const [row, store] = await Promise.all([deps.rows.get(input.deviceId), readBindingsStore(deps)]);
1380
+ deps.staleWrapperActivations.checkStore(store);
1268
1381
  return resolveBindingsForDevice(deps, input.deviceId, row, {
1269
1382
  store,
1270
1383
  ledgerNonEmpty: onceLedgerNonEmpty(deps)
@@ -1309,6 +1422,10 @@ async function resolveBindingsForDevice(deps, deviceId, row, pass) {
1309
1422
  const resolveRemote = (capName) => deps.remoteNativeCaps.get(deviceId)?.get(capName) ?? resolveRemoteNativeCapFromRegistry(deps, capName, deviceId);
1310
1423
  for (const [capName, { wrapperAddonId }] of Object.entries(perDevice)) {
1311
1424
  if (wrapperAddonId === void 0) continue;
1425
+ if (isRetiredWrapperActivation(capName, wrapperAddonId)) {
1426
+ deps.staleWrapperActivations.report(deviceId, capName, wrapperAddonId);
1427
+ continue;
1428
+ }
1312
1429
  const hubLocalNative = deps.capabilityRegistry?.getNativeAddonId(capName, deviceId) ?? null;
1313
1430
  const remoteNative = resolveRemote(capName);
1314
1431
  const nativeAddonId = hubLocalNative ?? remoteNative?.addonId ?? "";
@@ -1433,6 +1550,7 @@ async function resolveBindingsForDevice(deps, deviceId, row, pass) {
1433
1550
  async function getBindingsBatch(deps, input) {
1434
1551
  const ids = [...new Set(input.deviceIds)];
1435
1552
  const [rows, store] = await Promise.all([deps.rows.getMany(ids), readBindingsStore(deps)]);
1553
+ deps.staleWrapperActivations.checkStore(store);
1436
1554
  const pass = {
1437
1555
  store,
1438
1556
  ledgerNonEmpty: onceLedgerNonEmpty(deps)
@@ -1463,6 +1581,7 @@ async function getBindingsBatch(deps, input) {
1463
1581
  */
1464
1582
  async function getAllBindings(deps) {
1465
1583
  const [fleet, store] = await Promise.all([deps.rows.listAll(), readBindingsStore(deps)]);
1584
+ deps.staleWrapperActivations.checkStore(store);
1466
1585
  const rowById = /* @__PURE__ */ new Map();
1467
1586
  const ids = /* @__PURE__ */ new Set();
1468
1587
  for (const row of fleet) {
@@ -9638,6 +9757,12 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
9638
9757
  * one key range is the same defect one level up. Handed to both.
9639
9758
  */
9640
9759
  addonStoreWriteLock = createWriteLock();
9760
+ /** Stored activations of RETIRED wrappers, said once per process (task 17 review M1). */
9761
+ staleWrapperActivationsImpl = null;
9762
+ get staleWrapperActivations() {
9763
+ this.staleWrapperActivationsImpl ??= new StaleWrapperActivations(this.ctx.logger);
9764
+ return this.staleWrapperActivationsImpl;
9765
+ }
9641
9766
  /** Build the dependency context the extracted binding resolvers consume. */
9642
9767
  get bindingsDeps() {
9643
9768
  const rows = this.deviceRows;
@@ -9647,7 +9772,8 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
9647
9772
  capabilityRegistry: this.capabilityRegistry,
9648
9773
  remoteNativeCaps: this.remoteNativeCaps,
9649
9774
  rows,
9650
- withAddonStoreWriteLock: this.addonStoreWriteLock
9775
+ withAddonStoreWriteLock: this.addonStoreWriteLock,
9776
+ staleWrapperActivations: this.staleWrapperActivations
9651
9777
  };
9652
9778
  }
9653
9779
  async getBindings(input) {
@@ -9722,6 +9848,7 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
9722
9848
  const deviceRows = new DeviceRowStore(deviceRowBackendOf(settingsStoreApi), this.ctx.logger.child("rows"));
9723
9849
  await deviceRows.declare();
9724
9850
  this.deviceRows = deviceRows;
9851
+ this.staleWrapperActivations.checkOnce(() => readBindingsStore(this.bindingsDeps));
9725
9852
  try {
9726
9853
  await require_retired_settings_keys.purgeRetiredSettingsRows(deviceRows.retiredRowStore(), this.ctx.logger.child("RetiredRows"));
9727
9854
  } catch (err) {