@camstack/types 1.2.15 → 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.
@@ -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
  }>;
@@ -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
@@ -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
@@ -14269,7 +14276,10 @@ function createSystemProxy(api) {
14269
14276
  delete: (input) => dispatch("backup", "delete", "mutation", input),
14270
14277
  listArchives: (input) => dispatch("backup", "listArchives", "query", input),
14271
14278
  upsertDestinationPolicy: (input) => dispatch("backup", "upsertDestinationPolicy", "mutation", input),
14272
- 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)
14273
14283
  },
14274
14284
  broker: {
14275
14285
  list: (input) => dispatch("broker", "list", "query", input),
@@ -16301,6 +16311,41 @@ var LocationStatSchema = zod.z.object({
16301
16311
  present: zod.z.boolean()
16302
16312
  });
16303
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
+ /**
16304
16349
  * backup — singleton capability for backup management.
16305
16350
  *
16306
16351
  * Implemented by `local-backup` addon. Future providers (S3, rsync)
@@ -16327,7 +16372,14 @@ var backupCapability = {
16327
16372
  /** Subset of registered `backup-destination` addon ids to write to. */
16328
16373
  destinations: zod.z.array(zod.z.string()).optional(),
16329
16374
  locations: zod.z.array(zod.z.string()).optional(),
16330
- 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()
16331
16383
  }).optional(), zod.z.array(BackupEntrySchema).readonly(), {
16332
16384
  kind: "mutation",
16333
16385
  auth: "admin"
@@ -16414,7 +16466,36 @@ var backupCapability = {
16414
16466
  ok: zod.z.boolean(),
16415
16467
  error: zod.z.string().optional(),
16416
16468
  nextRuns: zod.z.array(zod.z.number()).readonly()
16417
- }))
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
+ })
16418
16499
  }
16419
16500
  };
16420
16501
  //#endregion
@@ -27657,6 +27738,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27657
27738
  addonId: null,
27658
27739
  access: "delete"
27659
27740
  },
27741
+ "backup.deleteSchedule": {
27742
+ capName: "backup",
27743
+ capScope: "system",
27744
+ addonId: null,
27745
+ access: "delete"
27746
+ },
27660
27747
  "backup.getEntries": {
27661
27748
  capName: "backup",
27662
27749
  capScope: "system",
@@ -27687,6 +27774,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27687
27774
  addonId: null,
27688
27775
  access: "view"
27689
27776
  },
27777
+ "backup.listSchedules": {
27778
+ capName: "backup",
27779
+ capScope: "system",
27780
+ addonId: null,
27781
+ access: "view"
27782
+ },
27690
27783
  "backup.previewSchedule": {
27691
27784
  capName: "backup",
27692
27785
  capScope: "system",
@@ -27711,6 +27804,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27711
27804
  addonId: null,
27712
27805
  access: "create"
27713
27806
  },
27807
+ "backup.upsertSchedule": {
27808
+ capName: "backup",
27809
+ capScope: "system",
27810
+ addonId: null,
27811
+ access: "create"
27812
+ },
27714
27813
  "battery.wakeForStream": {
27715
27814
  capName: "battery",
27716
27815
  capScope: "device",
package/dist/index.mjs CHANGED
@@ -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
@@ -14268,7 +14275,10 @@ function createSystemProxy(api) {
14268
14275
  delete: (input) => dispatch("backup", "delete", "mutation", input),
14269
14276
  listArchives: (input) => dispatch("backup", "listArchives", "query", input),
14270
14277
  upsertDestinationPolicy: (input) => dispatch("backup", "upsertDestinationPolicy", "mutation", input),
14271
- 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)
14272
14282
  },
14273
14283
  broker: {
14274
14284
  list: (input) => dispatch("broker", "list", "query", input),
@@ -16300,6 +16310,41 @@ var LocationStatSchema = z.object({
16300
16310
  present: z.boolean()
16301
16311
  });
16302
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
+ /**
16303
16348
  * backup — singleton capability for backup management.
16304
16349
  *
16305
16350
  * Implemented by `local-backup` addon. Future providers (S3, rsync)
@@ -16326,7 +16371,14 @@ var backupCapability = {
16326
16371
  /** Subset of registered `backup-destination` addon ids to write to. */
16327
16372
  destinations: z.array(z.string()).optional(),
16328
16373
  locations: z.array(z.string()).optional(),
16329
- 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()
16330
16382
  }).optional(), z.array(BackupEntrySchema).readonly(), {
16331
16383
  kind: "mutation",
16332
16384
  auth: "admin"
@@ -16413,7 +16465,36 @@ var backupCapability = {
16413
16465
  ok: z.boolean(),
16414
16466
  error: z.string().optional(),
16415
16467
  nextRuns: z.array(z.number()).readonly()
16416
- }))
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
+ })
16417
16498
  }
16418
16499
  };
16419
16500
  //#endregion
@@ -27656,6 +27737,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27656
27737
  addonId: null,
27657
27738
  access: "delete"
27658
27739
  },
27740
+ "backup.deleteSchedule": {
27741
+ capName: "backup",
27742
+ capScope: "system",
27743
+ addonId: null,
27744
+ access: "delete"
27745
+ },
27659
27746
  "backup.getEntries": {
27660
27747
  capName: "backup",
27661
27748
  capScope: "system",
@@ -27686,6 +27773,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27686
27773
  addonId: null,
27687
27774
  access: "view"
27688
27775
  },
27776
+ "backup.listSchedules": {
27777
+ capName: "backup",
27778
+ capScope: "system",
27779
+ addonId: null,
27780
+ access: "view"
27781
+ },
27689
27782
  "backup.previewSchedule": {
27690
27783
  capName: "backup",
27691
27784
  capScope: "system",
@@ -27710,6 +27803,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27710
27803
  addonId: null,
27711
27804
  access: "create"
27712
27805
  },
27806
+ "backup.upsertSchedule": {
27807
+ capName: "backup",
27808
+ capScope: "system",
27809
+ addonId: null,
27810
+ access: "create"
27811
+ },
27713
27812
  "battery.wakeForStream": {
27714
27813
  capName: "battery",
27715
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`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.15",
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",