@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.
@@ -8042,6 +8042,20 @@ var RelocateJobSchema = object({
8042
8042
  * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8043
8043
  */
8044
8044
  rowsReconciled: number().int().nonnegative().optional(),
8045
+ /**
8046
+ * Rows this run FORGOT because the file they name is not on disk.
8047
+ *
8048
+ * The mover derived the path from the row's own fields and `stat`ed it; an
8049
+ * ENOENT there is a per-path confirmation that the segment is gone (D296),
8050
+ * and the durable row is dropped through the same channel eviction uses. It
8051
+ * is reported for the same reason `rowsReconciled` is: this is a durable
8052
+ * mutation nobody asked for, and a migration that quietly erases hour rows is
8053
+ * the same failure as one that quietly skips them (D295).
8054
+ *
8055
+ * The production drain of 2026-08-30 would have reported 11 074 here — the
8056
+ * ledger claimed 5.65 GB of footage that no longer existed.
8057
+ */
8058
+ rowsForgotten: number().int().nonnegative().optional(),
8045
8059
  startedAt: number(),
8046
8060
  finishedAt: number().nullable(),
8047
8061
  error: string().nullable()
@@ -8106,6 +8120,13 @@ var MediaRelocateModeSchema = _enum([
8106
8120
  ]);
8107
8121
  var RelocateMediaInputSchema = object({
8108
8122
  toLocationId: string(),
8123
+ /**
8124
+ * Restrict the pass to rows currently on this location. Omitted / `'*'` =
8125
+ * every row that is not already on `toLocationId` (the historical
8126
+ * behaviour). A named source is what a from→to migration needs: without it
8127
+ * "move events off disk 2" also emptied disk 1.
8128
+ */
8129
+ fromLocationId: string().optional(),
8109
8130
  throttleMbps: number().min(1).max(1e3).optional(),
8110
8131
  /** Omitted = `move`, the pre-existing behaviour. */
8111
8132
  mode: MediaRelocateModeSchema.optional()
@@ -8173,6 +8194,19 @@ var StorageMigrationDestinationsSchema = object({
8173
8194
  galleryMedia: string().min(1).optional()
8174
8195
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8175
8196
  /**
8197
+ * Optional named source per class. Omitted = the class's current default
8198
+ * (the historical behaviour). A named source that is NOT the default is a
8199
+ * drain of that disk: bytes move, the default stays, and the source is
8200
+ * disabled when the move finishes.
8201
+ */
8202
+ var StorageMigrationSourcesSchema = object({
8203
+ recordings: string().min(1).optional(),
8204
+ recordingsLow: string().min(1).optional(),
8205
+ eventMedia: string().min(1).optional(),
8206
+ backups: string().min(1).optional(),
8207
+ galleryMedia: string().min(1).optional()
8208
+ }).optional();
8209
+ /**
8176
8210
  * How a migration sequences the cutover against the byte move.
8177
8211
  *
8178
8212
  * - `blocking` — the historical order: pause, move every byte, repoint,
@@ -8194,6 +8228,8 @@ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8194
8228
  /** Shared input for planning and starting an orchestrated storage migration. */
8195
8229
  var StorageMigrationInputSchema = object({
8196
8230
  destinations: StorageMigrationDestinationsSchema,
8231
+ /** Omitted = each class's current default. */
8232
+ sources: StorageMigrationSourcesSchema,
8197
8233
  throttleMbps: number().min(1).max(1e3).optional(),
8198
8234
  /** Omitted = `blocking`, which stays the default. */
8199
8235
  mode: StorageMigrationModeSchema.optional()
@@ -8273,6 +8309,13 @@ var StorageMigrationMoveSchema = object({
8273
8309
  storageClass: StorageMigrationClassSchema,
8274
8310
  fromLocationId: string(),
8275
8311
  toLocationId: string(),
8312
+ /**
8313
+ * True when `from` was NOT the class default at plan time. The move still
8314
+ * copies bytes, but the default is left alone and the source is disabled
8315
+ * once the copy verifies. Absent on jobs planned before this field existed
8316
+ * — those jobs always repointed, which is `false`.
8317
+ */
8318
+ freezeSource: boolean().optional(),
8276
8319
  moverJobId: string().nullable(),
8277
8320
  state: RelocateJobStateSchema.nullable(),
8278
8321
  error: string().nullable(),
@@ -8286,6 +8329,7 @@ var StorageMigrationJobSchema = object({
8286
8329
  * can tell a seconds-long cutover from a thirty-hour one. */
8287
8330
  mode: StorageMigrationModeSchema,
8288
8331
  destinations: StorageMigrationDestinationsSchema,
8332
+ sources: StorageMigrationSourcesSchema,
8289
8333
  throttleMbps: number(),
8290
8334
  moves: array(StorageMigrationMoveSchema),
8291
8335
  pauseLeaseId: string().nullable(),
@@ -8311,6 +8355,7 @@ var StorageMigrationFindingSchema = object({
8311
8355
  });
8312
8356
  var StorageMigrationPlanSchema = object({
8313
8357
  destinations: StorageMigrationDestinationsSchema,
8358
+ sources: StorageMigrationSourcesSchema,
8314
8359
  /** The mode this plan was built for. A plan is only valid for its mode: the
8315
8360
  * `eventMedia` seal gate and the single-cardinality refusal both depend on
8316
8361
  * it. */
@@ -8318,7 +8363,8 @@ var StorageMigrationPlanSchema = object({
8318
8363
  moves: array(object({
8319
8364
  storageClass: StorageMigrationClassSchema,
8320
8365
  fromLocationId: string(),
8321
- toLocationId: string()
8366
+ toLocationId: string(),
8367
+ freezeSource: boolean().optional()
8322
8368
  })),
8323
8369
  findings: array(StorageMigrationFindingSchema)
8324
8370
  });
@@ -8405,16 +8451,142 @@ var RelocateResidueSchema = object({
8405
8451
  segments: number().int().nonnegative(),
8406
8452
  bytes: number().int().nonnegative()
8407
8453
  }).nullable();
8454
+ /**
8455
+ * Ask one location whether its durable hour rows describe the disk — the walk
8456
+ * (D319).
8457
+ *
8458
+ * `apply` DEFAULTS TO FALSE and that default is the product: the operator's
8459
+ * missing tool is the question, and the dry run is how they sanity-check the
8460
+ * destructive run before authorising it.
8461
+ */
8462
+ var LedgerWalkInputSchema = object({
8463
+ locationId: string().min(1),
8464
+ /** Forget the confirmed-absent rows, rather than only counting them. */
8465
+ apply: boolean().optional(),
8466
+ /** Narrow to one camera. */
8467
+ deviceId: number().int().positive().optional(),
8468
+ /** Narrow to these recording profiles; empty/absent = every profile. */
8469
+ profiles: array(string().min(1)).optional()
8470
+ });
8471
+ /** Why a whole walk did nothing. Every one leaves the ledger untouched. */
8472
+ var LedgerWalkRefusalSchema = _enum([
8473
+ "location-unknown",
8474
+ "source-writable",
8475
+ "no-ledger",
8476
+ "archive-unreadable",
8477
+ "anchor-absent",
8478
+ "anchor-unreadable",
8479
+ "anchor-moved"
8480
+ ]);
8481
+ _enum([
8482
+ "live-tail",
8483
+ "listing-error",
8484
+ "path-mismatch",
8485
+ "durable-refused"
8486
+ ]);
8487
+ /** Every skip reason, always present, always a number — so a reason that never
8488
+ * fired reports as zero rather than absent and the report shape is constant
8489
+ * between passes. Spelled out rather than `z.record` for exactly that. */
8490
+ var LedgerWalkSkipCountsSchema = object({
8491
+ "live-tail": number().int().nonnegative(),
8492
+ "listing-error": number().int().nonnegative(),
8493
+ "path-mismatch": number().int().nonnegative(),
8494
+ "durable-refused": number().int().nonnegative()
8495
+ });
8496
+ /** One camera's share of a walk, so a report names cameras and not rows. */
8497
+ var LedgerWalkDeviceReportSchema = object({
8498
+ deviceId: number().int(),
8499
+ hoursWalked: number().int().nonnegative(),
8500
+ hoursMissing: number().int().nonnegative(),
8501
+ ghostSegments: number().int().nonnegative(),
8502
+ ghostBytes: number().int().nonnegative(),
8503
+ forgottenSegments: number().int().nonnegative(),
8504
+ orphanFiles: number().int().nonnegative()
8505
+ });
8506
+ /**
8507
+ * What one walk claimed, listed, found and (only when armed) forgot.
8508
+ *
8509
+ * `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
8510
+ * walk that saw a fraction of the location is visible in its own report rather
8511
+ * than in the absence of one.
8512
+ */
8513
+ var LedgerWalkReportSchema = object({
8514
+ locationId: string(),
8515
+ applied: boolean(),
8516
+ refused: LedgerWalkRefusalSchema.nullable(),
8517
+ archiveSegments: number().int().nonnegative().nullable(),
8518
+ archiveBytes: number().int().nonnegative().nullable(),
8519
+ hoursClaimed: number().int().nonnegative(),
8520
+ hoursWalked: number().int().nonnegative(),
8521
+ hoursMissing: number().int().nonnegative(),
8522
+ /** `readdir` calls issued — the cost, stated in the unit that is paid. */
8523
+ listings: number().int().nonnegative(),
8524
+ segmentsClaimed: number().int().nonnegative(),
8525
+ ghostSegments: number().int().nonnegative(),
8526
+ ghostBytes: number().int().nonnegative(),
8527
+ ghostHoursWhole: number().int().nonnegative(),
8528
+ forgottenSegments: number().int().nonnegative(),
8529
+ forgottenBytes: number().int().nonnegative(),
8530
+ /** Files under a claimed hour that no durable row names. Never deleted. */
8531
+ orphanFiles: number().int().nonnegative(),
8532
+ orphanSample: array(string()).readonly(),
8533
+ hoursSkipped: number().int().nonnegative(),
8534
+ skippedByReason: LedgerWalkSkipCountsSchema,
8535
+ /** The walk stopped at its per-pass hour bound with claims unwalked. */
8536
+ bounded: boolean(),
8537
+ byDevice: array(LedgerWalkDeviceReportSchema).readonly()
8538
+ });
8408
8539
  /** How many rows a media pass would still act on against a given target — the
8409
8540
  * media lane's denominator AND its residue, from ONE derivation so the two can
8410
8541
  * never disagree. `null` = the count could not be taken. */
8411
8542
  var RelocatableMediaCountSchema = object({ rows: number().int().nonnegative() }).nullable();
8412
8543
  var RelocatableMediaCountInputSchema = object({
8413
8544
  toLocationId: string().min(1),
8545
+ /** Restrict the count to one source; omitted / `'*'` = every non-target row. */
8546
+ fromLocationId: string().optional(),
8414
8547
  /** Omitted = `move`. */
8415
8548
  mode: MediaRelocateModeSchema.optional()
8416
8549
  });
8417
8550
  /**
8551
+ * Operator cleanup of leftover analytics rows, optional debug media, and
8552
+ * ghost ledger entries on frozen footage locations.
8553
+ *
8554
+ * A pass is tens of minutes on a standing backlog. The hub method RETURNS
8555
+ * `{ jobId }` immediately; progress is `cleanupStatus`. Awaiting the work
8556
+ * is how `addons.custom` hit the 60 s UDS deadline while reclaim continued
8557
+ * with no operator-visible status.
8558
+ */
8559
+ var StorageCleanupPhaseSchema = _enum([
8560
+ "orphans",
8561
+ "debug-media",
8562
+ "ghost-ledger",
8563
+ "done",
8564
+ "failed",
8565
+ "cancelled"
8566
+ ]);
8567
+ var StorageCleanupInputSchema = object({
8568
+ /** Also walk motion stills / track filmstrips. Off by default. */
8569
+ includeDebugMedia: boolean().optional() });
8570
+ var StorageCleanupJobSchema = object({
8571
+ jobId: string(),
8572
+ phase: StorageCleanupPhaseSchema,
8573
+ includeDebugMedia: boolean(),
8574
+ orphansReclaimed: number().int().nonnegative(),
8575
+ orphanBytesReclaimed: number().int().nonnegative(),
8576
+ debugMediaReclaimed: number().int().nonnegative(),
8577
+ debugMediaBytesReclaimed: number().int().nonnegative(),
8578
+ ghostsForgotten: number().int().nonnegative(),
8579
+ ghostBytesForgotten: number().int().nonnegative(),
8580
+ /** Short operator-facing line: current collection, pass, or location. */
8581
+ detail: string().nullable(),
8582
+ cancelRequested: boolean(),
8583
+ startedAt: number(),
8584
+ updatedAt: number(),
8585
+ finishedAt: number().nullable(),
8586
+ error: string().nullable()
8587
+ });
8588
+ var StorageCleanupStatusInputSchema = object({ jobId: string().optional() });
8589
+ /**
8418
8590
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
8419
8591
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
8420
8592
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -8442,11 +8614,10 @@ var StorageLocationTypeSchema = string().regex(/^[a-z][a-zA-Z0-9-]*$/);
8442
8614
  * The default location for a type uses `id === <type>:default` by
8443
8615
  * convention (the bare type ref like `'backups'` resolves to it).
8444
8616
  *
8445
- * `isSystem: true` marks a location as orchestrator-seeded and
8446
- * undeletable. The bootstrap-installed defaults (one per type) carry
8447
- * this flag; operator-added locations don't. Editing the config of
8448
- * a system location is allowed (path migration, provider swap) but
8449
- * deleting it is rejected at the cap level.
8617
+ * `isSystem` is a legacy persisted flag. Seed still creates the initial
8618
+ * `<type>:default` locations; the flag is no longer a lock, a badge, or a
8619
+ * prune selector. New writes leave it false. Deletion is gated on uniqueness
8620
+ * / last-enabled, not on this bit.
8450
8621
  */
8451
8622
  var StorageLocationSchema = object({
8452
8623
  id: string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
@@ -12757,6 +12928,12 @@ method(object({
12757
12928
  }), _void(), {
12758
12929
  kind: "mutation",
12759
12930
  auth: "admin"
12931
+ }), method(object({
12932
+ from: string(),
12933
+ to: string()
12934
+ }), object({ moved: number() }), {
12935
+ kind: "mutation",
12936
+ auth: "admin"
12760
12937
  }), method(object({
12761
12938
  deviceId: number(),
12762
12939
  disabled: boolean()
@@ -18706,53 +18883,15 @@ var RecentTracksPageSchema = object({
18706
18883
  /** Cursor for the next page, or null when this page is the last. */
18707
18884
  nextCursor: string().nullable()
18708
18885
  });
18709
- var LIST_GROUPS_DEFAULT_LIMIT = 40;
18710
- var LIST_GROUPS_MAX_LIMIT = 100;
18711
- var AnalyticsGroupRecordSchema = object({
18712
- id: string(),
18713
- deviceId: number().int(),
18714
- openedAt: number().int(),
18715
- closedAt: number().int(),
18716
- timestamp: number().int(),
18717
- memberCount: number().int(),
18718
- memberTrackIds: array(string()).readonly(),
18719
- className: string(),
18720
- classes: array(string()).readonly(),
18721
- /** Relative event-media path, or null when the group has no picture yet. */
18722
- mediaUrl: string().nullable(),
18723
- singleton: boolean()
18724
- });
18725
- var AnalyticsGroupMemberSchema = object({
18726
- trackId: string(),
18727
- deviceId: number().int(),
18728
- className: string(),
18729
- firstSeen: number().int(),
18730
- lastSeen: number().int(),
18731
- mediaUrl: string().nullable()
18732
- });
18733
- var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
18734
- var ListGroupsQueryInput = object({
18735
- /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
18736
- deviceIds: array(number()),
18737
- /** Window lower bound on `closedAt` (inclusive). */
18738
- since: number().optional(),
18739
- /** Window upper bound on `openedAt` (inclusive). */
18740
- until: number().optional(),
18741
- limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
18742
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
18743
- cursor: string().optional()
18744
- });
18745
- var ListGroupsPageSchema = object({
18746
- groups: array(AnalyticsGroupRecordSchema).readonly(),
18747
- nextCursor: string().nullable()
18748
- });
18886
+ var KEY_EVENTS_DEFAULT_LIMIT = 50;
18887
+ var KEY_EVENTS_MAX_LIMIT = 200;
18749
18888
  var KeyEventQueryInput = object({
18750
18889
  deviceId: number(),
18751
18890
  /** Window lower bound (track firstSeen ≥ since). */
18752
18891
  since: number(),
18753
18892
  /** Window upper bound (track firstSeen ≤ until). */
18754
18893
  until: number(),
18755
- limit: number().int().min(1).max(200).default(50),
18894
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18756
18895
  /** Drop tracks scoring below this importance. */
18757
18896
  minImportance: number().min(0).max(1).optional(),
18758
18897
  /** Restrict to a single class (e.g. 'person'). */
@@ -18774,6 +18913,32 @@ var KeyEventSchema = object({
18774
18913
  ...TrackFlagFields,
18775
18914
  ...TrackRetrainFields
18776
18915
  });
18916
+ /** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
18917
+ var KeyEventBatchQueryInput = object({
18918
+ deviceIds: array(number()).min(1).max(200),
18919
+ since: number(),
18920
+ until: number(),
18921
+ /** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
18922
+ * across the set, which would let a busy camera starve a quiet one of its
18923
+ * rows and change what the merged feed contains. */
18924
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18925
+ minImportance: number().min(0).max(1).optional(),
18926
+ classFilter: string().optional()
18927
+ });
18928
+ /**
18929
+ * One camera's key events in a batch answer.
18930
+ *
18931
+ * The row exists for every requested id. `getKeyEvents` degrades to `[]` on
18932
+ * error rather than throwing, so a camera whose store read failed and one with
18933
+ * no events in the window were ALREADY indistinguishable per camera — the
18934
+ * batch does not make that worse, and the row keeps the deviceId the single
18935
+ * method's output never carried (the caller used to stamp it from the fan-out
18936
+ * key, which only worked because there was one query per camera).
18937
+ */
18938
+ var KeyEventsForDeviceSchema = object({
18939
+ deviceId: number(),
18940
+ events: array(KeyEventSchema).readonly()
18941
+ });
18777
18942
  object({
18778
18943
  trackId: string(),
18779
18944
  className: string(),
@@ -18821,9 +18986,7 @@ var TrackCascadeCountsSchema = object({
18821
18986
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
18822
18987
  plates: number().int(),
18823
18988
  /** Per-track CLIP search vectors removed (best-effort). */
18824
- embeddings: number().int(),
18825
- /** Group membership + group rows removed with their last member (best-effort). */
18826
- groups: number().int()
18989
+ embeddings: number().int()
18827
18990
  });
18828
18991
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
18829
18992
  var DiskReconcileCountsSchema = object({
@@ -18993,6 +19156,47 @@ var RebuildStatusSchema = object({
18993
19156
  /** Present when the pass ended by throwing. */
18994
19157
  error: string().nullable()
18995
19158
  });
19159
+ /**
19160
+ * Acknowledgement that a debug-media reclaim STARTED.
19161
+ *
19162
+ * The pass is paced at ~2 MB/s over a standing 100 GB — tens of minutes — so
19163
+ * it runs detached and this returns immediately. Awaiting it is how the
19164
+ * `addons.custom` door hit the 60 s UDS deadline while the walk carried on
19165
+ * with no status. Poll {@link pipelineAnalyticsCapability.methods.getMediaReclaimStatus}.
19166
+ */
19167
+ var MediaReclaimStartResultSchema = object({
19168
+ started: boolean(),
19169
+ /** True when a pass was already running; the new request is ignored. */
19170
+ alreadyRunning: boolean()
19171
+ });
19172
+ var MediaReclaimInputSchema = object({
19173
+ mode: _enum(["report", "reclaim"]).default("report"),
19174
+ scopes: array(_enum(["motion-still", "track-filmstrip"])).min(1).optional(),
19175
+ deviceIds: array(number().int()).min(1).optional(),
19176
+ restart: boolean().optional(),
19177
+ pageSize: number().int().min(50).max(5e3).optional(),
19178
+ maxRowsPerDevice: number().int().min(1).max(5e5).optional(),
19179
+ maxReclaimPerDevice: number().int().min(1).max(5e5).optional(),
19180
+ maxBytesPerRun: number().int().min(1).optional(),
19181
+ budgetMinutes: number().int().min(1).max(720).optional(),
19182
+ throttleBytesPerSec: number().int().min(64 * 1024).optional(),
19183
+ graceMinutes: number().int().min(1).max(10080).optional()
19184
+ });
19185
+ var MediaReclaimStatusSchema = object({
19186
+ running: boolean(),
19187
+ mode: _enum(["report", "reclaim"]).nullable(),
19188
+ totalExamined: number(),
19189
+ totalEligible: number(),
19190
+ totalReclaimed: number(),
19191
+ totalBytesReclaimed: number(),
19192
+ totalRefused: number(),
19193
+ /** Device+scope windows finished in this pass. */
19194
+ devicesDone: number(),
19195
+ complete: boolean().nullable(),
19196
+ startedAtMs: number().nullable(),
19197
+ finishedAtMs: number().nullable(),
19198
+ error: string().nullable()
19199
+ });
18996
19200
  var ReplayFrameInputSchema = object({
18997
19201
  timestamp: number(),
18998
19202
  frame: PipelineRunResultBridge
@@ -19031,10 +19235,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19031
19235
  * stationary registry). Default false: the timeline lists passages,
19032
19236
  * not parking records (operator decision, 2026-08-15). */
19033
19237
  includeStationary: boolean().optional()
19034
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
19035
- deviceId: number(),
19036
- groupId: string().min(1)
19037
- }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
19238
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
19038
19239
  kind: "mutation",
19039
19240
  auth: "admin"
19040
19241
  }), 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({
@@ -19043,7 +19244,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19043
19244
  until: number().optional(),
19044
19245
  kinds: array(string()).optional(),
19045
19246
  limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
19046
- }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
19247
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
19047
19248
  deviceId: number(),
19048
19249
  since: number(),
19049
19250
  until: number(),
@@ -19134,6 +19335,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19134
19335
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19135
19336
  kind: "query",
19136
19337
  auth: "admin"
19338
+ }), method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
19339
+ kind: "mutation",
19340
+ auth: "admin"
19341
+ }), method(object({}), MediaReclaimStatusSchema, {
19342
+ kind: "query",
19343
+ auth: "admin"
19137
19344
  }), method(object({ deviceIds: array(number()).optional() }), TrainingExportSummarySchema, {
19138
19345
  kind: "query",
19139
19346
  auth: "admin"
@@ -21104,7 +21311,13 @@ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin"
21104
21311
  }), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({}), array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }), method(StorageMigrationDrainInputSchema, object({ jobId: string() }), {
21105
21312
  kind: "mutation",
21106
21313
  auth: "admin"
21107
- });
21314
+ }), method(StorageCleanupInputSchema, object({ jobId: string() }), {
21315
+ kind: "mutation",
21316
+ auth: "admin"
21317
+ }), method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
21318
+ kind: "mutation",
21319
+ auth: "admin"
21320
+ }), method(object({}), array(StorageMigrationJobSchema).readonly(), { auth: "admin" });
21108
21321
  var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
21109
21322
  providerId: string().min(1),
21110
21323
  displayName: string().min(1),
@@ -26482,6 +26695,33 @@ var RecordingRebalanceInputSchema = object({
26482
26695
  minMoveGb: number().min(0).optional()
26483
26696
  });
26484
26697
  /**
26698
+ * Operator-facing placement of one camera onto a recordings location.
26699
+ *
26700
+ * `pinLocationId` is the operator instruction: a location id, or `null` for
26701
+ * Auto (the planner may move this camera). `locationId` is where high/mid
26702
+ * currently write — the plan, which may disagree with the pin when Auto.
26703
+ */
26704
+ var RecordingDevicePlacementSchema = object({
26705
+ deviceId: number().int(),
26706
+ profile: string(),
26707
+ locationId: string()
26708
+ });
26709
+ var RecordingDevicePinSchema = object({
26710
+ deviceId: number().int(),
26711
+ /** Recordings-class location this camera is pinned to. */
26712
+ locationId: string()
26713
+ });
26714
+ var RecordingPlacementViewSchema = object({
26715
+ assignments: array(RecordingDevicePlacementSchema),
26716
+ pins: array(RecordingDevicePinSchema),
26717
+ defaultLocations: record(string(), string())
26718
+ });
26719
+ var RecordingSetDevicePlacementInputSchema = object({
26720
+ deviceId: number().int(),
26721
+ /** `null` = Auto. Otherwise a `recordings:*` location id. */
26722
+ locationId: string().nullable()
26723
+ });
26724
+ /**
26485
26725
  * Result of locating footage at a wall-clock instant for one device/profile.
26486
26726
  * `segment` carries the covering segment's window; `gap` reports the forward
26487
26727
  * nearest covered edge (`null` past the end of footage / when none exists)
@@ -26695,6 +26935,9 @@ method(object({
26695
26935
  }), method(RelocateResidueInputSchema, RelocateResidueSchema, {
26696
26936
  kind: "query",
26697
26937
  auth: "admin"
26938
+ }), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
26939
+ kind: "mutation",
26940
+ auth: "admin"
26698
26941
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
26699
26942
  kind: "mutation",
26700
26943
  auth: "admin"
@@ -26704,6 +26947,12 @@ method(object({
26704
26947
  }), method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
26705
26948
  kind: "mutation",
26706
26949
  auth: "admin"
26950
+ }), method(object({}), RecordingPlacementViewSchema, {
26951
+ kind: "query",
26952
+ auth: "admin"
26953
+ }), method(RecordingSetDevicePlacementInputSchema, object({ ok: literal(true) }), {
26954
+ kind: "mutation",
26955
+ auth: "admin"
26707
26956
  });
26708
26957
  /**
26709
26958
  * `recording-export` cap — render a footage time range into a single downloadable
@@ -27086,7 +27335,26 @@ var SceneMonitorStatusSchema = object({
27086
27335
  monitors: array(SceneMonitorSchema),
27087
27336
  lastFetchedAt: number()
27088
27337
  });
27089
- DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({
27338
+ /**
27339
+ * One camera's row in a `listScenesBatch` answer.
27340
+ *
27341
+ * `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
27342
+ * is a `defaultActive` wrapper, so every camera is asked; a camera whose
27343
+ * provider is absent (pipeline-analytics not deployed, the post-processing node
27344
+ * down) cannot answer, and that is not the same fact as a camera with no scenes
27345
+ * configured. Fanned out per camera the difference was visible — one query
27346
+ * errored while the others resolved — and a batch that returned only the rows
27347
+ * it managed would have destroyed it, silently, by making an unreachable camera
27348
+ * indistinguishable from one that answered `monitors: []`.
27349
+ *
27350
+ * So: EVERY requested deviceId gets a row. `status: null` means "this camera
27351
+ * could not be read"; `status.monitors: []` means "read, and it has none".
27352
+ */
27353
+ var SceneMonitorStatusForDeviceSchema = object({
27354
+ deviceId: number(),
27355
+ status: SceneMonitorStatusSchema.nullable()
27356
+ });
27357
+ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
27090
27358
  deviceId: number(),
27091
27359
  label: string(),
27092
27360
  roi: MaskRectShapeSchema,
@@ -28410,6 +28678,27 @@ var CameraOccupancySnapshotSchema = object({
28410
28678
  stationaryObjects: array(StationaryObjectSchema).readonly().optional()
28411
28679
  });
28412
28680
  /**
28681
+ * One camera's row in a `getCurrentSnapshotBatch` answer.
28682
+ *
28683
+ * THREE outcomes, and the single-camera method could only express two of them
28684
+ * because `snapshot: null` was already spoken for:
28685
+ *
28686
+ * - `read: 'read'`, `snapshot` present — the live occupancy reading.
28687
+ * - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
28688
+ * yet: no frame since boot, and no parked-object registry to hydrate from.
28689
+ * - `read: 'unreadable'` — the owner could not answer for this
28690
+ * camera. `snapshot` is null, and it does NOT mean "nothing parked here".
28691
+ *
28692
+ * Collapsing the last two is the failure this field exists to prevent: a
28693
+ * hydration that threw would otherwise render as an empty Stationary section,
28694
+ * which is a definite claim about a camera nobody could read.
28695
+ */
28696
+ var CameraOccupancySnapshotForDeviceSchema = object({
28697
+ deviceId: number(),
28698
+ read: _enum(["read", "unreadable"]),
28699
+ snapshot: CameraOccupancySnapshotSchema.nullable()
28700
+ });
28701
+ /**
28413
28702
  * Time-series resolution. The history methods return one bucket per
28414
28703
  * step over the requested range. Smaller resolutions cost more
28415
28704
  * memory + bandwidth; bound to discrete steps so caller cannot ask
@@ -28433,7 +28722,7 @@ var HistoryPointSchema = object({
28433
28722
  /** Object count averaged over the bucket (rounded to nearest integer). */
28434
28723
  count: number().int().nonnegative()
28435
28724
  });
28436
- DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
28725
+ DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
28437
28726
  deviceId: number(),
28438
28727
  zoneId: string(),
28439
28728
  className: string().optional()
@@ -30034,6 +30323,12 @@ Object.freeze({
30034
30323
  addonId: null,
30035
30324
  access: "delete"
30036
30325
  },
30326
+ "deviceManager.renameLocation": {
30327
+ capName: "device-manager",
30328
+ capScope: "system",
30329
+ addonId: null,
30330
+ access: "create"
30331
+ },
30037
30332
  "deviceManager.runDeviceAction": {
30038
30333
  capName: "device-manager",
30039
30334
  capScope: "system",
@@ -31726,13 +32021,19 @@ Object.freeze({
31726
32021
  addonId: null,
31727
32022
  access: "view"
31728
32023
  },
31729
- "pipelineAnalytics.getGroup": {
32024
+ "pipelineAnalytics.getKeyEvents": {
31730
32025
  capName: "pipeline-analytics",
31731
32026
  capScope: "device",
31732
32027
  addonId: null,
31733
32028
  access: "view"
31734
32029
  },
31735
- "pipelineAnalytics.getKeyEvents": {
32030
+ "pipelineAnalytics.getKeyEventsBatch": {
32031
+ capName: "pipeline-analytics",
32032
+ capScope: "device",
32033
+ addonId: null,
32034
+ access: "view"
32035
+ },
32036
+ "pipelineAnalytics.getMediaReclaimStatus": {
31736
32037
  capName: "pipeline-analytics",
31737
32038
  capScope: "device",
31738
32039
  addonId: null,
@@ -31822,12 +32123,6 @@ Object.freeze({
31822
32123
  addonId: null,
31823
32124
  access: "view"
31824
32125
  },
31825
- "pipelineAnalytics.listGroups": {
31826
- capName: "pipeline-analytics",
31827
- capScope: "device",
31828
- addonId: null,
31829
- access: "view"
31830
- },
31831
32126
  "pipelineAnalytics.listOpsLog": {
31832
32127
  capName: "pipeline-analytics",
31833
32128
  capScope: "device",
@@ -31912,6 +32207,12 @@ Object.freeze({
31912
32207
  addonId: null,
31913
32208
  access: "create"
31914
32209
  },
32210
+ "pipelineAnalytics.reclaimDebugMedia": {
32211
+ capName: "pipeline-analytics",
32212
+ capScope: "device",
32213
+ addonId: null,
32214
+ access: "create"
32215
+ },
31915
32216
  "pipelineAnalytics.reconcileFromDisk": {
31916
32217
  capName: "pipeline-analytics",
31917
32218
  capScope: "device",
@@ -32836,6 +33137,12 @@ Object.freeze({
32836
33137
  addonId: null,
32837
33138
  access: "view"
32838
33139
  },
33140
+ "recording.getPlacement": {
33141
+ capName: "recording",
33142
+ capScope: "system",
33143
+ addonId: null,
33144
+ access: "view"
33145
+ },
32839
33146
  "recording.getPlaybackManifest": {
32840
33147
  capName: "recording",
32841
33148
  capScope: "system",
@@ -32914,6 +33221,12 @@ Object.freeze({
32914
33221
  addonId: null,
32915
33222
  access: "view"
32916
33223
  },
33224
+ "recording.reconcileLedgerAgainstDisk": {
33225
+ capName: "recording",
33226
+ capScope: "system",
33227
+ addonId: null,
33228
+ access: "create"
33229
+ },
32917
33230
  "recording.refreshStorageLocationsForMigration": {
32918
33231
  capName: "recording",
32919
33232
  capScope: "system",
@@ -32956,6 +33269,12 @@ Object.freeze({
32956
33269
  addonId: null,
32957
33270
  access: "create"
32958
33271
  },
33272
+ "recording.setDevicePlacement": {
33273
+ capName: "recording",
33274
+ capScope: "system",
33275
+ addonId: null,
33276
+ access: "create"
33277
+ },
32959
33278
  "recording.startStorageMigrationMove": {
32960
33279
  capName: "recording",
32961
33280
  capScope: "system",
@@ -33040,6 +33359,12 @@ Object.freeze({
33040
33359
  addonId: null,
33041
33360
  access: "view"
33042
33361
  },
33362
+ "sceneMonitor.listScenesBatch": {
33363
+ capName: "scene-monitor",
33364
+ capScope: "device",
33365
+ addonId: null,
33366
+ access: "view"
33367
+ },
33043
33368
  "sceneMonitor.recheckNow": {
33044
33369
  capName: "scene-monitor",
33045
33370
  capScope: "device",
@@ -33394,12 +33719,36 @@ Object.freeze({
33394
33719
  addonId: null,
33395
33720
  access: "create"
33396
33721
  },
33722
+ "storageMigration.cleanupCancel": {
33723
+ capName: "storage-migration",
33724
+ capScope: "system",
33725
+ addonId: null,
33726
+ access: "create"
33727
+ },
33728
+ "storageMigration.cleanupStart": {
33729
+ capName: "storage-migration",
33730
+ capScope: "system",
33731
+ addonId: null,
33732
+ access: "create"
33733
+ },
33734
+ "storageMigration.cleanupStatus": {
33735
+ capName: "storage-migration",
33736
+ capScope: "system",
33737
+ addonId: null,
33738
+ access: "view"
33739
+ },
33397
33740
  "storageMigration.drain": {
33398
33741
  capName: "storage-migration",
33399
33742
  capScope: "system",
33400
33743
  addonId: null,
33401
33744
  access: "create"
33402
33745
  },
33746
+ "storageMigration.history": {
33747
+ capName: "storage-migration",
33748
+ capScope: "system",
33749
+ addonId: null,
33750
+ access: "view"
33751
+ },
33403
33752
  "storageMigration.movers": {
33404
33753
  capName: "storage-migration",
33405
33754
  capScope: "system",
@@ -34396,6 +34745,12 @@ Object.freeze({
34396
34745
  addonId: null,
34397
34746
  access: "view"
34398
34747
  },
34748
+ "zoneAnalytics.getCurrentSnapshotBatch": {
34749
+ capName: "zone-analytics",
34750
+ capScope: "device",
34751
+ addonId: null,
34752
+ access: "view"
34753
+ },
34399
34754
  "zoneAnalytics.getUnzonedHistory": {
34400
34755
  capName: "zone-analytics",
34401
34756
  capScope: "device",
@@ -35390,14 +35745,14 @@ Object.freeze({
35390
35745
  form: "single",
35391
35746
  optional: true
35392
35747
  }],
35393
- "pipelineAnalytics.getGroup": [{
35748
+ "pipelineAnalytics.getKeyEvents": [{
35394
35749
  name: "deviceId",
35395
35750
  form: "single",
35396
35751
  optional: false
35397
35752
  }],
35398
- "pipelineAnalytics.getKeyEvents": [{
35399
- name: "deviceId",
35400
- form: "single",
35753
+ "pipelineAnalytics.getKeyEventsBatch": [{
35754
+ name: "deviceIds",
35755
+ form: "array",
35401
35756
  optional: false
35402
35757
  }],
35403
35758
  "pipelineAnalytics.getMotionEvents": [{
@@ -35455,11 +35810,6 @@ Object.freeze({
35455
35810
  form: "single",
35456
35811
  optional: false
35457
35812
  }],
35458
- "pipelineAnalytics.listGroups": [{
35459
- name: "deviceIds",
35460
- form: "array",
35461
- optional: false
35462
- }],
35463
35813
  "pipelineAnalytics.listOpsLog": [{
35464
35814
  name: "deviceId",
35465
35815
  form: "single",
@@ -35505,6 +35855,11 @@ Object.freeze({
35505
35855
  form: "single",
35506
35856
  optional: true
35507
35857
  }],
35858
+ "pipelineAnalytics.reclaimDebugMedia": [{
35859
+ name: "deviceIds",
35860
+ form: "array",
35861
+ optional: true
35862
+ }],
35508
35863
  "pipelineAnalytics.reconcileFromDisk": [{
35509
35864
  name: "deviceId",
35510
35865
  form: "single",
@@ -35840,6 +36195,11 @@ Object.freeze({
35840
36195
  form: "single",
35841
36196
  optional: false
35842
36197
  }],
36198
+ "recording.reconcileLedgerAgainstDisk": [{
36199
+ name: "deviceId",
36200
+ form: "single",
36201
+ optional: true
36202
+ }],
35843
36203
  "recording.relocateFootage": [{
35844
36204
  name: "deviceId",
35845
36205
  form: "single",
@@ -35865,6 +36225,11 @@ Object.freeze({
35865
36225
  form: "single",
35866
36226
  optional: false
35867
36227
  }],
36228
+ "recording.setDevicePlacement": [{
36229
+ name: "deviceId",
36230
+ form: "single",
36231
+ optional: false
36232
+ }],
35868
36233
  "recording.startStorageMigrationMove": [{
35869
36234
  name: "deviceId",
35870
36235
  form: "single",
@@ -35905,6 +36270,11 @@ Object.freeze({
35905
36270
  form: "single",
35906
36271
  optional: false
35907
36272
  }],
36273
+ "sceneMonitor.listScenesBatch": [{
36274
+ name: "deviceIds",
36275
+ form: "array",
36276
+ optional: false
36277
+ }],
35908
36278
  "sceneMonitor.recheckNow": [{
35909
36279
  name: "deviceId",
35910
36280
  form: "single",
@@ -36166,6 +36536,11 @@ Object.freeze({
36166
36536
  form: "single",
36167
36537
  optional: false
36168
36538
  }],
36539
+ "zoneAnalytics.getCurrentSnapshotBatch": [{
36540
+ name: "deviceIds",
36541
+ form: "array",
36542
+ optional: false
36543
+ }],
36169
36544
  "zoneAnalytics.getUnzonedHistory": [{
36170
36545
  name: "deviceId",
36171
36546
  form: "single",