@camstack/addon-mqtt-broker 1.2.48 → 1.2.50

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.
@@ -8047,6 +8047,20 @@ var RelocateJobSchema = object({
8047
8047
  * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8048
8048
  */
8049
8049
  rowsReconciled: number().int().nonnegative().optional(),
8050
+ /**
8051
+ * Rows this run FORGOT because the file they name is not on disk.
8052
+ *
8053
+ * The mover derived the path from the row's own fields and `stat`ed it; an
8054
+ * ENOENT there is a per-path confirmation that the segment is gone (D296),
8055
+ * and the durable row is dropped through the same channel eviction uses. It
8056
+ * is reported for the same reason `rowsReconciled` is: this is a durable
8057
+ * mutation nobody asked for, and a migration that quietly erases hour rows is
8058
+ * the same failure as one that quietly skips them (D295).
8059
+ *
8060
+ * The production drain of 2026-08-30 would have reported 11 074 here — the
8061
+ * ledger claimed 5.65 GB of footage that no longer existed.
8062
+ */
8063
+ rowsForgotten: number().int().nonnegative().optional(),
8050
8064
  startedAt: number(),
8051
8065
  finishedAt: number().nullable(),
8052
8066
  error: string().nullable()
@@ -8111,6 +8125,13 @@ var MediaRelocateModeSchema = _enum([
8111
8125
  ]);
8112
8126
  var RelocateMediaInputSchema = object({
8113
8127
  toLocationId: string(),
8128
+ /**
8129
+ * Restrict the pass to rows currently on this location. Omitted / `'*'` =
8130
+ * every row that is not already on `toLocationId` (the historical
8131
+ * behaviour). A named source is what a from→to migration needs: without it
8132
+ * "move events off disk 2" also emptied disk 1.
8133
+ */
8134
+ fromLocationId: string().optional(),
8114
8135
  throttleMbps: number().min(1).max(1e3).optional(),
8115
8136
  /** Omitted = `move`, the pre-existing behaviour. */
8116
8137
  mode: MediaRelocateModeSchema.optional()
@@ -8178,6 +8199,19 @@ var StorageMigrationDestinationsSchema = object({
8178
8199
  galleryMedia: string().min(1).optional()
8179
8200
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8180
8201
  /**
8202
+ * Optional named source per class. Omitted = the class's current default
8203
+ * (the historical behaviour). A named source that is NOT the default is a
8204
+ * drain of that disk: bytes move, the default stays, and the source is
8205
+ * disabled when the move finishes.
8206
+ */
8207
+ var StorageMigrationSourcesSchema = object({
8208
+ recordings: string().min(1).optional(),
8209
+ recordingsLow: string().min(1).optional(),
8210
+ eventMedia: string().min(1).optional(),
8211
+ backups: string().min(1).optional(),
8212
+ galleryMedia: string().min(1).optional()
8213
+ }).optional();
8214
+ /**
8181
8215
  * How a migration sequences the cutover against the byte move.
8182
8216
  *
8183
8217
  * - `blocking` — the historical order: pause, move every byte, repoint,
@@ -8199,6 +8233,8 @@ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8199
8233
  /** Shared input for planning and starting an orchestrated storage migration. */
8200
8234
  var StorageMigrationInputSchema = object({
8201
8235
  destinations: StorageMigrationDestinationsSchema,
8236
+ /** Omitted = each class's current default. */
8237
+ sources: StorageMigrationSourcesSchema,
8202
8238
  throttleMbps: number().min(1).max(1e3).optional(),
8203
8239
  /** Omitted = `blocking`, which stays the default. */
8204
8240
  mode: StorageMigrationModeSchema.optional()
@@ -8278,6 +8314,13 @@ var StorageMigrationMoveSchema = object({
8278
8314
  storageClass: StorageMigrationClassSchema,
8279
8315
  fromLocationId: string(),
8280
8316
  toLocationId: string(),
8317
+ /**
8318
+ * True when `from` was NOT the class default at plan time. The move still
8319
+ * copies bytes, but the default is left alone and the source is disabled
8320
+ * once the copy verifies. Absent on jobs planned before this field existed
8321
+ * — those jobs always repointed, which is `false`.
8322
+ */
8323
+ freezeSource: boolean().optional(),
8281
8324
  moverJobId: string().nullable(),
8282
8325
  state: RelocateJobStateSchema.nullable(),
8283
8326
  error: string().nullable(),
@@ -8291,6 +8334,7 @@ var StorageMigrationJobSchema = object({
8291
8334
  * can tell a seconds-long cutover from a thirty-hour one. */
8292
8335
  mode: StorageMigrationModeSchema,
8293
8336
  destinations: StorageMigrationDestinationsSchema,
8337
+ sources: StorageMigrationSourcesSchema,
8294
8338
  throttleMbps: number(),
8295
8339
  moves: array(StorageMigrationMoveSchema),
8296
8340
  pauseLeaseId: string().nullable(),
@@ -8316,6 +8360,7 @@ var StorageMigrationFindingSchema = object({
8316
8360
  });
8317
8361
  var StorageMigrationPlanSchema = object({
8318
8362
  destinations: StorageMigrationDestinationsSchema,
8363
+ sources: StorageMigrationSourcesSchema,
8319
8364
  /** The mode this plan was built for. A plan is only valid for its mode: the
8320
8365
  * `eventMedia` seal gate and the single-cardinality refusal both depend on
8321
8366
  * it. */
@@ -8323,7 +8368,8 @@ var StorageMigrationPlanSchema = object({
8323
8368
  moves: array(object({
8324
8369
  storageClass: StorageMigrationClassSchema,
8325
8370
  fromLocationId: string(),
8326
- toLocationId: string()
8371
+ toLocationId: string(),
8372
+ freezeSource: boolean().optional()
8327
8373
  })),
8328
8374
  findings: array(StorageMigrationFindingSchema)
8329
8375
  });
@@ -8410,16 +8456,142 @@ var RelocateResidueSchema = object({
8410
8456
  segments: number().int().nonnegative(),
8411
8457
  bytes: number().int().nonnegative()
8412
8458
  }).nullable();
8459
+ /**
8460
+ * Ask one location whether its durable hour rows describe the disk — the walk
8461
+ * (D319).
8462
+ *
8463
+ * `apply` DEFAULTS TO FALSE and that default is the product: the operator's
8464
+ * missing tool is the question, and the dry run is how they sanity-check the
8465
+ * destructive run before authorising it.
8466
+ */
8467
+ var LedgerWalkInputSchema = object({
8468
+ locationId: string().min(1),
8469
+ /** Forget the confirmed-absent rows, rather than only counting them. */
8470
+ apply: boolean().optional(),
8471
+ /** Narrow to one camera. */
8472
+ deviceId: number().int().positive().optional(),
8473
+ /** Narrow to these recording profiles; empty/absent = every profile. */
8474
+ profiles: array(string().min(1)).optional()
8475
+ });
8476
+ /** Why a whole walk did nothing. Every one leaves the ledger untouched. */
8477
+ var LedgerWalkRefusalSchema = _enum([
8478
+ "location-unknown",
8479
+ "source-writable",
8480
+ "no-ledger",
8481
+ "archive-unreadable",
8482
+ "anchor-absent",
8483
+ "anchor-unreadable",
8484
+ "anchor-moved"
8485
+ ]);
8486
+ _enum([
8487
+ "live-tail",
8488
+ "listing-error",
8489
+ "path-mismatch",
8490
+ "durable-refused"
8491
+ ]);
8492
+ /** Every skip reason, always present, always a number — so a reason that never
8493
+ * fired reports as zero rather than absent and the report shape is constant
8494
+ * between passes. Spelled out rather than `z.record` for exactly that. */
8495
+ var LedgerWalkSkipCountsSchema = object({
8496
+ "live-tail": number().int().nonnegative(),
8497
+ "listing-error": number().int().nonnegative(),
8498
+ "path-mismatch": number().int().nonnegative(),
8499
+ "durable-refused": number().int().nonnegative()
8500
+ });
8501
+ /** One camera's share of a walk, so a report names cameras and not rows. */
8502
+ var LedgerWalkDeviceReportSchema = object({
8503
+ deviceId: number().int(),
8504
+ hoursWalked: number().int().nonnegative(),
8505
+ hoursMissing: number().int().nonnegative(),
8506
+ ghostSegments: number().int().nonnegative(),
8507
+ ghostBytes: number().int().nonnegative(),
8508
+ forgottenSegments: number().int().nonnegative(),
8509
+ orphanFiles: number().int().nonnegative()
8510
+ });
8511
+ /**
8512
+ * What one walk claimed, listed, found and (only when armed) forgot.
8513
+ *
8514
+ * `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
8515
+ * walk that saw a fraction of the location is visible in its own report rather
8516
+ * than in the absence of one.
8517
+ */
8518
+ var LedgerWalkReportSchema = object({
8519
+ locationId: string(),
8520
+ applied: boolean(),
8521
+ refused: LedgerWalkRefusalSchema.nullable(),
8522
+ archiveSegments: number().int().nonnegative().nullable(),
8523
+ archiveBytes: number().int().nonnegative().nullable(),
8524
+ hoursClaimed: number().int().nonnegative(),
8525
+ hoursWalked: number().int().nonnegative(),
8526
+ hoursMissing: number().int().nonnegative(),
8527
+ /** `readdir` calls issued — the cost, stated in the unit that is paid. */
8528
+ listings: number().int().nonnegative(),
8529
+ segmentsClaimed: number().int().nonnegative(),
8530
+ ghostSegments: number().int().nonnegative(),
8531
+ ghostBytes: number().int().nonnegative(),
8532
+ ghostHoursWhole: number().int().nonnegative(),
8533
+ forgottenSegments: number().int().nonnegative(),
8534
+ forgottenBytes: number().int().nonnegative(),
8535
+ /** Files under a claimed hour that no durable row names. Never deleted. */
8536
+ orphanFiles: number().int().nonnegative(),
8537
+ orphanSample: array(string()).readonly(),
8538
+ hoursSkipped: number().int().nonnegative(),
8539
+ skippedByReason: LedgerWalkSkipCountsSchema,
8540
+ /** The walk stopped at its per-pass hour bound with claims unwalked. */
8541
+ bounded: boolean(),
8542
+ byDevice: array(LedgerWalkDeviceReportSchema).readonly()
8543
+ });
8413
8544
  /** How many rows a media pass would still act on against a given target — the
8414
8545
  * media lane's denominator AND its residue, from ONE derivation so the two can
8415
8546
  * never disagree. `null` = the count could not be taken. */
8416
8547
  var RelocatableMediaCountSchema = object({ rows: number().int().nonnegative() }).nullable();
8417
8548
  var RelocatableMediaCountInputSchema = object({
8418
8549
  toLocationId: string().min(1),
8550
+ /** Restrict the count to one source; omitted / `'*'` = every non-target row. */
8551
+ fromLocationId: string().optional(),
8419
8552
  /** Omitted = `move`. */
8420
8553
  mode: MediaRelocateModeSchema.optional()
8421
8554
  });
8422
8555
  /**
8556
+ * Operator cleanup of leftover analytics rows, optional debug media, and
8557
+ * ghost ledger entries on frozen footage locations.
8558
+ *
8559
+ * A pass is tens of minutes on a standing backlog. The hub method RETURNS
8560
+ * `{ jobId }` immediately; progress is `cleanupStatus`. Awaiting the work
8561
+ * is how `addons.custom` hit the 60 s UDS deadline while reclaim continued
8562
+ * with no operator-visible status.
8563
+ */
8564
+ var StorageCleanupPhaseSchema = _enum([
8565
+ "orphans",
8566
+ "debug-media",
8567
+ "ghost-ledger",
8568
+ "done",
8569
+ "failed",
8570
+ "cancelled"
8571
+ ]);
8572
+ var StorageCleanupInputSchema = object({
8573
+ /** Also walk motion stills / track filmstrips. Off by default. */
8574
+ includeDebugMedia: boolean().optional() });
8575
+ var StorageCleanupJobSchema = object({
8576
+ jobId: string(),
8577
+ phase: StorageCleanupPhaseSchema,
8578
+ includeDebugMedia: boolean(),
8579
+ orphansReclaimed: number().int().nonnegative(),
8580
+ orphanBytesReclaimed: number().int().nonnegative(),
8581
+ debugMediaReclaimed: number().int().nonnegative(),
8582
+ debugMediaBytesReclaimed: number().int().nonnegative(),
8583
+ ghostsForgotten: number().int().nonnegative(),
8584
+ ghostBytesForgotten: number().int().nonnegative(),
8585
+ /** Short operator-facing line: current collection, pass, or location. */
8586
+ detail: string().nullable(),
8587
+ cancelRequested: boolean(),
8588
+ startedAt: number(),
8589
+ updatedAt: number(),
8590
+ finishedAt: number().nullable(),
8591
+ error: string().nullable()
8592
+ });
8593
+ var StorageCleanupStatusInputSchema = object({ jobId: string().optional() });
8594
+ /**
8423
8595
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
8424
8596
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
8425
8597
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -8447,11 +8619,10 @@ var StorageLocationTypeSchema = string().regex(/^[a-z][a-zA-Z0-9-]*$/);
8447
8619
  * The default location for a type uses `id === <type>:default` by
8448
8620
  * convention (the bare type ref like `'backups'` resolves to it).
8449
8621
  *
8450
- * `isSystem: true` marks a location as orchestrator-seeded and
8451
- * undeletable. The bootstrap-installed defaults (one per type) carry
8452
- * this flag; operator-added locations don't. Editing the config of
8453
- * a system location is allowed (path migration, provider swap) but
8454
- * deleting it is rejected at the cap level.
8622
+ * `isSystem` is a legacy persisted flag. Seed still creates the initial
8623
+ * `<type>:default` locations; the flag is no longer a lock, a badge, or a
8624
+ * prune selector. New writes leave it false. Deletion is gated on uniqueness
8625
+ * / last-enabled, not on this bit.
8455
8626
  */
8456
8627
  var StorageLocationSchema = object({
8457
8628
  id: string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
@@ -12762,6 +12933,12 @@ method(object({
12762
12933
  }), _void(), {
12763
12934
  kind: "mutation",
12764
12935
  auth: "admin"
12936
+ }), method(object({
12937
+ from: string(),
12938
+ to: string()
12939
+ }), object({ moved: number() }), {
12940
+ kind: "mutation",
12941
+ auth: "admin"
12765
12942
  }), method(object({
12766
12943
  deviceId: number(),
12767
12944
  disabled: boolean()
@@ -18711,53 +18888,15 @@ var RecentTracksPageSchema = object({
18711
18888
  /** Cursor for the next page, or null when this page is the last. */
18712
18889
  nextCursor: string().nullable()
18713
18890
  });
18714
- var LIST_GROUPS_DEFAULT_LIMIT = 40;
18715
- var LIST_GROUPS_MAX_LIMIT = 100;
18716
- var AnalyticsGroupRecordSchema = object({
18717
- id: string(),
18718
- deviceId: number().int(),
18719
- openedAt: number().int(),
18720
- closedAt: number().int(),
18721
- timestamp: number().int(),
18722
- memberCount: number().int(),
18723
- memberTrackIds: array(string()).readonly(),
18724
- className: string(),
18725
- classes: array(string()).readonly(),
18726
- /** Relative event-media path, or null when the group has no picture yet. */
18727
- mediaUrl: string().nullable(),
18728
- singleton: boolean()
18729
- });
18730
- var AnalyticsGroupMemberSchema = object({
18731
- trackId: string(),
18732
- deviceId: number().int(),
18733
- className: string(),
18734
- firstSeen: number().int(),
18735
- lastSeen: number().int(),
18736
- mediaUrl: string().nullable()
18737
- });
18738
- var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
18739
- var ListGroupsQueryInput = object({
18740
- /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
18741
- deviceIds: array(number()),
18742
- /** Window lower bound on `closedAt` (inclusive). */
18743
- since: number().optional(),
18744
- /** Window upper bound on `openedAt` (inclusive). */
18745
- until: number().optional(),
18746
- limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
18747
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
18748
- cursor: string().optional()
18749
- });
18750
- var ListGroupsPageSchema = object({
18751
- groups: array(AnalyticsGroupRecordSchema).readonly(),
18752
- nextCursor: string().nullable()
18753
- });
18891
+ var KEY_EVENTS_DEFAULT_LIMIT = 50;
18892
+ var KEY_EVENTS_MAX_LIMIT = 200;
18754
18893
  var KeyEventQueryInput = object({
18755
18894
  deviceId: number(),
18756
18895
  /** Window lower bound (track firstSeen ≥ since). */
18757
18896
  since: number(),
18758
18897
  /** Window upper bound (track firstSeen ≤ until). */
18759
18898
  until: number(),
18760
- limit: number().int().min(1).max(200).default(50),
18899
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18761
18900
  /** Drop tracks scoring below this importance. */
18762
18901
  minImportance: number().min(0).max(1).optional(),
18763
18902
  /** Restrict to a single class (e.g. 'person'). */
@@ -18779,6 +18918,32 @@ var KeyEventSchema = object({
18779
18918
  ...TrackFlagFields,
18780
18919
  ...TrackRetrainFields
18781
18920
  });
18921
+ /** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
18922
+ var KeyEventBatchQueryInput = object({
18923
+ deviceIds: array(number()).min(1).max(200),
18924
+ since: number(),
18925
+ until: number(),
18926
+ /** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
18927
+ * across the set, which would let a busy camera starve a quiet one of its
18928
+ * rows and change what the merged feed contains. */
18929
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18930
+ minImportance: number().min(0).max(1).optional(),
18931
+ classFilter: string().optional()
18932
+ });
18933
+ /**
18934
+ * One camera's key events in a batch answer.
18935
+ *
18936
+ * The row exists for every requested id. `getKeyEvents` degrades to `[]` on
18937
+ * error rather than throwing, so a camera whose store read failed and one with
18938
+ * no events in the window were ALREADY indistinguishable per camera — the
18939
+ * batch does not make that worse, and the row keeps the deviceId the single
18940
+ * method's output never carried (the caller used to stamp it from the fan-out
18941
+ * key, which only worked because there was one query per camera).
18942
+ */
18943
+ var KeyEventsForDeviceSchema = object({
18944
+ deviceId: number(),
18945
+ events: array(KeyEventSchema).readonly()
18946
+ });
18782
18947
  object({
18783
18948
  trackId: string(),
18784
18949
  className: string(),
@@ -18826,9 +18991,7 @@ var TrackCascadeCountsSchema = object({
18826
18991
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
18827
18992
  plates: number().int(),
18828
18993
  /** Per-track CLIP search vectors removed (best-effort). */
18829
- embeddings: number().int(),
18830
- /** Group membership + group rows removed with their last member (best-effort). */
18831
- groups: number().int()
18994
+ embeddings: number().int()
18832
18995
  });
18833
18996
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
18834
18997
  var DiskReconcileCountsSchema = object({
@@ -18998,6 +19161,47 @@ var RebuildStatusSchema = object({
18998
19161
  /** Present when the pass ended by throwing. */
18999
19162
  error: string().nullable()
19000
19163
  });
19164
+ /**
19165
+ * Acknowledgement that a debug-media reclaim STARTED.
19166
+ *
19167
+ * The pass is paced at ~2 MB/s over a standing 100 GB — tens of minutes — so
19168
+ * it runs detached and this returns immediately. Awaiting it is how the
19169
+ * `addons.custom` door hit the 60 s UDS deadline while the walk carried on
19170
+ * with no status. Poll {@link pipelineAnalyticsCapability.methods.getMediaReclaimStatus}.
19171
+ */
19172
+ var MediaReclaimStartResultSchema = object({
19173
+ started: boolean(),
19174
+ /** True when a pass was already running; the new request is ignored. */
19175
+ alreadyRunning: boolean()
19176
+ });
19177
+ var MediaReclaimInputSchema = object({
19178
+ mode: _enum(["report", "reclaim"]).default("report"),
19179
+ scopes: array(_enum(["motion-still", "track-filmstrip"])).min(1).optional(),
19180
+ deviceIds: array(number().int()).min(1).optional(),
19181
+ restart: boolean().optional(),
19182
+ pageSize: number().int().min(50).max(5e3).optional(),
19183
+ maxRowsPerDevice: number().int().min(1).max(5e5).optional(),
19184
+ maxReclaimPerDevice: number().int().min(1).max(5e5).optional(),
19185
+ maxBytesPerRun: number().int().min(1).optional(),
19186
+ budgetMinutes: number().int().min(1).max(720).optional(),
19187
+ throttleBytesPerSec: number().int().min(64 * 1024).optional(),
19188
+ graceMinutes: number().int().min(1).max(10080).optional()
19189
+ });
19190
+ var MediaReclaimStatusSchema = object({
19191
+ running: boolean(),
19192
+ mode: _enum(["report", "reclaim"]).nullable(),
19193
+ totalExamined: number(),
19194
+ totalEligible: number(),
19195
+ totalReclaimed: number(),
19196
+ totalBytesReclaimed: number(),
19197
+ totalRefused: number(),
19198
+ /** Device+scope windows finished in this pass. */
19199
+ devicesDone: number(),
19200
+ complete: boolean().nullable(),
19201
+ startedAtMs: number().nullable(),
19202
+ finishedAtMs: number().nullable(),
19203
+ error: string().nullable()
19204
+ });
19001
19205
  var ReplayFrameInputSchema = object({
19002
19206
  timestamp: number(),
19003
19207
  frame: PipelineRunResultBridge
@@ -19036,10 +19240,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19036
19240
  * stationary registry). Default false: the timeline lists passages,
19037
19241
  * not parking records (operator decision, 2026-08-15). */
19038
19242
  includeStationary: boolean().optional()
19039
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
19040
- deviceId: number(),
19041
- groupId: string().min(1)
19042
- }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
19243
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
19043
19244
  kind: "mutation",
19044
19245
  auth: "admin"
19045
19246
  }), 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({
@@ -19048,7 +19249,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19048
19249
  until: number().optional(),
19049
19250
  kinds: array(string()).optional(),
19050
19251
  limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
19051
- }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
19252
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
19052
19253
  deviceId: number(),
19053
19254
  since: number(),
19054
19255
  until: number(),
@@ -19139,6 +19340,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19139
19340
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19140
19341
  kind: "query",
19141
19342
  auth: "admin"
19343
+ }), method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
19344
+ kind: "mutation",
19345
+ auth: "admin"
19346
+ }), method(object({}), MediaReclaimStatusSchema, {
19347
+ kind: "query",
19348
+ auth: "admin"
19142
19349
  }), method(object({ deviceIds: array(number()).optional() }), TrainingExportSummarySchema, {
19143
19350
  kind: "query",
19144
19351
  auth: "admin"
@@ -21109,7 +21316,13 @@ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin"
21109
21316
  }), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({}), array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }), method(StorageMigrationDrainInputSchema, object({ jobId: string() }), {
21110
21317
  kind: "mutation",
21111
21318
  auth: "admin"
21112
- });
21319
+ }), method(StorageCleanupInputSchema, object({ jobId: string() }), {
21320
+ kind: "mutation",
21321
+ auth: "admin"
21322
+ }), method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
21323
+ kind: "mutation",
21324
+ auth: "admin"
21325
+ }), method(object({}), array(StorageMigrationJobSchema).readonly(), { auth: "admin" });
21113
21326
  var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
21114
21327
  providerId: string().min(1),
21115
21328
  displayName: string().min(1),
@@ -26487,6 +26700,33 @@ var RecordingRebalanceInputSchema = object({
26487
26700
  minMoveGb: number().min(0).optional()
26488
26701
  });
26489
26702
  /**
26703
+ * Operator-facing placement of one camera onto a recordings location.
26704
+ *
26705
+ * `pinLocationId` is the operator instruction: a location id, or `null` for
26706
+ * Auto (the planner may move this camera). `locationId` is where high/mid
26707
+ * currently write — the plan, which may disagree with the pin when Auto.
26708
+ */
26709
+ var RecordingDevicePlacementSchema = object({
26710
+ deviceId: number().int(),
26711
+ profile: string(),
26712
+ locationId: string()
26713
+ });
26714
+ var RecordingDevicePinSchema = object({
26715
+ deviceId: number().int(),
26716
+ /** Recordings-class location this camera is pinned to. */
26717
+ locationId: string()
26718
+ });
26719
+ var RecordingPlacementViewSchema = object({
26720
+ assignments: array(RecordingDevicePlacementSchema),
26721
+ pins: array(RecordingDevicePinSchema),
26722
+ defaultLocations: record(string(), string())
26723
+ });
26724
+ var RecordingSetDevicePlacementInputSchema = object({
26725
+ deviceId: number().int(),
26726
+ /** `null` = Auto. Otherwise a `recordings:*` location id. */
26727
+ locationId: string().nullable()
26728
+ });
26729
+ /**
26490
26730
  * Result of locating footage at a wall-clock instant for one device/profile.
26491
26731
  * `segment` carries the covering segment's window; `gap` reports the forward
26492
26732
  * nearest covered edge (`null` past the end of footage / when none exists)
@@ -26700,6 +26940,9 @@ method(object({
26700
26940
  }), method(RelocateResidueInputSchema, RelocateResidueSchema, {
26701
26941
  kind: "query",
26702
26942
  auth: "admin"
26943
+ }), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
26944
+ kind: "mutation",
26945
+ auth: "admin"
26703
26946
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
26704
26947
  kind: "mutation",
26705
26948
  auth: "admin"
@@ -26709,6 +26952,12 @@ method(object({
26709
26952
  }), method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
26710
26953
  kind: "mutation",
26711
26954
  auth: "admin"
26955
+ }), method(object({}), RecordingPlacementViewSchema, {
26956
+ kind: "query",
26957
+ auth: "admin"
26958
+ }), method(RecordingSetDevicePlacementInputSchema, object({ ok: literal(true) }), {
26959
+ kind: "mutation",
26960
+ auth: "admin"
26712
26961
  });
26713
26962
  /**
26714
26963
  * `recording-export` cap — render a footage time range into a single downloadable
@@ -27091,7 +27340,26 @@ var SceneMonitorStatusSchema = object({
27091
27340
  monitors: array(SceneMonitorSchema),
27092
27341
  lastFetchedAt: number()
27093
27342
  });
27094
- DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({
27343
+ /**
27344
+ * One camera's row in a `listScenesBatch` answer.
27345
+ *
27346
+ * `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
27347
+ * is a `defaultActive` wrapper, so every camera is asked; a camera whose
27348
+ * provider is absent (pipeline-analytics not deployed, the post-processing node
27349
+ * down) cannot answer, and that is not the same fact as a camera with no scenes
27350
+ * configured. Fanned out per camera the difference was visible — one query
27351
+ * errored while the others resolved — and a batch that returned only the rows
27352
+ * it managed would have destroyed it, silently, by making an unreachable camera
27353
+ * indistinguishable from one that answered `monitors: []`.
27354
+ *
27355
+ * So: EVERY requested deviceId gets a row. `status: null` means "this camera
27356
+ * could not be read"; `status.monitors: []` means "read, and it has none".
27357
+ */
27358
+ var SceneMonitorStatusForDeviceSchema = object({
27359
+ deviceId: number(),
27360
+ status: SceneMonitorStatusSchema.nullable()
27361
+ });
27362
+ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
27095
27363
  deviceId: number(),
27096
27364
  label: string(),
27097
27365
  roi: MaskRectShapeSchema,
@@ -28415,6 +28683,27 @@ var CameraOccupancySnapshotSchema = object({
28415
28683
  stationaryObjects: array(StationaryObjectSchema).readonly().optional()
28416
28684
  });
28417
28685
  /**
28686
+ * One camera's row in a `getCurrentSnapshotBatch` answer.
28687
+ *
28688
+ * THREE outcomes, and the single-camera method could only express two of them
28689
+ * because `snapshot: null` was already spoken for:
28690
+ *
28691
+ * - `read: 'read'`, `snapshot` present — the live occupancy reading.
28692
+ * - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
28693
+ * yet: no frame since boot, and no parked-object registry to hydrate from.
28694
+ * - `read: 'unreadable'` — the owner could not answer for this
28695
+ * camera. `snapshot` is null, and it does NOT mean "nothing parked here".
28696
+ *
28697
+ * Collapsing the last two is the failure this field exists to prevent: a
28698
+ * hydration that threw would otherwise render as an empty Stationary section,
28699
+ * which is a definite claim about a camera nobody could read.
28700
+ */
28701
+ var CameraOccupancySnapshotForDeviceSchema = object({
28702
+ deviceId: number(),
28703
+ read: _enum(["read", "unreadable"]),
28704
+ snapshot: CameraOccupancySnapshotSchema.nullable()
28705
+ });
28706
+ /**
28418
28707
  * Time-series resolution. The history methods return one bucket per
28419
28708
  * step over the requested range. Smaller resolutions cost more
28420
28709
  * memory + bandwidth; bound to discrete steps so caller cannot ask
@@ -28438,7 +28727,7 @@ var HistoryPointSchema = object({
28438
28727
  /** Object count averaged over the bucket (rounded to nearest integer). */
28439
28728
  count: number().int().nonnegative()
28440
28729
  });
28441
- DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
28730
+ DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
28442
28731
  deviceId: number(),
28443
28732
  zoneId: string(),
28444
28733
  className: string().optional()
@@ -30039,6 +30328,12 @@ Object.freeze({
30039
30328
  addonId: null,
30040
30329
  access: "delete"
30041
30330
  },
30331
+ "deviceManager.renameLocation": {
30332
+ capName: "device-manager",
30333
+ capScope: "system",
30334
+ addonId: null,
30335
+ access: "create"
30336
+ },
30042
30337
  "deviceManager.runDeviceAction": {
30043
30338
  capName: "device-manager",
30044
30339
  capScope: "system",
@@ -31731,13 +32026,19 @@ Object.freeze({
31731
32026
  addonId: null,
31732
32027
  access: "view"
31733
32028
  },
31734
- "pipelineAnalytics.getGroup": {
32029
+ "pipelineAnalytics.getKeyEvents": {
31735
32030
  capName: "pipeline-analytics",
31736
32031
  capScope: "device",
31737
32032
  addonId: null,
31738
32033
  access: "view"
31739
32034
  },
31740
- "pipelineAnalytics.getKeyEvents": {
32035
+ "pipelineAnalytics.getKeyEventsBatch": {
32036
+ capName: "pipeline-analytics",
32037
+ capScope: "device",
32038
+ addonId: null,
32039
+ access: "view"
32040
+ },
32041
+ "pipelineAnalytics.getMediaReclaimStatus": {
31741
32042
  capName: "pipeline-analytics",
31742
32043
  capScope: "device",
31743
32044
  addonId: null,
@@ -31827,12 +32128,6 @@ Object.freeze({
31827
32128
  addonId: null,
31828
32129
  access: "view"
31829
32130
  },
31830
- "pipelineAnalytics.listGroups": {
31831
- capName: "pipeline-analytics",
31832
- capScope: "device",
31833
- addonId: null,
31834
- access: "view"
31835
- },
31836
32131
  "pipelineAnalytics.listOpsLog": {
31837
32132
  capName: "pipeline-analytics",
31838
32133
  capScope: "device",
@@ -31917,6 +32212,12 @@ Object.freeze({
31917
32212
  addonId: null,
31918
32213
  access: "create"
31919
32214
  },
32215
+ "pipelineAnalytics.reclaimDebugMedia": {
32216
+ capName: "pipeline-analytics",
32217
+ capScope: "device",
32218
+ addonId: null,
32219
+ access: "create"
32220
+ },
31920
32221
  "pipelineAnalytics.reconcileFromDisk": {
31921
32222
  capName: "pipeline-analytics",
31922
32223
  capScope: "device",
@@ -32841,6 +33142,12 @@ Object.freeze({
32841
33142
  addonId: null,
32842
33143
  access: "view"
32843
33144
  },
33145
+ "recording.getPlacement": {
33146
+ capName: "recording",
33147
+ capScope: "system",
33148
+ addonId: null,
33149
+ access: "view"
33150
+ },
32844
33151
  "recording.getPlaybackManifest": {
32845
33152
  capName: "recording",
32846
33153
  capScope: "system",
@@ -32919,6 +33226,12 @@ Object.freeze({
32919
33226
  addonId: null,
32920
33227
  access: "view"
32921
33228
  },
33229
+ "recording.reconcileLedgerAgainstDisk": {
33230
+ capName: "recording",
33231
+ capScope: "system",
33232
+ addonId: null,
33233
+ access: "create"
33234
+ },
32922
33235
  "recording.refreshStorageLocationsForMigration": {
32923
33236
  capName: "recording",
32924
33237
  capScope: "system",
@@ -32961,6 +33274,12 @@ Object.freeze({
32961
33274
  addonId: null,
32962
33275
  access: "create"
32963
33276
  },
33277
+ "recording.setDevicePlacement": {
33278
+ capName: "recording",
33279
+ capScope: "system",
33280
+ addonId: null,
33281
+ access: "create"
33282
+ },
32964
33283
  "recording.startStorageMigrationMove": {
32965
33284
  capName: "recording",
32966
33285
  capScope: "system",
@@ -33045,6 +33364,12 @@ Object.freeze({
33045
33364
  addonId: null,
33046
33365
  access: "view"
33047
33366
  },
33367
+ "sceneMonitor.listScenesBatch": {
33368
+ capName: "scene-monitor",
33369
+ capScope: "device",
33370
+ addonId: null,
33371
+ access: "view"
33372
+ },
33048
33373
  "sceneMonitor.recheckNow": {
33049
33374
  capName: "scene-monitor",
33050
33375
  capScope: "device",
@@ -33399,12 +33724,36 @@ Object.freeze({
33399
33724
  addonId: null,
33400
33725
  access: "create"
33401
33726
  },
33727
+ "storageMigration.cleanupCancel": {
33728
+ capName: "storage-migration",
33729
+ capScope: "system",
33730
+ addonId: null,
33731
+ access: "create"
33732
+ },
33733
+ "storageMigration.cleanupStart": {
33734
+ capName: "storage-migration",
33735
+ capScope: "system",
33736
+ addonId: null,
33737
+ access: "create"
33738
+ },
33739
+ "storageMigration.cleanupStatus": {
33740
+ capName: "storage-migration",
33741
+ capScope: "system",
33742
+ addonId: null,
33743
+ access: "view"
33744
+ },
33402
33745
  "storageMigration.drain": {
33403
33746
  capName: "storage-migration",
33404
33747
  capScope: "system",
33405
33748
  addonId: null,
33406
33749
  access: "create"
33407
33750
  },
33751
+ "storageMigration.history": {
33752
+ capName: "storage-migration",
33753
+ capScope: "system",
33754
+ addonId: null,
33755
+ access: "view"
33756
+ },
33408
33757
  "storageMigration.movers": {
33409
33758
  capName: "storage-migration",
33410
33759
  capScope: "system",
@@ -34401,6 +34750,12 @@ Object.freeze({
34401
34750
  addonId: null,
34402
34751
  access: "view"
34403
34752
  },
34753
+ "zoneAnalytics.getCurrentSnapshotBatch": {
34754
+ capName: "zone-analytics",
34755
+ capScope: "device",
34756
+ addonId: null,
34757
+ access: "view"
34758
+ },
34404
34759
  "zoneAnalytics.getUnzonedHistory": {
34405
34760
  capName: "zone-analytics",
34406
34761
  capScope: "device",
@@ -35395,14 +35750,14 @@ Object.freeze({
35395
35750
  form: "single",
35396
35751
  optional: true
35397
35752
  }],
35398
- "pipelineAnalytics.getGroup": [{
35753
+ "pipelineAnalytics.getKeyEvents": [{
35399
35754
  name: "deviceId",
35400
35755
  form: "single",
35401
35756
  optional: false
35402
35757
  }],
35403
- "pipelineAnalytics.getKeyEvents": [{
35404
- name: "deviceId",
35405
- form: "single",
35758
+ "pipelineAnalytics.getKeyEventsBatch": [{
35759
+ name: "deviceIds",
35760
+ form: "array",
35406
35761
  optional: false
35407
35762
  }],
35408
35763
  "pipelineAnalytics.getMotionEvents": [{
@@ -35460,11 +35815,6 @@ Object.freeze({
35460
35815
  form: "single",
35461
35816
  optional: false
35462
35817
  }],
35463
- "pipelineAnalytics.listGroups": [{
35464
- name: "deviceIds",
35465
- form: "array",
35466
- optional: false
35467
- }],
35468
35818
  "pipelineAnalytics.listOpsLog": [{
35469
35819
  name: "deviceId",
35470
35820
  form: "single",
@@ -35510,6 +35860,11 @@ Object.freeze({
35510
35860
  form: "single",
35511
35861
  optional: true
35512
35862
  }],
35863
+ "pipelineAnalytics.reclaimDebugMedia": [{
35864
+ name: "deviceIds",
35865
+ form: "array",
35866
+ optional: true
35867
+ }],
35513
35868
  "pipelineAnalytics.reconcileFromDisk": [{
35514
35869
  name: "deviceId",
35515
35870
  form: "single",
@@ -35845,6 +36200,11 @@ Object.freeze({
35845
36200
  form: "single",
35846
36201
  optional: false
35847
36202
  }],
36203
+ "recording.reconcileLedgerAgainstDisk": [{
36204
+ name: "deviceId",
36205
+ form: "single",
36206
+ optional: true
36207
+ }],
35848
36208
  "recording.relocateFootage": [{
35849
36209
  name: "deviceId",
35850
36210
  form: "single",
@@ -35870,6 +36230,11 @@ Object.freeze({
35870
36230
  form: "single",
35871
36231
  optional: false
35872
36232
  }],
36233
+ "recording.setDevicePlacement": [{
36234
+ name: "deviceId",
36235
+ form: "single",
36236
+ optional: false
36237
+ }],
35873
36238
  "recording.startStorageMigrationMove": [{
35874
36239
  name: "deviceId",
35875
36240
  form: "single",
@@ -35910,6 +36275,11 @@ Object.freeze({
35910
36275
  form: "single",
35911
36276
  optional: false
35912
36277
  }],
36278
+ "sceneMonitor.listScenesBatch": [{
36279
+ name: "deviceIds",
36280
+ form: "array",
36281
+ optional: false
36282
+ }],
35913
36283
  "sceneMonitor.recheckNow": [{
35914
36284
  name: "deviceId",
35915
36285
  form: "single",
@@ -36171,6 +36541,11 @@ Object.freeze({
36171
36541
  form: "single",
36172
36542
  optional: false
36173
36543
  }],
36544
+ "zoneAnalytics.getCurrentSnapshotBatch": [{
36545
+ name: "deviceIds",
36546
+ form: "array",
36547
+ optional: false
36548
+ }],
36174
36549
  "zoneAnalytics.getUnzonedHistory": [{
36175
36550
  name: "deviceId",
36176
36551
  form: "single",