@camstack/types 1.2.332 → 1.2.334

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 (53) hide show
  1. package/dist/addon/base-addon.d.ts +32 -0
  2. package/dist/addon/secret-aware-context.d.ts +49 -6
  3. package/dist/addon/secret-settings-view.d.ts +23 -1
  4. package/dist/addon/secret-write-back.d.ts +40 -0
  5. package/dist/addon.js +5 -7
  6. package/dist/addon.mjs +5 -7
  7. package/dist/auth/app-callback.d.ts +28 -0
  8. package/dist/auth/sso-state.d.ts +16 -0
  9. package/dist/capabilities/addon-routes.cap.d.ts +3 -0
  10. package/dist/capabilities/addons.cap.d.ts +4 -4
  11. package/dist/capabilities/backup.cap.d.ts +101 -1
  12. package/dist/capabilities/broker.cap.d.ts +4 -4
  13. package/dist/capabilities/custom-model-registry.cap.d.ts +520 -0
  14. package/dist/capabilities/device-manager.cap.d.ts +4 -4
  15. package/dist/capabilities/hub-address.d.ts +2 -2
  16. package/dist/capabilities/index.d.ts +12 -6
  17. package/dist/capabilities/keychain-admin.cap.d.ts +83 -0
  18. package/dist/capabilities/login-method.cap.d.ts +5 -6
  19. package/dist/capabilities/nodes.cap.d.ts +8 -0
  20. package/dist/capabilities/notification-output.cap.d.ts +4 -4
  21. package/dist/capabilities/notification-rules.cap.d.ts +6 -6
  22. package/dist/capabilities/osd-manager.cap.d.ts +5 -5
  23. package/dist/capabilities/pipeline-analytics.cap.d.ts +39 -8
  24. package/dist/capabilities/recording.cap.d.ts +3 -3
  25. package/dist/capabilities/server-management.cap.d.ts +5 -5
  26. package/dist/capabilities/snapshot.cap.d.ts +2 -2
  27. package/dist/capabilities/sso-bridge.cap.d.ts +5 -2
  28. package/dist/capabilities/training-provider.cap.d.ts +373 -0
  29. package/dist/capabilities/training.cap.d.ts +1896 -0
  30. package/dist/capabilities/user-management.cap.d.ts +1 -64
  31. package/dist/capabilities/videoclips.cap.d.ts +3 -3
  32. package/dist/client.js +33 -5
  33. package/dist/client.mjs +33 -5
  34. package/dist/generated/addon-api.d.ts +872 -173
  35. package/dist/generated/cap-input-defaults.d.ts +1 -1
  36. package/dist/generated/capability-router-map.d.ts +10 -4
  37. package/dist/generated/collection-array-methods.d.ts +1 -1
  38. package/dist/generated/method-access-map.d.ts +1 -1
  39. package/dist/generated/method-device-selectors.d.ts +2 -2
  40. package/dist/generated/system-proxy.d.ts +5 -3
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.js +1469 -94
  43. package/dist/index.mjs +1420 -93
  44. package/dist/interfaces/addon-routes.d.ts +7 -0
  45. package/dist/interfaces/addon.d.ts +8 -0
  46. package/dist/interfaces/auth.d.ts +6 -3
  47. package/dist/interfaces/event-bus.d.ts +5 -0
  48. package/dist/schemas/auth-records.d.ts +1 -2
  49. package/dist/{sleep-ClNXPpWR.js → sleep-DiQYrfm9.js} +425 -75
  50. package/dist/{sleep-DujUvOcb.mjs → sleep-r3RWkGVx.mjs} +425 -75
  51. package/dist/training/index.d.ts +1 -0
  52. package/dist/training/trainer-contract.d.ts +468 -0
  53. package/package.json +1 -1
@@ -128,6 +128,14 @@ export declare abstract class BaseAddon<TConfig extends object = Record<string,
128
128
  private _secretChangeUnsub;
129
129
  /** >0 while an OPERATOR's settings write is being applied. */
130
130
  private _operatorWriteDepth;
131
+ /**
132
+ * The keychain-aware settings handle (D798). Its `raw` view is the ONLY way
133
+ * to the marker-bearing blobs and stays private to this class: the form
134
+ * hydrate and config resolution need markers, addon code never does.
135
+ */
136
+ private _secretSettings;
137
+ /** Refs an addon-facing read could not resolve — each is logged once per process. */
138
+ private _loggedUnresolvedReads;
131
139
  constructor(defaults: TConfig);
132
140
  /**
133
141
  * Override to opt out of the automatic `system.ready-state` emission.
@@ -279,8 +287,25 @@ export declare abstract class BaseAddon<TConfig extends object = Record<string,
279
287
  * the store for custom option logic (option narrowing, value snapping) to
280
288
  * read it per-node — never `ctx.settings.readAddonStore()` directly.
281
289
  * `nodeId` omitted ⇒ the local node (node-blind injection from ctx).
290
+ *
291
+ * Keychain values come back RESOLVED (D798): a secret reads as its value,
292
+ * never as a `{ $secret }` marker. One the keychain cannot serve right now
293
+ * stays a marker — "stored, unavailable" (`isSecretMarker()` is true, and it
294
+ * is listed in {@link unresolvedSecrets}) — never `''` and never absent, so
295
+ * it cannot be mistaken for "nothing stored, mint a new one". Writing the
296
+ * resolved blob back is a no-op for every unchanged secret.
282
297
  */
283
298
  protected resolveGlobalStore(nodeId?: string, cap?: string): Promise<Record<string, unknown>>;
299
+ private projectForNode;
300
+ /** The PROJECTED store with its markers — the form hydrate only (D798). */
301
+ private readRawProjectedStore;
302
+ /**
303
+ * `{ ...stored, ...overlay }`, except that an overlay member equal to the
304
+ * RESOLVED stored one keeps the stored (marker-bearing) member — so a form
305
+ * hydrated from a resolved overlay still shows a secret as "set", never as
306
+ * its value.
307
+ */
308
+ private overlayKeepingMarkers;
284
309
  /**
285
310
  * Whether ONE global key of this addon's store was written, read three-way
286
311
  * (D651). For a question a hydrated view cannot answer: `getGlobalSettings`
@@ -422,6 +447,13 @@ export declare abstract class BaseAddon<TConfig extends object = Record<string,
422
447
  * ever written back from here.
423
448
  */
424
449
  private resolveStoredSecrets;
450
+ /**
451
+ * The marker-bearing settings reads (D798) — private on purpose. Without a
452
+ * keychain the context's own view is already raw.
453
+ */
454
+ private rawSettings;
455
+ /** An addon-facing read met markers it could not resolve: say so once per ref. */
456
+ private logUnresolvedRead;
425
457
  /** Re-resolve the config (a keychain-only change, or a retry) and apply it. */
426
458
  private scheduleSecretReresolve;
427
459
  /**
@@ -1,9 +1,27 @@
1
1
  /**
2
- * Wrap an addon context so EVERY write to its settings store goes through the
3
- * keychain save path (D787) — `updateGlobalSettings`, `state()` handles, and an
4
- * addon's own direct `ctx.settings.writeAddonStore` / `writeDeviceStore` calls
5
- * alike. Reads stay raw (markers): a read surface never sees a value, and the
6
- * runtime resolves through `BaseAddon`.
2
+ * The settings view an addon sees once the kernel provides a keychain.
3
+ *
4
+ * READ (D798) — every addon-facing read answers VALUES, never markers:
5
+ * `readAddonStore`, `readAddonStoreResult`, `readAddonStoreKeyResult`,
6
+ * `readDeviceStore`, `readDeviceStoreBatch`. Markers are resolved through the
7
+ * addon's own `ctx.secrets` (owner-checked by the keychain, batched into one
8
+ * round trip per read, served from its cache). A marker that cannot be
9
+ * resolved STAYS a marker — "stored, unavailable right now" — and is reported
10
+ * through `onUnresolved`; it never reads as `''` or as absent, which is what
11
+ * invites a regenerate-and-save over the kept value. Three addons read their
12
+ * raw config and got a marker in place of their secret in one evening after
13
+ * the keychain migration (Wyze, ONVIF, Reolink); this is the root fix.
14
+ *
15
+ * WRITE (D787) — every write goes through the keychain save path, with the
16
+ * write-back of a resolved read made idempotent (`secret-write-back.ts`): an
17
+ * unchanged value becomes its marker again, nothing is put, a patch equal to
18
+ * what is stored is not written at all.
19
+ *
20
+ * RAW — the marker-bearing blob is reachable only through the handle's `raw`
21
+ * view, which `BaseAddon` keeps PRIVATE for the paths that need markers: the
22
+ * admin form hydrate (markers become "set" views), config resolution (which
23
+ * tracks unresolved refs for retry) and the save path itself. No addon code
24
+ * can reach it.
7
25
  *
8
26
  * A Proxy rather than a copy: an in-process context carries getters (`api`)
9
27
  * and a spread would freeze them at wrap time; a Proxy forwards every other
@@ -12,6 +30,8 @@
12
30
  import type { AddonContext } from '../interfaces/addon.js';
13
31
  import type { SecretsAccess } from '../keychain/secrets-access.js';
14
32
  import type { SecretTree } from './secret-paths.js';
33
+ import { type UnresolvedSecret } from './secret-settings-view.js';
34
+ type SettingsView = NonNullable<AddonContext['settings']>;
15
35
  export interface SecretAwareSettingsOptions {
16
36
  readonly secrets: SecretsAccess;
17
37
  /** The addon store's secret tree (schema + `secretStatePaths`). */
@@ -22,6 +42,29 @@ export interface SecretAwareSettingsOptions {
22
42
  readonly onOrphaned: (refs: readonly string[]) => void;
23
43
  /** Is the write in progress the OPERATOR's (see `SecretWriteInput.operatorWrite`)? */
24
44
  readonly isOperatorWrite?: () => boolean;
45
+ /** Told when an addon-facing read met markers it could not resolve. */
46
+ readonly onUnresolved?: (unresolved: readonly UnresolvedSecret[]) => void;
47
+ }
48
+ /** Whether a write reached the store or the keychain. */
49
+ export interface SecretAwareWriteOutcome {
50
+ readonly changed: boolean;
51
+ }
52
+ export interface SecretAwareSettingsHandle {
53
+ /** The view addon code gets: resolved reads, secret-aware writes. */
54
+ readonly settings: SettingsView;
55
+ /**
56
+ * The stored blobs WITH markers. For `BaseAddon`'s private use only — the
57
+ * form hydrate, config resolution, the save path. Never hand it to addon code.
58
+ */
59
+ readonly raw: Pick<SettingsView, 'readAddonStore' | 'readDeviceStore'>;
60
+ /** `settings.writeAddonStore`, also saying whether anything changed. */
61
+ writeAddonStore(patch: Record<string, unknown>): Promise<SecretAwareWriteOutcome>;
25
62
  }
26
- /** The context the addon sees: identical, except that its settings writes are secret-aware. */
63
+ /** The context the addon sees, plus the private raw view and write outcome. */
64
+ export declare function createSecretAwareContext(context: AddonContext, opts: SecretAwareSettingsOptions): {
65
+ readonly context: AddonContext;
66
+ readonly handle: SecretAwareSettingsHandle | null;
67
+ };
68
+ /** The context the addon sees: resolved reads, secret-aware writes. */
27
69
  export declare function withSecretAwareSettings(context: AddonContext, opts: SecretAwareSettingsOptions): AddonContext;
70
+ export {};
@@ -73,8 +73,30 @@ export interface ResolvedSecrets<T> {
73
73
  readonly value: T;
74
74
  readonly unresolved: readonly UnresolvedSecret[];
75
75
  }
76
+ /**
77
+ * What a marker that cannot be resolved becomes:
78
+ * - `omit` (default) — the member is LEFT OUT, so a typed default applies
79
+ * (`config`, `state()`, a driver's device config);
80
+ * - `keep-marker` — the marker STAYS where it is. An addon-facing raw read
81
+ * (D798) answers "stored, but unavailable right now": present, not a string,
82
+ * `isSecretMarker()` true. Never `''`, never absent — both of those read as
83
+ * "nothing stored" and invite a regenerate-and-save over the kept value.
84
+ */
85
+ export type UnresolvedMarkerMode = 'omit' | 'keep-marker';
86
+ export interface ResolveSecretMarkersOptions {
87
+ readonly unresolved?: UnresolvedMarkerMode;
88
+ /**
89
+ * Resolve only the markers this owner's refs: any other owner's marker is
90
+ * left exactly as it is — not resolved, not reported. A system builtin that
91
+ * keeps OTHER addons' markers in its own store (device-manager holds each
92
+ * driver's) must not ask the keychain for values it may not read.
93
+ */
94
+ readonly ownedBy?: string;
95
+ }
96
+ /** Is `ref` one of `owner`'s refs? */
97
+ export declare function isSecretRefOwnedBy(ref: string, owner: string): boolean;
76
98
  /**
77
99
  * Replace every marker in `value` with its keychain value. Returns the SAME
78
100
  * reference when there is no marker (no allocation, no keychain call).
79
101
  */
80
- export declare function resolveSecretMarkers<T>(value: T, secrets: SecretsAccess): Promise<ResolvedSecrets<T>>;
102
+ export declare function resolveSecretMarkers<T>(value: T, secrets: SecretsAccess, options?: ResolveSecretMarkersOptions): Promise<ResolvedSecrets<T>>;
@@ -0,0 +1,40 @@
1
+ import type { SecretsAccess } from '../keychain/secrets-access.js';
2
+ import type { SecretTree } from './secret-paths.js';
3
+ /** An addon tried to replace a stored secret it could not read. Nothing was written. */
4
+ export declare class SecretOverwriteRefusedError extends Error {
5
+ readonly ref: string;
6
+ readonly reason: string;
7
+ constructor(ref: string, reason: string);
8
+ }
9
+ export interface RestoreSecretsInput {
10
+ readonly patch: Record<string, unknown>;
11
+ /** The blob as stored now (markers). */
12
+ readonly stored: Record<string, unknown>;
13
+ readonly secrets: SecretsAccess;
14
+ /** The write is the operator's (a form, an admin API call), not the addon's own code. */
15
+ readonly operatorWrite: boolean;
16
+ }
17
+ export interface RestoreSecretsResult {
18
+ readonly patch: Record<string, unknown>;
19
+ /** Refs whose keychain value this pass changed (a `put`). */
20
+ readonly changedRefs: readonly string[];
21
+ }
22
+ /** Restore markers a write-back carries as values. See the file doc. */
23
+ export declare function restoreUnchangedSecrets(input: RestoreSecretsInput): Promise<RestoreSecretsResult>;
24
+ /** Structural equality over JSON-shaped values (key order does not matter). */
25
+ export declare function isJsonEqual(a: unknown, b: unknown): boolean;
26
+ /** The patch without the keys whose value already equals the stored one. */
27
+ export declare function dropUnchangedKeys(patch: Record<string, unknown>, stored: Record<string, unknown>): Record<string, unknown>;
28
+ /** The top-level keys of a blob that hold at least one of `owner`'s markers. */
29
+ export declare function markerKeysOf(blob: Record<string, unknown>, owner: string): Set<string>;
30
+ /**
31
+ * The declared secret tree, widened by every place the STORED blob holds a
32
+ * marker under one of `keys` — so a marker the schema no longer declares (or
33
+ * never declared: Wyze before b4906cec6) still gets the save path's
34
+ * KEEP / SET / CLEAR semantics instead of being overwritten by whatever the
35
+ * addon writes. Markers inside arrays are not added: a row has no id field to
36
+ * match by unless the schema declares one. Only `owner`'s markers count: a
37
+ * builtin that keeps another addon's marker (device-manager) never takes it
38
+ * over.
39
+ */
40
+ export declare function widenTreeWithStoredMarkers(declared: SecretTree, stored: Record<string, unknown>, keys: readonly string[], owner: string): SecretTree;
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-ClNXPpWR.js");
2
+ const require_sleep = require("./sleep-DiQYrfm9.js");
3
3
  const require_event_category = require("./event-category-CHduMGvg.js");
4
4
  const require_err_msg = require("./err-msg-Dx2Kor0g.js");
5
5
  //#region src/generated/cap-input-defaults.ts
@@ -16,7 +16,7 @@ const require_err_msg = require("./err-msg-Dx2Kor0g.js");
16
16
  * Plain data, zero Zod: a forked runner must not import the schema barrel
17
17
  * (~144MB RSS per runner — D28).
18
18
  *
19
- * Coverage: 24 caps, 62 methods with defaults.
19
+ * Coverage: 24 caps, 61 methods with defaults.
20
20
  */
21
21
  var CAP_INPUT_DEFAULTS = Object.freeze({
22
22
  "addons": { "getLogs": { "limit": 100 } },
@@ -254,10 +254,7 @@ var CAP_INPUT_DEFAULTS = Object.freeze({
254
254
  }
255
255
  },
256
256
  "terminal-session": { "pullOutput": { "waitMs": 0 } },
257
- "user-management": {
258
- "createApiKey": { "isAdmin": false },
259
- "createUser": { "isAdmin": false }
260
- },
257
+ "user-management": { "createUser": { "isAdmin": false } },
261
258
  "vector-store": {
262
259
  "declareIndex": { "metric": "cosine" },
263
260
  "scan": { "cursor": 0 }
@@ -337,7 +334,7 @@ function materialise(defaults) {
337
334
  * barrel (`ALL_CAPABILITY_DEFINITIONS`), which would cost ~144MB RSS per
338
335
  * forked runner. See docs/decisions/adr-0028.md.
339
336
  *
340
- * Coverage: 25 collection caps, 41 array methods.
337
+ * Coverage: 26 collection caps, 43 array methods.
341
338
  */
342
339
  var COLLECTION_ARRAY_METHODS = Object.freeze({
343
340
  "addon-pages-source": ["listPages"],
@@ -375,6 +372,7 @@ var COLLECTION_ARRAY_METHODS = Object.freeze({
375
372
  "recording": ["listSources"],
376
373
  "storage-occupancy": ["getOccupancy"],
377
374
  "storage-provider": ["list"],
375
+ "training-provider": ["describe", "listJobs"],
378
376
  "turn-provider": ["getTurnServers"],
379
377
  "user-passkeys": ["listPasskeys"],
380
378
  "videoclips": ["listClips", "listSources"]
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $t as normalizeSecretOwner, A as adminUiCapability, At as PEER_BYTES_MAX_OUTSTANDING, C as deviceOpsCapability, Ct as clearKnownSecrets, Dt as scrubKnownSecrets, Et as registerKnownSecret, I as expandCapMethods, It as DisposerChain, Jt as arrayItemFieldPath, K as ReadinessRegistry, Lt as BaseAddon, Mt as PEER_BYTES_TICKET_TTL_MS, O as describeCustomActions, Ot as shortSecretRefHash, Pt as DATAPLANE_SECRET_HEADER, Qt as isSecretRef, Rt as normalizeAddonInitResult, St as MIN_SCRUBBED_LENGTH, T as DEVICE_CHILDREN_BATCH_MAX, Tt as knownSecretCount, U as nodePin, W as readNodePin, X as scopeKey, Xt as formatSecretScope, Yt as buildSecretRef, Zt as globalSecretScope, _n as isSecretMarkerLike, a as asJsonObject, b as collectZodSecretPaths, bt as REVALIDATE_AFTER_MS, d as BOOT_RECOVERY_BACKOFF_MS, en as parseSecretRef, f as DEVICE_SCOPED_CAPS, fn as SECRET_CLEAR, gn as isSecretMarker, h as createEventBusSliceSource, hn as isSecretFieldView, in as emitReadiness, jt as PEER_BYTES_STALL_MS, kt as PEER_BYTES_CHUNK_BYTES, m as createDeviceProxy, mn as isSecretClear, p as isDeviceScopedCap, pn as classifySecretWrite, q as ReadinessTimeoutError, qt as SECRET_REF_SCHEME, s as asString, t as sleep, u as parseJsonUnknown, vn as makeSecretMarker, w as viewerUiCapability, wt as forgetKnownSecret, x as isZodSecret, xt as createSecretsAccess, yn as toSecretFieldView, yt as resolveSecretViewsIn } from "./sleep-DujUvOcb.mjs";
1
+ import { $t as normalizeSecretOwner, A as adminUiCapability, At as PEER_BYTES_MAX_OUTSTANDING, C as deviceOpsCapability, Ct as clearKnownSecrets, Dt as scrubKnownSecrets, Et as registerKnownSecret, I as expandCapMethods, It as DisposerChain, Jt as arrayItemFieldPath, K as ReadinessRegistry, Lt as BaseAddon, Mt as PEER_BYTES_TICKET_TTL_MS, O as describeCustomActions, Ot as shortSecretRefHash, Pt as DATAPLANE_SECRET_HEADER, Qt as isSecretRef, Rt as normalizeAddonInitResult, St as MIN_SCRUBBED_LENGTH, T as DEVICE_CHILDREN_BATCH_MAX, Tt as knownSecretCount, U as nodePin, W as readNodePin, X as scopeKey, Xt as formatSecretScope, Yt as buildSecretRef, Zt as globalSecretScope, _n as isSecretMarkerLike, a as asJsonObject, b as collectZodSecretPaths, bt as REVALIDATE_AFTER_MS, d as BOOT_RECOVERY_BACKOFF_MS, en as parseSecretRef, f as DEVICE_SCOPED_CAPS, fn as SECRET_CLEAR, gn as isSecretMarker, h as createEventBusSliceSource, hn as isSecretFieldView, in as emitReadiness, jt as PEER_BYTES_STALL_MS, kt as PEER_BYTES_CHUNK_BYTES, m as createDeviceProxy, mn as isSecretClear, p as isDeviceScopedCap, pn as classifySecretWrite, q as ReadinessTimeoutError, qt as SECRET_REF_SCHEME, s as asString, t as sleep, u as parseJsonUnknown, vn as makeSecretMarker, w as viewerUiCapability, wt as forgetKnownSecret, x as isZodSecret, xt as createSecretsAccess, yn as toSecretFieldView, yt as resolveSecretViewsIn } from "./sleep-r3RWkGVx.mjs";
2
2
  import { t as EventCategory } from "./event-category-DaIZi00R.mjs";
3
3
  import { a as DeviceType, t as errMsg } from "./err-msg-DX6i_MY4.mjs";
4
4
  //#region src/generated/cap-input-defaults.ts
@@ -15,7 +15,7 @@ import { a as DeviceType, t as errMsg } from "./err-msg-DX6i_MY4.mjs";
15
15
  * Plain data, zero Zod: a forked runner must not import the schema barrel
16
16
  * (~144MB RSS per runner — D28).
17
17
  *
18
- * Coverage: 24 caps, 62 methods with defaults.
18
+ * Coverage: 24 caps, 61 methods with defaults.
19
19
  */
20
20
  var CAP_INPUT_DEFAULTS = Object.freeze({
21
21
  "addons": { "getLogs": { "limit": 100 } },
@@ -253,10 +253,7 @@ var CAP_INPUT_DEFAULTS = Object.freeze({
253
253
  }
254
254
  },
255
255
  "terminal-session": { "pullOutput": { "waitMs": 0 } },
256
- "user-management": {
257
- "createApiKey": { "isAdmin": false },
258
- "createUser": { "isAdmin": false }
259
- },
256
+ "user-management": { "createUser": { "isAdmin": false } },
260
257
  "vector-store": {
261
258
  "declareIndex": { "metric": "cosine" },
262
259
  "scan": { "cursor": 0 }
@@ -336,7 +333,7 @@ function materialise(defaults) {
336
333
  * barrel (`ALL_CAPABILITY_DEFINITIONS`), which would cost ~144MB RSS per
337
334
  * forked runner. See docs/decisions/adr-0028.md.
338
335
  *
339
- * Coverage: 25 collection caps, 41 array methods.
336
+ * Coverage: 26 collection caps, 43 array methods.
340
337
  */
341
338
  var COLLECTION_ARRAY_METHODS = Object.freeze({
342
339
  "addon-pages-source": ["listPages"],
@@ -374,6 +371,7 @@ var COLLECTION_ARRAY_METHODS = Object.freeze({
374
371
  "recording": ["listSources"],
375
372
  "storage-occupancy": ["getOccupancy"],
376
373
  "storage-provider": ["list"],
374
+ "training-provider": ["describe", "listJobs"],
377
375
  "turn-provider": ["getTurnServers"],
378
376
  "user-passkeys": ["listPasskeys"],
379
377
  "videoclips": ["listClips", "listSources"]
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The viewer app's custom-scheme callback — the ONE list of URLs a hub flow
3
+ * may hand a browser back to the native app at.
4
+ *
5
+ * Two readers, one answer: the admin-ui login page (`redirect=` for the
6
+ * native sign-in handoff) and the hub itself (`auth.beginExternalLink`'s
7
+ * `returnTo` for a native account link, D801). Both validate against this
8
+ * list, so a scheme added for one flow can never be accepted by one side and
9
+ * refused by the other.
10
+ *
11
+ * `camstack` is the production app; `camstack.dev` the dev client
12
+ * (`APP_VARIANT=development`). Exact match after canonicalisation — no
13
+ * query or fragment riders, no http(s).
14
+ */
15
+ export declare const APP_AUTH_CALLBACK_URLS: readonly string[];
16
+ /** Longest raw callback value considered at all. */
17
+ export declare const APP_AUTH_CALLBACK_MAX_LENGTH = 512;
18
+ /**
19
+ * The variants the OS / linking layer produces for the same callback:
20
+ * `scheme:///auth-callback` (expo-linking's empty-host standalone form — three
21
+ * slashes) and a trailing `/` both mean `scheme://auth-callback`. Nothing else
22
+ * is normalised: riders keep failing the exact match.
23
+ */
24
+ export declare function canonicalizeAppCallback(raw: string): string;
25
+ /** The canonical allowlisted callback `raw` names, or `null`. */
26
+ export declare function parseAppAuthCallback(raw: string | null | undefined): string | null;
27
+ /** True for a URL with a scheme (`camstack://…`, `https://…`) — not a hub-relative path. */
28
+ export declare function hasUrlScheme(url: string): boolean;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The cookie that binds an SSO sign-in to the browser that started it.
3
+ *
4
+ * An IdP `/start` sets it to a random value and keeps only its SHA-256 in the
5
+ * server-side pending state; the login bridge carries that hash. The hub's
6
+ * `/api/auth/sso/finish` swaps a bridge for a session only when the request
7
+ * presents the cookie whose hash the bridge names — so a bridge copied out of
8
+ * a URL (history, a proxy log, a screenshot) is useless in any other browser.
9
+ * The finish clears the cookie, and records the bridge's `jti` so the same
10
+ * bridge never finishes twice.
11
+ *
12
+ * One name, two readers (the OIDC addon that sets it, the hub that checks it).
13
+ */
14
+ export declare const SSO_STATE_COOKIE = "camstack_sso_state";
15
+ /** Seconds the state cookie lives — the pending IdP state lasts 5 minutes, the bridge 5 more. */
16
+ export declare const SSO_STATE_COOKIE_MAX_AGE_SEC = 600;
@@ -50,6 +50,9 @@ export declare const addonRoutesCapability: {
50
50
  authenticated: "authenticated";
51
51
  }>>;
52
52
  description: z.ZodOptional<z.ZodString>;
53
+ rateLimit: z.ZodOptional<z.ZodEnum<{
54
+ auth: "auth";
55
+ }>>;
53
56
  }, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind>;
54
57
  /**
55
58
  * Cross-process dispatch entry point. Forked addons implement this
@@ -139,8 +139,8 @@ declare const AddonAutoUpdateSchema: z.ZodEnum<{
139
139
  * copy when the node registers again (only once the hub no longer has it).
140
140
  */
141
141
  declare const UninstallNodeOutcomeSchema: z.ZodEnum<{
142
- failed: "failed";
143
142
  refused: "refused";
143
+ failed: "failed";
144
144
  uninstalled: "uninstalled";
145
145
  "not-installed": "not-installed";
146
146
  "pending-reconnect": "pending-reconnect";
@@ -148,8 +148,8 @@ declare const UninstallNodeOutcomeSchema: z.ZodEnum<{
148
148
  declare const UninstallNodeResultSchema: z.ZodObject<{
149
149
  nodeId: z.ZodString;
150
150
  outcome: z.ZodEnum<{
151
- failed: "failed";
152
151
  refused: "refused";
152
+ failed: "failed";
153
153
  uninstalled: "uninstalled";
154
154
  "not-installed": "not-installed";
155
155
  "pending-reconnect": "pending-reconnect";
@@ -165,8 +165,8 @@ declare const UninstallPackageResultSchema: z.ZodObject<{
165
165
  results: z.ZodReadonly<z.ZodArray<z.ZodObject<{
166
166
  nodeId: z.ZodString;
167
167
  outcome: z.ZodEnum<{
168
- failed: "failed";
169
168
  refused: "refused";
169
+ failed: "failed";
170
170
  uninstalled: "uninstalled";
171
171
  "not-installed": "not-installed";
172
172
  "pending-reconnect": "pending-reconnect";
@@ -427,8 +427,8 @@ export declare const addonsCapability: {
427
427
  results: z.ZodReadonly<z.ZodArray<z.ZodObject<{
428
428
  nodeId: z.ZodString;
429
429
  outcome: z.ZodEnum<{
430
- failed: "failed";
431
430
  refused: "refused";
431
+ failed: "failed";
432
432
  uninstalled: "uninstalled";
433
433
  "not-installed": "not-installed";
434
434
  "pending-reconnect": "pending-reconnect";
@@ -57,6 +57,34 @@ declare const BackupDestinationInfoSchema: z.ZodObject<{
57
57
  lastAttemptAt: z.ZodOptional<z.ZodNumber>;
58
58
  lastError: z.ZodOptional<z.ZodString>;
59
59
  }, z.core.$strip>;
60
+ /**
61
+ * How an archive is encrypted (operator decision 2026-10-09): to a backup
62
+ * PUBLIC key the hub holds, so only the operator's secret key opens it.
63
+ * Absent on a plain `.tar.gz` — every archive made before encryption, or
64
+ * with it off — which restores without a key.
65
+ */
66
+ declare const BackupArchiveEncryptionSchema: z.ZodObject<{
67
+ scheme: z.ZodString;
68
+ keyId: z.ZodString;
69
+ }, z.core.$strip>;
70
+ /**
71
+ * The backup encryption setting. The hub keeps PUBLIC keys only: the active
72
+ * one new archives are encrypted to, and the retired ones older archives
73
+ * still need. The secret key is shown once, at `setupEncryption`.
74
+ */
75
+ declare const BackupEncryptionStatusSchema: z.ZodObject<{
76
+ enabled: z.ZodBoolean;
77
+ active: z.ZodNullable<z.ZodObject<{
78
+ keyId: z.ZodString;
79
+ publicKey: z.ZodString;
80
+ createdAt: z.ZodNumber;
81
+ }, z.core.$strip>>;
82
+ keys: z.ZodReadonly<z.ZodArray<z.ZodObject<{
83
+ keyId: z.ZodString;
84
+ createdAt: z.ZodNumber;
85
+ retiredAt: z.ZodNullable<z.ZodNumber>;
86
+ }, z.core.$strip>>>;
87
+ }, z.core.$strip>;
60
88
  /**
61
89
  * Per-archive entry returned by `backup.listArchives({ destinationId })`.
62
90
  * Same shape the destination drill-in renders. Sourced from the per-
@@ -69,6 +97,10 @@ declare const BackupArchiveEntrySchema: z.ZodObject<{
69
97
  sizeBytes: z.ZodNumber;
70
98
  label: z.ZodOptional<z.ZodString>;
71
99
  locations: z.ZodReadonly<z.ZodArray<z.ZodString>>;
100
+ encryption: z.ZodOptional<z.ZodObject<{
101
+ scheme: z.ZodString;
102
+ keyId: z.ZodString;
103
+ }, z.core.$strip>>;
72
104
  }, z.core.$strip>;
73
105
  declare const BackupEntrySchema: z.ZodObject<{
74
106
  id: z.ZodString;
@@ -77,6 +109,10 @@ declare const BackupEntrySchema: z.ZodObject<{
77
109
  createdAt: z.ZodNumber;
78
110
  sizeBytes: z.ZodNumber;
79
111
  locations: z.ZodOptional<z.ZodArray<z.ZodString>>;
112
+ encryption: z.ZodOptional<z.ZodObject<{
113
+ scheme: z.ZodString;
114
+ keyId: z.ZodString;
115
+ }, z.core.$strip>>;
80
116
  }, z.core.$strip>;
81
117
  declare const ArchiveEntrySchema: z.ZodObject<{
82
118
  path: z.ZodString;
@@ -200,6 +236,10 @@ declare const BackupTriggerResultSchema: z.ZodObject<{
200
236
  createdAt: z.ZodNumber;
201
237
  sizeBytes: z.ZodNumber;
202
238
  locations: z.ZodOptional<z.ZodArray<z.ZodString>>;
239
+ encryption: z.ZodOptional<z.ZodObject<{
240
+ scheme: z.ZodString;
241
+ keyId: z.ZodString;
242
+ }, z.core.$strip>>;
203
243
  }, z.core.$strip>>>;
204
244
  }, z.core.$strip>;
205
245
  /**
@@ -293,6 +333,10 @@ export declare const backupCapability: {
293
333
  createdAt: z.ZodNumber;
294
334
  sizeBytes: z.ZodNumber;
295
335
  locations: z.ZodOptional<z.ZodArray<z.ZodString>>;
336
+ encryption: z.ZodOptional<z.ZodObject<{
337
+ scheme: z.ZodString;
338
+ keyId: z.ZodString;
339
+ }, z.core.$strip>>;
296
340
  }, z.core.$strip>>>;
297
341
  }, z.core.$strip>, "mutation">;
298
342
  /**
@@ -354,6 +398,10 @@ export declare const backupCapability: {
354
398
  createdAt: z.ZodNumber;
355
399
  sizeBytes: z.ZodNumber;
356
400
  locations: z.ZodOptional<z.ZodArray<z.ZodString>>;
401
+ encryption: z.ZodOptional<z.ZodObject<{
402
+ scheme: z.ZodString;
403
+ keyId: z.ZodString;
404
+ }, z.core.$strip>>;
357
405
  }, z.core.$strip>>>, import("./capability-definition.js").CapabilityMethodKind>;
358
406
  /**
359
407
  * Pre-backup snapshot of the well-known locations on disk — sizes
@@ -413,7 +461,53 @@ export declare const backupCapability: {
413
461
  destinationId: z.ZodString;
414
462
  backupId: z.ZodString;
415
463
  locations: z.ZodOptional<z.ZodArray<z.ZodString>>;
464
+ backupSecretKey: z.ZodOptional<z.ZodString>;
416
465
  }, z.core.$strip>, z.ZodVoid, "mutation">;
466
+ /** The encryption setting — public keys only. */
467
+ readonly getEncryption: import("./capability-definition.js").CapabilityMethodSchema<z.ZodVoid, z.ZodObject<{
468
+ enabled: z.ZodBoolean;
469
+ active: z.ZodNullable<z.ZodObject<{
470
+ keyId: z.ZodString;
471
+ publicKey: z.ZodString;
472
+ createdAt: z.ZodNumber;
473
+ }, z.core.$strip>>;
474
+ keys: z.ZodReadonly<z.ZodArray<z.ZodObject<{
475
+ keyId: z.ZodString;
476
+ createdAt: z.ZodNumber;
477
+ retiredAt: z.ZodNullable<z.ZodNumber>;
478
+ }, z.core.$strip>>>;
479
+ }, z.core.$strip>, import("./capability-definition.js").CapabilityMethodKind>;
480
+ /**
481
+ * Turn encryption on, or replace the key: generates a new key pair, keeps
482
+ * the PUBLIC key, and returns the SECRET key — once. It is never stored
483
+ * on the hub and cannot be shown again; archives made from now on need
484
+ * it to be restored. A previous key is retired: archives made with it
485
+ * still need IT.
486
+ */
487
+ readonly setupEncryption: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
488
+ keyId: z.ZodString;
489
+ secretKey: z.ZodString;
490
+ publicKey: z.ZodString;
491
+ createdAt: z.ZodNumber;
492
+ replacedKeyId: z.ZodNullable<z.ZodString>;
493
+ }, z.core.$strip>, "mutation">;
494
+ /** New archives are plain again. Existing encrypted archives keep needing their key. */
495
+ readonly disableEncryption: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
496
+ disabledKeyId: z.ZodNullable<z.ZodString>;
497
+ }, z.core.$strip>, "mutation">;
498
+ /**
499
+ * Does this secret key parse, and which backup key is it? A mutation so
500
+ * the key never travels in a URL. Nothing is stored.
501
+ */
502
+ readonly checkBackupKey: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
503
+ backupSecretKey: z.ZodString;
504
+ }, z.core.$strip>, z.ZodObject<{
505
+ valid: z.ZodBoolean;
506
+ keyId: z.ZodNullable<z.ZodString>;
507
+ known: z.ZodBoolean;
508
+ active: z.ZodBoolean;
509
+ error: z.ZodOptional<z.ZodString>;
510
+ }, z.core.$strip>, "mutation">;
417
511
  readonly delete: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
418
512
  destinationId: z.ZodString;
419
513
  backupId: z.ZodString;
@@ -432,6 +526,10 @@ export declare const backupCapability: {
432
526
  sizeBytes: z.ZodNumber;
433
527
  label: z.ZodOptional<z.ZodString>;
434
528
  locations: z.ZodReadonly<z.ZodArray<z.ZodString>>;
529
+ encryption: z.ZodOptional<z.ZodObject<{
530
+ scheme: z.ZodString;
531
+ keyId: z.ZodString;
532
+ }, z.core.$strip>>;
435
533
  }, z.core.$strip>>>, import("./capability-definition.js").CapabilityMethodKind>;
436
534
  /**
437
535
  * Upsert a per-destination policy row. The `locationId` MUST be
@@ -510,7 +608,9 @@ export declare const backupCapability: {
510
608
  };
511
609
  };
512
610
  export type IBackupProvider = InferProvider<typeof backupCapability>;
513
- export { ArchiveEntrySchema, ArchiveManifestSchema, BackupArchiveEntrySchema, BackupDestinationInfoSchema, BackupEntrySchema, BackupRunPhaseSchema, BackupRunSchema, BackupRunStateSchema, BackupScheduleSchema, BackupSubDestinationInfoSchema, BackupTriggerResultSchema, LocationStatSchema, };
611
+ export { ArchiveEntrySchema, ArchiveManifestSchema, BackupArchiveEncryptionSchema, BackupArchiveEntrySchema, BackupEncryptionStatusSchema, BackupDestinationInfoSchema, BackupEntrySchema, BackupRunPhaseSchema, BackupRunSchema, BackupRunStateSchema, BackupScheduleSchema, BackupSubDestinationInfoSchema, BackupTriggerResultSchema, LocationStatSchema, };
612
+ export type BackupArchiveEncryption = z.infer<typeof BackupArchiveEncryptionSchema>;
613
+ export type BackupEncryptionStatus = z.infer<typeof BackupEncryptionStatusSchema>;
514
614
  export type BackupRunState = z.infer<typeof BackupRunStateSchema>;
515
615
  export type BackupRunPhase = z.infer<typeof BackupRunPhaseSchema>;
516
616
  export type BackupRun = z.infer<typeof BackupRunSchema>;
@@ -47,8 +47,8 @@ import { type InferProvider } from './capability-definition.js';
47
47
  */
48
48
  export declare const BrokerStatusEnum: z.ZodEnum<{
49
49
  error: "error";
50
- connecting: "connecting";
51
50
  unreachable: "unreachable";
51
+ connecting: "connecting";
52
52
  connected: "connected";
53
53
  disconnected: "disconnected";
54
54
  "auth-failed": "auth-failed";
@@ -61,8 +61,8 @@ declare const BrokerInfoSchema: z.ZodObject<{
61
61
  kind: z.ZodString;
62
62
  status: z.ZodEnum<{
63
63
  error: "error";
64
- connecting: "connecting";
65
64
  unreachable: "unreachable";
65
+ connecting: "connecting";
66
66
  connected: "connected";
67
67
  disconnected: "disconnected";
68
68
  "auth-failed": "auth-failed";
@@ -162,8 +162,8 @@ export declare const brokerCapability: {
162
162
  kind: z.ZodString;
163
163
  status: z.ZodEnum<{
164
164
  error: "error";
165
- connecting: "connecting";
166
165
  unreachable: "unreachable";
166
+ connecting: "connecting";
167
167
  connected: "connected";
168
168
  disconnected: "disconnected";
169
169
  "auth-failed": "auth-failed";
@@ -181,8 +181,8 @@ export declare const brokerCapability: {
181
181
  kind: z.ZodString;
182
182
  status: z.ZodEnum<{
183
183
  error: "error";
184
- connecting: "connecting";
185
184
  unreachable: "unreachable";
185
+ connecting: "connecting";
186
186
  connected: "connected";
187
187
  disconnected: "disconnected";
188
188
  "auth-failed": "auth-failed";