@camstack/types 1.2.14 → 1.2.16

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.
package/dist/addon.d.ts CHANGED
@@ -26,6 +26,8 @@ export { DisposerChain } from './disposer-chain.js';
26
26
  export { ReadinessRegistry, ReadinessTimeoutError, scopeKey, } from './readiness/readiness-registry.js';
27
27
  export { DATAPLANE_SECRET_HEADER } from './interfaces/addon-data-plane.js';
28
28
  export { expandCapMethods } from './capabilities/capability-definition.js';
29
+ export { nodePin, readNodePin } from './cap-call-context.js';
30
+ export { COLLECTION_ARRAY_METHODS, isCollectionArrayMethodName, } from './generated/collection-array-methods.js';
29
31
  export { deviceOpsCapability } from './capabilities/device-ops.cap.js';
30
32
  export { createDeviceProxy } from './generated/device-proxy.js';
31
33
  export { BaseAddon, normalizeAddonInitResult } from './addon/base-addon.js';
package/dist/addon.js CHANGED
@@ -1,8 +1,63 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-BG8hQTA8.js");
2
+ const require_sleep = require("./sleep-DRg9F6JJ.js");
3
3
  const require_event_category = require("./event-category-Cdyife4p.js");
4
4
  const require_err_msg = require("./err-msg-COpsHMw2.js");
5
+ //#region src/generated/collection-array-methods.ts
6
+ /**
7
+ * AUTO-GENERATED by scripts/generate-collection-array-methods.ts — DO NOT EDIT.
8
+ *
9
+ * For every COLLECTION-mode capability, the array-returning (non-subscription)
10
+ * method names the hub fans across providers. The addon-runner uses this to
11
+ * reproduce the hub's graceful "provider skips an unimplemented collection
12
+ * method" behaviour (see child-cap-dispatch) WITHOUT importing the schema
13
+ * barrel (`ALL_CAPABILITY_DEFINITIONS`), which would cost ~144MB RSS per
14
+ * forked runner. See docs/decisions/adr-0028.md.
15
+ *
16
+ * Coverage: 16 collection caps, 28 array methods.
17
+ */
18
+ var COLLECTION_ARRAY_METHODS = Object.freeze({
19
+ "addon-pages-source": ["listPages"],
20
+ "addon-routes": ["getRoutes"],
21
+ "addon-widgets-source": ["listWidgets"],
22
+ "broker": ["list", "listProviders"],
23
+ "custom-model-registry": ["listModels"],
24
+ "device-export": ["listExposedDevices", "listSupportedDeviceKinds"],
25
+ "device-provider": ["discoverDevices", "getDevices"],
26
+ "llm": [
27
+ "getDefaults",
28
+ "getUsage",
29
+ "listModelCatalog",
30
+ "listModels",
31
+ "listNodeModels",
32
+ "listProfileKinds",
33
+ "listProfiles",
34
+ "listRuntimeNodes"
35
+ ],
36
+ "log-destination": ["query"],
37
+ "login-method": ["getLoginMethods"],
38
+ "mqtt-broker": ["listBrokers"],
39
+ "network-access": ["listEndpoints"],
40
+ "notification-output": [
41
+ "discoverTargets",
42
+ "listTargetKinds",
43
+ "listTargets"
44
+ ],
45
+ "storage-provider": ["list"],
46
+ "turn-provider": ["getTurnServers"],
47
+ "user-passkeys": ["listPasskeys"]
48
+ });
49
+ /**
50
+ * True when `method` on cap `capName` is a COLLECTION cap's array-returning
51
+ * (non-subscription) method — the schema-free runner-side equivalent of
52
+ * `isCollectionArrayMethod(capDefsByName.get(capName), method)`.
53
+ */
54
+ function isCollectionArrayMethodName(capName, method) {
55
+ const methods = COLLECTION_ARRAY_METHODS[capName];
56
+ return methods !== void 0 && methods.includes(method);
57
+ }
58
+ //#endregion
5
59
  exports.BaseAddon = require_sleep.BaseAddon;
60
+ exports.COLLECTION_ARRAY_METHODS = COLLECTION_ARRAY_METHODS;
6
61
  exports.DATAPLANE_SECRET_HEADER = require_sleep.DATAPLANE_SECRET_HEADER;
7
62
  exports.DeviceType = require_sleep.DeviceType;
8
63
  exports.DisposerChain = require_sleep.DisposerChain;
@@ -17,8 +72,11 @@ exports.deviceOpsCapability = require_sleep.deviceOpsCapability;
17
72
  exports.emitReadiness = require_sleep.emitReadiness;
18
73
  exports.errMsg = require_err_msg.errMsg;
19
74
  exports.expandCapMethods = require_sleep.expandCapMethods;
75
+ exports.isCollectionArrayMethodName = isCollectionArrayMethodName;
76
+ exports.nodePin = require_sleep.nodePin;
20
77
  exports.normalizeAddonInitResult = require_sleep.normalizeAddonInitResult;
21
78
  exports.parseJsonUnknown = require_sleep.parseJsonUnknown;
79
+ exports.readNodePin = require_sleep.readNodePin;
22
80
  exports.scopeKey = require_sleep.scopeKey;
23
81
  exports.sleep = require_sleep.sleep;
24
82
  exports.viewerUiCapability = require_sleep.viewerUiCapability;
package/dist/addon.mjs CHANGED
@@ -1,4 +1,58 @@
1
- import { A as parseJsonUnknown, D as asString, I as scopeKey, M as ReadinessRegistry, N as ReadinessTimeoutError, S as DeviceType, T as asJsonObject, a as viewerUiCapability, bt as DisposerChain, ct as BaseAddon, ft as emitReadiness, i as deviceOpsCapability, j as DATAPLANE_SECRET_HEADER, lt as normalizeAddonInitResult, m as expandCapMethods, o as adminUiCapability, s as createDeviceProxy, t as sleep } from "./sleep-DiOnzenz.mjs";
1
+ import { A as parseJsonUnknown, Ct as DisposerChain, D as asString, F as ReadinessRegistry, I as ReadinessTimeoutError, M as nodePin, N as readNodePin, P as DATAPLANE_SECRET_HEADER, S as DeviceType, T as asJsonObject, a as viewerUiCapability, dt as BaseAddon, ft as normalizeAddonInitResult, ht as emitReadiness, i as deviceOpsCapability, m as expandCapMethods, o as adminUiCapability, s as createDeviceProxy, t as sleep, z as scopeKey } from "./sleep-C3ceNSsf.mjs";
2
2
  import { t as EventCategory } from "./event-category-BLcNejAE.mjs";
3
3
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
4
- export { BaseAddon, DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, ReadinessTimeoutError, adminUiCapability, asJsonObject, asString, createDeviceProxy, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, normalizeAddonInitResult, parseJsonUnknown, scopeKey, sleep, viewerUiCapability };
4
+ //#region src/generated/collection-array-methods.ts
5
+ /**
6
+ * AUTO-GENERATED by scripts/generate-collection-array-methods.ts — DO NOT EDIT.
7
+ *
8
+ * For every COLLECTION-mode capability, the array-returning (non-subscription)
9
+ * method names the hub fans across providers. The addon-runner uses this to
10
+ * reproduce the hub's graceful "provider skips an unimplemented collection
11
+ * method" behaviour (see child-cap-dispatch) WITHOUT importing the schema
12
+ * barrel (`ALL_CAPABILITY_DEFINITIONS`), which would cost ~144MB RSS per
13
+ * forked runner. See docs/decisions/adr-0028.md.
14
+ *
15
+ * Coverage: 16 collection caps, 28 array methods.
16
+ */
17
+ var COLLECTION_ARRAY_METHODS = Object.freeze({
18
+ "addon-pages-source": ["listPages"],
19
+ "addon-routes": ["getRoutes"],
20
+ "addon-widgets-source": ["listWidgets"],
21
+ "broker": ["list", "listProviders"],
22
+ "custom-model-registry": ["listModels"],
23
+ "device-export": ["listExposedDevices", "listSupportedDeviceKinds"],
24
+ "device-provider": ["discoverDevices", "getDevices"],
25
+ "llm": [
26
+ "getDefaults",
27
+ "getUsage",
28
+ "listModelCatalog",
29
+ "listModels",
30
+ "listNodeModels",
31
+ "listProfileKinds",
32
+ "listProfiles",
33
+ "listRuntimeNodes"
34
+ ],
35
+ "log-destination": ["query"],
36
+ "login-method": ["getLoginMethods"],
37
+ "mqtt-broker": ["listBrokers"],
38
+ "network-access": ["listEndpoints"],
39
+ "notification-output": [
40
+ "discoverTargets",
41
+ "listTargetKinds",
42
+ "listTargets"
43
+ ],
44
+ "storage-provider": ["list"],
45
+ "turn-provider": ["getTurnServers"],
46
+ "user-passkeys": ["listPasskeys"]
47
+ });
48
+ /**
49
+ * True when `method` on cap `capName` is a COLLECTION cap's array-returning
50
+ * (non-subscription) method — the schema-free runner-side equivalent of
51
+ * `isCollectionArrayMethod(capDefsByName.get(capName), method)`.
52
+ */
53
+ function isCollectionArrayMethodName(capName, method) {
54
+ const methods = COLLECTION_ARRAY_METHODS[capName];
55
+ return methods !== void 0 && methods.includes(method);
56
+ }
57
+ //#endregion
58
+ export { BaseAddon, COLLECTION_ARRAY_METHODS, DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, ReadinessTimeoutError, adminUiCapability, asJsonObject, asString, createDeviceProxy, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, isCollectionArrayMethodName, nodePin, normalizeAddonInitResult, parseJsonUnknown, readNodePin, scopeKey, sleep, viewerUiCapability };
@@ -111,6 +111,32 @@ declare const LocationStatSchema: z.ZodObject<{
111
111
  fileCount: z.ZodNumber;
112
112
  present: z.ZodBoolean;
113
113
  }, z.core.$strip>;
114
+ /**
115
+ * A backup schedule — the N:M "entry" that binds one cron cadence to a
116
+ * SET of destination locations. Supersedes the per-location cron on
117
+ * `BackupDestinationPolicy`: an operator creates a schedule, picks the
118
+ * `backups` locations it should write to, and the orchestrator fans a
119
+ * single archive out to all of them when the cron fires.
120
+ *
121
+ * `retentionCount` is per-schedule (D-decision 2026-07-28): every
122
+ * location targeted by this schedule keeps this many archives from
123
+ * this schedule's runs.
124
+ *
125
+ * `dataSources` optionally narrows which top-level state locations
126
+ * (db, addons, tls, …) are archived; omitted = the orchestrator's
127
+ * default full set.
128
+ */
129
+ declare const BackupScheduleSchema: z.ZodObject<{
130
+ id: z.ZodString;
131
+ label: z.ZodString;
132
+ cron: z.ZodString;
133
+ enabled: z.ZodBoolean;
134
+ locationIds: z.ZodReadonly<z.ZodArray<z.ZodString>>;
135
+ retentionCount: z.ZodNumber;
136
+ dataSources: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
137
+ lastRunAt: z.ZodOptional<z.ZodNumber>;
138
+ nextRunAt: z.ZodOptional<z.ZodNumber>;
139
+ }, z.core.$strip>;
114
140
  /**
115
141
  * backup — singleton capability for backup management.
116
142
  *
@@ -155,6 +181,7 @@ export declare const backupCapability: {
155
181
  destinations: z.ZodOptional<z.ZodArray<z.ZodString>>;
156
182
  locations: z.ZodOptional<z.ZodArray<z.ZodString>>;
157
183
  label: z.ZodOptional<z.ZodString>;
184
+ retentionCount: z.ZodOptional<z.ZodNumber>;
158
185
  }, z.core.$strip>>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
159
186
  id: z.ZodString;
160
187
  destinationId: z.ZodOptional<z.ZodString>;
@@ -262,7 +289,52 @@ export declare const backupCapability: {
262
289
  error: z.ZodOptional<z.ZodString>;
263
290
  nextRuns: z.ZodReadonly<z.ZodArray<z.ZodNumber>>;
264
291
  }, z.core.$strip>, import("./capability-definition.js").CapabilityMethodKind>;
292
+ /**
293
+ * List every backup schedule (the N:M entries), each with its
294
+ * computed `nextRunAt`. Powers the Schedules section of the
295
+ * admin-UI Backups page.
296
+ */
297
+ readonly listSchedules: import("./capability-definition.js").CapabilityMethodSchema<z.ZodVoid, z.ZodReadonly<z.ZodArray<z.ZodObject<{
298
+ id: z.ZodString;
299
+ label: z.ZodString;
300
+ cron: z.ZodString;
301
+ enabled: z.ZodBoolean;
302
+ locationIds: z.ZodReadonly<z.ZodArray<z.ZodString>>;
303
+ retentionCount: z.ZodNumber;
304
+ dataSources: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
305
+ lastRunAt: z.ZodOptional<z.ZodNumber>;
306
+ nextRunAt: z.ZodOptional<z.ZodNumber>;
307
+ }, z.core.$strip>>>, import("./capability-definition.js").CapabilityMethodKind>;
308
+ /**
309
+ * Create or replace a schedule. An empty / absent `id` mints a new
310
+ * one; a present `id` replaces in place. `cron` is validated
311
+ * server-side; `locationIds` must reference existing `backups`
312
+ * locations (unknown ids are dropped with a warning).
313
+ */
314
+ readonly upsertSchedule: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
315
+ id: z.ZodOptional<z.ZodString>;
316
+ label: z.ZodString;
317
+ cron: z.ZodString;
318
+ enabled: z.ZodBoolean;
319
+ locationIds: z.ZodReadonly<z.ZodArray<z.ZodString>>;
320
+ retentionCount: z.ZodNumber;
321
+ dataSources: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
322
+ }, z.core.$strip>, z.ZodObject<{
323
+ id: z.ZodString;
324
+ label: z.ZodString;
325
+ cron: z.ZodString;
326
+ enabled: z.ZodBoolean;
327
+ locationIds: z.ZodReadonly<z.ZodArray<z.ZodString>>;
328
+ retentionCount: z.ZodNumber;
329
+ dataSources: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
330
+ lastRunAt: z.ZodOptional<z.ZodNumber>;
331
+ nextRunAt: z.ZodOptional<z.ZodNumber>;
332
+ }, z.core.$strip>, "mutation">;
333
+ /** Delete a schedule by id. Does not touch the target locations. */
334
+ readonly deleteSchedule: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
335
+ id: z.ZodString;
336
+ }, z.core.$strip>, z.ZodVoid, "mutation">;
265
337
  };
266
338
  };
267
339
  export type IBackupProvider = InferProvider<typeof backupCapability>;
268
- export { BackupEntrySchema, BackupSubDestinationInfoSchema, BackupDestinationInfoSchema, BackupArchiveEntrySchema, ArchiveEntrySchema, ArchiveManifestSchema, LocationStatSchema, };
340
+ export { ArchiveEntrySchema, ArchiveManifestSchema, BackupArchiveEntrySchema, BackupDestinationInfoSchema, BackupEntrySchema, BackupScheduleSchema, BackupSubDestinationInfoSchema, LocationStatSchema, };
@@ -125,6 +125,7 @@ export declare const storageCapability: {
125
125
  defaultRoot: z.ZodOptional<z.ZodEnum<{
126
126
  data: "data";
127
127
  media: "media";
128
+ backup: "backup";
128
129
  }>>;
129
130
  }, z.core.$strip>>>, import("./capability-definition.js").CapabilityMethodKind>;
130
131
  readonly upsertLocation: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
@@ -2296,6 +2296,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
2296
2296
  destinations?: string[] | undefined;
2297
2297
  locations?: string[] | undefined;
2298
2298
  label?: string | undefined;
2299
+ retentionCount?: number | undefined;
2299
2300
  } | undefined;
2300
2301
  output: readonly {
2301
2302
  id: string;
@@ -2414,6 +2415,55 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
2414
2415
  };
2415
2416
  meta: object;
2416
2417
  }>;
2418
+ listSchedules: import("@trpc/server").TRPCQueryProcedure<{
2419
+ input: {
2420
+ nodeId?: string | undefined;
2421
+ } | undefined;
2422
+ output: readonly {
2423
+ id: string;
2424
+ label: string;
2425
+ cron: string;
2426
+ enabled: boolean;
2427
+ locationIds: readonly string[];
2428
+ retentionCount: number;
2429
+ dataSources?: readonly string[] | undefined;
2430
+ lastRunAt?: number | undefined;
2431
+ nextRunAt?: number | undefined;
2432
+ }[];
2433
+ meta: object;
2434
+ }>;
2435
+ upsertSchedule: import("@trpc/server").TRPCMutationProcedure<{
2436
+ input: {
2437
+ [x: string]: unknown;
2438
+ label: string;
2439
+ cron: string;
2440
+ enabled: boolean;
2441
+ locationIds: readonly string[];
2442
+ retentionCount: number;
2443
+ id?: string | undefined;
2444
+ dataSources?: readonly string[] | undefined;
2445
+ };
2446
+ output: {
2447
+ id: string;
2448
+ label: string;
2449
+ cron: string;
2450
+ enabled: boolean;
2451
+ locationIds: readonly string[];
2452
+ retentionCount: number;
2453
+ dataSources?: readonly string[] | undefined;
2454
+ lastRunAt?: number | undefined;
2455
+ nextRunAt?: number | undefined;
2456
+ };
2457
+ meta: object;
2458
+ }>;
2459
+ deleteSchedule: import("@trpc/server").TRPCMutationProcedure<{
2460
+ input: {
2461
+ [x: string]: unknown;
2462
+ id: string;
2463
+ };
2464
+ output: void;
2465
+ meta: object;
2466
+ }>;
2417
2467
  }>>;
2418
2468
  battery: import("@trpc/server").TRPCBuiltRouter<{
2419
2469
  ctx: TrpcContext;
@@ -14761,7 +14811,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
14761
14811
  cardinality: "single" | "multi";
14762
14812
  description?: string | undefined;
14763
14813
  defaultsTo?: string | undefined;
14764
- defaultRoot?: "data" | "media" | undefined;
14814
+ defaultRoot?: "backup" | "data" | "media" | undefined;
14765
14815
  }[];
14766
14816
  meta: object;
14767
14817
  }>;
@@ -19721,6 +19771,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
19721
19771
  destinations?: string[] | undefined;
19722
19772
  locations?: string[] | undefined;
19723
19773
  label?: string | undefined;
19774
+ retentionCount?: number | undefined;
19724
19775
  } | undefined;
19725
19776
  output: readonly {
19726
19777
  id: string;
@@ -19839,6 +19890,55 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
19839
19890
  };
19840
19891
  meta: object;
19841
19892
  }>;
19893
+ listSchedules: import("@trpc/server").TRPCQueryProcedure<{
19894
+ input: {
19895
+ nodeId?: string | undefined;
19896
+ } | undefined;
19897
+ output: readonly {
19898
+ id: string;
19899
+ label: string;
19900
+ cron: string;
19901
+ enabled: boolean;
19902
+ locationIds: readonly string[];
19903
+ retentionCount: number;
19904
+ dataSources?: readonly string[] | undefined;
19905
+ lastRunAt?: number | undefined;
19906
+ nextRunAt?: number | undefined;
19907
+ }[];
19908
+ meta: object;
19909
+ }>;
19910
+ upsertSchedule: import("@trpc/server").TRPCMutationProcedure<{
19911
+ input: {
19912
+ [x: string]: unknown;
19913
+ label: string;
19914
+ cron: string;
19915
+ enabled: boolean;
19916
+ locationIds: readonly string[];
19917
+ retentionCount: number;
19918
+ id?: string | undefined;
19919
+ dataSources?: readonly string[] | undefined;
19920
+ };
19921
+ output: {
19922
+ id: string;
19923
+ label: string;
19924
+ cron: string;
19925
+ enabled: boolean;
19926
+ locationIds: readonly string[];
19927
+ retentionCount: number;
19928
+ dataSources?: readonly string[] | undefined;
19929
+ lastRunAt?: number | undefined;
19930
+ nextRunAt?: number | undefined;
19931
+ };
19932
+ meta: object;
19933
+ }>;
19934
+ deleteSchedule: import("@trpc/server").TRPCMutationProcedure<{
19935
+ input: {
19936
+ [x: string]: unknown;
19937
+ id: string;
19938
+ };
19939
+ output: void;
19940
+ meta: object;
19941
+ }>;
19842
19942
  }>>;
19843
19943
  battery: import("@trpc/server").TRPCBuiltRouter<{
19844
19944
  ctx: TrpcContext;
@@ -32186,7 +32286,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
32186
32286
  cardinality: "single" | "multi";
32187
32287
  description?: string | undefined;
32188
32288
  defaultsTo?: string | undefined;
32189
- defaultRoot?: "data" | "media" | undefined;
32289
+ defaultRoot?: "backup" | "data" | "media" | undefined;
32190
32290
  }[];
32191
32291
  meta: object;
32192
32292
  }>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * AUTO-GENERATED by scripts/generate-collection-array-methods.ts — DO NOT EDIT.
3
+ *
4
+ * For every COLLECTION-mode capability, the array-returning (non-subscription)
5
+ * method names the hub fans across providers. The addon-runner uses this to
6
+ * reproduce the hub's graceful "provider skips an unimplemented collection
7
+ * method" behaviour (see child-cap-dispatch) WITHOUT importing the schema
8
+ * barrel (`ALL_CAPABILITY_DEFINITIONS`), which would cost ~144MB RSS per
9
+ * forked runner. See docs/decisions/adr-0028.md.
10
+ *
11
+ * Coverage: 16 collection caps, 28 array methods.
12
+ */
13
+ export declare const COLLECTION_ARRAY_METHODS: Readonly<Record<string, readonly string[]>>;
14
+ /**
15
+ * True when `method` on cap `capName` is a COLLECTION cap's array-returning
16
+ * (non-subscription) method — the schema-free runner-side equivalent of
17
+ * `isCollectionArrayMethod(capDefsByName.get(capName), method)`.
18
+ */
19
+ export declare function isCollectionArrayMethodName(capName: string, method: string): boolean;
@@ -6,7 +6,7 @@
6
6
  * scope+access check inside `protectedProcedure` (see
7
7
  * `server/backend/src/api/trpc/trpc.middleware.ts`).
8
8
  *
9
- * Coverage: 811 method paths across 117 capabilities.
9
+ * Coverage: 814 method paths across 117 capabilities.
10
10
  */
11
11
  import type { CapabilityMethodAccess } from '../capabilities/capability-definition.js';
12
12
  export interface MethodAccessRecord {
@@ -58,7 +58,7 @@ export interface SystemProxy {
58
58
  readonly alerts: Pick<InferProvider<typeof alertsCapability>, 'emit' | 'update' | 'list' | 'getUnreadCount' | 'markRead' | 'markAllRead' | 'dismiss'>;
59
59
  readonly audioAnalyzer: Pick<InferProvider<typeof audioAnalyzerCapability>, 'analyseChunk' | 'classify' | 'isReady' | 'dispose' | 'reprobeAudioEngine'>;
60
60
  readonly audioCodec: Pick<InferProvider<typeof audioCodecCapability>, 'listSupportedCodecs' | 'canHandle' | 'createDecodeSession' | 'createEncodeSession' | 'closeSession' | 'pushEncodedFrame' | 'pullPcm' | 'pushPcm' | 'pullEncoded' | 'flushEncode' | 'listActiveSessions'>;
61
- readonly backup: Pick<InferProvider<typeof backupCapability>, 'listDestinations' | 'trigger' | 'list' | 'listLocations' | 'getEntries' | 'restore' | 'delete' | 'listArchives' | 'upsertDestinationPolicy' | 'previewSchedule'>;
61
+ readonly backup: Pick<InferProvider<typeof backupCapability>, 'listDestinations' | 'trigger' | 'list' | 'listLocations' | 'getEntries' | 'restore' | 'delete' | 'listArchives' | 'upsertDestinationPolicy' | 'previewSchedule' | 'listSchedules' | 'upsertSchedule' | 'deleteSchedule'>;
62
62
  readonly broker: Pick<InferProvider<typeof brokerCapability>, 'list' | 'get' | 'listProviders' | 'add' | 'remove' | 'testConnection' | 'getSettings' | 'setSettings' | 'getBrokerConfig' | 'getSettingsSchema' | 'testSettings' | 'publish' | 'subscribe' | 'unsubscribe' | 'getState' | 'getStatus'>;
63
63
  readonly decoder: Pick<InferProvider<typeof decoderCapability>, 'supportsCodec' | 'getInfo' | 'createSession' | 'destroySession' | 'pushPacket' | 'openStream' | 'pullFrames' | 'pullHandles' | 'getFrame' | 'getShmStats' | 'updateConfig' | 'getStats' | 'listActiveSessions' | 'reprobeHwaccel'>;
64
64
  readonly deviceAdoption: Pick<InferProvider<typeof deviceAdoptionCapability>, 'listCandidateFilters' | 'listCandidates' | 'getCandidate' | 'refresh' | 'adopt' | 'release' | 'resync'>;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-BG8hQTA8.js");
2
+ const require_sleep = require("./sleep-DRg9F6JJ.js");
3
3
  const require_event_category = require("./event-category-Cdyife4p.js");
4
4
  const require_enums = require("./enums.js");
5
5
  const require_err_msg = require("./err-msg-COpsHMw2.js");
@@ -1260,16 +1260,23 @@ var StorageLocationDeclarationSchema = zod.z.object({
1260
1260
  * Which node root the seeded `<id>:default` instance is placed under on a
1261
1261
  * FRESH install:
1262
1262
  * - `'data'` (default) — the node's data dir (`CAMSTACK_DATA` / boot dir),
1263
- * the appData volume. Right for small/durable data (backups, logs, models).
1263
+ * the appData volume. Right for small/durable data (logs, models).
1264
1264
  * - `'media'` — the dedicated media volume (`CAMSTACK_MEDIA_ROOT`) when that
1265
1265
  * env is set, else falls back to the data root. Right for bulky, hot media
1266
1266
  * (recordings, event media) that should stay off the appData disk.
1267
+ * - `'backup'` — the dedicated backup volume (`CAMSTACK_BACKUP_ROOT`, default
1268
+ * `/backups` in the image) so archives live on their own mount rather than
1269
+ * filling the appData disk. Falls back to the data root when unset.
1267
1270
  *
1268
1271
  * Only affects the seeded default's `basePath`; operators can repoint any
1269
1272
  * location afterwards, and a `defaultsTo` slot inherits its parent's root
1270
1273
  * regardless of this field. Absent (the common case) is treated as `'data'`.
1271
1274
  */
1272
- defaultRoot: zod.z.enum(["data", "media"]).optional()
1275
+ defaultRoot: zod.z.enum([
1276
+ "data",
1277
+ "media",
1278
+ "backup"
1279
+ ]).optional()
1273
1280
  });
1274
1281
  //#endregion
1275
1282
  //#region src/interfaces/device-capabilities/camera.ts
@@ -1704,47 +1711,6 @@ var RUNTIME_DEFAULTS = {
1704
1711
  "auth.tokenExpiry": "7d"
1705
1712
  };
1706
1713
  //#endregion
1707
- //#region src/cap-call-context.ts
1708
- /**
1709
- * Per-call node pinning for `ctx.api` capability calls.
1710
- *
1711
- * A capability call normally resolves to its DEFAULT provider — a `singleton`
1712
- * cap resolves to the hub, a device-scoped cap to the device's owning node. To
1713
- * query a SPECIFIC node's provider instead (e.g. a remote agent's own
1714
- * in-process `platform-probe` hardware, which the hub cannot probe), pin the
1715
- * call to that node.
1716
- *
1717
- * The nodeId rides OUT-OF-BAND in the tRPC call context (NOT in the validated
1718
- * method args), so capability method signatures stay `nodeId`-free — node
1719
- * targeting is a property of the CALL, not of the method. The transport lifts
1720
- * it from `op.context` onto the `CapCallInput.nodeId` field (`ipcParentLink`),
1721
- * and the hub parent's `onUnownedCall` passes it to the `CapRouteResolver`,
1722
- * which classifies a pinned agent node as `agent-child-forward`
1723
- * (`$agent-cap-fwd.forward` → the agent's in-process provider).
1724
- *
1725
- * Usage at a call site:
1726
- *
1727
- * await api.platformProbe.getCapabilities.query(undefined, nodePin(nodeId))
1728
- */
1729
- /** tRPC `op.context` key carrying a per-call node pin. */
1730
- var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
1731
- /**
1732
- * Build the tRPC request options that pin a single capability call to `nodeId`.
1733
- * Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
1734
- */
1735
- function nodePin(nodeId) {
1736
- return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
1737
- }
1738
- /**
1739
- * Read a per-call node pin out of a tRPC `op.context` (transport side).
1740
- * Returns the pinned nodeId, or `undefined` when no pin is present.
1741
- */
1742
- function readNodePin(context) {
1743
- if (context === null || typeof context !== "object") return void 0;
1744
- const value = Reflect.get(context, CAP_NODE_PIN_CONTEXT_KEY);
1745
- return typeof value === "string" ? value : void 0;
1746
- }
1747
- //#endregion
1748
1714
  //#region src/utils/hf-url.ts
1749
1715
  function hfModelUrl(repo, path) {
1750
1716
  return `https://huggingface.co/${repo}/resolve/main/${path}`;
@@ -14310,7 +14276,10 @@ function createSystemProxy(api) {
14310
14276
  delete: (input) => dispatch("backup", "delete", "mutation", input),
14311
14277
  listArchives: (input) => dispatch("backup", "listArchives", "query", input),
14312
14278
  upsertDestinationPolicy: (input) => dispatch("backup", "upsertDestinationPolicy", "mutation", input),
14313
- previewSchedule: (input) => dispatch("backup", "previewSchedule", "query", input)
14279
+ previewSchedule: (input) => dispatch("backup", "previewSchedule", "query", input),
14280
+ listSchedules: (input) => dispatch("backup", "listSchedules", "query", input),
14281
+ upsertSchedule: (input) => dispatch("backup", "upsertSchedule", "mutation", input),
14282
+ deleteSchedule: (input) => dispatch("backup", "deleteSchedule", "mutation", input)
14314
14283
  },
14315
14284
  broker: {
14316
14285
  list: (input) => dispatch("broker", "list", "query", input),
@@ -16342,6 +16311,41 @@ var LocationStatSchema = zod.z.object({
16342
16311
  present: zod.z.boolean()
16343
16312
  });
16344
16313
  /**
16314
+ * A backup schedule — the N:M "entry" that binds one cron cadence to a
16315
+ * SET of destination locations. Supersedes the per-location cron on
16316
+ * `BackupDestinationPolicy`: an operator creates a schedule, picks the
16317
+ * `backups` locations it should write to, and the orchestrator fans a
16318
+ * single archive out to all of them when the cron fires.
16319
+ *
16320
+ * `retentionCount` is per-schedule (D-decision 2026-07-28): every
16321
+ * location targeted by this schedule keeps this many archives from
16322
+ * this schedule's runs.
16323
+ *
16324
+ * `dataSources` optionally narrows which top-level state locations
16325
+ * (db, addons, tls, …) are archived; omitted = the orchestrator's
16326
+ * default full set.
16327
+ */
16328
+ var BackupScheduleSchema = zod.z.object({
16329
+ /** Stable id. Generated by the orchestrator on first upsert if absent. */
16330
+ id: zod.z.string(),
16331
+ /** Operator-facing display name. */
16332
+ label: zod.z.string(),
16333
+ /** 5-field POSIX cron. Empty = disabled cadence (kept for editing). */
16334
+ cron: zod.z.string(),
16335
+ /** Master on/off toggle for the whole schedule. */
16336
+ enabled: zod.z.boolean(),
16337
+ /** `backups`-location ids this schedule writes to (fan-out set). */
16338
+ locationIds: zod.z.array(zod.z.string()).readonly(),
16339
+ /** Archives kept per targeted location for this schedule. */
16340
+ retentionCount: zod.z.number().int().min(1).max(1e3),
16341
+ /** Optional subset of source locations to include; omitted = all. */
16342
+ dataSources: zod.z.array(zod.z.string()).readonly().optional(),
16343
+ /** ms-epoch of last successful run. */
16344
+ lastRunAt: zod.z.number().optional(),
16345
+ /** ms-epoch of next computed firing (read-only, filled on list). */
16346
+ nextRunAt: zod.z.number().optional()
16347
+ });
16348
+ /**
16345
16349
  * backup — singleton capability for backup management.
16346
16350
  *
16347
16351
  * Implemented by `local-backup` addon. Future providers (S3, rsync)
@@ -16368,7 +16372,14 @@ var backupCapability = {
16368
16372
  /** Subset of registered `backup-destination` addon ids to write to. */
16369
16373
  destinations: zod.z.array(zod.z.string()).optional(),
16370
16374
  locations: zod.z.array(zod.z.string()).optional(),
16371
- label: zod.z.string().optional()
16375
+ label: zod.z.string().optional(),
16376
+ /**
16377
+ * Per-run retention override applied to every targeted
16378
+ * destination. Used by schedule-driven runs (per-entry
16379
+ * retention). Omitted = each destination's own policy
16380
+ * retention (manual runs).
16381
+ */
16382
+ retentionCount: zod.z.number().int().min(1).max(1e3).optional()
16372
16383
  }).optional(), zod.z.array(BackupEntrySchema).readonly(), {
16373
16384
  kind: "mutation",
16374
16385
  auth: "admin"
@@ -16455,7 +16466,36 @@ var backupCapability = {
16455
16466
  ok: zod.z.boolean(),
16456
16467
  error: zod.z.string().optional(),
16457
16468
  nextRuns: zod.z.array(zod.z.number()).readonly()
16458
- }))
16469
+ })),
16470
+ /**
16471
+ * List every backup schedule (the N:M entries), each with its
16472
+ * computed `nextRunAt`. Powers the Schedules section of the
16473
+ * admin-UI Backups page.
16474
+ */
16475
+ listSchedules: require_sleep.method(zod.z.void(), zod.z.array(BackupScheduleSchema).readonly(), { auth: "admin" }),
16476
+ /**
16477
+ * Create or replace a schedule. An empty / absent `id` mints a new
16478
+ * one; a present `id` replaces in place. `cron` is validated
16479
+ * server-side; `locationIds` must reference existing `backups`
16480
+ * locations (unknown ids are dropped with a warning).
16481
+ */
16482
+ upsertSchedule: require_sleep.method(zod.z.object({
16483
+ id: zod.z.string().optional(),
16484
+ label: zod.z.string(),
16485
+ cron: zod.z.string(),
16486
+ enabled: zod.z.boolean(),
16487
+ locationIds: zod.z.array(zod.z.string()).readonly(),
16488
+ retentionCount: zod.z.number().int().min(1).max(1e3),
16489
+ dataSources: zod.z.array(zod.z.string()).readonly().optional()
16490
+ }), BackupScheduleSchema, {
16491
+ kind: "mutation",
16492
+ auth: "admin"
16493
+ }),
16494
+ /** Delete a schedule by id. Does not touch the target locations. */
16495
+ deleteSchedule: require_sleep.method(zod.z.object({ id: zod.z.string() }), zod.z.void(), {
16496
+ kind: "mutation",
16497
+ auth: "admin"
16498
+ })
16459
16499
  }
16460
16500
  };
16461
16501
  //#endregion
@@ -27698,6 +27738,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27698
27738
  addonId: null,
27699
27739
  access: "delete"
27700
27740
  },
27741
+ "backup.deleteSchedule": {
27742
+ capName: "backup",
27743
+ capScope: "system",
27744
+ addonId: null,
27745
+ access: "delete"
27746
+ },
27701
27747
  "backup.getEntries": {
27702
27748
  capName: "backup",
27703
27749
  capScope: "system",
@@ -27728,6 +27774,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27728
27774
  addonId: null,
27729
27775
  access: "view"
27730
27776
  },
27777
+ "backup.listSchedules": {
27778
+ capName: "backup",
27779
+ capScope: "system",
27780
+ addonId: null,
27781
+ access: "view"
27782
+ },
27731
27783
  "backup.previewSchedule": {
27732
27784
  capName: "backup",
27733
27785
  capScope: "system",
@@ -27752,6 +27804,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27752
27804
  addonId: null,
27753
27805
  access: "create"
27754
27806
  },
27807
+ "backup.upsertSchedule": {
27808
+ capName: "backup",
27809
+ capScope: "system",
27810
+ addonId: null,
27811
+ access: "create"
27812
+ },
27755
27813
  "battery.wakeForStream": {
27756
27814
  capName: "battery",
27757
27815
  capScope: "device",
@@ -33001,7 +33059,7 @@ exports.CAM_PROFILE_ORDER = require_sleep.CAM_PROFILE_ORDER;
33001
33059
  exports.CAPABILITY_NAMES = CAPABILITY_NAMES;
33002
33060
  exports.CAPABILITY_ROUTER_KEYS = CAPABILITY_ROUTER_KEYS;
33003
33061
  exports.CAP_NAMES_WITH_STATUS = CAP_NAMES_WITH_STATUS;
33004
- exports.CAP_NODE_PIN_CONTEXT_KEY = CAP_NODE_PIN_CONTEXT_KEY;
33062
+ exports.CAP_NODE_PIN_CONTEXT_KEY = require_sleep.CAP_NODE_PIN_CONTEXT_KEY;
33005
33063
  exports.CAP_PROVIDER_KIND_MAP = CAP_PROVIDER_KIND_MAP;
33006
33064
  exports.COCO_80_LABELS = COCO_80_LABELS;
33007
33065
  exports.COCO_TO_MACRO = COCO_TO_MACRO;
@@ -33738,7 +33796,7 @@ exports.mqttBrokerCapability = mqttBrokerCapability;
33738
33796
  exports.nativeObjectDetectionCapability = nativeObjectDetectionCapability;
33739
33797
  exports.networkAccessCapability = networkAccessCapability;
33740
33798
  exports.networkQualityCapability = networkQualityCapability;
33741
- exports.nodePin = nodePin;
33799
+ exports.nodePin = require_sleep.nodePin;
33742
33800
  exports.nodesCapability = nodesCapability;
33743
33801
  exports.normalizeAddonInitResult = require_sleep.normalizeAddonInitResult;
33744
33802
  exports.normalizeUnit = normalizeUnit;
@@ -33774,7 +33832,7 @@ exports.procedureAuthKey = procedureAuthKey;
33774
33832
  exports.ptzAutotrackCapability = ptzAutotrackCapability;
33775
33833
  exports.ptzCapability = ptzCapability;
33776
33834
  exports.pythonScriptForBackend = pythonScriptForBackend;
33777
- exports.readNodePin = readNodePin;
33835
+ exports.readNodePin = require_sleep.readNodePin;
33778
33836
  exports.readinessKey = require_sleep.readinessKey;
33779
33837
  exports.rebootCapability = rebootCapability;
33780
33838
  exports.recordingCapability = recordingCapability;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as StreamSourceSchema, A as parseJsonUnknown, B as CamProfileSchema, C as asBoolean, D as asString, E as asNumber, F as readinessKey, G as DecodedFrameSchema, H as CamStreamResolutionSchema, I as scopeKey, J as FrameHandleSchema, K as EncodedPacketSchema, L as BrokerStatsSchema, M as ReadinessRegistry, N as ReadinessTimeoutError, O as parseJsonArray, P as emitDownForOwnedCaps, Q as StreamSourceEntrySchema, R as BrokerStatusSchema, S as DeviceType, T as asJsonObject, U as CameraStreamSchema, V as CamStreamKindSchema, W as DecodedAudioChunkSchema, X as ProfileSlotSchema, Y as ProfileRtspEntrySchema, Z as ProfileSlotStatusSchema, _ as resolveCapMount, _t as collectHydratedFieldValues, a as viewerUiCapability, at as makeSourceBrokerId, b as DeviceFeature, bt as DisposerChain, c as createLazyTrpcSource, ct as BaseAddon, d as DEVICE_SETTINGS_CONTRIBUTION_METHODS, dt as createEvent, et as SubscribeAudioChunksInputSchema, f as DEVICE_STATUS_METHOD, ft as emitReadiness, g as method, gt as collectHydratedFieldEntries, h as isDeviceConfigCap, ht as WELL_KNOWN_TAB_MAP, i as deviceOpsCapability, it as makeProfileBrokerId, j as DATAPLANE_SECRET_HEADER, k as parseJsonObject, l as createMirrorSource, lt as normalizeAddonInitResult, m as expandCapMethods, mt as WELL_KNOWN_TABS, n as sleepCancellable, nt as SubscribeFramesInputSchema, o as adminUiCapability, ot as parseProfileBrokerId, p as event, pt as isEvent, q as FrameHandleFormatSchema, r as RawStateResultSchema, rt as SubscribeFramesResultSchema, s as createDeviceProxy, st as selectAssignedProfileSlots, t as sleep, tt as SubscribeAudioChunksResultSchema, u as createSliceHandle, ut as createDurableState, v as systemMethod, vt as hydrateSchema, w as asJsonArray, x as DeviceRole, y as ChargingStatus, yt as resolveHydratedFieldValue, z as CAM_PROFILE_ORDER } from "./sleep-DiOnzenz.mjs";
1
+ import { $ as ProfileSlotSchema, A as parseJsonUnknown, B as BrokerStatsSchema, C as asBoolean, Ct as DisposerChain, D as asString, E as asNumber, F as ReadinessRegistry, G as CamStreamResolutionSchema, H as CAM_PROFILE_ORDER, I as ReadinessTimeoutError, J as DecodedFrameSchema, K as CameraStreamSchema, L as emitDownForOwnedCaps, M as nodePin, N as readNodePin, O as parseJsonArray, P as DATAPLANE_SECRET_HEADER, Q as ProfileRtspEntrySchema, R as readinessKey, S as DeviceType, St as resolveHydratedFieldValue, T as asJsonObject, U as CamProfileSchema, V as BrokerStatusSchema, W as CamStreamKindSchema, X as FrameHandleFormatSchema, Y as EncodedPacketSchema, Z as FrameHandleSchema, _ as resolveCapMount, _t as WELL_KNOWN_TABS, a as viewerUiCapability, at as SubscribeFramesInputSchema, b as DeviceFeature, bt as collectHydratedFieldValues, c as createLazyTrpcSource, ct as makeSourceBrokerId, d as DEVICE_SETTINGS_CONTRIBUTION_METHODS, dt as BaseAddon, et as ProfileSlotStatusSchema, f as DEVICE_STATUS_METHOD, ft as normalizeAddonInitResult, g as method, gt as isEvent, h as isDeviceConfigCap, ht as emitReadiness, i as deviceOpsCapability, it as SubscribeAudioChunksResultSchema, j as CAP_NODE_PIN_CONTEXT_KEY, k as parseJsonObject, l as createMirrorSource, lt as parseProfileBrokerId, m as expandCapMethods, mt as createEvent, n as sleepCancellable, nt as StreamSourceSchema, o as adminUiCapability, ot as SubscribeFramesResultSchema, p as event, pt as createDurableState, q as DecodedAudioChunkSchema, r as RawStateResultSchema, rt as SubscribeAudioChunksInputSchema, s as createDeviceProxy, st as makeProfileBrokerId, t as sleep, tt as StreamSourceEntrySchema, u as createSliceHandle, ut as selectAssignedProfileSlots, v as systemMethod, vt as WELL_KNOWN_TAB_MAP, w as asJsonArray, x as DeviceRole, xt as hydrateSchema, y as ChargingStatus, yt as collectHydratedFieldEntries, z as scopeKey } from "./sleep-C3ceNSsf.mjs";
2
2
  import { t as EventCategory } from "./event-category-BLcNejAE.mjs";
3
3
  import { EventSourceType } from "./enums.mjs";
4
4
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
@@ -1259,16 +1259,23 @@ var StorageLocationDeclarationSchema = z.object({
1259
1259
  * Which node root the seeded `<id>:default` instance is placed under on a
1260
1260
  * FRESH install:
1261
1261
  * - `'data'` (default) — the node's data dir (`CAMSTACK_DATA` / boot dir),
1262
- * the appData volume. Right for small/durable data (backups, logs, models).
1262
+ * the appData volume. Right for small/durable data (logs, models).
1263
1263
  * - `'media'` — the dedicated media volume (`CAMSTACK_MEDIA_ROOT`) when that
1264
1264
  * env is set, else falls back to the data root. Right for bulky, hot media
1265
1265
  * (recordings, event media) that should stay off the appData disk.
1266
+ * - `'backup'` — the dedicated backup volume (`CAMSTACK_BACKUP_ROOT`, default
1267
+ * `/backups` in the image) so archives live on their own mount rather than
1268
+ * filling the appData disk. Falls back to the data root when unset.
1266
1269
  *
1267
1270
  * Only affects the seeded default's `basePath`; operators can repoint any
1268
1271
  * location afterwards, and a `defaultsTo` slot inherits its parent's root
1269
1272
  * regardless of this field. Absent (the common case) is treated as `'data'`.
1270
1273
  */
1271
- defaultRoot: z.enum(["data", "media"]).optional()
1274
+ defaultRoot: z.enum([
1275
+ "data",
1276
+ "media",
1277
+ "backup"
1278
+ ]).optional()
1272
1279
  });
1273
1280
  //#endregion
1274
1281
  //#region src/interfaces/device-capabilities/camera.ts
@@ -1703,47 +1710,6 @@ var RUNTIME_DEFAULTS = {
1703
1710
  "auth.tokenExpiry": "7d"
1704
1711
  };
1705
1712
  //#endregion
1706
- //#region src/cap-call-context.ts
1707
- /**
1708
- * Per-call node pinning for `ctx.api` capability calls.
1709
- *
1710
- * A capability call normally resolves to its DEFAULT provider — a `singleton`
1711
- * cap resolves to the hub, a device-scoped cap to the device's owning node. To
1712
- * query a SPECIFIC node's provider instead (e.g. a remote agent's own
1713
- * in-process `platform-probe` hardware, which the hub cannot probe), pin the
1714
- * call to that node.
1715
- *
1716
- * The nodeId rides OUT-OF-BAND in the tRPC call context (NOT in the validated
1717
- * method args), so capability method signatures stay `nodeId`-free — node
1718
- * targeting is a property of the CALL, not of the method. The transport lifts
1719
- * it from `op.context` onto the `CapCallInput.nodeId` field (`ipcParentLink`),
1720
- * and the hub parent's `onUnownedCall` passes it to the `CapRouteResolver`,
1721
- * which classifies a pinned agent node as `agent-child-forward`
1722
- * (`$agent-cap-fwd.forward` → the agent's in-process provider).
1723
- *
1724
- * Usage at a call site:
1725
- *
1726
- * await api.platformProbe.getCapabilities.query(undefined, nodePin(nodeId))
1727
- */
1728
- /** tRPC `op.context` key carrying a per-call node pin. */
1729
- var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
1730
- /**
1731
- * Build the tRPC request options that pin a single capability call to `nodeId`.
1732
- * Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
1733
- */
1734
- function nodePin(nodeId) {
1735
- return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
1736
- }
1737
- /**
1738
- * Read a per-call node pin out of a tRPC `op.context` (transport side).
1739
- * Returns the pinned nodeId, or `undefined` when no pin is present.
1740
- */
1741
- function readNodePin(context) {
1742
- if (context === null || typeof context !== "object") return void 0;
1743
- const value = Reflect.get(context, CAP_NODE_PIN_CONTEXT_KEY);
1744
- return typeof value === "string" ? value : void 0;
1745
- }
1746
- //#endregion
1747
1713
  //#region src/utils/hf-url.ts
1748
1714
  function hfModelUrl(repo, path) {
1749
1715
  return `https://huggingface.co/${repo}/resolve/main/${path}`;
@@ -14309,7 +14275,10 @@ function createSystemProxy(api) {
14309
14275
  delete: (input) => dispatch("backup", "delete", "mutation", input),
14310
14276
  listArchives: (input) => dispatch("backup", "listArchives", "query", input),
14311
14277
  upsertDestinationPolicy: (input) => dispatch("backup", "upsertDestinationPolicy", "mutation", input),
14312
- previewSchedule: (input) => dispatch("backup", "previewSchedule", "query", input)
14278
+ previewSchedule: (input) => dispatch("backup", "previewSchedule", "query", input),
14279
+ listSchedules: (input) => dispatch("backup", "listSchedules", "query", input),
14280
+ upsertSchedule: (input) => dispatch("backup", "upsertSchedule", "mutation", input),
14281
+ deleteSchedule: (input) => dispatch("backup", "deleteSchedule", "mutation", input)
14313
14282
  },
14314
14283
  broker: {
14315
14284
  list: (input) => dispatch("broker", "list", "query", input),
@@ -16341,6 +16310,41 @@ var LocationStatSchema = z.object({
16341
16310
  present: z.boolean()
16342
16311
  });
16343
16312
  /**
16313
+ * A backup schedule — the N:M "entry" that binds one cron cadence to a
16314
+ * SET of destination locations. Supersedes the per-location cron on
16315
+ * `BackupDestinationPolicy`: an operator creates a schedule, picks the
16316
+ * `backups` locations it should write to, and the orchestrator fans a
16317
+ * single archive out to all of them when the cron fires.
16318
+ *
16319
+ * `retentionCount` is per-schedule (D-decision 2026-07-28): every
16320
+ * location targeted by this schedule keeps this many archives from
16321
+ * this schedule's runs.
16322
+ *
16323
+ * `dataSources` optionally narrows which top-level state locations
16324
+ * (db, addons, tls, …) are archived; omitted = the orchestrator's
16325
+ * default full set.
16326
+ */
16327
+ var BackupScheduleSchema = z.object({
16328
+ /** Stable id. Generated by the orchestrator on first upsert if absent. */
16329
+ id: z.string(),
16330
+ /** Operator-facing display name. */
16331
+ label: z.string(),
16332
+ /** 5-field POSIX cron. Empty = disabled cadence (kept for editing). */
16333
+ cron: z.string(),
16334
+ /** Master on/off toggle for the whole schedule. */
16335
+ enabled: z.boolean(),
16336
+ /** `backups`-location ids this schedule writes to (fan-out set). */
16337
+ locationIds: z.array(z.string()).readonly(),
16338
+ /** Archives kept per targeted location for this schedule. */
16339
+ retentionCount: z.number().int().min(1).max(1e3),
16340
+ /** Optional subset of source locations to include; omitted = all. */
16341
+ dataSources: z.array(z.string()).readonly().optional(),
16342
+ /** ms-epoch of last successful run. */
16343
+ lastRunAt: z.number().optional(),
16344
+ /** ms-epoch of next computed firing (read-only, filled on list). */
16345
+ nextRunAt: z.number().optional()
16346
+ });
16347
+ /**
16344
16348
  * backup — singleton capability for backup management.
16345
16349
  *
16346
16350
  * Implemented by `local-backup` addon. Future providers (S3, rsync)
@@ -16367,7 +16371,14 @@ var backupCapability = {
16367
16371
  /** Subset of registered `backup-destination` addon ids to write to. */
16368
16372
  destinations: z.array(z.string()).optional(),
16369
16373
  locations: z.array(z.string()).optional(),
16370
- label: z.string().optional()
16374
+ label: z.string().optional(),
16375
+ /**
16376
+ * Per-run retention override applied to every targeted
16377
+ * destination. Used by schedule-driven runs (per-entry
16378
+ * retention). Omitted = each destination's own policy
16379
+ * retention (manual runs).
16380
+ */
16381
+ retentionCount: z.number().int().min(1).max(1e3).optional()
16371
16382
  }).optional(), z.array(BackupEntrySchema).readonly(), {
16372
16383
  kind: "mutation",
16373
16384
  auth: "admin"
@@ -16454,7 +16465,36 @@ var backupCapability = {
16454
16465
  ok: z.boolean(),
16455
16466
  error: z.string().optional(),
16456
16467
  nextRuns: z.array(z.number()).readonly()
16457
- }))
16468
+ })),
16469
+ /**
16470
+ * List every backup schedule (the N:M entries), each with its
16471
+ * computed `nextRunAt`. Powers the Schedules section of the
16472
+ * admin-UI Backups page.
16473
+ */
16474
+ listSchedules: method(z.void(), z.array(BackupScheduleSchema).readonly(), { auth: "admin" }),
16475
+ /**
16476
+ * Create or replace a schedule. An empty / absent `id` mints a new
16477
+ * one; a present `id` replaces in place. `cron` is validated
16478
+ * server-side; `locationIds` must reference existing `backups`
16479
+ * locations (unknown ids are dropped with a warning).
16480
+ */
16481
+ upsertSchedule: method(z.object({
16482
+ id: z.string().optional(),
16483
+ label: z.string(),
16484
+ cron: z.string(),
16485
+ enabled: z.boolean(),
16486
+ locationIds: z.array(z.string()).readonly(),
16487
+ retentionCount: z.number().int().min(1).max(1e3),
16488
+ dataSources: z.array(z.string()).readonly().optional()
16489
+ }), BackupScheduleSchema, {
16490
+ kind: "mutation",
16491
+ auth: "admin"
16492
+ }),
16493
+ /** Delete a schedule by id. Does not touch the target locations. */
16494
+ deleteSchedule: method(z.object({ id: z.string() }), z.void(), {
16495
+ kind: "mutation",
16496
+ auth: "admin"
16497
+ })
16458
16498
  }
16459
16499
  };
16460
16500
  //#endregion
@@ -27697,6 +27737,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27697
27737
  addonId: null,
27698
27738
  access: "delete"
27699
27739
  },
27740
+ "backup.deleteSchedule": {
27741
+ capName: "backup",
27742
+ capScope: "system",
27743
+ addonId: null,
27744
+ access: "delete"
27745
+ },
27700
27746
  "backup.getEntries": {
27701
27747
  capName: "backup",
27702
27748
  capScope: "system",
@@ -27727,6 +27773,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27727
27773
  addonId: null,
27728
27774
  access: "view"
27729
27775
  },
27776
+ "backup.listSchedules": {
27777
+ capName: "backup",
27778
+ capScope: "system",
27779
+ addonId: null,
27780
+ access: "view"
27781
+ },
27730
27782
  "backup.previewSchedule": {
27731
27783
  capName: "backup",
27732
27784
  capScope: "system",
@@ -27751,6 +27803,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27751
27803
  addonId: null,
27752
27804
  access: "create"
27753
27805
  },
27806
+ "backup.upsertSchedule": {
27807
+ capName: "backup",
27808
+ capScope: "system",
27809
+ addonId: null,
27810
+ access: "create"
27811
+ },
27754
27812
  "battery.wakeForStream": {
27755
27813
  capName: "battery",
27756
27814
  capScope: "device",
@@ -31,6 +31,7 @@ export declare const StorageLocationDeclarationSchema: z.ZodObject<{
31
31
  defaultRoot: z.ZodOptional<z.ZodEnum<{
32
32
  data: "data";
33
33
  media: "media";
34
+ backup: "backup";
34
35
  }>>;
35
36
  }, z.core.$strip>;
36
37
  /** Inferred TypeScript type for `StorageLocationDeclarationSchema`. */
@@ -1880,6 +1880,47 @@ function emitDownForOwnedCaps(registry, owned) {
1880
1880
  */
1881
1881
  var DATAPLANE_SECRET_HEADER = "x-camstack-dataplane-secret";
1882
1882
  //#endregion
1883
+ //#region src/cap-call-context.ts
1884
+ /**
1885
+ * Per-call node pinning for `ctx.api` capability calls.
1886
+ *
1887
+ * A capability call normally resolves to its DEFAULT provider — a `singleton`
1888
+ * cap resolves to the hub, a device-scoped cap to the device's owning node. To
1889
+ * query a SPECIFIC node's provider instead (e.g. a remote agent's own
1890
+ * in-process `platform-probe` hardware, which the hub cannot probe), pin the
1891
+ * call to that node.
1892
+ *
1893
+ * The nodeId rides OUT-OF-BAND in the tRPC call context (NOT in the validated
1894
+ * method args), so capability method signatures stay `nodeId`-free — node
1895
+ * targeting is a property of the CALL, not of the method. The transport lifts
1896
+ * it from `op.context` onto the `CapCallInput.nodeId` field (`ipcParentLink`),
1897
+ * and the hub parent's `onUnownedCall` passes it to the `CapRouteResolver`,
1898
+ * which classifies a pinned agent node as `agent-child-forward`
1899
+ * (`$agent-cap-fwd.forward` → the agent's in-process provider).
1900
+ *
1901
+ * Usage at a call site:
1902
+ *
1903
+ * await api.platformProbe.getCapabilities.query(undefined, nodePin(nodeId))
1904
+ */
1905
+ /** tRPC `op.context` key carrying a per-call node pin. */
1906
+ var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
1907
+ /**
1908
+ * Build the tRPC request options that pin a single capability call to `nodeId`.
1909
+ * Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
1910
+ */
1911
+ function nodePin(nodeId) {
1912
+ return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
1913
+ }
1914
+ /**
1915
+ * Read a per-call node pin out of a tRPC `op.context` (transport side).
1916
+ * Returns the pinned nodeId, or `undefined` when no pin is present.
1917
+ */
1918
+ function readNodePin(context) {
1919
+ if (context === null || typeof context !== "object") return void 0;
1920
+ const value = Reflect.get(context, CAP_NODE_PIN_CONTEXT_KEY);
1921
+ return typeof value === "string" ? value : void 0;
1922
+ }
1923
+ //#endregion
1883
1924
  //#region src/utils/json-safe.ts
1884
1925
  /**
1885
1926
  * Type-safe JSON parsing helpers.
@@ -3456,4 +3497,4 @@ function sleepCancellable(ms, signal) {
3456
3497
  });
3457
3498
  }
3458
3499
  //#endregion
3459
- export { StreamSourceSchema as $, parseJsonUnknown as A, CamProfileSchema as B, asBoolean as C, asString as D, asNumber as E, readinessKey as F, DecodedFrameSchema as G, CamStreamResolutionSchema as H, scopeKey as I, FrameHandleSchema as J, EncodedPacketSchema as K, BrokerStatsSchema as L, ReadinessRegistry as M, ReadinessTimeoutError as N, parseJsonArray as O, emitDownForOwnedCaps as P, StreamSourceEntrySchema$1 as Q, BrokerStatusSchema as R, DeviceType as S, asJsonObject as T, CameraStreamSchema as U, CamStreamKindSchema as V, DecodedAudioChunkSchema as W, ProfileSlotSchema as X, ProfileRtspEntrySchema as Y, ProfileSlotStatusSchema as Z, resolveCapMount as _, collectHydratedFieldValues as _t, viewerUiCapability as a, makeSourceBrokerId as at, DeviceFeature as b, DisposerChain as bt, createLazyTrpcSource as c, BaseAddon as ct, DEVICE_SETTINGS_CONTRIBUTION_METHODS as d, createEvent as dt, SubscribeAudioChunksInputSchema as et, DEVICE_STATUS_METHOD as f, emitReadiness as ft, method as g, collectHydratedFieldEntries as gt, isDeviceConfigCap as h, WELL_KNOWN_TAB_MAP as ht, deviceOpsCapability as i, makeProfileBrokerId as it, DATAPLANE_SECRET_HEADER as j, parseJsonObject as k, createMirrorSource as l, normalizeAddonInitResult as lt, expandCapMethods as m, WELL_KNOWN_TABS as mt, sleepCancellable as n, SubscribeFramesInputSchema as nt, adminUiCapability as o, parseProfileBrokerId as ot, event as p, isEvent as pt, FrameHandleFormatSchema as q, RawStateResultSchema as r, SubscribeFramesResultSchema as rt, createDeviceProxy as s, selectAssignedProfileSlots as st, sleep as t, SubscribeAudioChunksResultSchema as tt, createSliceHandle as u, createDurableState as ut, systemMethod as v, hydrateSchema as vt, asJsonArray as w, DeviceRole as x, ChargingStatus as y, resolveHydratedFieldValue as yt, CAM_PROFILE_ORDER as z };
3500
+ export { ProfileSlotSchema as $, parseJsonUnknown as A, BrokerStatsSchema as B, asBoolean as C, DisposerChain as Ct, asString as D, asNumber as E, ReadinessRegistry as F, CamStreamResolutionSchema as G, CAM_PROFILE_ORDER as H, ReadinessTimeoutError as I, DecodedFrameSchema as J, CameraStreamSchema as K, emitDownForOwnedCaps as L, nodePin as M, readNodePin as N, parseJsonArray as O, DATAPLANE_SECRET_HEADER as P, ProfileRtspEntrySchema as Q, readinessKey as R, DeviceType as S, resolveHydratedFieldValue as St, asJsonObject as T, CamProfileSchema as U, BrokerStatusSchema as V, CamStreamKindSchema as W, FrameHandleFormatSchema as X, EncodedPacketSchema as Y, FrameHandleSchema as Z, resolveCapMount as _, WELL_KNOWN_TABS as _t, viewerUiCapability as a, SubscribeFramesInputSchema as at, DeviceFeature as b, collectHydratedFieldValues as bt, createLazyTrpcSource as c, makeSourceBrokerId as ct, DEVICE_SETTINGS_CONTRIBUTION_METHODS as d, BaseAddon as dt, ProfileSlotStatusSchema as et, DEVICE_STATUS_METHOD as f, normalizeAddonInitResult as ft, method as g, isEvent as gt, isDeviceConfigCap as h, emitReadiness as ht, deviceOpsCapability as i, SubscribeAudioChunksResultSchema as it, CAP_NODE_PIN_CONTEXT_KEY as j, parseJsonObject as k, createMirrorSource as l, parseProfileBrokerId as lt, expandCapMethods as m, createEvent as mt, sleepCancellable as n, StreamSourceSchema as nt, adminUiCapability as o, SubscribeFramesResultSchema as ot, event as p, createDurableState as pt, DecodedAudioChunkSchema as q, RawStateResultSchema as r, SubscribeAudioChunksInputSchema as rt, createDeviceProxy as s, makeProfileBrokerId as st, sleep as t, StreamSourceEntrySchema$1 as tt, createSliceHandle as u, selectAssignedProfileSlots as ut, systemMethod as v, WELL_KNOWN_TAB_MAP as vt, asJsonArray as w, DeviceRole as x, hydrateSchema as xt, ChargingStatus as y, collectHydratedFieldEntries as yt, scopeKey as z };
@@ -1880,6 +1880,47 @@ function emitDownForOwnedCaps(registry, owned) {
1880
1880
  */
1881
1881
  var DATAPLANE_SECRET_HEADER = "x-camstack-dataplane-secret";
1882
1882
  //#endregion
1883
+ //#region src/cap-call-context.ts
1884
+ /**
1885
+ * Per-call node pinning for `ctx.api` capability calls.
1886
+ *
1887
+ * A capability call normally resolves to its DEFAULT provider — a `singleton`
1888
+ * cap resolves to the hub, a device-scoped cap to the device's owning node. To
1889
+ * query a SPECIFIC node's provider instead (e.g. a remote agent's own
1890
+ * in-process `platform-probe` hardware, which the hub cannot probe), pin the
1891
+ * call to that node.
1892
+ *
1893
+ * The nodeId rides OUT-OF-BAND in the tRPC call context (NOT in the validated
1894
+ * method args), so capability method signatures stay `nodeId`-free — node
1895
+ * targeting is a property of the CALL, not of the method. The transport lifts
1896
+ * it from `op.context` onto the `CapCallInput.nodeId` field (`ipcParentLink`),
1897
+ * and the hub parent's `onUnownedCall` passes it to the `CapRouteResolver`,
1898
+ * which classifies a pinned agent node as `agent-child-forward`
1899
+ * (`$agent-cap-fwd.forward` → the agent's in-process provider).
1900
+ *
1901
+ * Usage at a call site:
1902
+ *
1903
+ * await api.platformProbe.getCapabilities.query(undefined, nodePin(nodeId))
1904
+ */
1905
+ /** tRPC `op.context` key carrying a per-call node pin. */
1906
+ var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
1907
+ /**
1908
+ * Build the tRPC request options that pin a single capability call to `nodeId`.
1909
+ * Pass as the second argument to `.query(input, …)` / `.mutate(input, …)`.
1910
+ */
1911
+ function nodePin(nodeId) {
1912
+ return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
1913
+ }
1914
+ /**
1915
+ * Read a per-call node pin out of a tRPC `op.context` (transport side).
1916
+ * Returns the pinned nodeId, or `undefined` when no pin is present.
1917
+ */
1918
+ function readNodePin(context) {
1919
+ if (context === null || typeof context !== "object") return void 0;
1920
+ const value = Reflect.get(context, CAP_NODE_PIN_CONTEXT_KEY);
1921
+ return typeof value === "string" ? value : void 0;
1922
+ }
1923
+ //#endregion
1883
1924
  //#region src/utils/json-safe.ts
1884
1925
  /**
1885
1926
  * Type-safe JSON parsing helpers.
@@ -3480,6 +3521,12 @@ Object.defineProperty(exports, "CAM_PROFILE_ORDER", {
3480
3521
  return CAM_PROFILE_ORDER;
3481
3522
  }
3482
3523
  });
3524
+ Object.defineProperty(exports, "CAP_NODE_PIN_CONTEXT_KEY", {
3525
+ enumerable: true,
3526
+ get: function() {
3527
+ return CAP_NODE_PIN_CONTEXT_KEY;
3528
+ }
3529
+ });
3483
3530
  Object.defineProperty(exports, "CamProfileSchema", {
3484
3531
  enumerable: true,
3485
3532
  get: function() {
@@ -3816,6 +3863,12 @@ Object.defineProperty(exports, "method", {
3816
3863
  return method;
3817
3864
  }
3818
3865
  });
3866
+ Object.defineProperty(exports, "nodePin", {
3867
+ enumerable: true,
3868
+ get: function() {
3869
+ return nodePin;
3870
+ }
3871
+ });
3819
3872
  Object.defineProperty(exports, "normalizeAddonInitResult", {
3820
3873
  enumerable: true,
3821
3874
  get: function() {
@@ -3846,6 +3899,12 @@ Object.defineProperty(exports, "parseProfileBrokerId", {
3846
3899
  return parseProfileBrokerId;
3847
3900
  }
3848
3901
  });
3902
+ Object.defineProperty(exports, "readNodePin", {
3903
+ enumerable: true,
3904
+ get: function() {
3905
+ return readNodePin;
3906
+ }
3907
+ });
3849
3908
  Object.defineProperty(exports, "readinessKey", {
3850
3909
  enumerable: true,
3851
3910
  get: function() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.14",
3
+ "version": "1.2.16",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",