@camstack/addon-export-google 0.1.12 → 0.1.14

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.
@@ -8211,6 +8211,20 @@ var RelocateJobSchema = object({
8211
8211
  * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8212
8212
  */
8213
8213
  rowsReconciled: number().int().nonnegative().optional(),
8214
+ /**
8215
+ * Rows this run FORGOT because the file they name is not on disk.
8216
+ *
8217
+ * The mover derived the path from the row's own fields and `stat`ed it; an
8218
+ * ENOENT there is a per-path confirmation that the segment is gone (D296),
8219
+ * and the durable row is dropped through the same channel eviction uses. It
8220
+ * is reported for the same reason `rowsReconciled` is: this is a durable
8221
+ * mutation nobody asked for, and a migration that quietly erases hour rows is
8222
+ * the same failure as one that quietly skips them (D295).
8223
+ *
8224
+ * The production drain of 2026-08-30 would have reported 11 074 here — the
8225
+ * ledger claimed 5.65 GB of footage that no longer existed.
8226
+ */
8227
+ rowsForgotten: number().int().nonnegative().optional(),
8214
8228
  startedAt: number(),
8215
8229
  finishedAt: number().nullable(),
8216
8230
  error: string().nullable()
@@ -8275,6 +8289,13 @@ var MediaRelocateModeSchema = _enum([
8275
8289
  ]);
8276
8290
  var RelocateMediaInputSchema = object({
8277
8291
  toLocationId: string(),
8292
+ /**
8293
+ * Restrict the pass to rows currently on this location. Omitted / `'*'` =
8294
+ * every row that is not already on `toLocationId` (the historical
8295
+ * behaviour). A named source is what a from→to migration needs: without it
8296
+ * "move events off disk 2" also emptied disk 1.
8297
+ */
8298
+ fromLocationId: string().optional(),
8278
8299
  throttleMbps: number().min(1).max(1e3).optional(),
8279
8300
  /** Omitted = `move`, the pre-existing behaviour. */
8280
8301
  mode: MediaRelocateModeSchema.optional()
@@ -8342,6 +8363,19 @@ var StorageMigrationDestinationsSchema = object({
8342
8363
  galleryMedia: string().min(1).optional()
8343
8364
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8344
8365
  /**
8366
+ * Optional named source per class. Omitted = the class's current default
8367
+ * (the historical behaviour). A named source that is NOT the default is a
8368
+ * drain of that disk: bytes move, the default stays, and the source is
8369
+ * disabled when the move finishes.
8370
+ */
8371
+ var StorageMigrationSourcesSchema = object({
8372
+ recordings: string().min(1).optional(),
8373
+ recordingsLow: string().min(1).optional(),
8374
+ eventMedia: string().min(1).optional(),
8375
+ backups: string().min(1).optional(),
8376
+ galleryMedia: string().min(1).optional()
8377
+ }).optional();
8378
+ /**
8345
8379
  * How a migration sequences the cutover against the byte move.
8346
8380
  *
8347
8381
  * - `blocking` — the historical order: pause, move every byte, repoint,
@@ -8363,6 +8397,8 @@ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8363
8397
  /** Shared input for planning and starting an orchestrated storage migration. */
8364
8398
  var StorageMigrationInputSchema = object({
8365
8399
  destinations: StorageMigrationDestinationsSchema,
8400
+ /** Omitted = each class's current default. */
8401
+ sources: StorageMigrationSourcesSchema,
8366
8402
  throttleMbps: number().min(1).max(1e3).optional(),
8367
8403
  /** Omitted = `blocking`, which stays the default. */
8368
8404
  mode: StorageMigrationModeSchema.optional()
@@ -8442,6 +8478,13 @@ var StorageMigrationMoveSchema = object({
8442
8478
  storageClass: StorageMigrationClassSchema,
8443
8479
  fromLocationId: string(),
8444
8480
  toLocationId: string(),
8481
+ /**
8482
+ * True when `from` was NOT the class default at plan time. The move still
8483
+ * copies bytes, but the default is left alone and the source is disabled
8484
+ * once the copy verifies. Absent on jobs planned before this field existed
8485
+ * — those jobs always repointed, which is `false`.
8486
+ */
8487
+ freezeSource: boolean().optional(),
8445
8488
  moverJobId: string().nullable(),
8446
8489
  state: RelocateJobStateSchema.nullable(),
8447
8490
  error: string().nullable(),
@@ -8455,6 +8498,7 @@ var StorageMigrationJobSchema = object({
8455
8498
  * can tell a seconds-long cutover from a thirty-hour one. */
8456
8499
  mode: StorageMigrationModeSchema,
8457
8500
  destinations: StorageMigrationDestinationsSchema,
8501
+ sources: StorageMigrationSourcesSchema,
8458
8502
  throttleMbps: number(),
8459
8503
  moves: array(StorageMigrationMoveSchema),
8460
8504
  pauseLeaseId: string().nullable(),
@@ -8480,6 +8524,7 @@ var StorageMigrationFindingSchema = object({
8480
8524
  });
8481
8525
  var StorageMigrationPlanSchema = object({
8482
8526
  destinations: StorageMigrationDestinationsSchema,
8527
+ sources: StorageMigrationSourcesSchema,
8483
8528
  /** The mode this plan was built for. A plan is only valid for its mode: the
8484
8529
  * `eventMedia` seal gate and the single-cardinality refusal both depend on
8485
8530
  * it. */
@@ -8487,7 +8532,8 @@ var StorageMigrationPlanSchema = object({
8487
8532
  moves: array(object({
8488
8533
  storageClass: StorageMigrationClassSchema,
8489
8534
  fromLocationId: string(),
8490
- toLocationId: string()
8535
+ toLocationId: string(),
8536
+ freezeSource: boolean().optional()
8491
8537
  })),
8492
8538
  findings: array(StorageMigrationFindingSchema)
8493
8539
  });
@@ -8574,16 +8620,142 @@ var RelocateResidueSchema = object({
8574
8620
  segments: number().int().nonnegative(),
8575
8621
  bytes: number().int().nonnegative()
8576
8622
  }).nullable();
8623
+ /**
8624
+ * Ask one location whether its durable hour rows describe the disk — the walk
8625
+ * (D319).
8626
+ *
8627
+ * `apply` DEFAULTS TO FALSE and that default is the product: the operator's
8628
+ * missing tool is the question, and the dry run is how they sanity-check the
8629
+ * destructive run before authorising it.
8630
+ */
8631
+ var LedgerWalkInputSchema = object({
8632
+ locationId: string().min(1),
8633
+ /** Forget the confirmed-absent rows, rather than only counting them. */
8634
+ apply: boolean().optional(),
8635
+ /** Narrow to one camera. */
8636
+ deviceId: number().int().positive().optional(),
8637
+ /** Narrow to these recording profiles; empty/absent = every profile. */
8638
+ profiles: array(string().min(1)).optional()
8639
+ });
8640
+ /** Why a whole walk did nothing. Every one leaves the ledger untouched. */
8641
+ var LedgerWalkRefusalSchema = _enum([
8642
+ "location-unknown",
8643
+ "source-writable",
8644
+ "no-ledger",
8645
+ "archive-unreadable",
8646
+ "anchor-absent",
8647
+ "anchor-unreadable",
8648
+ "anchor-moved"
8649
+ ]);
8650
+ _enum([
8651
+ "live-tail",
8652
+ "listing-error",
8653
+ "path-mismatch",
8654
+ "durable-refused"
8655
+ ]);
8656
+ /** Every skip reason, always present, always a number — so a reason that never
8657
+ * fired reports as zero rather than absent and the report shape is constant
8658
+ * between passes. Spelled out rather than `z.record` for exactly that. */
8659
+ var LedgerWalkSkipCountsSchema = object({
8660
+ "live-tail": number().int().nonnegative(),
8661
+ "listing-error": number().int().nonnegative(),
8662
+ "path-mismatch": number().int().nonnegative(),
8663
+ "durable-refused": number().int().nonnegative()
8664
+ });
8665
+ /** One camera's share of a walk, so a report names cameras and not rows. */
8666
+ var LedgerWalkDeviceReportSchema = object({
8667
+ deviceId: number().int(),
8668
+ hoursWalked: number().int().nonnegative(),
8669
+ hoursMissing: number().int().nonnegative(),
8670
+ ghostSegments: number().int().nonnegative(),
8671
+ ghostBytes: number().int().nonnegative(),
8672
+ forgottenSegments: number().int().nonnegative(),
8673
+ orphanFiles: number().int().nonnegative()
8674
+ });
8675
+ /**
8676
+ * What one walk claimed, listed, found and (only when armed) forgot.
8677
+ *
8678
+ * `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
8679
+ * walk that saw a fraction of the location is visible in its own report rather
8680
+ * than in the absence of one.
8681
+ */
8682
+ var LedgerWalkReportSchema = object({
8683
+ locationId: string(),
8684
+ applied: boolean(),
8685
+ refused: LedgerWalkRefusalSchema.nullable(),
8686
+ archiveSegments: number().int().nonnegative().nullable(),
8687
+ archiveBytes: number().int().nonnegative().nullable(),
8688
+ hoursClaimed: number().int().nonnegative(),
8689
+ hoursWalked: number().int().nonnegative(),
8690
+ hoursMissing: number().int().nonnegative(),
8691
+ /** `readdir` calls issued — the cost, stated in the unit that is paid. */
8692
+ listings: number().int().nonnegative(),
8693
+ segmentsClaimed: number().int().nonnegative(),
8694
+ ghostSegments: number().int().nonnegative(),
8695
+ ghostBytes: number().int().nonnegative(),
8696
+ ghostHoursWhole: number().int().nonnegative(),
8697
+ forgottenSegments: number().int().nonnegative(),
8698
+ forgottenBytes: number().int().nonnegative(),
8699
+ /** Files under a claimed hour that no durable row names. Never deleted. */
8700
+ orphanFiles: number().int().nonnegative(),
8701
+ orphanSample: array(string()).readonly(),
8702
+ hoursSkipped: number().int().nonnegative(),
8703
+ skippedByReason: LedgerWalkSkipCountsSchema,
8704
+ /** The walk stopped at its per-pass hour bound with claims unwalked. */
8705
+ bounded: boolean(),
8706
+ byDevice: array(LedgerWalkDeviceReportSchema).readonly()
8707
+ });
8577
8708
  /** How many rows a media pass would still act on against a given target — the
8578
8709
  * media lane's denominator AND its residue, from ONE derivation so the two can
8579
8710
  * never disagree. `null` = the count could not be taken. */
8580
8711
  var RelocatableMediaCountSchema = object({ rows: number().int().nonnegative() }).nullable();
8581
8712
  var RelocatableMediaCountInputSchema = object({
8582
8713
  toLocationId: string().min(1),
8714
+ /** Restrict the count to one source; omitted / `'*'` = every non-target row. */
8715
+ fromLocationId: string().optional(),
8583
8716
  /** Omitted = `move`. */
8584
8717
  mode: MediaRelocateModeSchema.optional()
8585
8718
  });
8586
8719
  /**
8720
+ * Operator cleanup of leftover analytics rows, optional debug media, and
8721
+ * ghost ledger entries on frozen footage locations.
8722
+ *
8723
+ * A pass is tens of minutes on a standing backlog. The hub method RETURNS
8724
+ * `{ jobId }` immediately; progress is `cleanupStatus`. Awaiting the work
8725
+ * is how `addons.custom` hit the 60 s UDS deadline while reclaim continued
8726
+ * with no operator-visible status.
8727
+ */
8728
+ var StorageCleanupPhaseSchema = _enum([
8729
+ "orphans",
8730
+ "debug-media",
8731
+ "ghost-ledger",
8732
+ "done",
8733
+ "failed",
8734
+ "cancelled"
8735
+ ]);
8736
+ var StorageCleanupInputSchema = object({
8737
+ /** Also walk motion stills / track filmstrips. Off by default. */
8738
+ includeDebugMedia: boolean().optional() });
8739
+ var StorageCleanupJobSchema = object({
8740
+ jobId: string(),
8741
+ phase: StorageCleanupPhaseSchema,
8742
+ includeDebugMedia: boolean(),
8743
+ orphansReclaimed: number().int().nonnegative(),
8744
+ orphanBytesReclaimed: number().int().nonnegative(),
8745
+ debugMediaReclaimed: number().int().nonnegative(),
8746
+ debugMediaBytesReclaimed: number().int().nonnegative(),
8747
+ ghostsForgotten: number().int().nonnegative(),
8748
+ ghostBytesForgotten: number().int().nonnegative(),
8749
+ /** Short operator-facing line: current collection, pass, or location. */
8750
+ detail: string().nullable(),
8751
+ cancelRequested: boolean(),
8752
+ startedAt: number(),
8753
+ updatedAt: number(),
8754
+ finishedAt: number().nullable(),
8755
+ error: string().nullable()
8756
+ });
8757
+ var StorageCleanupStatusInputSchema = object({ jobId: string().optional() });
8758
+ /**
8587
8759
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
8588
8760
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
8589
8761
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -8611,11 +8783,10 @@ var StorageLocationTypeSchema = string().regex(/^[a-z][a-zA-Z0-9-]*$/);
8611
8783
  * The default location for a type uses `id === <type>:default` by
8612
8784
  * convention (the bare type ref like `'backups'` resolves to it).
8613
8785
  *
8614
- * `isSystem: true` marks a location as orchestrator-seeded and
8615
- * undeletable. The bootstrap-installed defaults (one per type) carry
8616
- * this flag; operator-added locations don't. Editing the config of
8617
- * a system location is allowed (path migration, provider swap) but
8618
- * deleting it is rejected at the cap level.
8786
+ * `isSystem` is a legacy persisted flag. Seed still creates the initial
8787
+ * `<type>:default` locations; the flag is no longer a lock, a badge, or a
8788
+ * prune selector. New writes leave it false. Deletion is gated on uniqueness
8789
+ * / last-enabled, not on this bit.
8619
8790
  */
8620
8791
  var StorageLocationSchema = object({
8621
8792
  id: string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
@@ -12950,6 +13121,12 @@ method(object({
12950
13121
  }), _void(), {
12951
13122
  kind: "mutation",
12952
13123
  auth: "admin"
13124
+ }), method(object({
13125
+ from: string(),
13126
+ to: string()
13127
+ }), object({ moved: number() }), {
13128
+ kind: "mutation",
13129
+ auth: "admin"
12953
13130
  }), method(object({
12954
13131
  deviceId: number(),
12955
13132
  disabled: boolean()
@@ -18896,53 +19073,15 @@ var RecentTracksPageSchema = object({
18896
19073
  /** Cursor for the next page, or null when this page is the last. */
18897
19074
  nextCursor: string().nullable()
18898
19075
  });
18899
- var LIST_GROUPS_DEFAULT_LIMIT = 40;
18900
- var LIST_GROUPS_MAX_LIMIT = 100;
18901
- var AnalyticsGroupRecordSchema = object({
18902
- id: string(),
18903
- deviceId: number().int(),
18904
- openedAt: number().int(),
18905
- closedAt: number().int(),
18906
- timestamp: number().int(),
18907
- memberCount: number().int(),
18908
- memberTrackIds: array(string()).readonly(),
18909
- className: string(),
18910
- classes: array(string()).readonly(),
18911
- /** Relative event-media path, or null when the group has no picture yet. */
18912
- mediaUrl: string().nullable(),
18913
- singleton: boolean()
18914
- });
18915
- var AnalyticsGroupMemberSchema = object({
18916
- trackId: string(),
18917
- deviceId: number().int(),
18918
- className: string(),
18919
- firstSeen: number().int(),
18920
- lastSeen: number().int(),
18921
- mediaUrl: string().nullable()
18922
- });
18923
- var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
18924
- var ListGroupsQueryInput = object({
18925
- /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
18926
- deviceIds: array(number()),
18927
- /** Window lower bound on `closedAt` (inclusive). */
18928
- since: number().optional(),
18929
- /** Window upper bound on `openedAt` (inclusive). */
18930
- until: number().optional(),
18931
- limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
18932
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
18933
- cursor: string().optional()
18934
- });
18935
- var ListGroupsPageSchema = object({
18936
- groups: array(AnalyticsGroupRecordSchema).readonly(),
18937
- nextCursor: string().nullable()
18938
- });
19076
+ var KEY_EVENTS_DEFAULT_LIMIT = 50;
19077
+ var KEY_EVENTS_MAX_LIMIT = 200;
18939
19078
  var KeyEventQueryInput = object({
18940
19079
  deviceId: number(),
18941
19080
  /** Window lower bound (track firstSeen ≥ since). */
18942
19081
  since: number(),
18943
19082
  /** Window upper bound (track firstSeen ≤ until). */
18944
19083
  until: number(),
18945
- limit: number().int().min(1).max(200).default(50),
19084
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18946
19085
  /** Drop tracks scoring below this importance. */
18947
19086
  minImportance: number().min(0).max(1).optional(),
18948
19087
  /** Restrict to a single class (e.g. 'person'). */
@@ -18964,6 +19103,32 @@ var KeyEventSchema = object({
18964
19103
  ...TrackFlagFields,
18965
19104
  ...TrackRetrainFields
18966
19105
  });
19106
+ /** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
19107
+ var KeyEventBatchQueryInput = object({
19108
+ deviceIds: array(number()).min(1).max(200),
19109
+ since: number(),
19110
+ until: number(),
19111
+ /** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
19112
+ * across the set, which would let a busy camera starve a quiet one of its
19113
+ * rows and change what the merged feed contains. */
19114
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
19115
+ minImportance: number().min(0).max(1).optional(),
19116
+ classFilter: string().optional()
19117
+ });
19118
+ /**
19119
+ * One camera's key events in a batch answer.
19120
+ *
19121
+ * The row exists for every requested id. `getKeyEvents` degrades to `[]` on
19122
+ * error rather than throwing, so a camera whose store read failed and one with
19123
+ * no events in the window were ALREADY indistinguishable per camera — the
19124
+ * batch does not make that worse, and the row keeps the deviceId the single
19125
+ * method's output never carried (the caller used to stamp it from the fan-out
19126
+ * key, which only worked because there was one query per camera).
19127
+ */
19128
+ var KeyEventsForDeviceSchema = object({
19129
+ deviceId: number(),
19130
+ events: array(KeyEventSchema).readonly()
19131
+ });
18967
19132
  object({
18968
19133
  trackId: string(),
18969
19134
  className: string(),
@@ -19011,9 +19176,7 @@ var TrackCascadeCountsSchema = object({
19011
19176
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
19012
19177
  plates: number().int(),
19013
19178
  /** Per-track CLIP search vectors removed (best-effort). */
19014
- embeddings: number().int(),
19015
- /** Group membership + group rows removed with their last member (best-effort). */
19016
- groups: number().int()
19179
+ embeddings: number().int()
19017
19180
  });
19018
19181
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
19019
19182
  var DiskReconcileCountsSchema = object({
@@ -19183,6 +19346,47 @@ var RebuildStatusSchema = object({
19183
19346
  /** Present when the pass ended by throwing. */
19184
19347
  error: string().nullable()
19185
19348
  });
19349
+ /**
19350
+ * Acknowledgement that a debug-media reclaim STARTED.
19351
+ *
19352
+ * The pass is paced at ~2 MB/s over a standing 100 GB — tens of minutes — so
19353
+ * it runs detached and this returns immediately. Awaiting it is how the
19354
+ * `addons.custom` door hit the 60 s UDS deadline while the walk carried on
19355
+ * with no status. Poll {@link pipelineAnalyticsCapability.methods.getMediaReclaimStatus}.
19356
+ */
19357
+ var MediaReclaimStartResultSchema = object({
19358
+ started: boolean(),
19359
+ /** True when a pass was already running; the new request is ignored. */
19360
+ alreadyRunning: boolean()
19361
+ });
19362
+ var MediaReclaimInputSchema = object({
19363
+ mode: _enum(["report", "reclaim"]).default("report"),
19364
+ scopes: array(_enum(["motion-still", "track-filmstrip"])).min(1).optional(),
19365
+ deviceIds: array(number().int()).min(1).optional(),
19366
+ restart: boolean().optional(),
19367
+ pageSize: number().int().min(50).max(5e3).optional(),
19368
+ maxRowsPerDevice: number().int().min(1).max(5e5).optional(),
19369
+ maxReclaimPerDevice: number().int().min(1).max(5e5).optional(),
19370
+ maxBytesPerRun: number().int().min(1).optional(),
19371
+ budgetMinutes: number().int().min(1).max(720).optional(),
19372
+ throttleBytesPerSec: number().int().min(64 * 1024).optional(),
19373
+ graceMinutes: number().int().min(1).max(10080).optional()
19374
+ });
19375
+ var MediaReclaimStatusSchema = object({
19376
+ running: boolean(),
19377
+ mode: _enum(["report", "reclaim"]).nullable(),
19378
+ totalExamined: number(),
19379
+ totalEligible: number(),
19380
+ totalReclaimed: number(),
19381
+ totalBytesReclaimed: number(),
19382
+ totalRefused: number(),
19383
+ /** Device+scope windows finished in this pass. */
19384
+ devicesDone: number(),
19385
+ complete: boolean().nullable(),
19386
+ startedAtMs: number().nullable(),
19387
+ finishedAtMs: number().nullable(),
19388
+ error: string().nullable()
19389
+ });
19186
19390
  var ReplayFrameInputSchema = object({
19187
19391
  timestamp: number(),
19188
19392
  frame: PipelineRunResultBridge
@@ -19221,10 +19425,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19221
19425
  * stationary registry). Default false: the timeline lists passages,
19222
19426
  * not parking records (operator decision, 2026-08-15). */
19223
19427
  includeStationary: boolean().optional()
19224
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
19225
- deviceId: number(),
19226
- groupId: string().min(1)
19227
- }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
19428
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
19228
19429
  kind: "mutation",
19229
19430
  auth: "admin"
19230
19431
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -19233,7 +19434,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19233
19434
  until: number().optional(),
19234
19435
  kinds: array(string()).optional(),
19235
19436
  limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
19236
- }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
19437
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
19237
19438
  deviceId: number(),
19238
19439
  since: number(),
19239
19440
  until: number(),
@@ -19324,6 +19525,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19324
19525
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19325
19526
  kind: "query",
19326
19527
  auth: "admin"
19528
+ }), method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
19529
+ kind: "mutation",
19530
+ auth: "admin"
19531
+ }), method(object({}), MediaReclaimStatusSchema, {
19532
+ kind: "query",
19533
+ auth: "admin"
19327
19534
  }), method(object({ deviceIds: array(number()).optional() }), TrainingExportSummarySchema, {
19328
19535
  kind: "query",
19329
19536
  auth: "admin"
@@ -21294,7 +21501,13 @@ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin"
21294
21501
  }), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({}), array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }), method(StorageMigrationDrainInputSchema, object({ jobId: string() }), {
21295
21502
  kind: "mutation",
21296
21503
  auth: "admin"
21297
- });
21504
+ }), method(StorageCleanupInputSchema, object({ jobId: string() }), {
21505
+ kind: "mutation",
21506
+ auth: "admin"
21507
+ }), method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
21508
+ kind: "mutation",
21509
+ auth: "admin"
21510
+ }), method(object({}), array(StorageMigrationJobSchema).readonly(), { auth: "admin" });
21298
21511
  var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
21299
21512
  providerId: string().min(1),
21300
21513
  displayName: string().min(1),
@@ -26684,6 +26897,33 @@ var RecordingRebalanceInputSchema = object({
26684
26897
  minMoveGb: number().min(0).optional()
26685
26898
  });
26686
26899
  /**
26900
+ * Operator-facing placement of one camera onto a recordings location.
26901
+ *
26902
+ * `pinLocationId` is the operator instruction: a location id, or `null` for
26903
+ * Auto (the planner may move this camera). `locationId` is where high/mid
26904
+ * currently write — the plan, which may disagree with the pin when Auto.
26905
+ */
26906
+ var RecordingDevicePlacementSchema = object({
26907
+ deviceId: number().int(),
26908
+ profile: string(),
26909
+ locationId: string()
26910
+ });
26911
+ var RecordingDevicePinSchema = object({
26912
+ deviceId: number().int(),
26913
+ /** Recordings-class location this camera is pinned to. */
26914
+ locationId: string()
26915
+ });
26916
+ var RecordingPlacementViewSchema = object({
26917
+ assignments: array(RecordingDevicePlacementSchema),
26918
+ pins: array(RecordingDevicePinSchema),
26919
+ defaultLocations: record(string(), string())
26920
+ });
26921
+ var RecordingSetDevicePlacementInputSchema = object({
26922
+ deviceId: number().int(),
26923
+ /** `null` = Auto. Otherwise a `recordings:*` location id. */
26924
+ locationId: string().nullable()
26925
+ });
26926
+ /**
26687
26927
  * Result of locating footage at a wall-clock instant for one device/profile.
26688
26928
  * `segment` carries the covering segment's window; `gap` reports the forward
26689
26929
  * nearest covered edge (`null` past the end of footage / when none exists)
@@ -26897,6 +27137,9 @@ method(object({
26897
27137
  }), method(RelocateResidueInputSchema, RelocateResidueSchema, {
26898
27138
  kind: "query",
26899
27139
  auth: "admin"
27140
+ }), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
27141
+ kind: "mutation",
27142
+ auth: "admin"
26900
27143
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
26901
27144
  kind: "mutation",
26902
27145
  auth: "admin"
@@ -26906,6 +27149,12 @@ method(object({
26906
27149
  }), method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
26907
27150
  kind: "mutation",
26908
27151
  auth: "admin"
27152
+ }), method(object({}), RecordingPlacementViewSchema, {
27153
+ kind: "query",
27154
+ auth: "admin"
27155
+ }), method(RecordingSetDevicePlacementInputSchema, object({ ok: literal(true) }), {
27156
+ kind: "mutation",
27157
+ auth: "admin"
26909
27158
  });
26910
27159
  /**
26911
27160
  * `recording-export` cap — render a footage time range into a single downloadable
@@ -27288,7 +27537,26 @@ var SceneMonitorStatusSchema = object({
27288
27537
  monitors: array(SceneMonitorSchema),
27289
27538
  lastFetchedAt: number()
27290
27539
  });
27291
- DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({
27540
+ /**
27541
+ * One camera's row in a `listScenesBatch` answer.
27542
+ *
27543
+ * `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
27544
+ * is a `defaultActive` wrapper, so every camera is asked; a camera whose
27545
+ * provider is absent (pipeline-analytics not deployed, the post-processing node
27546
+ * down) cannot answer, and that is not the same fact as a camera with no scenes
27547
+ * configured. Fanned out per camera the difference was visible — one query
27548
+ * errored while the others resolved — and a batch that returned only the rows
27549
+ * it managed would have destroyed it, silently, by making an unreachable camera
27550
+ * indistinguishable from one that answered `monitors: []`.
27551
+ *
27552
+ * So: EVERY requested deviceId gets a row. `status: null` means "this camera
27553
+ * could not be read"; `status.monitors: []` means "read, and it has none".
27554
+ */
27555
+ var SceneMonitorStatusForDeviceSchema = object({
27556
+ deviceId: number(),
27557
+ status: SceneMonitorStatusSchema.nullable()
27558
+ });
27559
+ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
27292
27560
  deviceId: number(),
27293
27561
  label: string(),
27294
27562
  roi: MaskRectShapeSchema,
@@ -28619,6 +28887,27 @@ var CameraOccupancySnapshotSchema = object({
28619
28887
  stationaryObjects: array(StationaryObjectSchema).readonly().optional()
28620
28888
  });
28621
28889
  /**
28890
+ * One camera's row in a `getCurrentSnapshotBatch` answer.
28891
+ *
28892
+ * THREE outcomes, and the single-camera method could only express two of them
28893
+ * because `snapshot: null` was already spoken for:
28894
+ *
28895
+ * - `read: 'read'`, `snapshot` present — the live occupancy reading.
28896
+ * - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
28897
+ * yet: no frame since boot, and no parked-object registry to hydrate from.
28898
+ * - `read: 'unreadable'` — the owner could not answer for this
28899
+ * camera. `snapshot` is null, and it does NOT mean "nothing parked here".
28900
+ *
28901
+ * Collapsing the last two is the failure this field exists to prevent: a
28902
+ * hydration that threw would otherwise render as an empty Stationary section,
28903
+ * which is a definite claim about a camera nobody could read.
28904
+ */
28905
+ var CameraOccupancySnapshotForDeviceSchema = object({
28906
+ deviceId: number(),
28907
+ read: _enum(["read", "unreadable"]),
28908
+ snapshot: CameraOccupancySnapshotSchema.nullable()
28909
+ });
28910
+ /**
28622
28911
  * Time-series resolution. The history methods return one bucket per
28623
28912
  * step over the requested range. Smaller resolutions cost more
28624
28913
  * memory + bandwidth; bound to discrete steps so caller cannot ask
@@ -28642,7 +28931,7 @@ var HistoryPointSchema = object({
28642
28931
  /** Object count averaged over the bucket (rounded to nearest integer). */
28643
28932
  count: number().int().nonnegative()
28644
28933
  });
28645
- DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
28934
+ DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
28646
28935
  deviceId: number(),
28647
28936
  zoneId: string(),
28648
28937
  className: string().optional()
@@ -30243,6 +30532,12 @@ Object.freeze({
30243
30532
  addonId: null,
30244
30533
  access: "delete"
30245
30534
  },
30535
+ "deviceManager.renameLocation": {
30536
+ capName: "device-manager",
30537
+ capScope: "system",
30538
+ addonId: null,
30539
+ access: "create"
30540
+ },
30246
30541
  "deviceManager.runDeviceAction": {
30247
30542
  capName: "device-manager",
30248
30543
  capScope: "system",
@@ -31935,13 +32230,19 @@ Object.freeze({
31935
32230
  addonId: null,
31936
32231
  access: "view"
31937
32232
  },
31938
- "pipelineAnalytics.getGroup": {
32233
+ "pipelineAnalytics.getKeyEvents": {
31939
32234
  capName: "pipeline-analytics",
31940
32235
  capScope: "device",
31941
32236
  addonId: null,
31942
32237
  access: "view"
31943
32238
  },
31944
- "pipelineAnalytics.getKeyEvents": {
32239
+ "pipelineAnalytics.getKeyEventsBatch": {
32240
+ capName: "pipeline-analytics",
32241
+ capScope: "device",
32242
+ addonId: null,
32243
+ access: "view"
32244
+ },
32245
+ "pipelineAnalytics.getMediaReclaimStatus": {
31945
32246
  capName: "pipeline-analytics",
31946
32247
  capScope: "device",
31947
32248
  addonId: null,
@@ -32031,12 +32332,6 @@ Object.freeze({
32031
32332
  addonId: null,
32032
32333
  access: "view"
32033
32334
  },
32034
- "pipelineAnalytics.listGroups": {
32035
- capName: "pipeline-analytics",
32036
- capScope: "device",
32037
- addonId: null,
32038
- access: "view"
32039
- },
32040
32335
  "pipelineAnalytics.listOpsLog": {
32041
32336
  capName: "pipeline-analytics",
32042
32337
  capScope: "device",
@@ -32121,6 +32416,12 @@ Object.freeze({
32121
32416
  addonId: null,
32122
32417
  access: "create"
32123
32418
  },
32419
+ "pipelineAnalytics.reclaimDebugMedia": {
32420
+ capName: "pipeline-analytics",
32421
+ capScope: "device",
32422
+ addonId: null,
32423
+ access: "create"
32424
+ },
32124
32425
  "pipelineAnalytics.reconcileFromDisk": {
32125
32426
  capName: "pipeline-analytics",
32126
32427
  capScope: "device",
@@ -33045,6 +33346,12 @@ Object.freeze({
33045
33346
  addonId: null,
33046
33347
  access: "view"
33047
33348
  },
33349
+ "recording.getPlacement": {
33350
+ capName: "recording",
33351
+ capScope: "system",
33352
+ addonId: null,
33353
+ access: "view"
33354
+ },
33048
33355
  "recording.getPlaybackManifest": {
33049
33356
  capName: "recording",
33050
33357
  capScope: "system",
@@ -33123,6 +33430,12 @@ Object.freeze({
33123
33430
  addonId: null,
33124
33431
  access: "view"
33125
33432
  },
33433
+ "recording.reconcileLedgerAgainstDisk": {
33434
+ capName: "recording",
33435
+ capScope: "system",
33436
+ addonId: null,
33437
+ access: "create"
33438
+ },
33126
33439
  "recording.refreshStorageLocationsForMigration": {
33127
33440
  capName: "recording",
33128
33441
  capScope: "system",
@@ -33165,6 +33478,12 @@ Object.freeze({
33165
33478
  addonId: null,
33166
33479
  access: "create"
33167
33480
  },
33481
+ "recording.setDevicePlacement": {
33482
+ capName: "recording",
33483
+ capScope: "system",
33484
+ addonId: null,
33485
+ access: "create"
33486
+ },
33168
33487
  "recording.startStorageMigrationMove": {
33169
33488
  capName: "recording",
33170
33489
  capScope: "system",
@@ -33249,6 +33568,12 @@ Object.freeze({
33249
33568
  addonId: null,
33250
33569
  access: "view"
33251
33570
  },
33571
+ "sceneMonitor.listScenesBatch": {
33572
+ capName: "scene-monitor",
33573
+ capScope: "device",
33574
+ addonId: null,
33575
+ access: "view"
33576
+ },
33252
33577
  "sceneMonitor.recheckNow": {
33253
33578
  capName: "scene-monitor",
33254
33579
  capScope: "device",
@@ -33603,12 +33928,36 @@ Object.freeze({
33603
33928
  addonId: null,
33604
33929
  access: "create"
33605
33930
  },
33931
+ "storageMigration.cleanupCancel": {
33932
+ capName: "storage-migration",
33933
+ capScope: "system",
33934
+ addonId: null,
33935
+ access: "create"
33936
+ },
33937
+ "storageMigration.cleanupStart": {
33938
+ capName: "storage-migration",
33939
+ capScope: "system",
33940
+ addonId: null,
33941
+ access: "create"
33942
+ },
33943
+ "storageMigration.cleanupStatus": {
33944
+ capName: "storage-migration",
33945
+ capScope: "system",
33946
+ addonId: null,
33947
+ access: "view"
33948
+ },
33606
33949
  "storageMigration.drain": {
33607
33950
  capName: "storage-migration",
33608
33951
  capScope: "system",
33609
33952
  addonId: null,
33610
33953
  access: "create"
33611
33954
  },
33955
+ "storageMigration.history": {
33956
+ capName: "storage-migration",
33957
+ capScope: "system",
33958
+ addonId: null,
33959
+ access: "view"
33960
+ },
33612
33961
  "storageMigration.movers": {
33613
33962
  capName: "storage-migration",
33614
33963
  capScope: "system",
@@ -34605,6 +34954,12 @@ Object.freeze({
34605
34954
  addonId: null,
34606
34955
  access: "view"
34607
34956
  },
34957
+ "zoneAnalytics.getCurrentSnapshotBatch": {
34958
+ capName: "zone-analytics",
34959
+ capScope: "device",
34960
+ addonId: null,
34961
+ access: "view"
34962
+ },
34608
34963
  "zoneAnalytics.getUnzonedHistory": {
34609
34964
  capName: "zone-analytics",
34610
34965
  capScope: "device",
@@ -35599,14 +35954,14 @@ Object.freeze({
35599
35954
  form: "single",
35600
35955
  optional: true
35601
35956
  }],
35602
- "pipelineAnalytics.getGroup": [{
35957
+ "pipelineAnalytics.getKeyEvents": [{
35603
35958
  name: "deviceId",
35604
35959
  form: "single",
35605
35960
  optional: false
35606
35961
  }],
35607
- "pipelineAnalytics.getKeyEvents": [{
35608
- name: "deviceId",
35609
- form: "single",
35962
+ "pipelineAnalytics.getKeyEventsBatch": [{
35963
+ name: "deviceIds",
35964
+ form: "array",
35610
35965
  optional: false
35611
35966
  }],
35612
35967
  "pipelineAnalytics.getMotionEvents": [{
@@ -35664,11 +36019,6 @@ Object.freeze({
35664
36019
  form: "single",
35665
36020
  optional: false
35666
36021
  }],
35667
- "pipelineAnalytics.listGroups": [{
35668
- name: "deviceIds",
35669
- form: "array",
35670
- optional: false
35671
- }],
35672
36022
  "pipelineAnalytics.listOpsLog": [{
35673
36023
  name: "deviceId",
35674
36024
  form: "single",
@@ -35714,6 +36064,11 @@ Object.freeze({
35714
36064
  form: "single",
35715
36065
  optional: true
35716
36066
  }],
36067
+ "pipelineAnalytics.reclaimDebugMedia": [{
36068
+ name: "deviceIds",
36069
+ form: "array",
36070
+ optional: true
36071
+ }],
35717
36072
  "pipelineAnalytics.reconcileFromDisk": [{
35718
36073
  name: "deviceId",
35719
36074
  form: "single",
@@ -36049,6 +36404,11 @@ Object.freeze({
36049
36404
  form: "single",
36050
36405
  optional: false
36051
36406
  }],
36407
+ "recording.reconcileLedgerAgainstDisk": [{
36408
+ name: "deviceId",
36409
+ form: "single",
36410
+ optional: true
36411
+ }],
36052
36412
  "recording.relocateFootage": [{
36053
36413
  name: "deviceId",
36054
36414
  form: "single",
@@ -36074,6 +36434,11 @@ Object.freeze({
36074
36434
  form: "single",
36075
36435
  optional: false
36076
36436
  }],
36437
+ "recording.setDevicePlacement": [{
36438
+ name: "deviceId",
36439
+ form: "single",
36440
+ optional: false
36441
+ }],
36077
36442
  "recording.startStorageMigrationMove": [{
36078
36443
  name: "deviceId",
36079
36444
  form: "single",
@@ -36114,6 +36479,11 @@ Object.freeze({
36114
36479
  form: "single",
36115
36480
  optional: false
36116
36481
  }],
36482
+ "sceneMonitor.listScenesBatch": [{
36483
+ name: "deviceIds",
36484
+ form: "array",
36485
+ optional: false
36486
+ }],
36117
36487
  "sceneMonitor.recheckNow": [{
36118
36488
  name: "deviceId",
36119
36489
  form: "single",
@@ -36375,6 +36745,11 @@ Object.freeze({
36375
36745
  form: "single",
36376
36746
  optional: false
36377
36747
  }],
36748
+ "zoneAnalytics.getCurrentSnapshotBatch": [{
36749
+ name: "deviceIds",
36750
+ form: "array",
36751
+ optional: false
36752
+ }],
36378
36753
  "zoneAnalytics.getUnzonedHistory": [{
36379
36754
  name: "deviceId",
36380
36755
  form: "single",