@camstack/system 1.2.303 → 1.2.305

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 (71) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/addon-utils.d.ts +1 -1
  4. package/dist/addon-utils.js +3 -1
  5. package/dist/addon-utils.mjs +2 -2
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  7. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  9. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  10. package/dist/builtins/alerts/alerts.addon.js +1 -1
  11. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  12. package/dist/builtins/autotrack/index.js +1 -1
  13. package/dist/builtins/autotrack/index.mjs +1 -1
  14. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  15. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  16. package/dist/builtins/camera-grid/index.js +1 -1
  17. package/dist/builtins/camera-grid/index.mjs +1 -1
  18. package/dist/builtins/console-logging/index.js +1 -1
  19. package/dist/builtins/console-logging/index.mjs +1 -1
  20. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  21. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  22. package/dist/builtins/device-manager/device-extension-linked-slot.d.ts +8 -0
  23. package/dist/builtins/device-manager/device-linked-devices.d.ts +34 -0
  24. package/dist/builtins/device-manager/device-manager.addon.js +188 -22
  25. package/dist/builtins/device-manager/device-manager.addon.mjs +188 -22
  26. package/dist/builtins/doorbell/binding-mirror.d.ts +24 -0
  27. package/dist/builtins/doorbell/doorbell-extension-slot.d.ts +66 -0
  28. package/dist/builtins/doorbell/virtual-doorbell.addon.d.ts +14 -0
  29. package/dist/builtins/doorbell/virtual-doorbell.addon.js +307 -38
  30. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +307 -38
  31. package/dist/builtins/hub-forwarder/index.js +1 -1
  32. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  33. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  34. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  35. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  36. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  37. package/dist/builtins/local-network/local-network.addon.js +1 -1
  38. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  39. package/dist/builtins/loki-logging/index.js +1 -1
  40. package/dist/builtins/loki-logging/index.mjs +1 -1
  41. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  42. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  43. package/dist/builtins/platform-probe/index.js +3 -3
  44. package/dist/builtins/platform-probe/index.mjs +3 -3
  45. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  46. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  47. package/dist/builtins/snapshot/index.js +1 -1
  48. package/dist/builtins/snapshot/index.mjs +1 -1
  49. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  50. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  51. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  52. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  53. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  54. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  55. package/dist/builtins/system-config/system-config.addon.js +1 -1
  56. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  57. package/dist/builtins/winston-logging/index.js +1 -1
  58. package/dist/builtins/winston-logging/index.mjs +1 -1
  59. package/dist/{child-cap-dispatch-C1c3rWaX.mjs → child-cap-dispatch-BCJjUtXV.mjs} +9 -1
  60. package/dist/{child-cap-dispatch-De5_HcvR.js → child-cap-dispatch-Be8e2cBP.js} +9 -1
  61. package/dist/{dist-DzHjDpU7.js → dist-BK4iP6ab.js} +2700 -1583
  62. package/dist/{dist-FwpS07w3.mjs → dist-Df1NhKxm.mjs} +2677 -1584
  63. package/dist/download/model-downloader.d.ts +15 -0
  64. package/dist/{event-loop-stall-monitor-GPrVvx14.mjs → event-loop-stall-monitor-EXjzIxDz.mjs} +25 -3
  65. package/dist/{event-loop-stall-monitor-CAsHdMwP.js → event-loop-stall-monitor-ey4mbofz.js} +36 -2
  66. package/dist/index.js +21 -3
  67. package/dist/index.mjs +21 -3
  68. package/dist/kernel/config-manager.d.ts +3 -1
  69. package/dist/{retired-settings-keys-CNcKBSQS.js → retired-settings-keys-DwWMph6F.js} +1 -1
  70. package/dist/{retired-settings-keys-rDPn2MMp.mjs → retired-settings-keys-dC4ckbXJ.mjs} +1 -1
  71. package/package.json +7 -1
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_child_cap_dispatch = require("./child-cap-dispatch-De5_HcvR.js");
2
+ const require_child_cap_dispatch = require("./child-cap-dispatch-Be8e2cBP.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 { B as LocalChildClient, Ct as installManifestNativeDeps, Ht as RUNNER_RSS_BUDGET_ENV, N as createUdsLoggerWithControl, at as getWorkerNativeCapProvider, ct as setWorkerNativeCapsChangeListener, i as installManifestPythonDeps, n as createChildCapDispatch, ot as getWorkerNativeCapSnapshot, pn as emitHeapDiagnosticReport, r as installManifestSystemDeps, s as createUdsAddonContext, tn as startRunnerHeapWatch, ut as validateProviderRegistrations, wt as resolveAddonClass } from "./child-cap-dispatch-C1c3rWaX.mjs";
1
+ import { B as LocalChildClient, Ct as installManifestNativeDeps, Ht as RUNNER_RSS_BUDGET_ENV, N as createUdsLoggerWithControl, at as getWorkerNativeCapProvider, ct as setWorkerNativeCapsChangeListener, i as installManifestPythonDeps, n as createChildCapDispatch, ot as getWorkerNativeCapSnapshot, pn as emitHeapDiagnosticReport, r as installManifestSystemDeps, s as createUdsAddonContext, tn as startRunnerHeapWatch, ut as validateProviderRegistrations, wt as resolveAddonClass } from "./child-cap-dispatch-BCJjUtXV.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";
@@ -14,7 +14,7 @@
14
14
  *
15
15
  * See memory: camstack_runner_ram_and_build_rootcause.
16
16
  */
17
- export { downloadFile, ensureModel, isModelDownloaded, deleteModelFromDisk, collectModelFiles, getModelFilePath, type DownloadFileOptions, type DownloadRedirectPolicy, } from './download/model-downloader.js';
17
+ export { downloadFile, ensureModel, isModelDownloaded, deleteModelFromDisk, collectModelFiles, getModelFilePath, isModelDownloadHttpError, ModelDownloadHttpError, type DownloadFileOptions, type DownloadRedirectPolicy, } from './download/model-downloader.js';
18
18
  export { ModelDownloadService } from './download/model-download-service.js';
19
19
  export { createFileDataPlaneHandler } from './http/file-data-plane.js';
20
20
  export { parseRangeHeader, contentTypeFor, type ByteRange, } from './http/authenticated-file-server.js';
@@ -1,10 +1,11 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("./chunk-Cek0wNdY.js");
3
- const require_event_loop_stall_monitor = require("./event-loop-stall-monitor-CAsHdMwP.js");
3
+ const require_event_loop_stall_monitor = require("./event-loop-stall-monitor-ey4mbofz.js");
4
4
  const require_custom_action_registry = require("./custom-action-registry-acBY3mHA.js");
5
5
  const require_snapshot_courtesy = require("./snapshot-courtesy-Cqs7GkOV.js");
6
6
  exports.COURTESY_DEFAULT_WIDTH = require_snapshot_courtesy.COURTESY_DEFAULT_WIDTH;
7
7
  exports.CustomActionRegistry = require_custom_action_registry.CustomActionRegistry;
8
+ exports.ModelDownloadHttpError = require_event_loop_stall_monitor.ModelDownloadHttpError;
8
9
  exports.ModelDownloadService = require_event_loop_stall_monitor.ModelDownloadService;
9
10
  exports.STALL_REPORT_MS = require_event_loop_stall_monitor.STALL_REPORT_MS;
10
11
  exports.STALL_TICK_MS = require_event_loop_stall_monitor.STALL_TICK_MS;
@@ -17,6 +18,7 @@ exports.deleteModelFromDisk = require_event_loop_stall_monitor.deleteModelFromDi
17
18
  exports.downloadFile = require_event_loop_stall_monitor.downloadFile;
18
19
  exports.ensureModel = require_event_loop_stall_monitor.ensureModel;
19
20
  exports.getModelFilePath = require_event_loop_stall_monitor.getModelFilePath;
21
+ exports.isModelDownloadHttpError = require_event_loop_stall_monitor.isModelDownloadHttpError;
20
22
  exports.isModelDownloaded = require_event_loop_stall_monitor.isModelDownloaded;
21
23
  exports.parseRangeHeader = require_event_loop_stall_monitor.parseRangeHeader;
22
24
  exports.renderCourtesyJpeg = require_snapshot_courtesy.renderCourtesyJpeg;
@@ -1,4 +1,4 @@
1
- import { a as createFileDataPlaneHandler, c as parseRangeHeader, d as ModelDownloadService, f as collectModelFiles, g as ensureModel, i as startEventLoopStallMonitor, m as downloadFile, n as STALL_TICK_MS, o as contentTypeFor, p as deleteModelFromDisk, r as attributeStall, t as STALL_REPORT_MS, v as getModelFilePath, y as isModelDownloaded } from "./event-loop-stall-monitor-GPrVvx14.mjs";
1
+ import { _ as ensureModel, a as createFileDataPlaneHandler, b as isModelDownloadHttpError, c as parseRangeHeader, d as ModelDownloadService, f as ModelDownloadHttpError, h as downloadFile, i as startEventLoopStallMonitor, m as deleteModelFromDisk, n as STALL_TICK_MS, o as contentTypeFor, p as collectModelFiles, r as attributeStall, t as STALL_REPORT_MS, x as isModelDownloaded, y as getModelFilePath } from "./event-loop-stall-monitor-EXjzIxDz.mjs";
2
2
  import { t as CustomActionRegistry } from "./custom-action-registry-B4Cf4O_X.mjs";
3
3
  import { i as renderCourtesyOverlayJpeg, n as courtesyCacheKey, r as renderCourtesyJpeg, t as COURTESY_DEFAULT_WIDTH } from "./snapshot-courtesy-CZPvteq2.mjs";
4
- export { COURTESY_DEFAULT_WIDTH, CustomActionRegistry, ModelDownloadService, STALL_REPORT_MS, STALL_TICK_MS, attributeStall, collectModelFiles, contentTypeFor, courtesyCacheKey, createFileDataPlaneHandler, deleteModelFromDisk, downloadFile, ensureModel, getModelFilePath, isModelDownloaded, parseRangeHeader, renderCourtesyJpeg, renderCourtesyOverlayJpeg, startEventLoopStallMonitor };
4
+ export { COURTESY_DEFAULT_WIDTH, CustomActionRegistry, ModelDownloadHttpError, ModelDownloadService, STALL_REPORT_MS, STALL_TICK_MS, attributeStall, collectModelFiles, contentTypeFor, courtesyCacheKey, createFileDataPlaneHandler, deleteModelFromDisk, downloadFile, ensureModel, getModelFilePath, isModelDownloadHttpError, isModelDownloaded, parseRangeHeader, renderCourtesyJpeg, renderCourtesyOverlayJpeg, startEventLoopStallMonitor };
@@ -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-DzHjDpU7.js");
6
+ const require_dist = require("../../dist-BK4iP6ab.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 { Bn as EventCategory, L as addonPagesCapability, dn as errMsg, pn as BaseAddon } from "../../dist-FwpS07w3.mjs";
1
+ import { L as addonPagesCapability, Wn as EventCategory, _n as BaseAddon, hn as errMsg } from "../../dist-Df1NhKxm.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-DzHjDpU7.js");
6
+ const require_dist = require("../../dist-BK4iP6ab.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 { Bn as EventCategory, dn as errMsg, pn as BaseAddon, z as addonWidgetsCapability } from "../../dist-FwpS07w3.mjs";
1
+ import { Wn as EventCategory, _n as BaseAddon, hn as errMsg, z as addonWidgetsCapability } from "../../dist-Df1NhKxm.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-DzHjDpU7.js");
6
+ const require_dist = require("../../dist-BK4iP6ab.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 { B as alertsCapability, Bn as EventCategory, En as createEvent, dn as errMsg, n as AlertSchema, pn as BaseAddon } from "../../dist-FwpS07w3.mjs";
1
+ import { An as createEvent, B as alertsCapability, Wn as EventCategory, _n as BaseAddon, hn as errMsg, n as AlertSchema } from "../../dist-Df1NhKxm.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-DzHjDpU7.js");
6
+ const require_dist = require("../../dist-BK4iP6ab.js");
7
7
  //#region src/builtins/autotrack/autotrack-config.ts
8
8
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
9
9
  deadZoneFraction: .5,
@@ -1,4 +1,4 @@
1
- import { Bn as EventCategory, Mn as isEvent, U as bareAddonId, Ut as ptzAutotrackCapability, dn as errMsg, g as FIRST_LEVEL_MACRO_CLASSES, pn as BaseAddon } from "../../dist-FwpS07w3.mjs";
1
+ import { In as isEvent, Kt as ptzAutotrackCapability, U as bareAddonId, Wn as EventCategory, _n as BaseAddon, g as FIRST_LEVEL_MACRO_CLASSES, hn as errMsg } from "../../dist-Df1NhKxm.mjs";
2
2
  //#region src/builtins/autotrack/autotrack-config.ts
3
3
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
4
4
  deadZoneFraction: .5,
@@ -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-DzHjDpU7.js");
6
+ const require_dist = require("../../dist-BK4iP6ab.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 { Bn as EventCategory, H as backupCapability, Nt as mayWriteToLocation, pn as BaseAddon, rn as storageOccupancyCapability } from "../../dist-FwpS07w3.mjs";
1
+ import { H as backupCapability, It as mayWriteToLocation, Wn as EventCategory, _n as BaseAddon, on as storageOccupancyCapability } from "../../dist-Df1NhKxm.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-DzHjDpU7.js");
6
+ const require_dist = require("../../dist-BK4iP6ab.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 { An as hydrateSchema, Bn as EventCategory, En as createEvent, It as motionCapability, K as cameraGridLayoutCapability, Q as declarationOwnerNodeId, S as MOTION_CLOSE_AFTER_MS, _n as DeviceFeature, an as streamCatalogCapability, dn as errMsg, en as snapshotCapability, fn as buildFfmpegArgs, i as BaseDevice, m as DeclaredDevices, p as DERIVED_CAMERA_SILENCED_CAP_NAMES, pn as BaseAddon, yn as DeviceType } from "../../dist-FwpS07w3.mjs";
1
+ import { $ as declarationOwnerNodeId, An as createEvent, Cn as DeviceType, K as cameraGridLayoutCapability, Pn as hydrateSchema, S as MOTION_CLOSE_AFTER_MS, Wn as EventCategory, _n as BaseAddon, cn as streamCatalogCapability, gn as buildFfmpegArgs, hn as errMsg, i as BaseDevice, m as DeclaredDevices, p as DERIVED_CAMERA_SILENCED_CAP_NAMES, rn as snapshotCapability, xn as DeviceFeature, zt as motionCapability } from "../../dist-Df1NhKxm.mjs";
2
2
  import { z } from "zod";
3
3
  import { FfmpegProcess } from "@camstack/types/node";
4
4
  import { join } from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-DzHjDpU7.js");
6
+ const require_dist = require("../../dist-BK4iP6ab.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 { kt as logDestinationCapability, pn as BaseAddon } from "../../dist-FwpS07w3.mjs";
1
+ import { Mt as logDestinationCapability, _n as BaseAddon } from "../../dist-Df1NhKxm.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-DzHjDpU7.js");
3
+ const require_dist = require("../../dist-BK4iP6ab.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 { J as coreBlockAddonId, X as coreBlocksCapability, Y as coreBlockIdFromAddonId, c as CORE_BLOCKS_ADDON_ID, dn as errMsg, l as CORE_BLOCK_ADDON_PREFIX, m as DeclaredDevices, pn as BaseAddon, u as CoreBlockSchema } from "../../dist-FwpS07w3.mjs";
1
+ import { J as coreBlockAddonId, X as coreBlocksCapability, Y as coreBlockIdFromAddonId, _n as BaseAddon, c as CORE_BLOCKS_ADDON_ID, hn as errMsg, l as CORE_BLOCK_ADDON_PREFIX, m as DeclaredDevices, u as CoreBlockSchema } from "../../dist-Df1NhKxm.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";
@@ -0,0 +1,8 @@
1
+ import { IDeviceExtensionProvider } from '@camstack/types';
2
+ import { ProviderContext } from './device-provider-context.js';
3
+ /** The routing prefix of this owner's `slotRef`s. */
4
+ export declare const DEVICE_MANAGER_EXTENSION_SOURCE = "device-manager";
5
+ /** The store the slot reads and writes, named (D62). */
6
+ export declare const LINKED_DEVICES_AUTHORITY = "device-manager:_linkedDeviceIds";
7
+ /** Build the `device-extension` provider the device manager registers. */
8
+ export declare function createDeviceManagerExtensionProvider(pctx: ProviderContext): IDeviceExtensionProvider;
@@ -96,3 +96,37 @@ export declare function buildLinkedDevicesContribution(pctx: ProviderContext, de
96
96
  export declare function applyLinkedDevicesPatch(pctx: Pick<ProviderContext, 'settings'>, deviceId: number, patch: Record<string, unknown>): Promise<{
97
97
  success: true;
98
98
  }>;
99
+ /** The one field a pick is judged by. */
100
+ export interface LinkedPickDevice {
101
+ readonly type: string;
102
+ }
103
+ /** What `refusedLinkedPicks` judges: the write, and what it is judged against. */
104
+ export interface LinkedPicksInput {
105
+ readonly selfId: number;
106
+ readonly picked: readonly number[];
107
+ readonly persisted: readonly number[];
108
+ readonly fleet: ReadonlyMap<number, LinkedPickDevice>;
109
+ }
110
+ /** One refused pick, named — the refusal message is built from these. */
111
+ export interface LinkedPickRefusal {
112
+ readonly deviceId: number;
113
+ readonly reason: 'self' | 'container' | 'unknown';
114
+ }
115
+ /**
116
+ * Which NEW picks a linked-devices write must refuse: the camera itself, a
117
+ * container (never a pick — its children are, D356 and the file header), and
118
+ * an id no device has.
119
+ *
120
+ * Only ids that are not ALREADY persisted are judged. A list written before
121
+ * this rule existed may hold a container or a device that has since been
122
+ * deleted; the editor shows those as unavailable / missing, and keeping them
123
+ * is not a new link. Removing them is the operator's call, never this
124
+ * function's (a missing source is shown, never silently dropped).
125
+ *
126
+ * Deliberately NOT applied to the settings-section save
127
+ * (`applyLinkedDevicesPatch` via `DEVICE_STORE_SECTIONS`): that surface has
128
+ * never refused, its picker never offers a container, and the Locations page
129
+ * writes the list through it. Slice 1 changes no behaviour on the old path;
130
+ * both paths persist through `applyLinkedDevicesPatch`.
131
+ */
132
+ export declare function refusedLinkedPicks(params: LinkedPicksInput): readonly LinkedPickRefusal[];
@@ -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-DzHjDpU7.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-CNcKBSQS.js");
6
+ const require_dist = require("../../dist-BK4iP6ab.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-DwWMph6F.js");
8
8
  let node_crypto = require("node:crypto");
9
9
  let _camstack_types_node = require("@camstack/types/node");
10
10
  //#region src/builtins/device-manager/adoption-job-engine.ts
@@ -2942,6 +2942,47 @@ async function applyLinkedDevicesPatch(pctx, deviceId, patch) {
2942
2942
  await pctx.settings.writeDeviceStore(deviceId, next);
2943
2943
  return { success: true };
2944
2944
  }
2945
+ /**
2946
+ * Which NEW picks a linked-devices write must refuse: the camera itself, a
2947
+ * container (never a pick — its children are, D356 and the file header), and
2948
+ * an id no device has.
2949
+ *
2950
+ * Only ids that are not ALREADY persisted are judged. A list written before
2951
+ * this rule existed may hold a container or a device that has since been
2952
+ * deleted; the editor shows those as unavailable / missing, and keeping them
2953
+ * is not a new link. Removing them is the operator's call, never this
2954
+ * function's (a missing source is shown, never silently dropped).
2955
+ *
2956
+ * Deliberately NOT applied to the settings-section save
2957
+ * (`applyLinkedDevicesPatch` via `DEVICE_STORE_SECTIONS`): that surface has
2958
+ * never refused, its picker never offers a container, and the Locations page
2959
+ * writes the list through it. Slice 1 changes no behaviour on the old path;
2960
+ * both paths persist through `applyLinkedDevicesPatch`.
2961
+ */
2962
+ function refusedLinkedPicks(params) {
2963
+ const kept = new Set(params.persisted);
2964
+ const out = [];
2965
+ for (const deviceId of params.picked) {
2966
+ if (kept.has(deviceId)) continue;
2967
+ if (deviceId === params.selfId) {
2968
+ out.push({
2969
+ deviceId,
2970
+ reason: "self"
2971
+ });
2972
+ continue;
2973
+ }
2974
+ const device = params.fleet.get(deviceId);
2975
+ if (device === void 0) out.push({
2976
+ deviceId,
2977
+ reason: "unknown"
2978
+ });
2979
+ else if (device.type === require_dist.DeviceType.Container) out.push({
2980
+ deviceId,
2981
+ reason: "container"
2982
+ });
2983
+ }
2984
+ return out;
2985
+ }
2945
2986
  //#endregion
2946
2987
  //#region src/builtins/device-manager/device-store-sections.ts
2947
2988
  /** The device-manager's device-store-backed sections. Add an entry to extend. */
@@ -3931,6 +3972,124 @@ var DeviceEventPropagator = class {
3931
3972
  return chain;
3932
3973
  }
3933
3974
  };
3975
+ //#endregion
3976
+ //#region src/builtins/device-manager/device-extension-linked-slot.ts
3977
+ /** The routing prefix of this owner's `slotRef`s. */
3978
+ var DEVICE_MANAGER_EXTENSION_SOURCE = "device-manager";
3979
+ /** The store the slot reads and writes, named (D62). */
3980
+ var LINKED_DEVICES_AUTHORITY = `device-manager:${LINKED_IDS_CONFIG_KEY}`;
3981
+ /**
3982
+ * The picked ids' ledger rows, in ONE indexed read of the device manager's own
3983
+ * store (`rows.getMany`) — never the whole fleet to label a handful of ids.
3984
+ * An id no device has is absent from the map.
3985
+ */
3986
+ async function pickedDevices(pctx, ids) {
3987
+ const rows = await pctx.metaStore.rows.getMany(ids);
3988
+ const out = /* @__PURE__ */ new Map();
3989
+ for (const [id, row] of rows) out.set(id, {
3990
+ name: row.meta.name,
3991
+ type: row.meta.type
3992
+ });
3993
+ return out;
3994
+ }
3995
+ /** What a camera's picked id is, said once for the editor. */
3996
+ function sourceOf(deviceId, byId) {
3997
+ const device = byId.get(deviceId);
3998
+ if (device === void 0) return {
3999
+ deviceId,
4000
+ name: null,
4001
+ health: "missing",
4002
+ detail: "No device has this id any more — it links nothing until removed."
4003
+ };
4004
+ if (device.type === require_dist.DeviceType.Container) return {
4005
+ deviceId,
4006
+ name: device.name,
4007
+ health: "unavailable",
4008
+ detail: "A container is never a pick (D356): its children are linked in its place. Pick the children instead."
4009
+ };
4010
+ return {
4011
+ deviceId,
4012
+ name: device.name,
4013
+ health: "ok"
4014
+ };
4015
+ }
4016
+ function describeRefusal(deviceId, reason) {
4017
+ if (reason === "self") return `${deviceId} is the camera itself`;
4018
+ if (reason === "container") return `${deviceId} is a container — pick its children`;
4019
+ return `${deviceId} is not a device`;
4020
+ }
4021
+ async function fleetOf(pctx) {
4022
+ const all = await listAll(pctx, LINK_CANDIDATE_PROJECTION);
4023
+ return new Map(all.map((d) => [d.id, d]));
4024
+ }
4025
+ function candidatesFor(deviceId, byId) {
4026
+ const location = byId.get(deviceId)?.location ?? null;
4027
+ const out = [];
4028
+ for (const device of byId.values()) {
4029
+ if (device.id === deviceId) continue;
4030
+ if (device.parentDeviceId === deviceId) continue;
4031
+ if (device.type === require_dist.DeviceType.Container) continue;
4032
+ const suggested = location !== null && device.location === location;
4033
+ const parent = device.parentDeviceId === null ? void 0 : byId.get(device.parentDeviceId);
4034
+ out.push({
4035
+ deviceId: device.id,
4036
+ name: device.name,
4037
+ type: device.type,
4038
+ location: device.location,
4039
+ parentName: parent?.name ?? null,
4040
+ suggested,
4041
+ reason: suggested ? "same location" : null
4042
+ });
4043
+ }
4044
+ return out.toSorted((a, b) => Number(b.suggested) - Number(a.suggested) || a.name.localeCompare(b.name));
4045
+ }
4046
+ /** Build the `device-extension` provider the device manager registers. */
4047
+ function createDeviceManagerExtensionProvider(pctx) {
4048
+ return require_dist.createDeviceExtensionProvider({
4049
+ source: DEVICE_MANAGER_EXTENSION_SOURCE,
4050
+ label: "Device manager",
4051
+ slots: [require_dist.defineExtensionSlotProvider("linked-devices", {
4052
+ list: async (deviceId) => {
4053
+ const { manualIds } = parseLinkedDevicesConfig(await pctx.settings.readDeviceStore(deviceId));
4054
+ const byId = await pickedDevices(pctx, manualIds);
4055
+ return {
4056
+ authority: LINKED_DEVICES_AUTHORITY,
4057
+ enabled: null,
4058
+ activation: null,
4059
+ value: {
4060
+ slot: "linked-devices",
4061
+ deviceIds: [...manualIds]
4062
+ },
4063
+ sources: manualIds.map((id) => sourceOf(id, byId))
4064
+ };
4065
+ },
4066
+ set: async (deviceId, value) => {
4067
+ const [byId, blob] = await Promise.all([pickedDevices(pctx, value.deviceIds), pctx.settings.readDeviceStore(deviceId)]);
4068
+ const refused = refusedLinkedPicks({
4069
+ selfId: deviceId,
4070
+ picked: value.deviceIds,
4071
+ persisted: parseLinkedDevicesConfig(blob).manualIds,
4072
+ fleet: byId
4073
+ });
4074
+ if (refused.length > 0) {
4075
+ pctx.host.ctx.logger.warn("linked-devices: write refused — nothing persisted", {
4076
+ tags: { deviceId },
4077
+ meta: { refused }
4078
+ });
4079
+ throw new Error(`linked-devices on ${deviceId}: refused — ` + refused.map((r) => describeRefusal(r.deviceId, r.reason)).join("; "));
4080
+ }
4081
+ await applyLinkedDevicesPatch(pctx, deviceId, { [LINKED_IDS_CONFIG_KEY]: value.deviceIds });
4082
+ return {
4083
+ applied: true,
4084
+ reload: "none"
4085
+ };
4086
+ },
4087
+ candidates: async (deviceId) => candidatesFor(deviceId, await fleetOf(pctx))
4088
+ })],
4089
+ hostTypeOf: async (deviceId) => (await pctx.metaStore.resolvePersistedById(deviceId))?.meta.type ?? null,
4090
+ logger: pctx.host.ctx.logger
4091
+ });
4092
+ }
3934
4093
  /** A refusal that names a switch the camera does not offer, rather than one it
3935
4094
  * could not be asked about. The cap documents rejecting the former; anything
3936
4095
  * else is treated as the camera being out of reach, which is the safe reading:
@@ -8049,28 +8208,35 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
8049
8208
  this.propagator.start();
8050
8209
  this.ctx.logger.info("device-event-propagator started");
8051
8210
  }
8052
- return [{
8053
- capability: require_dist.deviceManagerCapability,
8054
- provider
8055
- }, {
8056
- capability: require_dist.deviceStateCapability,
8057
- provider: {
8058
- getSnapshot: async (input) => {
8059
- return stateMirror.snapshotForDevice(input.deviceId);
8060
- },
8061
- getCapSlice: async (input) => {
8062
- return stateMirror.capSlice(input.deviceId, input.capName);
8063
- },
8064
- getAllSnapshots: async () => {
8065
- return stateMirror.allSnapshots();
8066
- },
8067
- setCapSlice: async (input) => {
8068
- const { deviceId, capName, slice } = input;
8069
- if (!await resolvePersistedById(deviceId)) throw new Error(`[device-manager] setCapSlice: unknown device id=${deviceId}`);
8070
- if (stateMirror.applySingleCapUpdate(deviceId, capName, slice)) stateMirror.scheduleRuntimeStateDiskWrite(deviceId, settings, capName);
8211
+ return [
8212
+ {
8213
+ capability: require_dist.deviceManagerCapability,
8214
+ provider
8215
+ },
8216
+ {
8217
+ capability: require_dist.deviceStateCapability,
8218
+ provider: {
8219
+ getSnapshot: async (input) => {
8220
+ return stateMirror.snapshotForDevice(input.deviceId);
8221
+ },
8222
+ getCapSlice: async (input) => {
8223
+ return stateMirror.capSlice(input.deviceId, input.capName);
8224
+ },
8225
+ getAllSnapshots: async () => {
8226
+ return stateMirror.allSnapshots();
8227
+ },
8228
+ setCapSlice: async (input) => {
8229
+ const { deviceId, capName, slice } = input;
8230
+ if (!await resolvePersistedById(deviceId)) throw new Error(`[device-manager] setCapSlice: unknown device id=${deviceId}`);
8231
+ if (stateMirror.applySingleCapUpdate(deviceId, capName, slice)) stateMirror.scheduleRuntimeStateDiskWrite(deviceId, settings, capName);
8232
+ }
8071
8233
  }
8234
+ },
8235
+ {
8236
+ capability: require_dist.deviceExtensionCapability,
8237
+ provider: createDeviceManagerExtensionProvider(pctx)
8072
8238
  }
8073
- }];
8239
+ ];
8074
8240
  }
8075
8241
  async onShutdown() {
8076
8242
  this.propagator?.stop();