@camstack/system 1.2.377 → 1.2.379

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 (93) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/addon-utils.js +1 -1
  4. package/dist/addon-utils.mjs +1 -1
  5. package/dist/auth/auth-manager.d.ts +10 -2
  6. package/dist/auth/jwt-signing-key.d.ts +42 -0
  7. package/dist/auth/user-manager.d.ts +19 -19
  8. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  9. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  10. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  11. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  12. package/dist/builtins/alerts/alerts.addon.js +1 -1
  13. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  14. package/dist/builtins/autotrack/index.js +1 -1
  15. package/dist/builtins/autotrack/index.mjs +1 -1
  16. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  17. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  18. package/dist/builtins/calendars/calendars.addon.js +1 -1
  19. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  20. package/dist/builtins/camera-grid/index.js +1 -1
  21. package/dist/builtins/camera-grid/index.mjs +1 -1
  22. package/dist/builtins/composer/composer.addon.js +2 -2
  23. package/dist/builtins/composer/composer.addon.mjs +2 -2
  24. package/dist/builtins/console-logging/index.js +1 -1
  25. package/dist/builtins/console-logging/index.mjs +1 -1
  26. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  27. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  28. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  29. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  30. package/dist/builtins/hub-forwarder/index.js +1 -1
  31. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  32. package/dist/builtins/keychain/index.js +67 -11
  33. package/dist/builtins/keychain/index.mjs +67 -11
  34. package/dist/builtins/keychain/keychain-service.d.ts +14 -2
  35. package/dist/builtins/keychain/system-held-secrets.d.ts +11 -0
  36. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  37. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  38. package/dist/builtins/local-auth/admin-account-boot.d.ts +1 -1
  39. package/dist/builtins/local-auth/auth-config-reader.d.ts +9 -7
  40. package/dist/builtins/local-auth/jwt-signing-key-keeper.d.ts +30 -0
  41. package/dist/builtins/local-auth/local-auth.addon.d.ts +2 -6
  42. package/dist/builtins/local-auth/local-auth.addon.js +127 -221
  43. package/dist/builtins/local-auth/local-auth.addon.mjs +126 -220
  44. package/dist/builtins/local-network/local-network.addon.js +1 -1
  45. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  46. package/dist/builtins/loki-logging/index.js +1 -1
  47. package/dist/builtins/loki-logging/index.mjs +1 -1
  48. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  49. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  50. package/dist/builtins/platform-probe/index.js +1 -1
  51. package/dist/builtins/platform-probe/index.mjs +1 -1
  52. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  53. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  54. package/dist/builtins/snapshot/index.js +1 -1
  55. package/dist/builtins/snapshot/index.mjs +1 -1
  56. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  57. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  58. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  59. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  60. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  61. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  62. package/dist/builtins/system-config/cluster-secret-keeper.d.ts +36 -0
  63. package/dist/builtins/system-config/system-config.addon.d.ts +13 -0
  64. package/dist/builtins/system-config/system-config.addon.js +244 -53
  65. package/dist/builtins/system-config/system-config.addon.mjs +244 -54
  66. package/dist/builtins/winston-logging/index.js +1 -1
  67. package/dist/builtins/winston-logging/index.mjs +1 -1
  68. package/dist/{child-cap-dispatch-DlDSoqm1.js → child-cap-dispatch-CZeRUgYF.js} +1 -1
  69. package/dist/{child-cap-dispatch-CgmOo0yl.mjs → child-cap-dispatch-CpjohToR.mjs} +1 -1
  70. package/dist/cluster-secret-BDue-uJj.mjs +83 -0
  71. package/dist/cluster-secret-Dg0OOOSr.js +148 -0
  72. package/dist/{composition-sources-BNyXPSs_.js → composition-sources-CHvLMrFI.js} +1 -1
  73. package/dist/{composition-sources-D39bl0nP.mjs → composition-sources-DT_uJwI3.mjs} +1 -1
  74. package/dist/{dist-BWNoS-1S.mjs → dist-B9oFw2jh.mjs} +200 -3
  75. package/dist/{dist-D_a9mUiM.js → dist-Cc6KOdY-.js} +211 -2
  76. package/dist/{event-loop-stall-monitor-ClPhfx7Y.mjs → event-loop-stall-monitor-anUH2IE1.mjs} +21 -20
  77. package/dist/{event-loop-stall-monitor-DuOn8H1n.js → event-loop-stall-monitor-mk6WGxir.js} +21 -20
  78. package/dist/index.d.ts +4 -2
  79. package/dist/index.js +192 -62
  80. package/dist/index.mjs +171 -55
  81. package/dist/jwt-signing-key-C2rE3wH6.js +174 -0
  82. package/dist/jwt-signing-key-Qhde8r82.mjs +127 -0
  83. package/dist/kernel/config-manager.d.ts +1 -1
  84. package/dist/kernel/config-schema.d.ts +4 -11
  85. package/dist/kernel/index.d.ts +2 -1
  86. package/dist/kernel/moleculer/broker-factory.d.ts +0 -2
  87. package/dist/kernel/moleculer/cluster-secret.d.ts +31 -0
  88. package/dist/kernel/moleculer/hub-service.d.ts +7 -4
  89. package/dist/kernel/moleculer/node-registry.d.ts +1 -1
  90. package/dist/kernel/system-settings-policy.d.ts +7 -9
  91. package/dist/{retired-settings-keys-iGcmzwLV.mjs → retired-settings-keys-DlZ3VV6x.mjs} +1 -1
  92. package/dist/{retired-settings-keys-CDyOGAje.js → retired-settings-keys-YOOKLA3v.js} +1 -1
  93. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_child_cap_dispatch = require("./child-cap-dispatch-DlDSoqm1.js");
2
+ const require_child_cap_dispatch = require("./child-cap-dispatch-CZeRUgYF.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 { 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";
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-CpjohToR.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";
@@ -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-DuOn8H1n.js");
3
+ const require_event_loop_stall_monitor = require("./event-loop-stall-monitor-mk6WGxir.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-ClPhfx7Y.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-anUH2IE1.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 };
@@ -1,5 +1,6 @@
1
1
  import { IScopedLogger, TokenPayload, SsoBridgeClaimsSchema } from '@camstack/types';
2
2
  import { z } from 'zod';
3
+ import { JwtSigningKeySource } from './jwt-signing-key.js';
3
4
  export type { TokenPayload };
4
5
  export type AuthConfigReader = {
5
6
  /**
@@ -13,7 +14,7 @@ export type AuthConfigReader = {
13
14
  };
14
15
  export declare class AuthManager {
15
16
  private readonly config;
16
- private readonly jwtSecret;
17
+ private readonly signingKey;
17
18
  private readonly logger;
18
19
  /**
19
20
  * Offending `auth.tokenExpiry` values already reported by this instance.
@@ -25,7 +26,14 @@ export declare class AuthManager {
25
26
  * rest resolve silently to the same default until the value changes.
26
27
  */
27
28
  private readonly reportedInvalidExpiries;
28
- constructor(config: AuthConfigReader, logger?: IScopedLogger);
29
+ /**
30
+ * @param signingKey where the session signing key comes from — the process
31
+ * slot `local-auth` fills from the keychain (D797). Never config, never
32
+ * env; read on every mint and verify, and it THROWS while unavailable.
33
+ */
34
+ constructor(config: AuthConfigReader, logger?: IScopedLogger, signingKey?: JwtSigningKeySource);
35
+ /** The current signing key; throws `JwtSigningKeyUnavailableError` while there is none. */
36
+ private get jwtSecret();
29
37
  signToken(payload: Omit<TokenPayload, 'iat' | 'exp'>): string;
30
38
  /**
31
39
  * The operator's `auth.tokenExpiry`, or `undefined` → DEFAULT_TOKEN_EXPIRY.
@@ -0,0 +1,42 @@
1
+ import { SecretsAccess } from '@camstack/types';
2
+ /** The keychain owner of every system-held secret. */
3
+ export declare const SYSTEM_SECRET_OWNER = "system";
4
+ /** `secret://system/global/jwtSigningKey`. */
5
+ export declare const JWT_SIGNING_KEY_REF: string;
6
+ export type JwtSigningKeyState = {
7
+ readonly state: 'ready';
8
+ readonly key: string;
9
+ } | {
10
+ readonly state: 'unavailable';
11
+ readonly reason: string;
12
+ };
13
+ /** Sessions cannot be minted or verified: the signing key is not loaded. */
14
+ export declare class JwtSigningKeyUnavailableError extends Error {
15
+ readonly reason: string;
16
+ constructor(reason: string);
17
+ }
18
+ /** Where an `AuthManager` gets its key. `current()` throws while there is none. */
19
+ export interface JwtSigningKeySource {
20
+ current(): string;
21
+ }
22
+ /** Register the loaded (or unloadable) key. Called by the hub's `local-auth`. */
23
+ export declare function setProcessJwtSigningKey(state: JwtSigningKeyState): void;
24
+ /** Forget the key (tests, shutdown). */
25
+ export declare function clearProcessJwtSigningKey(): void;
26
+ export declare function getProcessJwtSigningKeyState(): JwtSigningKeyState;
27
+ /** The process slot — the default source of every `AuthManager`. */
28
+ export declare const processJwtSigningKey: JwtSigningKeySource;
29
+ /** A fixed key — tests, and nothing else. */
30
+ export declare function staticJwtSigningKey(key: string): JwtSigningKeySource;
31
+ /** 32 random bytes, hex. */
32
+ export declare function generateJwtSigningKey(): string;
33
+ export interface LoadJwtSigningKeyDeps {
34
+ /** A keychain handle acting for owner `system`. */
35
+ readonly secrets: SecretsAccess;
36
+ readonly generate?: () => string;
37
+ }
38
+ /**
39
+ * Read the key from the keychain; generate and store one ONLY when the
40
+ * keychain answers that none exists. Never throws.
41
+ */
42
+ export declare function loadJwtSigningKey(deps: LoadJwtSigningKeyDeps): Promise<JwtSigningKeyState>;
@@ -10,14 +10,20 @@ interface CreateUserInput {
10
10
  scopes?: TokenScope[];
11
11
  }
12
12
  type UpdatableUserFields = Partial<Pick<UserRecord, 'isAdmin' | 'allowedProviders' | 'allowedDevices' | 'scopes'>>;
13
+ /**
14
+ * The account a fresh hub seeds on its first boot (D797). Not configurable —
15
+ * no env variable, no config.yaml key: the first sign-in with this password
16
+ * forces a change (admin-ui `mustChangePassword`), and an existing user is
17
+ * never overwritten (D728).
18
+ */
19
+ export declare const FIRST_BOOT_ADMIN_USERNAME = "admin";
20
+ export declare const FIRST_BOOT_ADMIN_PASSWORD = "changeme";
13
21
  export interface EnsureAdminOptions {
14
22
  /** The operator's explicit, one-shot recovery request. Never a default. */
15
23
  readonly resetPassword?: boolean;
16
24
  }
17
25
  /** What `ensureAdminExists` did — every branch is named so the caller can log it. */
18
26
  export type AdminSeedOutcome = {
19
- readonly kind: 'not-configured';
20
- } | {
21
27
  readonly kind: 'seeded';
22
28
  readonly username: string;
23
29
  } | {
@@ -33,15 +39,10 @@ export type AdminSeedOutcome = {
33
39
  export interface UserStorageAccess {
34
40
  getStore(): SettingsStoreClient;
35
41
  }
36
- export interface UserConfigReader {
37
- /** See `AuthConfigReader.get` — a reader answers only the paths it resolved. */
38
- get<T>(path: string): T | undefined;
39
- }
40
42
  export declare class UserManager {
41
43
  private readonly storageAccess;
42
44
  private readonly auth;
43
- private readonly config;
44
- constructor(storageAccess: UserStorageAccess, auth: AuthManager, config: UserConfigReader);
45
+ constructor(storageAccess: UserStorageAccess, auth: AuthManager);
45
46
  private get store();
46
47
  create(input: CreateUserInput): Promise<UserRecord>;
47
48
  findByUsername(username: string): Promise<UserRecord | null>;
@@ -52,20 +53,19 @@ export declare class UserManager {
52
53
  delete(id: string): Promise<void>;
53
54
  resetPassword(id: string, newPassword: string): Promise<void>;
54
55
  /**
55
- * Seed the configured admin (`auth.adminUsername` / `auth.adminPassword`,
56
- * i.e. `CAMSTACK_ADMIN_USER` / `CAMSTACK_ADMIN_PASS`) — on FIRST boot only.
56
+ * Seed {@link FIRST_BOOT_ADMIN_USERNAME} / {@link FIRST_BOOT_ADMIN_PASSWORD}
57
+ * — on FIRST boot only, i.e. when no admin account exists.
57
58
  *
58
- * The configured password is a seed, never an authority. Once any admin
59
- * exists, this never writes a password: the operator's own change in the
60
- * admin UI is the truth from then on. This method used to compare the stored
61
- * hash with the configured password on every boot and rewrite it when they
62
- * differed, so a password changed in the UI went back to the configured one
63
- * (`changeme` on a Mac hub and on any container without `CAMSTACK_ADMIN_PASS`)
64
- * at the next restart.
59
+ * The seed is never an authority. Once any admin exists, this never writes a
60
+ * password: the operator's own change in the admin UI is the truth from then
61
+ * on (D728). This method once compared the stored hash with a configured
62
+ * password on every boot and rewrote it when they differed, so a password
63
+ * changed in the UI went back at the next restart.
65
64
  *
66
65
  * `resetPassword: true` is the one explicit exception — the operator's
67
- * one-shot recovery request (see `admin-password-reset.ts`): the configured
68
- * admin's password is set back to the configured one.
66
+ * one-shot recovery request (`RESET_ADMIN_PASSWORD`, see
67
+ * `admin-account-boot.ts`): the `admin` user's password goes back to
68
+ * `changeme`, and the next sign-in forces a change again.
69
69
  */
70
70
  ensureAdminExists(options?: EnsureAdminOptions): Promise<AdminSeedOutcome>;
71
71
  /**
@@ -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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.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 { Gr as EventCategory, W as addonPagesCapability, cr as errMsg, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
1
+ import { W as addonPagesCapability, cr as errMsg, lr as BaseAddon, qr as EventCategory } from "../../dist-B9oFw2jh.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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.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 { Gr as EventCategory, K as addonWidgetsCapability, cr as errMsg, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
1
+ import { K as addonWidgetsCapability, cr as errMsg, lr as BaseAddon, qr as EventCategory } from "../../dist-B9oFw2jh.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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.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 { Gr as EventCategory, Sr as createEvent, cr as errMsg, lr as BaseAddon, n as AlertSchema, q as alertsCapability } from "../../dist-BWNoS-1S.mjs";
1
+ import { Cr as createEvent, cr as errMsg, lr as BaseAddon, n as AlertSchema, q as alertsCapability, qr as EventCategory } from "../../dist-B9oFw2jh.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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.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 { 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";
1
+ import { Ar as isEvent, S as FIRST_LEVEL_MACRO_CLASSES, X as bareAddonId, cr as errMsg, gn as ptzAutotrackCapability, lr as BaseAddon, qr as EventCategory } from "../../dist-B9oFw2jh.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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.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 { 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";
1
+ import { Gr as toNodeId, In as storageOccupancyCapability, Mr as nodePin, Y as backupCapability, g as DATABASE_SNAPSHOT_SUFFIX, lr as BaseAddon, nn as mayWriteToLocation, qr as EventCategory } from "../../dist-B9oFw2jh.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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.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 { et as calendarsCapability, lr as BaseAddon, p as CalendarPreferencesSchema } from "../../dist-BWNoS-1S.mjs";
1
+ import { et as calendarsCapability, lr as BaseAddon, p as CalendarPreferencesSchema } from "../../dist-B9oFw2jh.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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.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 { 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";
1
+ import { Cr as createEvent, Jn as buildFfmpegArgs, M as MOTION_CLOSE_AFTER_MS, Nn as snapshotCapability, Or as hydrateSchema, Rn as streamCatalogCapability, ar as DeviceFeature, b as DeclaredDevices, cr as errMsg, i as BaseDevice, lr as BaseAddon, mt as declarationOwnerNodeId, on as motionCapability, qr as EventCategory, rn as memoizePinnedFfmpeg, sr as DeviceType, tt as cameraGridLayoutCapability, y as DERIVED_CAMERA_SILENCED_CAP_NAMES } from "../../dist-B9oFw2jh.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-D_a9mUiM.js");
7
- const require_composition_sources = require("../../composition-sources-BNyXPSs_.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.js");
7
+ const require_composition_sources = require("../../composition-sources-CHvLMrFI.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 { $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";
1
+ import { $n as compositionItemFieldPath, Cr as createEvent, Et as evaluateCompositionField, Q as buildCapabilityLookup, Qn as compositionFeatureEnabled, 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, qr as EventCategory, rr as disarmRoseMemory, rt as composerCapability, sr as DeviceType, t as ALL_CAPABILITY_DEFINITIONS, tr as compositionSourceKey } from "../../dist-B9oFw2jh.mjs";
2
+ import { n as normalizedNativeOwner } from "../../composition-sources-DT_uJwI3.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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.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, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
1
+ import { Zt as logDestinationCapability, lr as BaseAddon } from "../../dist-B9oFw2jh.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-D_a9mUiM.js");
4
- const require_composition_sources = require("../../composition-sources-BNyXPSs_.js");
3
+ const require_dist = require("../../dist-Cc6KOdY-.js");
4
+ const require_composition_sources = require("../../composition-sources-CHvLMrFI.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 { 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";
1
+ import { Or 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-B9oFw2jh.mjs";
2
+ import { t as describeCompositionSources } from "../../composition-sources-DT_uJwI3.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { customizationBlockName } from "@camstack/types/node";
@@ -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-D_a9mUiM.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-CDyOGAje.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-YOOKLA3v.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");
@@ -1,5 +1,5 @@
1
- import { $ as buildStreamParamsConfigSchema, A as MINUTES_PER_DAY, C as FieldClaimModeSchema, Dn as runtimeStatePolicyFor, Gr as EventCategory, Hr as sleep$1, Kt as legacyAutoLinkIds, L as STREAM_PROFILE_META, Mn as siteZoneKey, Nt as formatMinutes, O as LocationIconIdSchema, Or as isDeviceConfigCap, Ot as expandContainer, Rr as resolveSecretMarkers, St as deviceStatusCapability, Tt as enumerateSchemaFields, Vr as secretTreeFromPaths, Wr as transformSecretWrite, Xt as locationIconKey, ar as DeviceFeature, bt as deviceManagerCapability, c as CAP_NAMES_WITH_STATUS, cn as normalizeUnit, cr as errMsg, dn as parseStreamParamsFormPatch, dt as createDeviceExtensionProvider, gr as WELL_KNOWN_TAB_MAP, gt as defineExtensionSlotProvider, lr as BaseAddon, o as CAMERA_SWITCH_ORDER, or as DeviceRole, sr as DeviceType, t as ALL_CAPABILITY_DEFINITIONS, v as DAY_NAMES, w as FieldClaimSchema, wt as enumerateItemArrayFields, x as DeviceStatusSchema, xr as collectZodSecretPaths, xt as deviceStateCapability, yt as deviceExtensionCapability } from "../../dist-BWNoS-1S.mjs";
2
- import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-iGcmzwLV.mjs";
1
+ import { $ as buildStreamParamsConfigSchema, A as MINUTES_PER_DAY, C as FieldClaimModeSchema, Dn as runtimeStatePolicyFor, Hr as secretTreeFromPaths, Kr as transformSecretWrite, Kt as legacyAutoLinkIds, L as STREAM_PROFILE_META, Mn as siteZoneKey, Nt as formatMinutes, O as LocationIconIdSchema, Ot as expandContainer, Sr as collectZodSecretPaths, St as deviceStatusCapability, Tt as enumerateSchemaFields, Wr as sleep$1, Xt as locationIconKey, ar as DeviceFeature, bt as deviceManagerCapability, c as CAP_NAMES_WITH_STATUS, cn as normalizeUnit, cr as errMsg, dn as parseStreamParamsFormPatch, dt as createDeviceExtensionProvider, gr as WELL_KNOWN_TAB_MAP, gt as defineExtensionSlotProvider, kr as isDeviceConfigCap, lr as BaseAddon, o as CAMERA_SWITCH_ORDER, or as DeviceRole, qr as EventCategory, sr as DeviceType, t as ALL_CAPABILITY_DEFINITIONS, v as DAY_NAMES, w as FieldClaimSchema, wt as enumerateItemArrayFields, x as DeviceStatusSchema, xt as deviceStateCapability, yt as deviceExtensionCapability, zr as resolveSecretMarkers } from "../../dist-B9oFw2jh.mjs";
2
+ import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-DlZ3VV6x.mjs";
3
3
  import { z } from "zod";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { canonicalDeviceFingerprint } from "@camstack/types/node";
@@ -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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
9
9
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -1,4 +1,4 @@
1
- import { Zt as logDestinationCapability, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
1
+ import { Zt as logDestinationCapability, lr as BaseAddon } from "../../dist-B9oFw2jh.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
4
4
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -3,7 +3,9 @@ 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-D_a9mUiM.js");
6
+ const require_dist = require("../../dist-Cc6KOdY-.js");
7
+ const require_jwt_signing_key = require("../../jwt-signing-key-C2rE3wH6.js");
8
+ const require_cluster_secret = require("../../cluster-secret-Dg0OOOSr.js");
7
9
  const require_platform_key_source = require("../../platform-key-source-Di7HrlGR.js");
8
10
  let node_crypto = require("node:crypto");
9
11
  let node_path = require("node:path");
@@ -203,6 +205,13 @@ function buildKeySourceCandidates(opts) {
203
205
  */
204
206
  async function writeDefaultKeyFile(dataDir, key, opts) {
205
207
  const file = defaultKeyFilePath(dataDir);
208
+ try {
209
+ return await writeKeyFileAt(file, key, opts);
210
+ } catch (err) {
211
+ throw new Error(`could not write the master key at ${file}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
212
+ }
213
+ }
214
+ async function writeKeyFileAt(file, key, opts) {
206
215
  const dir = node_path.dirname(file);
207
216
  await node_fs.promises.mkdir(dir, {
208
217
  recursive: true,
@@ -223,6 +232,8 @@ async function writeDefaultKeyFile(dataDir, key, opts) {
223
232
  await node_fs.promises.writeFile(tmp, `${encodeKeyMaterial(key)}\n`, { mode: 384 });
224
233
  await node_fs.promises.rename(tmp, file);
225
234
  await node_fs.promises.chmod(file, 384);
235
+ const back = await loadKeyFile(file);
236
+ if (back.kind !== "loaded" || !back.key.equals(key)) throw new Error("the written key file does not read back as the generated key");
226
237
  return movedAside;
227
238
  }
228
239
  //#endregion
@@ -626,6 +637,14 @@ var KeychainRepository = class {
626
637
  return rows.length;
627
638
  }
628
639
  };
640
+ //#endregion
641
+ //#region src/builtins/keychain/system-held-secrets.ts
642
+ /** The refs `keychain-admin.setSystemSecret` may write, by name. */
643
+ var SYSTEM_HELD_SECRET_REFS = { "jwt-signing-key": require_jwt_signing_key.JWT_SIGNING_KEY_REF };
644
+ /** System refs no blob points at — in use for as long as they exist. */
645
+ var PROCESS_HELD_SECRET_REFS = new Set([require_jwt_signing_key.JWT_SIGNING_KEY_REF]);
646
+ /** `system-settings` keys that may hold a system-owned secret's marker. */
647
+ var SYSTEM_SECRET_SETTINGS_KEYS = [require_cluster_secret.CLUSTER_SECRET_SETTINGS_KEY];
629
648
  var KeychainLockedError = class extends Error {
630
649
  reason;
631
650
  constructor(reason) {
@@ -670,10 +689,14 @@ var KeychainService = class {
670
689
  this.unlock = await this.computeUnlock();
671
690
  if (this.unlock.state === "ready") this.deps.logger.info("keychain unlocked", {
672
691
  source: this.unlock.source.kind,
692
+ path: this.unlock.source.path,
673
693
  fingerprint: shortFingerprint(this.unlock.fingerprint),
674
694
  rotationPending: this.unlock.rotationPending
675
695
  });
676
- else this.deps.logger.error("keychain LOCKED — every secret resolves unavailable", { reason: this.unlock.reason });
696
+ else this.deps.logger.error("keychain LOCKED — every secret resolves unavailable", {
697
+ reason: this.unlock.reason,
698
+ path: this.configuredSource?.path
699
+ });
677
700
  try {
678
701
  await this.deps.repo.pruneAudit(this.now());
679
702
  } catch (err) {
@@ -765,10 +788,19 @@ var KeychainService = class {
765
788
  };
766
789
  else if (primary.source.kind === "default-file") {
767
790
  kek = generateKey();
768
- await writeDefaultKeyFile(this.deps.dataDir, kek, {
769
- replace: false,
770
- nowMs: this.now()
771
- });
791
+ try {
792
+ await writeDefaultKeyFile(this.deps.dataDir, kek, {
793
+ replace: false,
794
+ nowMs: this.now()
795
+ });
796
+ } catch (err) {
797
+ this.deps.logger.error("keychain master key could NOT be generated — no key stored", {
798
+ path: primary.source.path,
799
+ error: errMsg(err)
800
+ });
801
+ throw err;
802
+ }
803
+ this.deps.logger.info("keychain master key generated", { path: primary.source.path });
772
804
  } else return {
773
805
  state: "locked",
774
806
  reason: "key-missing"
@@ -823,7 +855,11 @@ var KeychainService = class {
823
855
  if (parts === null || !this.owns(caller, parts.owner)) throw new KeychainForbiddenError(ref, caller);
824
856
  return parts.owner;
825
857
  }
826
- async put(caller, ref, value) {
858
+ /**
859
+ * @param actor who the audit names — the owner addon by default; the
860
+ * operator (`user:<id>`) for {@link setSystemSecret}.
861
+ */
862
+ async put(caller, ref, value, actor = actorOfAddon(caller)) {
827
863
  const owner = this.ownerOf(ref, caller);
828
864
  const unlocked = this.requireReady();
829
865
  if (value.length === 0) throw new Error("keychain.put: an empty value is not stored — delete the ref");
@@ -849,10 +885,10 @@ var KeychainService = class {
849
885
  version,
850
886
  createdAt: existing?.createdAt ?? t,
851
887
  updatedAt: t,
852
- updatedBy: actorOfAddon(caller),
888
+ updatedBy: actor,
853
889
  lastReadAt: existing?.lastReadAt ?? null
854
890
  });
855
- await this.audit("put", actorOfAddon(caller), ref, `version=${version}`);
891
+ await this.audit("put", actor, ref, `version=${version}`);
856
892
  this.deps.events.emit({
857
893
  ref,
858
894
  owner,
@@ -982,6 +1018,14 @@ var KeychainService = class {
982
1018
  usage: usage.get(row.ref) ?? "unknown"
983
1019
  }));
984
1020
  }
1021
+ /**
1022
+ * The operator replaces a system-held secret no form edits (D797) — the
1023
+ * session signing key. Stored under owner `system`, audited as the user.
1024
+ */
1025
+ async setSystemSecret(userId, name, value) {
1026
+ const ref = SYSTEM_HELD_SECRET_REFS[name];
1027
+ return this.put(require_jwt_signing_key.SYSTEM_SECRET_OWNER, ref, value, `user:${userId}`);
1028
+ }
985
1029
  async listAudit(limit) {
986
1030
  return this.deps.repo.listAudit(limit);
987
1031
  }
@@ -1221,6 +1265,13 @@ async function prefixRows(door, collection, prefix) {
1221
1265
  }
1222
1266
  /** The blobs that may hold the marker of a ref in `scope`; `null` = cannot tell. */
1223
1267
  async function blobsFor(door, owner, scope) {
1268
+ if (owner === "system" && scope.kind === "global") return [[...PROCESS_HELD_SECRET_REFS].map((ref) => ({
1269
+ $secret: ref,
1270
+ v: 1
1271
+ })), ...await Promise.all(SYSTEM_SECRET_SETTINGS_KEYS.map((key) => door.get({
1272
+ collection: "system-settings",
1273
+ key
1274
+ })))];
1224
1275
  switch (scope.kind) {
1225
1276
  case "global":
1226
1277
  case "node": {
@@ -1309,8 +1360,12 @@ function createKeychainUsageCheck(door) {
1309
1360
  * orphans, rotation, recovery key, reset. Every method admin; the four
1310
1361
  * that change or hand out material take the session's user for the audit.
1311
1362
  *
1312
- * It does not run on agents: the manifest places it `hub-only`, and an agent
1313
- * addon reaches it through `$hub-cap-fwd` like every other hub cap.
1363
+ * It does not run on agents: an agent's Phase 1 drops `keychain` from its infra
1364
+ * list (`server/backend/src/agent/agent-infra-capabilities.ts`), and an agent
1365
+ * addon reaches it through `$hub-cap-fwd` like every other hub cap. Until
1366
+ * 2026-10-08 agents DID boot it — their store door forwards to the hub, so an
1367
+ * agent wrote the hub's `keychain:keys` row with a key file on its own disk.
1368
+ * Booting first, it left the hub locked `key-missing`.
1314
1369
  */
1315
1370
  var DAY_MS = 1440 * 6e4;
1316
1371
  /** The caller the transport stamped (or an in-process caller stated). */
@@ -1398,6 +1453,7 @@ var KeychainAddon = class extends require_dist.BaseAddon {
1398
1453
  listSecrets: () => service.listSecrets(),
1399
1454
  listAudit: (input) => service.listAudit(input.limit ?? 100),
1400
1455
  reveal: (input) => service.reveal(input.caller.userId, input.ref),
1456
+ setSystemSecret: (input) => service.setSystemSecret(input.caller.userId, input.name, input.value),
1401
1457
  deleteOrphans: (input) => service.deleteOrphans(input.caller.userId, input.refs),
1402
1458
  rotateMasterKey: (input) => service.rotateMasterKey(input.caller.userId),
1403
1459
  purgeRetiredKeys: async (input) => ({ purged: await service.purgeRetiredKeys(input.caller.userId) }),