@camstack/system 1.2.375 → 1.2.377

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 (99) hide show
  1. package/dist/addon-runner.js +9 -4
  2. package/dist/addon-runner.mjs +10 -5
  3. package/dist/addon-utils.js +1 -1
  4. package/dist/addon-utils.mjs +1 -1
  5. package/dist/auth/external-identity-manager.d.ts +43 -0
  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/calendars/calendars.addon.js +1 -1
  17. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  18. package/dist/builtins/camera-grid/index.js +1 -1
  19. package/dist/builtins/camera-grid/index.mjs +1 -1
  20. package/dist/builtins/composer/composer.addon.js +2 -2
  21. package/dist/builtins/composer/composer.addon.mjs +2 -2
  22. package/dist/builtins/console-logging/index.js +1 -1
  23. package/dist/builtins/console-logging/index.mjs +1 -1
  24. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  25. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  26. package/dist/builtins/device-manager/device-config-secrets.d.ts +21 -0
  27. package/dist/builtins/device-manager/device-manager.addon.d.ts +2 -0
  28. package/dist/builtins/device-manager/device-manager.addon.js +119 -6
  29. package/dist/builtins/device-manager/device-manager.addon.mjs +119 -6
  30. package/dist/builtins/device-manager/device-projection.d.ts +2 -1
  31. package/dist/builtins/device-manager/device-provider-context.d.ts +3 -0
  32. package/dist/builtins/device-manager/secret-config-paths.d.ts +24 -0
  33. package/dist/builtins/hub-forwarder/index.js +1 -1
  34. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  35. package/dist/builtins/keychain/index.d.ts +1 -0
  36. package/dist/builtins/keychain/index.js +1416 -0
  37. package/dist/builtins/keychain/index.mjs +1409 -0
  38. package/dist/builtins/keychain/key-sources.d.ts +37 -0
  39. package/dist/builtins/keychain/keychain-crypto.d.ts +28 -0
  40. package/dist/builtins/keychain/keychain-service.d.ts +103 -0
  41. package/dist/builtins/keychain/keychain-store.d.ts +82 -0
  42. package/dist/builtins/keychain/keychain-usage.d.ts +6 -0
  43. package/dist/builtins/keychain/keychain.addon.d.ts +11 -0
  44. package/dist/builtins/keychain/platform-key-source.d.ts +24 -0
  45. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  46. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  47. package/dist/builtins/local-auth/auth-schema.d.ts +14 -0
  48. package/dist/builtins/local-auth/local-auth.addon.d.ts +1 -0
  49. package/dist/builtins/local-auth/local-auth.addon.js +1358 -1129
  50. package/dist/builtins/local-auth/local-auth.addon.mjs +1358 -1129
  51. package/dist/builtins/local-network/local-network.addon.js +1 -1
  52. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  53. package/dist/builtins/loki-logging/index.js +1 -1
  54. package/dist/builtins/loki-logging/index.mjs +1 -1
  55. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  56. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  57. package/dist/builtins/platform-probe/index.js +1 -1
  58. package/dist/builtins/platform-probe/index.mjs +1 -1
  59. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  60. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  61. package/dist/builtins/snapshot/index.js +1 -1
  62. package/dist/builtins/snapshot/index.mjs +1 -1
  63. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  64. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  65. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  66. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  67. package/dist/builtins/storage-orchestrator/location-store.d.ts +6 -0
  68. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +15 -0
  69. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +74 -14
  70. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +74 -14
  71. package/dist/builtins/system-config/system-config.addon.js +1 -1
  72. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  73. package/dist/builtins/winston-logging/index.js +1 -1
  74. package/dist/builtins/winston-logging/index.mjs +1 -1
  75. package/dist/{child-cap-dispatch-B9kziY4L.mjs → child-cap-dispatch-CgmOo0yl.mjs} +184 -29
  76. package/dist/{child-cap-dispatch-Bfdgkbq3.js → child-cap-dispatch-DlDSoqm1.js} +212 -27
  77. package/dist/{composition-sources-DYlXX2qW.js → composition-sources-BNyXPSs_.js} +1 -1
  78. package/dist/{composition-sources-BfZgiTYD.mjs → composition-sources-D39bl0nP.mjs} +1 -1
  79. package/dist/{dist-ZdSg09GJ.mjs → dist-BWNoS-1S.mjs} +2454 -108
  80. package/dist/{dist-CNbnikIh.js → dist-D_a9mUiM.js} +2525 -107
  81. package/dist/{event-loop-stall-monitor-DKcYBHdH.mjs → event-loop-stall-monitor-ClPhfx7Y.mjs} +1 -1
  82. package/dist/{event-loop-stall-monitor-CpEH3CoV.js → event-loop-stall-monitor-DuOn8H1n.js} +1 -1
  83. package/dist/{hub-cap-forward-BdT320dq.mjs → hub-cap-forward-CH6_VWVO.mjs} +13 -4
  84. package/dist/{hub-cap-forward-DmHNjbB0.js → hub-cap-forward-COCmYaup.js} +13 -4
  85. package/dist/index.d.ts +2 -0
  86. package/dist/index.js +20 -6
  87. package/dist/index.mjs +13 -7
  88. package/dist/kernel/config-schema.d.ts +4 -0
  89. package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +6 -0
  90. package/dist/kernel/transport/cap-route-resolver.d.ts +19 -0
  91. package/dist/kernel/transport/hub-cap-forward.d.ts +22 -1
  92. package/dist/kernel/transport/index.d.ts +2 -2
  93. package/dist/kernel/transport/local-child-registry.d.ts +4 -3
  94. package/dist/logging/log-redactor.d.ts +9 -0
  95. package/dist/platform-key-source-BWlq0jjn.mjs +23 -0
  96. package/dist/platform-key-source-Di7HrlGR.js +40 -0
  97. package/dist/{retired-settings-keys-CcWvdy6u.js → retired-settings-keys-CDyOGAje.js} +1 -1
  98. package/dist/{retired-settings-keys-B4ZeKrbR.mjs → retired-settings-keys-iGcmzwLV.mjs} +1 -1
  99. package/package.json +17 -1
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_child_cap_dispatch = require("./child-cap-dispatch-Bfdgkbq3.js");
2
+ const require_child_cap_dispatch = require("./child-cap-dispatch-DlDSoqm1.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);
@@ -44,7 +44,8 @@ async function dispatchSettings(addon, addonId, method, args) {
44
44
  case "getGlobalSettings": return typeof addon.getGlobalSettings === "function" ? await addon.getGlobalSettings(args.overlay, args.cap, args.nodeId) ?? null : null;
45
45
  case "updateGlobalSettings":
46
46
  if (typeof addon.updateGlobalSettings !== "function") throw new Error(`child-addon-call: addon "${addonId}" does not implement updateGlobalSettings`);
47
- await addon.updateGlobalSettings(args.patch ?? {}, args.nodeId);
47
+ if (typeof addon.updateGlobalSettingsAsOperator === "function") await addon.updateGlobalSettingsAsOperator(args.patch ?? {}, args.nodeId);
48
+ else await addon.updateGlobalSettings(args.patch ?? {}, args.nodeId);
48
49
  return { success: true };
49
50
  case "getIntegrationSettings": return typeof addon.getIntegrationSettings === "function" ? await addon.getIntegrationSettings(args.nodeId) ?? null : null;
50
51
  case "getDeviceSettings": return typeof addon.getDeviceSettings === "function" && typeof args.deviceId === "number" ? await addon.getDeviceSettings(args.deviceId) ?? null : null;
@@ -85,7 +86,8 @@ function createChildAddonCallDispatch(deps) {
85
86
  if (typeof action !== "string" || action.length === 0) throw new Error(`child-addon-call: addon "${addonId}" custom call missing action name`);
86
87
  const entry = deps.customActions.resolve(addonId, action);
87
88
  if (entry === null) throw new Error(`child-addon-call: addon "${addonId}" has no custom action "${action}"`);
88
- const parsedInput = entry.spec.input.safeParse(call.args);
89
+ const args = deps.resolveSecretViews !== void 0 ? await deps.resolveSecretViews(addonId, call.args) : call.args;
90
+ const parsedInput = entry.spec.input.safeParse(args);
89
91
  if (!parsedInput.success) throw new Error(`child-addon-call: addon "${addonId}" custom action "${action}" rejected its input — ` + parsedInput.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; "));
90
92
  const result = await entry.handler(parsedInput.data, call.caller);
91
93
  return entry.spec.output.parse(result);
@@ -529,11 +531,13 @@ async function main() {
529
531
  isProviderOptionalMethod: (capName, method) => (0, _camstack_types_addon.isProviderOptionalMethodName)(capName, method)
530
532
  })
531
533
  });
534
+ const addonSecrets = /* @__PURE__ */ new Map();
532
535
  udsChildClient.onAddonCall(createChildAddonCallDispatch({
533
536
  getRouteProvider: (addonId) => addonRouteProviders.get(addonId) ?? null,
534
537
  customActions: customActionRegistry,
535
538
  getAddonInstance: (addonId) => loadedAddonInstances.get(addonId) ?? null,
536
- getDataPlanes: (addonId) => addonDataPlanes.get(addonId) ?? []
539
+ getDataPlanes: (addonId) => addonDataPlanes.get(addonId) ?? [],
540
+ resolveSecretViews: (addonId, args) => (0, _camstack_types_addon.resolveSecretViewsIn)(args, addonSecrets.get(addonId))
537
541
  }));
538
542
  const { logger: runnerLog, control: runnerLogControl } = require_child_cap_dispatch.createUdsLoggerWithControl(udsChildClient, runnerId, nodeId, "addon-runner");
539
543
  udsChildClient.onSetLogLevel((level) => {
@@ -574,6 +578,7 @@ async function main() {
574
578
  addonDataPlanes.set(addonId, endpoints);
575
579
  } }
576
580
  });
581
+ if (context.secrets !== void 0) addonSecrets.set(spec.addonId, context.secrets);
577
582
  try {
578
583
  const pkgRaw = JSON.parse(node_fs.readFileSync(node_path.join(spec.addonDir, "package.json"), "utf-8"));
579
584
  await require_child_cap_dispatch.installManifestNativeDeps(spec.addonDir, pkgRaw, context.logger);
@@ -1,10 +1,10 @@
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-B9kziY4L.mjs";
1
+ import { Ft as installManifestNativeDeps, H as createUdsLoggerWithControl, It as resolveAddonClass, St as validateProviderRegistrations, U as LocalChildClient, _n as startRunnerHeapWatch, _t as getWorkerNativeCapProvider, bt as setWorkerNativeCapsChangeListener, f as installManifestSystemDeps, g as createUdsAddonContext, i as killOwnRunnerGroupAfterParentLoss, in as RUNNER_RSS_BUDGET_ENV, kn as emitHeapDiagnosticReport, n as createChildCapDispatch, p as installManifestPythonDeps, u as startRunnerParentDeathWatchdog, vt as getWorkerNativeCapSnapshot } from "./child-cap-dispatch-CgmOo0yl.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";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import * as fs from "node:fs";
7
- import { ReadinessRegistry, ReadinessTimeoutError, errMsg, isCollectionArrayMethodName, isProviderOptionalMethodName, normalizeAddonInitResult } from "@camstack/types/addon";
7
+ import { ReadinessRegistry, ReadinessTimeoutError, errMsg, isCollectionArrayMethodName, isProviderOptionalMethodName, normalizeAddonInitResult, resolveSecretViewsIn } from "@camstack/types/addon";
8
8
  //#region src/kernel/moleculer/child-addon-call-dispatch.ts
9
9
  function isRecord$1(value) {
10
10
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -41,7 +41,8 @@ async function dispatchSettings(addon, addonId, method, args) {
41
41
  case "getGlobalSettings": return typeof addon.getGlobalSettings === "function" ? await addon.getGlobalSettings(args.overlay, args.cap, args.nodeId) ?? null : null;
42
42
  case "updateGlobalSettings":
43
43
  if (typeof addon.updateGlobalSettings !== "function") throw new Error(`child-addon-call: addon "${addonId}" does not implement updateGlobalSettings`);
44
- await addon.updateGlobalSettings(args.patch ?? {}, args.nodeId);
44
+ if (typeof addon.updateGlobalSettingsAsOperator === "function") await addon.updateGlobalSettingsAsOperator(args.patch ?? {}, args.nodeId);
45
+ else await addon.updateGlobalSettings(args.patch ?? {}, args.nodeId);
45
46
  return { success: true };
46
47
  case "getIntegrationSettings": return typeof addon.getIntegrationSettings === "function" ? await addon.getIntegrationSettings(args.nodeId) ?? null : null;
47
48
  case "getDeviceSettings": return typeof addon.getDeviceSettings === "function" && typeof args.deviceId === "number" ? await addon.getDeviceSettings(args.deviceId) ?? null : null;
@@ -82,7 +83,8 @@ function createChildAddonCallDispatch(deps) {
82
83
  if (typeof action !== "string" || action.length === 0) throw new Error(`child-addon-call: addon "${addonId}" custom call missing action name`);
83
84
  const entry = deps.customActions.resolve(addonId, action);
84
85
  if (entry === null) throw new Error(`child-addon-call: addon "${addonId}" has no custom action "${action}"`);
85
- const parsedInput = entry.spec.input.safeParse(call.args);
86
+ const args = deps.resolveSecretViews !== void 0 ? await deps.resolveSecretViews(addonId, call.args) : call.args;
87
+ const parsedInput = entry.spec.input.safeParse(args);
86
88
  if (!parsedInput.success) throw new Error(`child-addon-call: addon "${addonId}" custom action "${action}" rejected its input — ` + parsedInput.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; "));
87
89
  const result = await entry.handler(parsedInput.data, call.caller);
88
90
  return entry.spec.output.parse(result);
@@ -526,11 +528,13 @@ async function main() {
526
528
  isProviderOptionalMethod: (capName, method) => isProviderOptionalMethodName(capName, method)
527
529
  })
528
530
  });
531
+ const addonSecrets = /* @__PURE__ */ new Map();
529
532
  udsChildClient.onAddonCall(createChildAddonCallDispatch({
530
533
  getRouteProvider: (addonId) => addonRouteProviders.get(addonId) ?? null,
531
534
  customActions: customActionRegistry,
532
535
  getAddonInstance: (addonId) => loadedAddonInstances.get(addonId) ?? null,
533
- getDataPlanes: (addonId) => addonDataPlanes.get(addonId) ?? []
536
+ getDataPlanes: (addonId) => addonDataPlanes.get(addonId) ?? [],
537
+ resolveSecretViews: (addonId, args) => resolveSecretViewsIn(args, addonSecrets.get(addonId))
534
538
  }));
535
539
  const { logger: runnerLog, control: runnerLogControl } = createUdsLoggerWithControl(udsChildClient, runnerId, nodeId, "addon-runner");
536
540
  udsChildClient.onSetLogLevel((level) => {
@@ -571,6 +575,7 @@ async function main() {
571
575
  addonDataPlanes.set(addonId, endpoints);
572
576
  } }
573
577
  });
578
+ if (context.secrets !== void 0) addonSecrets.set(spec.addonId, context.secrets);
574
579
  try {
575
580
  const pkgRaw = JSON.parse(fs.readFileSync(path$1.join(spec.addonDir, "package.json"), "utf-8"));
576
581
  await installManifestNativeDeps(spec.addonDir, pkgRaw, context.logger);
@@ -1,6 +1,6 @@
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-CpEH3CoV.js");
3
+ const require_event_loop_stall_monitor = require("./event-loop-stall-monitor-DuOn8H1n.js");
4
4
  const require_custom_action_registry = require("./custom-action-registry-acBY3mHA.js");
5
5
  const require_snapshot_courtesy = require("./snapshot-courtesy-D_C5-nC0.js");
6
6
  exports.COURTESY_DEFAULT_WIDTH = require_snapshot_courtesy.COURTESY_DEFAULT_WIDTH;
@@ -1,4 +1,4 @@
1
- import { C as resolveFormatRevision, S as isModelDownloaded, a as createFileDataPlaneHandler, b as getModelFilePath, c as parseRangeHeader, d as ModelDownloadService, f as ModelDownloadHttpError, g as downloadFile, h as deleteModelFromDisk, i as startEventLoopStallMonitor, m as collectModelFiles, n as STALL_TICK_MS, o as contentTypeFor, p as adoptModelRevisions, r as attributeStall, t as STALL_REPORT_MS, v as ensureModel, x as isModelDownloadHttpError } from "./event-loop-stall-monitor-DKcYBHdH.mjs";
1
+ import { C as resolveFormatRevision, S as isModelDownloaded, a as createFileDataPlaneHandler, b as getModelFilePath, c as parseRangeHeader, d as ModelDownloadService, f as ModelDownloadHttpError, g as downloadFile, h as deleteModelFromDisk, i as startEventLoopStallMonitor, m as collectModelFiles, n as STALL_TICK_MS, o as contentTypeFor, p as adoptModelRevisions, r as attributeStall, t as STALL_REPORT_MS, v as ensureModel, x as isModelDownloadHttpError } from "./event-loop-stall-monitor-ClPhfx7Y.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-CyFs1M3I.mjs";
4
4
  export { COURTESY_DEFAULT_WIDTH, CustomActionRegistry, ModelDownloadHttpError, ModelDownloadService, STALL_REPORT_MS, STALL_TICK_MS, adoptModelRevisions, attributeStall, collectModelFiles, contentTypeFor, courtesyCacheKey, createFileDataPlaneHandler, deleteModelFromDisk, downloadFile, ensureModel, getModelFilePath, isModelDownloadHttpError, isModelDownloaded, parseRangeHeader, renderCourtesyJpeg, renderCourtesyOverlayJpeg, resolveFormatRevision, startEventLoopStallMonitor };
@@ -0,0 +1,43 @@
1
+ import { SettingsStoreClient } from '@camstack/types';
2
+ export interface ExternalIdentityRecord {
3
+ readonly provider: string;
4
+ readonly subject: string;
5
+ /** Verified `iss` the identity was linked under. */
6
+ readonly issuer: string;
7
+ readonly userId: string;
8
+ readonly label?: string;
9
+ readonly linkedAt: number;
10
+ }
11
+ export interface ExternalIdentityKey {
12
+ readonly provider: string;
13
+ readonly subject: string;
14
+ }
15
+ /** The identity is already linked to a different user. */
16
+ export declare class ExternalIdentityConflictError extends Error {
17
+ constructor();
18
+ }
19
+ export declare class ExternalIdentityManager {
20
+ private readonly store;
21
+ constructor(store: SettingsStoreClient);
22
+ private find;
23
+ /** The link of `(provider, subject)`, or `null`. */
24
+ findLink(provider: string, subject: string): Promise<ExternalIdentityRecord | null>;
25
+ /** The user `(provider, subject)` is linked to, or `null`. */
26
+ findUser(provider: string, subject: string): Promise<string | null>;
27
+ listForUser(userId: string): Promise<readonly ExternalIdentityRecord[]>;
28
+ /**
29
+ * Link `(provider, subject)` to `userId`. Idempotent for the same user;
30
+ * {@link ExternalIdentityConflictError} when another user holds it.
31
+ */
32
+ link(input: ExternalIdentityKey & {
33
+ userId: string;
34
+ issuer: string;
35
+ label?: string;
36
+ }): Promise<void>;
37
+ /** Remove one link of `userId`; `false` when that user did not hold it. */
38
+ unlink(input: ExternalIdentityKey & {
39
+ userId: string;
40
+ }): Promise<boolean>;
41
+ /** Delete every link of a user being deleted. Returns how many were removed. */
42
+ removeAllForUser(userId: string): Promise<number>;
43
+ }
@@ -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-CNbnikIh.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.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 { G as addonPagesCapability, Nr as EventCategory, cr as BaseAddon, sr as errMsg } from "../../dist-ZdSg09GJ.mjs";
1
+ import { Gr as EventCategory, W as addonPagesCapability, cr as errMsg, lr as BaseAddon } from "../../dist-BWNoS-1S.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-CNbnikIh.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.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 { Nr as EventCategory, cr as BaseAddon, q as addonWidgetsCapability, sr as errMsg } from "../../dist-ZdSg09GJ.mjs";
1
+ import { Gr as EventCategory, K as addonWidgetsCapability, cr as errMsg, lr as BaseAddon } from "../../dist-BWNoS-1S.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-CNbnikIh.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  //#region src/builtins/alerts/device-label.ts
8
8
  /**
9
9
  * Operator-facing device label for alert messages.
@@ -1,4 +1,4 @@
1
- import { J as alertsCapability, Nr as EventCategory, cr as BaseAddon, n as AlertSchema, sr as errMsg, vr as createEvent } from "../../dist-ZdSg09GJ.mjs";
1
+ import { Gr as EventCategory, Sr as createEvent, cr as errMsg, lr as BaseAddon, n as AlertSchema, q as alertsCapability } from "../../dist-BWNoS-1S.mjs";
2
2
  //#region src/builtins/alerts/device-label.ts
3
3
  /**
4
4
  * Operator-facing device label for alert messages.
@@ -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-CNbnikIh.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.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 { Nr as EventCategory, S as FIRST_LEVEL_MACRO_CLASSES, Z as bareAddonId, cr as BaseAddon, hn as ptzAutotrackCapability, sr as errMsg, wr as isEvent } from "../../dist-ZdSg09GJ.mjs";
1
+ import { Gr as EventCategory, S as FIRST_LEVEL_MACRO_CLASSES, X as bareAddonId, cr as errMsg, gn as ptzAutotrackCapability, kr as isEvent, lr as BaseAddon } from "../../dist-BWNoS-1S.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-CNbnikIh.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.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 { Fn as storageOccupancyCapability, Mr as toNodeId, Nr as EventCategory, Tr as nodePin, X as backupCapability, cr as BaseAddon, g as DATABASE_SNAPSHOT_SUFFIX, tn as mayWriteToLocation } from "../../dist-ZdSg09GJ.mjs";
1
+ import { Gr as EventCategory, In as storageOccupancyCapability, Ur as toNodeId, Y as backupCapability, g as DATABASE_SNAPSHOT_SUFFIX, jr as nodePin, lr as BaseAddon, nn as mayWriteToLocation } from "../../dist-BWNoS-1S.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-CNbnikIh.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let zod = require("zod");
9
9
  //#region src/builtins/calendars/calendar-color.ts
@@ -1,4 +1,4 @@
1
- import { cr as BaseAddon, p as CalendarPreferencesSchema, tt as calendarsCapability } from "../../dist-ZdSg09GJ.mjs";
1
+ import { et as calendarsCapability, lr as BaseAddon, p as CalendarPreferencesSchema } from "../../dist-BWNoS-1S.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/builtins/calendars/calendar-color.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-CNbnikIh.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.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 { Ln as streamCatalogCapability, M as MOTION_CLOSE_AFTER_MS, Mn as snapshotCapability, Nr as EventCategory, Sr as hydrateSchema, an as motionCapability, b as DeclaredDevices, cr as BaseAddon, gt as declarationOwnerNodeId, i as BaseDevice, ir as DeviceFeature, nn as memoizePinnedFfmpeg, nt as cameraGridLayoutCapability, or as DeviceType, qn as buildFfmpegArgs, sr as errMsg, vr as createEvent, y as DERIVED_CAMERA_SILENCED_CAP_NAMES } from "../../dist-ZdSg09GJ.mjs";
1
+ import { Dr as hydrateSchema, Gr as EventCategory, Jn as buildFfmpegArgs, M as MOTION_CLOSE_AFTER_MS, Nn as snapshotCapability, Rn as streamCatalogCapability, Sr as createEvent, ar as DeviceFeature, b as DeclaredDevices, cr as errMsg, i as BaseDevice, lr as BaseAddon, mt as declarationOwnerNodeId, on as motionCapability, rn as memoizePinnedFfmpeg, sr as DeviceType, tt as cameraGridLayoutCapability, y as DERIVED_CAMERA_SILENCED_CAP_NAMES } from "../../dist-BWNoS-1S.mjs";
2
2
  import { z } from "zod";
3
3
  import { FfmpegProcess } from "@camstack/types/node";
4
4
  import { join } from "node:path";
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CNbnikIh.js");
7
- const require_composition_sources = require("../../composition-sources-DYlXX2qW.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
+ const require_composition_sources = require("../../composition-sources-BNyXPSs_.js");
8
8
  let zod = require("zod");
9
9
  //#region src/builtins/shared/device-state-changed.ts
10
10
  /** Structural narrowing helper for untrusted bus payloads. */
@@ -1,5 +1,5 @@
1
- import { $ as buildCapabilityLookup, $n as compositionSliceKey, Jn as cloneStatefulExpressionMemory, Kn as COMPOSER_ADDON_ID, Nr as EventCategory, Ot as evaluateCompositionField, Qn as compositionItemFieldPath, Xn as composedDeviceStableId, Yn as composedDeviceRef, Zn as compositionFeatureEnabled, at as composerCapability, b as DeclaredDevices, cr as BaseAddon, er as compositionSourceKey, fn as planComposition, i as BaseDevice, jt as expressionContainsBuiltinCall, l as COMPOSED_ITEM_FIXED_FIELDS, nr as disarmRoseMemory, or as DeviceType, ot as compositionFieldKey, rr as toExpressionValue, sr as errMsg, t as ALL_CAPABILITY_DEFINITIONS, tr as createStatefulExpressionMemory, vr as createEvent } from "../../dist-ZdSg09GJ.mjs";
2
- import { n as normalizedNativeOwner } from "../../composition-sources-BfZgiTYD.mjs";
1
+ import { $n as compositionItemFieldPath, Et as evaluateCompositionField, Gr as EventCategory, Q as buildCapabilityLookup, Qn as compositionFeatureEnabled, Sr as createEvent, Xn as composedDeviceRef, Yn as cloneStatefulExpressionMemory, Zn as composedDeviceStableId, b as DeclaredDevices, cr as errMsg, er as compositionSliceKey, i as BaseDevice, ir as toExpressionValue, it as compositionFieldKey, kt as expressionContainsBuiltinCall, l as COMPOSED_ITEM_FIXED_FIELDS, lr as BaseAddon, nr as createStatefulExpressionMemory, pn as planComposition, qn as COMPOSER_ADDON_ID, rr as disarmRoseMemory, rt as composerCapability, sr as DeviceType, t as ALL_CAPABILITY_DEFINITIONS, tr as compositionSourceKey } from "../../dist-BWNoS-1S.mjs";
2
+ import { n as normalizedNativeOwner } from "../../composition-sources-D39bl0nP.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/builtins/shared/device-state-changed.ts
5
5
  /** Structural narrowing helper for untrusted bus payloads. */
@@ -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-CNbnikIh.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.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 { Zt as logDestinationCapability, cr as BaseAddon } from "../../dist-ZdSg09GJ.mjs";
1
+ import { Zt as logDestinationCapability, lr as BaseAddon } from "../../dist-BWNoS-1S.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-CNbnikIh.js");
4
- const require_composition_sources = require("../../composition-sources-DYlXX2qW.js");
3
+ const require_dist = require("../../dist-D_a9mUiM.js");
4
+ const require_composition_sources = require("../../composition-sources-BNyXPSs_.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 { $ as buildCapabilityLookup, Bn as validateComposition, Sr as hydrateSchema, Yn as composedDeviceRef, _n as replacedFieldKeys, b as DeclaredDevices, bn as resolveCoreBlockEntry, bt as describeComposableCaps, cr as BaseAddon, ct as coreBlockAddonId, d as CORE_BLOCKS_ADDON_ID, dt as coreBlockSourceKind, er as compositionSourceKey, f as CORE_BLOCK_ADDON_PREFIX, fn as planComposition, ft as coreBlocksCapability, lt as coreBlockComposition, m as CoreBlockSchema, on as normalizeCoreBlockWrite, sr as errMsg, st as compositionSourceRefs, t as ALL_CAPABILITY_DEFINITIONS, u as COMPOSER_RUNNER_ID, ut as coreBlockIdFromAddonId, xn as resolveCoreBlockFiles } from "../../dist-ZdSg09GJ.mjs";
2
- import { t as describeCompositionSources } from "../../composition-sources-BfZgiTYD.mjs";
1
+ import { Dr as hydrateSchema, Q as buildCapabilityLookup, Sn as resolveCoreBlockFiles, Vn as validateComposition, Xn as composedDeviceRef, at as compositionSourceRefs, b as DeclaredDevices, cr as errMsg, ct as coreBlockIdFromAddonId, d as CORE_BLOCKS_ADDON_ID, f as CORE_BLOCK_ADDON_PREFIX, lr as BaseAddon, lt as coreBlockSourceKind, m as CoreBlockSchema, ot as coreBlockAddonId, pn as planComposition, sn as normalizeCoreBlockWrite, st as coreBlockComposition, t as ALL_CAPABILITY_DEFINITIONS, tr as compositionSourceKey, u as COMPOSER_RUNNER_ID, ut as coreBlocksCapability, vn as replacedFieldKeys, vt as describeComposableCaps, xn as resolveCoreBlockEntry } from "../../dist-BWNoS-1S.mjs";
2
+ import { t as describeCompositionSources } from "../../composition-sources-D39bl0nP.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { customizationBlockName } from "@camstack/types/node";
@@ -0,0 +1,21 @@
1
+ import { AddonContext } from '@camstack/types';
2
+ export interface DeviceConfigSecretDeps {
3
+ readonly ctx: AddonContext;
4
+ readonly readStored: () => Promise<Record<string, unknown>>;
5
+ readonly write: (patch: Record<string, unknown>) => Promise<void>;
6
+ }
7
+ /** Persist a device config patch with its declared secrets kept in the keychain. */
8
+ export declare function persistDeviceConfigWithSecrets(deps: DeviceConfigSecretDeps, input: {
9
+ readonly deviceId: number;
10
+ readonly ownerAddonId: string;
11
+ readonly data: Record<string, unknown>;
12
+ readonly secretPaths: readonly string[];
13
+ /** The write was made by the operator (no driver stamped it). */
14
+ readonly operatorWrite: boolean;
15
+ }): Promise<void>;
16
+ /** A stored device config with its markers resolved for the driver. */
17
+ export declare function loadDeviceConfigWithSecrets(ctx: AddonContext, input: {
18
+ readonly deviceId: number;
19
+ readonly ownerAddonId: string;
20
+ readonly stored: Record<string, unknown>;
21
+ }): Promise<Record<string, unknown>>;
@@ -69,6 +69,8 @@ export declare class DeviceManagerAddon extends BaseAddon {
69
69
  * `allocateDeviceId` never consults.
70
70
  */
71
71
  private readonly removalFence;
72
+ /** Declared secret config paths per device, as last registered (D783). */
73
+ private readonly secretConfigPaths;
72
74
  /** The runtime-state mirror, asserted present (constructed in onInitialize). */
73
75
  private get stateMirror();
74
76
  /**
@@ -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-CNbnikIh.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-CcWvdy6u.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-CDyOGAje.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");
@@ -396,6 +396,13 @@ function isDeviceRole(value) {
396
396
  function toDeviceRole(value) {
397
397
  return value != null && isDeviceRole(value) ? value : null;
398
398
  }
399
+ /** The secret paths a live device's config schema declares (D783), as a spreadable field. */
400
+ function liveSecretConfigPaths(device) {
401
+ const schema = device.config?.schema;
402
+ if (schema === void 0 || schema === null || typeof schema !== "object") return {};
403
+ const paths = require_dist.collectZodSecretPaths(schema);
404
+ return paths.length > 0 ? { secretConfigPaths: [...paths] } : {};
405
+ }
399
406
  function toDeviceInfo(addonId, device, metadata = null, metaRow = null) {
400
407
  const configValues = {};
401
408
  for (const entry of device.config.entries()) configValues[entry.key] = entry.value;
@@ -419,6 +426,7 @@ function toDeviceInfo(addonId, device, metadata = null, metaRow = null) {
419
426
  features: device.features.length > 0 ? [...device.features] : persistedFeatures(metaRow?.features),
420
427
  isCamera: isCameraDevice(device),
421
428
  config: configValues,
429
+ ...liveSecretConfigPaths(device),
422
430
  metadata,
423
431
  ...metaRow?.integrationId !== void 0 ? { integrationId: metaRow.integrationId } : {},
424
432
  ...metaRow?.linkDeviceId !== void 0 ? { linkDeviceId: metaRow.linkDeviceId } : {},
@@ -2491,6 +2499,24 @@ function persistedOnlineFallback(input) {
2491
2499
  return Object.keys(input.config ?? {}).length > 0;
2492
2500
  }
2493
2501
  //#endregion
2502
+ //#region src/builtins/device-manager/secret-config-paths.ts
2503
+ function createSecretConfigPathRegistry() {
2504
+ const byDevice = /* @__PURE__ */ new Map();
2505
+ return {
2506
+ get: (deviceId) => byDevice.get(deviceId),
2507
+ set: (deviceId, paths) => {
2508
+ byDevice.set(deviceId, Object.freeze([...new Set(paths)]));
2509
+ },
2510
+ delete: (deviceId) => {
2511
+ byDevice.delete(deviceId);
2512
+ }
2513
+ };
2514
+ }
2515
+ /** `{ secretConfigPaths }` when any are known, `{}` otherwise — spread into a `DeviceInfo`. */
2516
+ function secretConfigPathsField(paths) {
2517
+ return paths !== void 0 && paths.length > 0 ? { secretConfigPaths: [...paths] } : {};
2518
+ }
2519
+ //#endregion
2494
2520
  //#region src/builtins/device-manager/device-queries.ts
2495
2521
  /**
2496
2522
  * The ORIGINATING addon id off a cap-channel call's `args`, or `undefined`.
@@ -2629,6 +2655,7 @@ async function listAll(pctx, input) {
2629
2655
  features: persistedFeatures(m.features),
2630
2656
  isCamera: persistedIsCamera(persistedType),
2631
2657
  config: persistedConfig ?? {},
2658
+ ...secretConfigPathsField(pctx.secretConfigPaths.get(m.id)),
2632
2659
  metadata,
2633
2660
  ...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
2634
2661
  ...m.linkDeviceId !== void 0 ? { linkDeviceId: m.linkDeviceId } : {},
@@ -2678,6 +2705,7 @@ async function getDevice(pctx, input) {
2678
2705
  features: persistedFeatures(m.features),
2679
2706
  isCamera: persistedIsCamera(m.type),
2680
2707
  config: persistedConfig ?? {},
2708
+ ...secretConfigPathsField(pctx.secretConfigPaths.get(deviceId)),
2681
2709
  metadata,
2682
2710
  ...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
2683
2711
  ...m.linkDeviceId !== void 0 ? { linkDeviceId: m.linkDeviceId } : {},
@@ -2754,6 +2782,7 @@ function projectChildren(pctx, parentDeviceId, ownerAddonId, childRows, liveChil
2754
2782
  features: persistedFeatures(m.features),
2755
2783
  isCamera: persistedIsCamera(m.type),
2756
2784
  config: persistedConfig,
2785
+ ...secretConfigPathsField(pctx.secretConfigPaths.get(m.id)),
2757
2786
  metadata,
2758
2787
  ...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
2759
2788
  ...m.linkDeviceId !== void 0 ? { linkDeviceId: m.linkDeviceId } : {},
@@ -5073,6 +5102,69 @@ async function swapHardwareState(settings, sourceId, targetId) {
5073
5102
  };
5074
5103
  }
5075
5104
  //#endregion
5105
+ //#region src/builtins/device-manager/device-config-secrets.ts
5106
+ /**
5107
+ * The device-config door of the keychain (D787) — device CONNECTION config
5108
+ * (camera passwords, controller API keys) lives in device-manager's per-device
5109
+ * store, written by the driver's `persistConfig` and read back by its
5110
+ * `loadConfig`. Resolving HERE, at the door, means no driver ever sees a
5111
+ * marker and no driver has to change.
5112
+ *
5113
+ * - WRITE: the paths the device's own schema declares secret (D783:
5114
+ * `secretConfigPaths`, from the persist call or from its last
5115
+ * `registerDevice`) go through the keychain save path, owned by the DRIVER
5116
+ * addon (`device/<id>` scope). A value equal to an inline pre-keychain one
5117
+ * stays inline (no silent migration); `''` keeps.
5118
+ * - READ: every marker in the stored blob is resolved for the driver; one that
5119
+ * cannot be is LEFT OUT (the driver's schema default applies) and logged by
5120
+ * ref — never answered as `''`, never written back.
5121
+ *
5122
+ * device-manager runs in hub-main, so it acts for the driver through
5123
+ * `ctx.secrets.forOwner` — the in-process delegate no forked addon has.
5124
+ */
5125
+ function ownerSecrets(ctx, ownerAddonId) {
5126
+ const forOwner = ctx.secrets?.forOwner ?? null;
5127
+ return forOwner === null ? null : forOwner(ownerAddonId);
5128
+ }
5129
+ /** Persist a device config patch with its declared secrets kept in the keychain. */
5130
+ async function persistDeviceConfigWithSecrets(deps, input) {
5131
+ const secrets = ownerSecrets(deps.ctx, input.ownerAddonId);
5132
+ const tree = require_dist.secretTreeFromPaths(input.secretPaths);
5133
+ if (secrets === null || tree.size === 0) return deps.write(input.data);
5134
+ const stored = await deps.readStored();
5135
+ const result = await require_dist.transformSecretWrite({
5136
+ tree,
5137
+ secrets,
5138
+ patch: input.data,
5139
+ stored,
5140
+ scope: {
5141
+ kind: "device",
5142
+ deviceId: input.deviceId
5143
+ },
5144
+ operatorWrite: input.operatorWrite
5145
+ });
5146
+ if (Object.keys(result.patch).length > 0) await deps.write(result.patch);
5147
+ const { orphaned } = await result.afterWrite();
5148
+ if (orphaned.length > 0) deps.ctx.logger.warn("device config: dropped keychain refs could not be deleted", {
5149
+ tags: { deviceId: input.deviceId },
5150
+ meta: { refs: [...orphaned] }
5151
+ });
5152
+ }
5153
+ /** A stored device config with its markers resolved for the driver. */
5154
+ async function loadDeviceConfigWithSecrets(ctx, input) {
5155
+ const secrets = ownerSecrets(ctx, input.ownerAddonId);
5156
+ if (secrets === null) return input.stored;
5157
+ const { value, unresolved } = await require_dist.resolveSecretMarkers(input.stored, secrets);
5158
+ if (unresolved.length > 0) ctx.logger.error("device config: secret unavailable — the device starts without it", {
5159
+ tags: { deviceId: input.deviceId },
5160
+ meta: { secrets: unresolved.map((u) => ({
5161
+ ref: u.ref,
5162
+ reason: u.reason
5163
+ })) }
5164
+ });
5165
+ return value;
5166
+ }
5167
+ //#endregion
5076
5168
  //#region src/builtins/device-manager/location-alignment.ts
5077
5169
  /**
5078
5170
  * Location alignment — closes the RETROACTIVITY hole D252/D329 left open, and
@@ -5547,6 +5639,7 @@ async function registerDevice(pctx, input) {
5547
5639
  });
5548
5640
  throw new Error(`[device-manager] registerDevice: device ${id} (${addonId}/${stableId}) was removed — refusing to resurrect it`);
5549
5641
  }
5642
+ if (Array.isArray(input.secretConfigPaths)) pctx.secretConfigPaths.set(id, input.secretConfigPaths);
5550
5643
  const { isFirstRegistration, exportFingerprint, fingerprintChanged, inheritedLocation, inheritedDescendantIds, inheritFailed } = await pctx.metaStore.withMetaWriteLock(async () => {
5551
5644
  const existingRow = await pctx.metaStore.rows.get(id);
5552
5645
  const existingMeta = existingRow?.meta;
@@ -5693,6 +5786,7 @@ async function removeDevice(pctx, input) {
5693
5786
  stableId
5694
5787
  });
5695
5788
  });
5789
+ pctx.secretConfigPaths.delete(deviceId);
5696
5790
  await pctx.settings.clearDeviceStore(deviceId);
5697
5791
  await pctx.host.forgetMirrorDevice(deviceId);
5698
5792
  await pctx.settings.clearDeviceRuntimeState(deviceId);
@@ -5728,13 +5822,29 @@ async function removeDevice(pctx, input) {
5728
5822
  }
5729
5823
  async function persistConfig(pctx, input) {
5730
5824
  const { deviceId, data } = input;
5731
- if (!await pctx.metaStore.resolvePersistedById(deviceId)) throw new Error(`[device-manager] persistConfig: unknown device id=${deviceId}`);
5732
- await pctx.settings.writeDeviceStore(deviceId, data);
5825
+ const persisted = await pctx.metaStore.resolvePersistedById(deviceId);
5826
+ if (!persisted) throw new Error(`[device-manager] persistConfig: unknown device id=${deviceId}`);
5827
+ await persistDeviceConfigWithSecrets({
5828
+ ctx: pctx.host.ctx,
5829
+ readStored: () => pctx.settings.readDeviceStore(deviceId),
5830
+ write: (patch) => pctx.settings.writeDeviceStore(deviceId, patch)
5831
+ }, {
5832
+ deviceId,
5833
+ ownerAddonId: persisted.addonId,
5834
+ data,
5835
+ secretPaths: input.secretConfigPaths ?? pctx.secretConfigPaths.get(deviceId) ?? [],
5836
+ operatorWrite: typeof Reflect.get(input, "callerAddonId") !== "string"
5837
+ });
5733
5838
  }
5734
5839
  async function loadConfig(pctx, input) {
5735
5840
  const { deviceId } = input;
5736
- if (!await pctx.metaStore.resolvePersistedById(deviceId)) return {};
5737
- return pctx.settings.readDeviceStore(deviceId);
5841
+ const persisted = await pctx.metaStore.resolvePersistedById(deviceId);
5842
+ if (!persisted) return {};
5843
+ return loadDeviceConfigWithSecrets(pctx.host.ctx, {
5844
+ deviceId,
5845
+ ownerAddonId: persisted.addonId,
5846
+ stored: await pctx.settings.readDeviceStore(deviceId)
5847
+ });
5738
5848
  }
5739
5849
  /**
5740
5850
  * Load the operator-organisational meta surface for one device
@@ -9605,6 +9715,8 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
9605
9715
  * `allocateDeviceId` never consults.
9606
9716
  */
9607
9717
  removalFence = createRemovalFence();
9718
+ /** Declared secret config paths per device, as last registered (D783). */
9719
+ secretConfigPaths = createSecretConfigPathRegistry();
9608
9720
  /** The runtime-state mirror, asserted present (constructed in onInitialize). */
9609
9721
  get stateMirror() {
9610
9722
  if (!this.stateMirrorImpl) throw new Error("DeviceManagerAddon: state mirror accessed before onInitialize");
@@ -9846,6 +9958,7 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
9846
9958
  bindingsDeps: this.bindingsDeps,
9847
9959
  migrationGuard: createMigrationGuard(),
9848
9960
  removalFence: this.removalFence,
9961
+ secretConfigPaths: this.secretConfigPaths,
9849
9962
  requireDeviceOps,
9850
9963
  stampIntegrationId: stampIntegrationId$1,
9851
9964
  get provider() {