@camstack/system 1.2.376 → 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 (92) 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/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  9. package/dist/builtins/alerts/alerts.addon.js +1 -1
  10. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  11. package/dist/builtins/autotrack/index.js +1 -1
  12. package/dist/builtins/autotrack/index.mjs +1 -1
  13. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  14. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  15. package/dist/builtins/calendars/calendars.addon.js +1 -1
  16. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  17. package/dist/builtins/camera-grid/index.js +1 -1
  18. package/dist/builtins/camera-grid/index.mjs +1 -1
  19. package/dist/builtins/composer/composer.addon.js +2 -2
  20. package/dist/builtins/composer/composer.addon.mjs +2 -2
  21. package/dist/builtins/console-logging/index.js +1 -1
  22. package/dist/builtins/console-logging/index.mjs +1 -1
  23. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  24. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  25. package/dist/builtins/device-manager/device-config-secrets.d.ts +21 -0
  26. package/dist/builtins/device-manager/device-manager.addon.js +85 -6
  27. package/dist/builtins/device-manager/device-manager.addon.mjs +85 -6
  28. package/dist/builtins/hub-forwarder/index.js +1 -1
  29. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  30. package/dist/builtins/keychain/index.d.ts +1 -0
  31. package/dist/builtins/keychain/index.js +1416 -0
  32. package/dist/builtins/keychain/index.mjs +1409 -0
  33. package/dist/builtins/keychain/key-sources.d.ts +37 -0
  34. package/dist/builtins/keychain/keychain-crypto.d.ts +28 -0
  35. package/dist/builtins/keychain/keychain-service.d.ts +103 -0
  36. package/dist/builtins/keychain/keychain-store.d.ts +82 -0
  37. package/dist/builtins/keychain/keychain-usage.d.ts +6 -0
  38. package/dist/builtins/keychain/keychain.addon.d.ts +11 -0
  39. package/dist/builtins/keychain/platform-key-source.d.ts +24 -0
  40. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  41. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  42. package/dist/builtins/local-auth/local-auth.addon.js +19 -2
  43. package/dist/builtins/local-auth/local-auth.addon.mjs +19 -2
  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/location-store.d.ts +6 -0
  61. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +15 -0
  62. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +74 -14
  63. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +74 -14
  64. package/dist/builtins/system-config/system-config.addon.js +1 -1
  65. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  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-8qMgog1O.mjs → child-cap-dispatch-CgmOo0yl.mjs} +170 -27
  69. package/dist/{child-cap-dispatch-BWtaSmWf.js → child-cap-dispatch-DlDSoqm1.js} +198 -25
  70. package/dist/{composition-sources-DW7CgMsg.js → composition-sources-BNyXPSs_.js} +1 -1
  71. package/dist/{composition-sources-zxQPPtP_.mjs → composition-sources-D39bl0nP.mjs} +1 -1
  72. package/dist/{dist-D732NygW.mjs → dist-BWNoS-1S.mjs} +2195 -105
  73. package/dist/{dist-BcUWQGr9.js → dist-D_a9mUiM.js} +2260 -104
  74. package/dist/{event-loop-stall-monitor-8W4yWNVW.mjs → event-loop-stall-monitor-ClPhfx7Y.mjs} +1 -1
  75. package/dist/{event-loop-stall-monitor-QX4RjNe7.js → event-loop-stall-monitor-DuOn8H1n.js} +1 -1
  76. package/dist/{hub-cap-forward-BdT320dq.mjs → hub-cap-forward-CH6_VWVO.mjs} +13 -4
  77. package/dist/{hub-cap-forward-DmHNjbB0.js → hub-cap-forward-COCmYaup.js} +13 -4
  78. package/dist/index.d.ts +2 -0
  79. package/dist/index.js +20 -6
  80. package/dist/index.mjs +13 -7
  81. package/dist/kernel/config-schema.d.ts +4 -0
  82. package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +6 -0
  83. package/dist/kernel/transport/cap-route-resolver.d.ts +19 -0
  84. package/dist/kernel/transport/hub-cap-forward.d.ts +22 -1
  85. package/dist/kernel/transport/index.d.ts +2 -2
  86. package/dist/kernel/transport/local-child-registry.d.ts +4 -3
  87. package/dist/logging/log-redactor.d.ts +9 -0
  88. package/dist/platform-key-source-BWlq0jjn.mjs +23 -0
  89. package/dist/platform-key-source-Di7HrlGR.js +40 -0
  90. package/dist/{retired-settings-keys-MaESpO18.js → retired-settings-keys-CDyOGAje.js} +1 -1
  91. package/dist/{retired-settings-keys-CxPOg7BF.mjs → retired-settings-keys-iGcmzwLV.mjs} +1 -1
  92. package/package.json +17 -1
@@ -0,0 +1,37 @@
1
+ import { KeychainKeySource } from '@camstack/types';
2
+ /** The `keychain` section of `config.yaml`. */
3
+ export interface KeychainKeyConfig {
4
+ readonly keyFile?: string | undefined;
5
+ readonly previousKeyFile?: string | undefined;
6
+ }
7
+ export type KeyLoadResult = {
8
+ readonly kind: 'loaded';
9
+ readonly key: Buffer;
10
+ } | {
11
+ readonly kind: 'absent';
12
+ } | {
13
+ readonly kind: 'unreadable';
14
+ readonly error: string;
15
+ };
16
+ export interface KeySourceCandidate {
17
+ readonly source: KeychainKeySource;
18
+ readonly primary: boolean;
19
+ load(): Promise<KeyLoadResult>;
20
+ }
21
+ /** The default key file's location under the data root. */
22
+ export declare function defaultKeyFilePath(dataDir: string): string;
23
+ export interface KeySourceOptions {
24
+ readonly config: KeychainKeyConfig;
25
+ readonly dataDir: string;
26
+ }
27
+ /** Every candidate, primary first. */
28
+ export declare function buildKeySourceCandidates(opts: KeySourceOptions): readonly KeySourceCandidate[];
29
+ /**
30
+ * Write a master key to the default location: directory 0700, file 0600,
31
+ * atomically (temp + rename), never over an existing file unless `replace`.
32
+ * Returns the previous file's new name when one was moved aside.
33
+ */
34
+ export declare function writeDefaultKeyFile(dataDir: string, key: Buffer, opts: {
35
+ readonly replace: boolean;
36
+ readonly nowMs: number;
37
+ }): Promise<string | null>;
@@ -0,0 +1,28 @@
1
+ export declare const KEY_BYTES = 32;
2
+ /** 32 fresh random bytes — a master or a data key. */
3
+ export declare function generateKey(): Buffer;
4
+ /** A short random id for a data key (no dots — it is a segment of `ck1`). */
5
+ export declare function generateKeyId(): string;
6
+ /** The full fingerprint of a master key. */
7
+ export declare function kekFingerprint(kek: Buffer): string;
8
+ /** What the operator sees: the first 16 hex chars. */
9
+ export declare function shortFingerprint(fingerprint: string): string;
10
+ /** Constant-time string equality (lengths may differ). */
11
+ export declare function constantTimeEquals(a: string, b: string): boolean;
12
+ /**
13
+ * Key material from a key file: base64 (the format we write) or hex of
14
+ * exactly 32 bytes, surrounding whitespace ignored. Anything else is `null` —
15
+ * a file holding a password or a PEM is refused, never stretched into a key.
16
+ */
17
+ export declare function decodeKeyMaterial(text: string): Buffer | null;
18
+ export declare function encodeKeyMaterial(key: Buffer): string;
19
+ /** Wrap a data key under a master key. */
20
+ export declare function wrapDek(kek: Buffer, dek: Buffer, keyId: string): string;
21
+ /** Unwrap; `null` when the master key is not the one that wrapped it. */
22
+ export declare function unwrapDek(kek: Buffer, wrapped: string, keyId: string): Buffer | null;
23
+ /** Encrypt one value for one ref. */
24
+ export declare function encryptValue(dek: Buffer, keyId: string, ref: string, value: string): string;
25
+ /** The data-key id an envelope was written under, or `null` if it is not one. */
26
+ export declare function envelopeKeyId(envelope: string): string | null;
27
+ /** Decrypt; `null` on any failure — wrong key, wrong ref, tampered bytes. */
28
+ export declare function decryptValue(dek: Buffer, ref: string, envelope: string): string | null;
@@ -0,0 +1,103 @@
1
+ import { EventCategory, KeychainAuditEntry, KeychainKeySource, KeychainResolveResult, KeychainSecretMeta, KeychainSecretUsage, KeychainState, KeychainStatus, KeychainUnavailableReason } from '@camstack/types';
2
+ import { KeychainRepository, KeychainSecretRow } from './keychain-store.js';
3
+ import { KeySourceCandidate } from './key-sources.js';
4
+ /** `lastReadAt` is written at most this often per ref (hub I/O is the bottleneck). */
5
+ export declare const LAST_READ_GRANULARITY_MS: number;
6
+ export declare class KeychainLockedError extends Error {
7
+ readonly reason: KeychainUnavailableReason;
8
+ constructor(reason: KeychainUnavailableReason);
9
+ }
10
+ export declare class KeychainForbiddenError extends Error {
11
+ readonly ref: string;
12
+ constructor(ref: string, caller: string | null);
13
+ }
14
+ export interface KeychainEventSink {
15
+ emit(payload: {
16
+ readonly ref: string;
17
+ readonly owner: string;
18
+ readonly version: number | null;
19
+ readonly change: 'put' | 'delete';
20
+ }): void;
21
+ }
22
+ export interface KeychainLogger {
23
+ info(message: string, meta?: Record<string, unknown>): void;
24
+ warn(message: string, meta?: Record<string, unknown>): void;
25
+ error(message: string, meta?: Record<string, unknown>): void;
26
+ }
27
+ /** Answers whether a stored ref is still pointed at by its owner's settings. */
28
+ export type KeychainUsageCheck = (rows: readonly KeychainSecretRow[]) => Promise<ReadonlyMap<string, KeychainSecretUsage>>;
29
+ export interface KeychainServiceDeps {
30
+ readonly repo: KeychainRepository;
31
+ /** Rebuilt on every unlock / rotation — the configuration may have changed. */
32
+ readonly candidates: () => Promise<readonly KeySourceCandidate[]>;
33
+ readonly dataDir: string;
34
+ readonly events: KeychainEventSink;
35
+ readonly logger: KeychainLogger;
36
+ /** The runner id hosting an addon (its group, or itself). */
37
+ readonly runnerIdOf: (addonId: string) => string;
38
+ readonly usage: KeychainUsageCheck;
39
+ readonly now?: () => number;
40
+ }
41
+ export declare class KeychainService {
42
+ private readonly deps;
43
+ private unlock;
44
+ private configuredSource;
45
+ private readonly now;
46
+ constructor(deps: KeychainServiceDeps);
47
+ /** Load the keys and unlock. Never throws for a key problem — it locks. */
48
+ init(): Promise<KeychainState>;
49
+ private computeUnlock;
50
+ /** No wrapped data key yet: create one — only when nothing could be lost. */
51
+ private firstBoot;
52
+ getState(): KeychainState;
53
+ private requireReady;
54
+ /** May `caller` touch values owned by `owner`? */
55
+ owns(caller: string | null, owner: string): boolean;
56
+ private ownerOf;
57
+ put(caller: string | null, ref: string, value: string): Promise<{
58
+ ref: string;
59
+ version: number;
60
+ }>;
61
+ resolve(caller: string | null, refs: readonly string[]): Promise<KeychainResolveResult>;
62
+ private touchLastRead;
63
+ delete(caller: string | null, refs: readonly string[]): Promise<number>;
64
+ listMeta(caller: string | null): Promise<readonly KeychainSecretMeta[]>;
65
+ status(): Promise<KeychainStatus>;
66
+ listSecrets(): Promise<readonly (KeychainSecretMeta & {
67
+ usage: KeychainSecretUsage;
68
+ })[]>;
69
+ listAudit(limit: number): Promise<readonly KeychainAuditEntry[]>;
70
+ reveal(userId: string, ref: string): Promise<{
71
+ value: string;
72
+ version: number;
73
+ }>;
74
+ deleteOrphans(userId: string, refs: readonly string[]): Promise<{
75
+ deleted: readonly string[];
76
+ kept: readonly {
77
+ ref: string;
78
+ usage: KeychainSecretUsage;
79
+ }[];
80
+ }>;
81
+ downloadRecoveryKey(userId: string): Promise<{
82
+ key: string;
83
+ fingerprint: string;
84
+ keySource: KeychainKeySource;
85
+ }>;
86
+ /** See `keychain-admin.rotateMasterKey`. */
87
+ rotateMasterKey(userId: string): Promise<{
88
+ fingerprint: string;
89
+ keySource: KeychainKeySource;
90
+ }>;
91
+ /** Delete retired wraps, and the default file's previous copies with them. */
92
+ purgeRetiredKeys(userId: string): Promise<number>;
93
+ /** Lost-key recovery — see `keychain-admin.resetKeychain`. */
94
+ resetKeychain(userId: string): Promise<{
95
+ archivedCollection: string | null;
96
+ archived: number;
97
+ }>;
98
+ private audit;
99
+ /** Daily ring prune, driven by the addon's timer. */
100
+ pruneAudit(): Promise<void>;
101
+ }
102
+ /** The event the provider emits — exported for the addon's bus adapter. */
103
+ export declare const KEYCHAIN_CHANGED = EventCategory.KeychainChanged;
@@ -0,0 +1,82 @@
1
+ import { ISettingsStoreProvider, KeychainAuditAction } from '@camstack/types';
2
+ /**
3
+ * @durable class=config owner=keychain
4
+ * write="`keychain.put` upserts one row per ref; `delete` removes it"
5
+ * retention="none — a row lives until its owner deletes the ref or the
6
+ * operator deletes it as an orphan. Losing the table loses every secret
7
+ * value; the settings blobs then point at refs that resolve `missing`."
8
+ */
9
+ export declare const KEYCHAIN_SECRETS_COLLECTION = "keychain:secrets";
10
+ /**
11
+ * @durable class=config owner=keychain
12
+ * write="first boot writes the wrapped data key; `rotateMasterKey` adds a
13
+ * wrap and retires the previous one"
14
+ * retention="retired wraps until `purgeRetiredKeys`. Losing the table with
15
+ * the secrets intact makes every value undecryptable."
16
+ */
17
+ export declare const KEYCHAIN_KEYS_COLLECTION = "keychain:keys";
18
+ /**
19
+ * @durable class=ring owner=keychain
20
+ * write="one row per write / delete / rotation / reveal / recovery download"
21
+ * retention="90 days and at most 20 000 rows, pruned at boot and daily"
22
+ */
23
+ export declare const KEYCHAIN_AUDIT_COLLECTION = "keychain:audit";
24
+ export declare const AUDIT_RETENTION_MS: number;
25
+ export declare const AUDIT_MAX_ROWS = 20000;
26
+ export interface KeychainSecretRow {
27
+ readonly ref: string;
28
+ readonly owner: string;
29
+ readonly scope: string;
30
+ readonly fieldPath: string;
31
+ readonly ciphertext: string;
32
+ readonly keyId: string;
33
+ readonly version: number;
34
+ readonly createdAt: number;
35
+ readonly updatedAt: number;
36
+ readonly updatedBy: string;
37
+ readonly lastReadAt: number | null;
38
+ }
39
+ export type KeyWrapState = 'active' | 'retired';
40
+ export interface KeychainKeyRow {
41
+ readonly wrapId: string;
42
+ readonly keyId: string;
43
+ readonly wrappedDek: string;
44
+ readonly kekFingerprint: string;
45
+ readonly kekSource: string;
46
+ readonly createdAt: number;
47
+ readonly state: KeyWrapState;
48
+ readonly recoveryDownloadedAt: number | null;
49
+ }
50
+ export interface KeychainAuditRow {
51
+ readonly id: string;
52
+ readonly at: number;
53
+ readonly action: KeychainAuditAction;
54
+ readonly actor: string;
55
+ readonly ref: string | null;
56
+ readonly detail: string | null;
57
+ }
58
+ /** The subset of the settings door the repository uses. */
59
+ export type KeychainDoor = Pick<ISettingsStoreProvider, 'declareCollection' | 'get' | 'set' | 'query' | 'delete' | 'deleteWhere'>;
60
+ export declare class KeychainRepository {
61
+ private readonly door;
62
+ constructor(door: KeychainDoor);
63
+ init(): Promise<void>;
64
+ getSecrets(refs: readonly string[]): Promise<ReadonlyMap<string, KeychainSecretRow>>;
65
+ /** Every row, paged by primary key. */
66
+ listSecrets(): Promise<readonly KeychainSecretRow[]>;
67
+ putSecret(row: KeychainSecretRow): Promise<void>;
68
+ deleteSecrets(refs: readonly string[]): Promise<number>;
69
+ listKeys(): Promise<readonly KeychainKeyRow[]>;
70
+ putKey(row: KeychainKeyRow): Promise<void>;
71
+ deleteKey(wrapId: string): Promise<void>;
72
+ appendAudit(row: KeychainAuditRow): Promise<void>;
73
+ listAudit(limit: number): Promise<readonly KeychainAuditRow[]>;
74
+ /** Drop audit rows older than the retention window, then beyond the row bound. */
75
+ pruneAudit(nowMs: number): Promise<number>;
76
+ /**
77
+ * Lost-key recovery: copy every secret row into `archive`, then empty the
78
+ * live table. The archive is ciphertext under a key nobody has — it exists
79
+ * so a key that turns up later can still recover it.
80
+ */
81
+ archiveAllSecrets(archive: string): Promise<number>;
82
+ }
@@ -0,0 +1,6 @@
1
+ import { KeychainSecretUsage } from '@camstack/types';
2
+ import { KeychainDoor, KeychainSecretRow } from './keychain-store.js';
3
+ /** Every `$secret` ref inside a value, at any depth. */
4
+ export declare function collectMarkerRefs(value: unknown, out?: Set<string>): Set<string>;
5
+ /** Build the usage check the service uses. */
6
+ export declare function createKeychainUsageCheck(door: KeychainDoor): (rows: readonly KeychainSecretRow[]) => Promise<ReadonlyMap<string, KeychainSecretUsage>>;
@@ -0,0 +1,11 @@
1
+ import { BaseAddon, ProviderRegistration } from '@camstack/types';
2
+ /** The caller the transport stamped (or an in-process caller stated). */
3
+ export declare function callerOf(input: unknown): string | null;
4
+ export declare class KeychainAddon extends BaseAddon {
5
+ readonly id = "keychain";
6
+ private pruneTimer;
7
+ constructor();
8
+ protected onInitialize(): Promise<ProviderRegistration[]>;
9
+ protected onShutdown(): Promise<void>;
10
+ }
11
+ export default KeychainAddon;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The OS-keychain master key of a DESKTOP hub.
3
+ *
4
+ * Electron's `safeStorage` exists only in the Electron main process, and the
5
+ * hub runs as a plain Node child of it. So the desktop app reads (or creates)
6
+ * the master key through `safeStorage`, and hands the raw bytes to the hub
7
+ * over an inherited pipe (`--keychain-key-fd=<n>`) — never an env var, never a
8
+ * file at rest in the clear. The hub's boot reads the descriptor once and
9
+ * registers the key here; the keychain builtin, in the same process, asks.
10
+ *
11
+ * Process-global through a registered symbol, so a second copy of this module
12
+ * (an addon bundle) sees the same key rather than none.
13
+ */
14
+ export interface PlatformKeychainKey {
15
+ /** Where it came from, for the status page (`macOS Keychain`, `Windows DPAPI`, …). */
16
+ readonly label: string;
17
+ readonly key: Buffer;
18
+ }
19
+ /** Register the platform key. Called once, by the hub's boot. */
20
+ export declare function setPlatformKeychainKey(entry: PlatformKeychainKey): void;
21
+ /** Drop the platform key (tests). */
22
+ export declare function clearPlatformKeychainKey(): void;
23
+ /** The platform key, when this hub was started by the desktop app with one. */
24
+ export declare function getPlatformKeychainKey(): PlatformKeychainKey | null;
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-BcUWQGr9.js");
3
+ const require_dist = require("../../dist-D_a9mUiM.js");
4
4
  //#region src/builtins/liveness-monitor/liveness-checks.ts
5
5
  var NO_DEVICES = "liveness:no-devices";
6
6
  var ALL_OFFLINE = "liveness:all-devices-offline";
@@ -1,4 +1,4 @@
1
- import { I as RecordingStatusSchema, N as RECORDING_SOURCE_CAMSTACK_ADDON, Pr as EventCategory, cr as BaseAddon, sr as errMsg, yr as createEvent } from "../../dist-D732NygW.mjs";
1
+ import { F as RecordingStatusSchema, Gr as EventCategory, N as RECORDING_SOURCE_CAMSTACK_ADDON, Sr as createEvent, cr as errMsg, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
2
2
  //#region src/builtins/liveness-monitor/liveness-checks.ts
3
3
  var NO_DEVICES = "liveness:no-devices";
4
4
  var ALL_OFFLINE = "liveness:all-devices-offline";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BcUWQGr9.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  let zod = require("zod");
8
8
  let node_crypto = require("node:crypto");
9
9
  node_crypto = require_chunk.__toESM(node_crypto);
@@ -9677,6 +9677,21 @@ var bootstrapAddonsSchema = zod.z.object({
9677
9677
  */
9678
9678
  forceDisable: zod.z.array(zod.z.string()).default([])
9679
9679
  });
9680
+ /**
9681
+ * Where the keychain's master key lives (D788). config.yaml ONLY: no env var
9682
+ * maps here, and the settings store may not answer it
9683
+ * (`BOOTSTRAP_OWNED_SECTIONS`). Absent → the desktop OS keychain when the hub
9684
+ * runs inside the desktop app, else `<dataDir>/.keychain/master.key`.
9685
+ */
9686
+ var keychainSchema = zod.z.object({
9687
+ /** A file holding 32 random bytes, base64 (or hex). Keep it OFF the data volume. */
9688
+ keyFile: zod.z.string().min(1).optional(),
9689
+ /**
9690
+ * The key being rotated away from — consulted only to UNLOCK, so a move to a
9691
+ * new key file is: new file, old one here, restart, rotate, remove this.
9692
+ */
9693
+ previousKeyFile: zod.z.string().min(1).optional()
9694
+ });
9680
9695
  /** Bootstrap config -- loaded from config.yaml ONLY at startup.
9681
9696
  * All other settings live in SQL (system_settings table). */
9682
9697
  var bootstrapSchema = zod.z.object({
@@ -9695,7 +9710,9 @@ var bootstrapSchema = zod.z.object({
9695
9710
  * kernel can reach the settings-store. See bootstrapAddonsSchema.
9696
9711
  * Spec: docs/superpowers/specs/2026-05-15-yaml-bootstrap-expansion.md
9697
9712
  */
9698
- bootstrap: bootstrapAddonsSchema.default(bootstrapAddonsSchema.parse({}))
9713
+ bootstrap: bootstrapAddonsSchema.default(bootstrapAddonsSchema.parse({})),
9714
+ /** Keychain master-key location (config.yaml only). */
9715
+ keychain: keychainSchema.default({})
9699
9716
  });
9700
9717
  //#endregion
9701
9718
  //#region src/builtins/local-auth/admin-account-boot.ts
@@ -1,5 +1,5 @@
1
1
  import { i as __require, o as __toESM, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
2
- import { W as UserRecordSchema, Y as authProviderCapability, cr as BaseAddon, r as ApiKeyRecordSchema, z as ScopedTokenSchema, zn as userManagementCapability } from "../../dist-D732NygW.mjs";
2
+ import { Bn as userManagementCapability, J as authProviderCapability, R as ScopedTokenSchema, U as UserRecordSchema, lr as BaseAddon, r as ApiKeyRecordSchema } from "../../dist-BWNoS-1S.mjs";
3
3
  import { z } from "zod";
4
4
  import * as crypto$2 from "node:crypto";
5
5
  import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
@@ -9667,6 +9667,21 @@ var bootstrapAddonsSchema = z.object({
9667
9667
  */
9668
9668
  forceDisable: z.array(z.string()).default([])
9669
9669
  });
9670
+ /**
9671
+ * Where the keychain's master key lives (D788). config.yaml ONLY: no env var
9672
+ * maps here, and the settings store may not answer it
9673
+ * (`BOOTSTRAP_OWNED_SECTIONS`). Absent → the desktop OS keychain when the hub
9674
+ * runs inside the desktop app, else `<dataDir>/.keychain/master.key`.
9675
+ */
9676
+ var keychainSchema = z.object({
9677
+ /** A file holding 32 random bytes, base64 (or hex). Keep it OFF the data volume. */
9678
+ keyFile: z.string().min(1).optional(),
9679
+ /**
9680
+ * The key being rotated away from — consulted only to UNLOCK, so a move to a
9681
+ * new key file is: new file, old one here, restart, rotate, remove this.
9682
+ */
9683
+ previousKeyFile: z.string().min(1).optional()
9684
+ });
9670
9685
  /** Bootstrap config -- loaded from config.yaml ONLY at startup.
9671
9686
  * All other settings live in SQL (system_settings table). */
9672
9687
  var bootstrapSchema = z.object({
@@ -9685,7 +9700,9 @@ var bootstrapSchema = z.object({
9685
9700
  * kernel can reach the settings-store. See bootstrapAddonsSchema.
9686
9701
  * Spec: docs/superpowers/specs/2026-05-15-yaml-bootstrap-expansion.md
9687
9702
  */
9688
- bootstrap: bootstrapAddonsSchema.default(bootstrapAddonsSchema.parse({}))
9703
+ bootstrap: bootstrapAddonsSchema.default(bootstrapAddonsSchema.parse({})),
9704
+ /** Keychain master-key location (config.yaml only). */
9705
+ keychain: keychainSchema.default({})
9689
9706
  });
9690
9707
  //#endregion
9691
9708
  //#region src/builtins/local-auth/admin-account-boot.ts
@@ -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-BcUWQGr9.js");
3
+ const require_dist = require("../../dist-D_a9mUiM.js");
4
4
  const require_tls = require("../../tls-CCMX7MjX.js");
5
5
  let zod = require("zod");
6
6
  let node_os = require("node:os");
@@ -1,4 +1,4 @@
1
- import { Pr as EventCategory, Rt as isAppLinkBase, Sn as resolveHubAddressRoles, Tn as resolveNotificationTapAddress, Vn as validateCustomAddress, Vt as isDefaultAppConnectionEndpoint, Yt as localNetworkCapability, cr as BaseAddon, dn as pickAppLinkHub, rt as checkRoleAddress, s as CAMSTACK_APP_LINK_ORIGIN, vn as resolveAppConnections } from "../../dist-D732NygW.mjs";
1
+ import { Cn as resolveHubAddressRoles, En as resolveNotificationTapAddress, Gr as EventCategory, Hn as validateCustomAddress, It as isAppLinkBase, Yt as localNetworkCapability, fn as pickAppLinkHub, lr as BaseAddon, nt as checkRoleAddress, s as CAMSTACK_APP_LINK_ORIGIN, yn as resolveAppConnections, zt as isDefaultAppConnectionEndpoint } from "../../dist-BWNoS-1S.mjs";
2
2
  import { P as readLanHttpState, _ as writeExtraSans, h as readTlsMode, i as storeUploadedCertificate, j as applyLanHttp, k as DEFAULT_LAN_HTTP_PORT, m as readTlsAccessStatus, n as regenerateCertificate, p as readExtraSans, r as revertToGeneratedCertificate, t as applyCertificateToListener, u as servedHttpsLeafFingerprint, y as ensureTlsCert } from "../../tls-CJHogwTl.mjs";
3
3
  import { z } from "zod";
4
4
  import * as os from "node:os";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BcUWQGr9.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  //#region src/builtins/loki-logging/loki-payload.ts
8
8
  /**
9
9
  * Loki rejects a label name that is not a valid Prometheus label
@@ -1,4 +1,4 @@
1
- import { Zt as logDestinationCapability, cr as BaseAddon } from "../../dist-D732NygW.mjs";
1
+ import { Zt as logDestinationCapability, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
2
2
  //#region src/builtins/loki-logging/loki-payload.ts
3
3
  /**
4
4
  * Loki rejects a label name that is not a valid Prometheus label
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BcUWQGr9.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  const require_proc_stat = require("../../proc-stat-DL-WUOhl.js");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  let node_os = require("node:os");
@@ -1,4 +1,4 @@
1
- import { Pr as EventCategory, Pt as foldSnapshotByFunction, cr as BaseAddon, gn as reducePoints, rn as metricsProviderCapability, sr as errMsg, yn as resolveBucketMs, yr as createEvent } from "../../dist-D732NygW.mjs";
1
+ import { Gr as EventCategory, Mt as foldSnapshotByFunction, Sr as createEvent, _n as reducePoints, bn as resolveBucketMs, cr as errMsg, in as metricsProviderCapability, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
2
2
  import { a as parseProcStat, i as nodeProcReader, n as elapsedSecSince, o as parseProcStatusRss, r as lifetimeCpuPercent, t as commandFromCmdline } from "../../proc-stat-CbC55Kqi.mjs";
3
3
  import { access, readFile, readdir } from "node:fs/promises";
4
4
  import * as os from "node:os";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BcUWQGr9.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  let node_os = require("node:os");
8
8
  node_os = require_chunk.__toESM(node_os);
9
9
  let node_fs = require("node:fs");
@@ -1,5 +1,5 @@
1
1
  import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
2
- import { Pr as EventCategory, Tt as enumerateInferenceDevices, cr as BaseAddon, kn as scoreRuntimes, pn as platformProbeCapability, sr as errMsg, xr as emitReadiness } from "../../dist-D732NygW.mjs";
2
+ import { An as scoreRuntimes, Ct as enumerateInferenceDevices, Gr as EventCategory, cr as errMsg, lr as BaseAddon, mn as platformProbeCapability, wr as emitReadiness } from "../../dist-BWNoS-1S.mjs";
3
3
  import * as os from "node:os";
4
4
  import * as fs from "node:fs";
5
5
  import { execFile } from "node:child_process";
@@ -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-BcUWQGr9.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
8
8
  /**
9
9
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -1,4 +1,4 @@
1
- import { Pr as EventCategory, cr as BaseAddon } from "../../dist-D732NygW.mjs";
1
+ import { Gr as EventCategory, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
2
2
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
3
3
  /**
4
4
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-BcUWQGr9.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  const require_snapshot_courtesy = require("../../snapshot-courtesy-D_C5-nC0.js");
8
8
  let zod = require("zod");
9
9
  let node_crypto = require("node:crypto");
@@ -1,4 +1,4 @@
1
- import { Er as nodePin, Mn as snapshotCapability, Pr as EventCategory, Q as batteryCapability, Rn as streamQualityLabel, Z as bareAddonId, a as BatteryStatusSchema, cr as BaseAddon, ir as DeviceFeature, nn as memoizePinnedFfmpeg, or as DeviceType, sr as errMsg, yt as deriveBatteryPresence } from "../../dist-D732NygW.mjs";
1
+ import { Gr as EventCategory, Nn as snapshotCapability, X as bareAddonId, Z as batteryCapability, _t as deriveBatteryPresence, a as BatteryStatusSchema, ar as DeviceFeature, cr as errMsg, jr as nodePin, lr as BaseAddon, rn as memoizePinnedFfmpeg, sr as DeviceType, zn as streamQualityLabel } from "../../dist-BWNoS-1S.mjs";
2
2
  import { i as renderCourtesyOverlayJpeg, n as courtesyCacheKey, r as renderCourtesyJpeg } from "../../snapshot-courtesy-CyFs1M3I.mjs";
3
3
  import { z } from "zod";
4
4
  import { randomUUID } from "node:crypto";
@@ -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-BcUWQGr9.js");
6
+ const require_dist = require("../../dist-D_a9mUiM.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { In as storageProviderCapability, Nt as filesystemBrowseCapability, cr as BaseAddon } from "../../dist-D732NygW.mjs";
1
+ import { Ln as storageProviderCapability, jt as filesystemBrowseCapability, lr as BaseAddon } from "../../dist-BWNoS-1S.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -22,6 +22,12 @@ export interface ILocationStore {
22
22
  /** Remove a location by id. */
23
23
  delete(id: string): Promise<void>;
24
24
  }
25
+ /**
26
+ * @durable class=config owner=storage-orchestrator
27
+ * write="an operator creates or edits a location (basePath, minFreePercent, enabled, node pin); plus the boot reconcile — declared defaults seeded on a fresh install, and in-memory-only locations backfilled when the store is late-wired"
28
+ * retention="none — a row goes only when the operator deletes the location, or when the declaration pass prunes one whose declaring addon is gone. Bounded by the storage targets a human configures."
29
+ */
30
+ export declare const STORAGE_LOCATIONS = "storage_locations";
25
31
  /**
26
32
  * `ILocationStore` on the `settings-store` collection surface — the same door
27
33
  * every other consumer uses. It holds the `data-store-provider` engine object
@@ -167,6 +167,21 @@ export declare class StorageOrchestratorAddon extends BaseAddon<StorageOrchestra
167
167
  */
168
168
  private announceLocationsChanged;
169
169
  /** A location with its provider's declared secrets replaced by the sentinel. */
170
+ /**
171
+ * The location as a PROVIDER must see it: every keychain marker in its
172
+ * config resolved (D787). The same object when it holds none — a filesystem
173
+ * location costs nothing. An unresolvable secret is left out and logged by
174
+ * ref; the provider then fails its own connection, by name.
175
+ */
176
+ private withResolvedSecrets;
177
+ /**
178
+ * Strip the provider's DECLARED secrets (its form schema, by type) out of a
179
+ * location config into the keychain, under `row/storage_locations/<id>`.
180
+ * A provider that has not registered declares nothing: only keys that
181
+ * already hold a marker are handled then — a new plaintext is never guessed
182
+ * at, it stays as sent until the provider is back and the location is saved.
183
+ */
184
+ private keepSecretsInKeychain;
170
185
  private redacted;
171
186
  /**
172
187
  * Is this location backed by a provider that serves a genuine local