@camstack/types 1.2.246 → 1.2.248

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.
@@ -1,108 +1,114 @@
1
1
  /**
2
- * `recording` cap — footage availability + HLS playback manifests + per-device
3
- * recording config. NOTE on events (source of truth, R5/C3): this cap carries
4
- * NO event surface — `getPlaybackManifest` returns playlist URLs only. Timeline
5
- * events (motion/object/audio) come from `pipelineAnalytics` (durable SQLite
6
- * rows) and are the ONLY event surface — the recorder has none. The in-RAM
7
- * playback markers it used to build were deleted on 2026-08-29 because nothing
8
- * ever read them. Event<->footage joins are by time, padded with the shared
9
- * `EVENT_PAD_MS` (`interfaces/recording-config.ts`).
2
+ * `recording` — a camera's recorded COVERAGE and PLAYBACK, from whichever
3
+ * source the operator picked.
4
+ *
5
+ * A device-scoped wrapper COLLECTION since D625, and the five lines that make
6
+ * it one (`scope`/`mode`/`kind`/`defaultActive`/`deviceTypes`) are copied from
7
+ * `videoclips.cap.ts` deliberately: `scope: 'device'` + `mode: 'collection'` is
8
+ * what makes `resolveCapMount` keep the PER-DEVICE mount while the collection
9
+ * dispatcher fans out, and a device's sources are then its BINDINGS
10
+ * (`deviceManager.getBindings`, D554 amended) rather than "every addon that
11
+ * registered the cap somewhere".
12
+ *
13
+ * ## What is here and what is not
14
+ *
15
+ * FIVE of them — `listSources`, `getAvailability`, `getDaysWithRecordings`,
16
+ * `getPlayback`, `getPlaybackOptions`. Every source must be able to answer
17
+ * these or it is not a source. Everything else that used to live on this cap —
18
+ * storage locations, retention, relocation, rebalance, the ops log, the
19
+ * placement table, the `mfra` byte plane, `getDeviceConfig`/`setDeviceConfig`
20
+ * and the two batch reads — is on `recording-archive`, a system singleton, and
21
+ * the reasons are argued there.
22
+ *
23
+ * ## The default is OURS, and there is nowhere to say otherwise
24
+ *
25
+ * {@link RECORDING_SOURCE_CAMSTACK} is RESERVED. The absence of an operator
26
+ * choice MEANS that value; it is not a row that happened to sort first. Clips
27
+ * end their resolver with `?? sources[0]` and that is right for clips — a
28
+ * camera full of onboard clips that says "no clips" is the defect that work
29
+ * exists to end. For a TIMELINE it is wrong and the measurement says why: on
30
+ * 592, ours covers 85 362 s of the day and the card 21 388 s, and
31
+ * `videoclips.listSources` answers the ONBOARD row first. A silent fall to the
32
+ * first row would swap a 98.8 % bar for a 24.8 % one with nothing saying so.
33
+ *
34
+ * So a surface that cannot find our row says `ours-absent` and offers the
35
+ * others as a CHOICE; it never takes one on the operator's behalf. The
36
+ * reservation is enforced in the collection dispatcher — a `listSources` row
37
+ * carrying this id from any addon but the recorder is refused by name — and by
38
+ * `scripts/check-reserved-collection-sources.ts` in CI.
39
+ *
40
+ * NOTE on events (source of truth, R5/C3): this cap carries NO event surface.
41
+ * Timeline events (motion/object/audio) come from `pipelineAnalytics` (durable
42
+ * SQLite rows) and are the ONLY event surface — the recorder has none.
43
+ * Event<->footage joins are by time, padded with the shared `EVENT_PAD_MS`
44
+ * (`interfaces/recording-config.ts`).
10
45
  */
11
46
  import { z } from 'zod';
47
+ import { DeviceType } from '../device/device-type.js';
12
48
  import { type InferProvider } from './capability-definition.js';
13
- export declare const RecordingStatusSchema: z.ZodObject<{
14
- deviceId: z.ZodNumber;
15
- enabled: z.ZodBoolean;
16
- activeMode: z.ZodEnum<{
17
- events: "events";
18
- off: "off";
19
- continuous: "continuous";
20
- "on-device-decision": "on-device-decision";
21
- }>;
22
- nodeId: z.ZodString;
23
- storageBytes: z.ZodNumber;
24
- }, z.core.$strip>;
25
- export type RecordingStatus = z.infer<typeof RecordingStatusSchema>;
49
+ /**
50
+ * OUR recorder's source id. RESERVED: no other provider may return it from
51
+ * `listSources`, and the absence of an operator choice MEANS this value.
52
+ *
53
+ * Reserved is ENFORCED, not requested — `device-collection-dispatch.ts` drops a
54
+ * row spelling it from any addon but {@link RECORDING_SOURCE_CAMSTACK_ADDON},
55
+ * naming the impostor, and `scripts/check-reserved-collection-sources.ts`
56
+ * fails CI on a provider package that spells it at all. A rule nothing checks
57
+ * has already been broken somewhere.
58
+ */
59
+ export declare const RECORDING_SOURCE_CAMSTACK = "camstack";
60
+ /** The one addon allowed to serve {@link RECORDING_SOURCE_CAMSTACK}: the
61
+ * recorder, which is the addon that writes the footage (D560). */
62
+ export declare const RECORDING_SOURCE_CAMSTACK_ADDON = "recorder";
26
63
  export declare const RecordingRangeSchema: z.ZodObject<{
27
64
  profile: z.ZodString;
28
65
  startMs: z.ZodNumber;
29
66
  endMs: z.ZodNumber;
30
67
  }, z.core.$strip>;
31
- export declare const RecordingAvailabilitySchema: z.ZodObject<{
32
- deviceId: z.ZodNumber;
33
- ranges: z.ZodArray<z.ZodObject<{
34
- profile: z.ZodString;
35
- startMs: z.ZodNumber;
36
- endMs: z.ZodNumber;
37
- }, z.core.$strip>>;
38
- profilesWithFootage: z.ZodArray<z.ZodString>;
39
- }, z.core.$strip>;
40
- export type RecordingAvailability = z.infer<typeof RecordingAvailabilitySchema>;
41
- export declare const RecordingDaysSchema: z.ZodObject<{
42
- deviceId: z.ZodNumber;
43
- days: z.ZodArray<z.ZodNumber>;
44
- }, z.core.$strip>;
45
- export type RecordingDays = z.infer<typeof RecordingDaysSchema>;
46
- /**
47
- * Most cameras one `getAvailabilityBatch` / `getDaysWithRecordingsBatch` may
48
- * name.
49
- *
50
- * Matches the ceiling the per-camera batches elsewhere in the system carry
51
- * (`pipelineAnalytics.getKeyEventsBatch`, `sceneMonitor.listScenesBatch`): a
52
- * grid is tens of cameras, never hundreds, and each id costs the recorder one
53
- * calendar walk whose answer crosses a process boundary.
54
- *
55
- * The ceiling is on the SCHEMA. An over-eager ask is REFUSED, never truncated
56
- * to the first {@link RECORDING_TIMELINE_BATCH_MAX} ids — a truncated answer
57
- * looks exactly like a complete one, and the caller would draw an empty
58
- * timeline for the cameras it never learned were dropped.
59
- */
60
- export declare const RECORDING_TIMELINE_BATCH_MAX = 200;
61
68
  /**
62
- * One camera's row in a `getAvailabilityBatch` answer.
63
- *
64
- * `ranges` is EXACTLY what `getAvailability` returns for that camera — the
65
- * batch collapses the transport, not the work — plus the one thing the singular
66
- * method never had to say:
69
+ * How a source ANSWERED, on every singular read of this cap.
67
70
  *
68
- * - `read: 'read'` — answered. `ranges: []` means "read, and this camera has
69
- * no footage in the window", which is a real claim.
70
- * - `read: 'unreadable'` — the recorder could not answer for this camera (its
71
- * calendar rung threw, its location is unmounted). `ranges` is empty and
72
- * that emptiness means NOTHING.
71
+ * `'read'` — it looked. `ranges: []` / `days: []` is then a real claim: this
72
+ * source has no coverage in the window. `'unreadable'` — nobody could look
73
+ * (the camera was unreachable, the calendar rung threw, the location is
74
+ * unmounted, the node is still on the old build), and the emptiness beside it
75
+ * means NOTHING.
73
76
  *
74
- * A timeline that renders the second as the first tells an operator there is no
75
- * footage when the truth is that nobody looked.
77
+ * The batch rows have carried this since the grid existed; the SINGULAR
78
+ * answers gained it with the collection (D625 §10.4), because they are the
79
+ * ones the single-camera picker uses and because a half-converted fleet makes
80
+ * "nobody looked" common for the length of a deploy. Without it the timeline
81
+ * has no vocabulary for it, and `(data ?? [])` in a viewer turns a rollout into
82
+ * a fleet of cameras that appear to have lost their recordings (D315, D393).
76
83
  */
77
- export declare const RecordingAvailabilityForDeviceSchema: z.ZodObject<{
84
+ export declare const RecordingReadSchema: z.ZodEnum<{
85
+ read: "read";
86
+ unreadable: "unreadable";
87
+ }>;
88
+ export type RecordingRead = z.infer<typeof RecordingReadSchema>;
89
+ export declare const RecordingAvailabilitySchema: z.ZodObject<{
78
90
  deviceId: z.ZodNumber;
79
91
  read: z.ZodEnum<{
80
92
  read: "read";
81
93
  unreadable: "unreadable";
82
94
  }>;
83
- ranges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
95
+ ranges: z.ZodArray<z.ZodObject<{
84
96
  profile: z.ZodString;
85
97
  startMs: z.ZodNumber;
86
98
  endMs: z.ZodNumber;
87
- }, z.core.$strip>>>;
88
- profilesWithFootage: z.ZodReadonly<z.ZodArray<z.ZodString>>;
99
+ }, z.core.$strip>>;
100
+ profilesWithFootage: z.ZodArray<z.ZodString>;
89
101
  }, z.core.$strip>;
90
- export type RecordingAvailabilityForDevice = z.infer<typeof RecordingAvailabilityForDeviceSchema>;
91
- /**
92
- * One camera's row in a `getDaysWithRecordingsBatch` answer. Same rule as
93
- * {@link RecordingAvailabilityForDeviceSchema}: `days: []` on a `'read'` row is
94
- * "no footage in this month", `read: 'unreadable'` is "nobody could look", and
95
- * the date-picker's day dots must not spell them the same.
96
- */
97
- export declare const RecordingDaysForDeviceSchema: z.ZodObject<{
102
+ export type RecordingAvailability = z.infer<typeof RecordingAvailabilitySchema>;
103
+ export declare const RecordingDaysSchema: z.ZodObject<{
98
104
  deviceId: z.ZodNumber;
99
105
  read: z.ZodEnum<{
100
106
  read: "read";
101
107
  unreadable: "unreadable";
102
108
  }>;
103
- days: z.ZodReadonly<z.ZodArray<z.ZodNumber>>;
109
+ days: z.ZodArray<z.ZodNumber>;
104
110
  }, z.core.$strip>;
105
- export type RecordingDaysForDevice = z.infer<typeof RecordingDaysForDeviceSchema>;
111
+ export type RecordingDays = z.infer<typeof RecordingDaysSchema>;
106
112
  export declare const RecordingManifestSchema: z.ZodObject<{
107
113
  deviceId: z.ZodNumber;
108
114
  localMasterPath: z.ZodNullable<z.ZodString>;
@@ -110,1016 +116,256 @@ export declare const RecordingManifestSchema: z.ZodObject<{
110
116
  playbackEndpoints: z.ZodArray<z.ZodString>;
111
117
  }, z.core.$strip>;
112
118
  export type RecordingManifest = z.infer<typeof RecordingManifestSchema>;
119
+ export declare const RecordingSourceAvailabilitySchema: z.ZodObject<{
120
+ state: z.ZodEnum<{
121
+ ok: "ok";
122
+ sleeping: "sleeping";
123
+ unreachable: "unreachable";
124
+ "no-storage": "no-storage";
125
+ "index-empty": "index-empty";
126
+ }>;
127
+ reason: z.ZodOptional<z.ZodString>;
128
+ coverageAsOf: z.ZodOptional<z.ZodNumber>;
129
+ }, z.core.$strip>;
130
+ export type RecordingSourceAvailability = z.infer<typeof RecordingSourceAvailabilitySchema>;
113
131
  /**
114
- * Recording storage usage for one camera — what the ARCHIVE holds for it,
115
- * across every profile and every resolvable location on this node.
132
+ * One SOURCE of recorded coverage for a camera — a row of the picker.
116
133
  *
117
- * ## Archive vs residency, which is the whole point of this shape (D418)
118
- *
119
- * `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
120
- * the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
121
- * this camera writes to, so the two can be added up and compared.
122
- *
123
- * They were not always. Until D418 this row came from the recorder's in-RAM
124
- * `RecordingIndex`, which since D287 holds only the live tail plus the hours
125
- * somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
126
- * 60.5 GB and "oldest: three hours ago" on the same page as the volume row
127
- * that said otherwise, and two people read it as retention eating recent
128
- * footage. Residency is still reported, under `residentBytes` /
129
- * `residentOldestMs`, which answer a different question and say so.
134
+ * A provider lists the sources IT serves for that device, and answers for each
135
+ * of them whether it can answer at all. A provider with nothing to offer on a
136
+ * camera returns `[]` — it is not that camera's business. The five availability
137
+ * states are `ClipSourceAvailability`'s verbatim: they mean exactly the same
138
+ * things about a coverage index as about a clip catalog, and `sleeping` in
139
+ * particular is what stops a battery camera being woken to paint a bar.
130
140
  */
131
- export declare const RecordingDeviceUsageSchema: z.ZodObject<{
132
- deviceId: z.ZodNumber;
133
- usedBytes: z.ZodNumber;
134
- oldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
135
- segments: z.ZodOptional<z.ZodNumber>;
136
- residentBytes: z.ZodOptional<z.ZodNumber>;
137
- residentOldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
138
- }, z.core.$strip>;
139
- export type RecordingDeviceUsage = z.infer<typeof RecordingDeviceUsageSchema>;
140
- /** Recording storage usage + capacity for one storage location. */
141
- export declare const RecordingLocationUsageSchema: z.ZodObject<{
142
- locationId: z.ZodNullable<z.ZodString>;
143
- locationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
144
- root: z.ZodOptional<z.ZodString>;
145
- usedBytes: z.ZodNumber;
146
- availableBytes: z.ZodNullable<z.ZodNumber>;
147
- totalBytes: z.ZodNullable<z.ZodNumber>;
148
- }, z.core.$strip>;
149
- export type RecordingLocationUsage = z.infer<typeof RecordingLocationUsageSchema>;
150
- /** Aggregate recordings storage usage for a node: global total + per-camera +
151
- * per-location used/available. Stat-based (accurate even for detached cameras),
152
- * computed on demand — not from the name-only playback index. */
153
- export declare const RecordingStorageUsageSchema: z.ZodObject<{
154
- nodeId: z.ZodString;
155
- totalUsedBytes: z.ZodNumber;
156
- devices: z.ZodArray<z.ZodObject<{
157
- deviceId: z.ZodNumber;
158
- usedBytes: z.ZodNumber;
159
- oldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
160
- segments: z.ZodOptional<z.ZodNumber>;
161
- residentBytes: z.ZodOptional<z.ZodNumber>;
162
- residentOldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
163
- }, z.core.$strip>>;
164
- devicesRead: z.ZodOptional<z.ZodEnum<{
165
- unavailable: "unavailable";
166
- archive: "archive";
167
- }>>;
168
- locations: z.ZodOptional<z.ZodArray<z.ZodObject<{
169
- locationId: z.ZodNullable<z.ZodString>;
170
- locationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
171
- root: z.ZodOptional<z.ZodString>;
172
- usedBytes: z.ZodNumber;
173
- availableBytes: z.ZodNullable<z.ZodNumber>;
174
- totalBytes: z.ZodNullable<z.ZodNumber>;
175
- }, z.core.$strip>>>;
141
+ export declare const RecordingSourceSchema: z.ZodObject<{
142
+ source: z.ZodString;
143
+ label: z.ZodString;
144
+ addonId: z.ZodOptional<z.ZodString>;
145
+ availability: z.ZodObject<{
146
+ state: z.ZodEnum<{
147
+ ok: "ok";
148
+ sleeping: "sleeping";
149
+ unreachable: "unreachable";
150
+ "no-storage": "no-storage";
151
+ "index-empty": "index-empty";
152
+ }>;
153
+ reason: z.ZodOptional<z.ZodString>;
154
+ coverageAsOf: z.ZodOptional<z.ZodNumber>;
155
+ }, z.core.$strip>;
176
156
  }, z.core.$strip>;
177
- export type RecordingStorageUsage = z.infer<typeof RecordingStorageUsageSchema>;
157
+ export type RecordingSource = z.infer<typeof RecordingSourceSchema>;
178
158
  /**
179
- * The OPERATOR-ARMED half of multi-location recordings (D116).
180
- *
181
- * The placement plan decides where NEW writes go and moves nothing. A rebalance
182
- * is the operator asking for the EXISTING archive to be brought into line with
183
- * that plan: one relocate job per (camera, profile) pile that sits on the wrong
184
- * location, run FIFO behind the single-flight mover.
159
+ * What a surface may DRAW for this (camera, source) — D612's rule applied to a
160
+ * timeline: **the source declares what it can do, and the surface draws what
161
+ * was declared. It never assumes, and never offers a gesture it will then
162
+ * refuse.** D612 exists because `8` and `16` were offered as clip rates, the
163
+ * broker clamped them to `4`, and no line anywhere said so.
185
164
  *
186
- * `plan…` and `start…` return the SAME shape deliberately — what the operator
187
- * confirms is exactly what gets enqueued, and `jobIds` is the only difference
188
- * (empty on the plan).
165
+ * Asked once per (camera, source) before anything is drawn — never replaced by
166
+ * a constant the surface keeps, which is the second authority D612 ends.
189
167
  */
190
- export declare const RecordingRebalanceMoveSchema: z.ZodObject<{
191
- deviceId: z.ZodNumber;
192
- profile: z.ZodString;
193
- fromLocationId: z.ZodString;
194
- toLocationId: z.ZodString;
195
- bytes: z.ZodNumber;
196
- files: z.ZodNumber;
197
- }, z.core.$strip>;
198
- export type RecordingRebalanceMove = z.infer<typeof RecordingRebalanceMoveSchema>;
199
- /** Why a pile that is out of place is staying there. Every refusal is
200
- * reported: a rebalance that silently drops a camera reads exactly like one
201
- * that had nothing to do. */
202
- export declare const RecordingRebalanceSkipReasonSchema: z.ZodEnum<{
203
- unassigned: "unassigned";
204
- "below-threshold": "below-threshold";
205
- "target-not-writable": "target-not-writable";
206
- "no-headroom": "no-headroom";
207
- }>;
208
- export type RecordingRebalanceSkipReason = z.infer<typeof RecordingRebalanceSkipReasonSchema>;
209
- export declare const RecordingRebalanceSkipSchema: z.ZodObject<{
210
- deviceId: z.ZodNumber;
211
- profile: z.ZodString;
212
- fromLocationId: z.ZodString;
213
- toLocationId: z.ZodNullable<z.ZodString>;
214
- bytes: z.ZodNumber;
215
- reason: z.ZodEnum<{
216
- unassigned: "unassigned";
217
- "below-threshold": "below-threshold";
218
- "target-not-writable": "target-not-writable";
219
- "no-headroom": "no-headroom";
168
+ export declare const RecordingSourceOptionsSchema: z.ZodObject<{
169
+ transport: z.ZodEnum<{
170
+ archive: "archive";
171
+ stream: "stream";
172
+ realtime: "realtime";
220
173
  }>;
174
+ coverage: z.ZodEnum<{
175
+ continuous: "continuous";
176
+ sparse: "sparse";
177
+ }>;
178
+ seek: z.ZodEnum<{
179
+ forward: "forward";
180
+ free: "free";
181
+ segment: "segment";
182
+ }>;
183
+ stepBack: z.ZodBoolean;
184
+ scrub: z.ZodBoolean;
185
+ rates: z.ZodReadonly<z.ZodArray<z.ZodNumber>>;
186
+ exclusive: z.ZodBoolean;
221
187
  }, z.core.$strip>;
222
- export type RecordingRebalanceSkip = z.infer<typeof RecordingRebalanceSkipSchema>;
223
- export declare const RecordingRebalancePlanSchema: z.ZodObject<{
224
- moves: z.ZodArray<z.ZodObject<{
225
- deviceId: z.ZodNumber;
226
- profile: z.ZodString;
227
- fromLocationId: z.ZodString;
228
- toLocationId: z.ZodString;
229
- bytes: z.ZodNumber;
230
- files: z.ZodNumber;
231
- }, z.core.$strip>>;
232
- skipped: z.ZodArray<z.ZodObject<{
233
- deviceId: z.ZodNumber;
234
- profile: z.ZodString;
235
- fromLocationId: z.ZodString;
236
- toLocationId: z.ZodNullable<z.ZodString>;
237
- bytes: z.ZodNumber;
238
- reason: z.ZodEnum<{
239
- unassigned: "unassigned";
240
- "below-threshold": "below-threshold";
241
- "target-not-writable": "target-not-writable";
242
- "no-headroom": "no-headroom";
243
- }>;
244
- }, z.core.$strip>>;
245
- bytesToMove: z.ZodNumber;
246
- jobIds: z.ZodArray<z.ZodString>;
247
- }, z.core.$strip>;
248
- export type RecordingRebalancePlan = z.infer<typeof RecordingRebalancePlanSchema>;
249
- export declare const RecordingRebalanceInputSchema: z.ZodObject<{
250
- throttleMbps: z.ZodOptional<z.ZodNumber>;
251
- minMoveGb: z.ZodOptional<z.ZodNumber>;
252
- }, z.core.$strip>;
253
- export type RecordingRebalanceInput = z.infer<typeof RecordingRebalanceInputSchema>;
188
+ export type RecordingSourceOptions = z.infer<typeof RecordingSourceOptionsSchema>;
254
189
  /**
255
- * Operator-facing placement of one camera onto a recordings location.
190
+ * How to PLAY the instant that was asked for, from the chosen source.
256
191
  *
257
- * `pinLocationId` is the operator instruction: a location id, or `null` for
258
- * Auto (the planner may move this camera). `locationId` is where high/mid
259
- * currently write — the plan, which may disagree with the pin when Auto.
192
+ * No new media transport is built for onboard sources: the `clip` arm is a
193
+ * DELEGATION to the `videoclips` transport that vendor already has (D597 /
194
+ * D616 / D617). The onboard half of this collection is a PROJECTION of
195
+ * `videoclips` for coverage and a delegation to it for bytes.
260
196
  */
261
- export declare const RecordingDevicePlacementSchema: z.ZodObject<{
262
- deviceId: z.ZodNumber;
263
- profile: z.ZodString;
264
- locationId: z.ZodString;
265
- }, z.core.$strip>;
266
- export type RecordingDevicePlacement = z.infer<typeof RecordingDevicePlacementSchema>;
267
- export declare const RecordingDevicePinSchema: z.ZodObject<{
268
- deviceId: z.ZodNumber;
269
- locationId: z.ZodString;
270
- }, z.core.$strip>;
271
- export type RecordingDevicePin = z.infer<typeof RecordingDevicePinSchema>;
272
- export declare const RecordingPlacementViewSchema: z.ZodObject<{
273
- assignments: z.ZodArray<z.ZodObject<{
274
- deviceId: z.ZodNumber;
275
- profile: z.ZodString;
276
- locationId: z.ZodString;
277
- }, z.core.$strip>>;
278
- pins: z.ZodArray<z.ZodObject<{
197
+ export declare const RecordingPlaybackSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
198
+ kind: z.ZodLiteral<"hls">;
199
+ manifest: z.ZodObject<{
279
200
  deviceId: z.ZodNumber;
280
- locationId: z.ZodString;
281
- }, z.core.$strip>>;
282
- defaultLocations: z.ZodRecord<z.ZodString, z.ZodString>;
283
- }, z.core.$strip>;
284
- export type RecordingPlacementView = z.infer<typeof RecordingPlacementViewSchema>;
285
- export declare const RecordingSetDevicePlacementInputSchema: z.ZodObject<{
286
- deviceId: z.ZodNumber;
287
- locationId: z.ZodNullable<z.ZodString>;
288
- }, z.core.$strip>;
289
- export type RecordingSetDevicePlacementInput = z.infer<typeof RecordingSetDevicePlacementInputSchema>;
290
- /**
291
- * Result of locating footage at a wall-clock instant for one device/profile.
292
- * `segment` carries the covering segment's window; `gap` reports the forward
293
- * nearest covered edge (`null` past the end of footage / when none exists)
294
- * and the backward covered edge `prevEndMs` (exclusive end of the nearest
295
- * footage behind the epoch; `null` when none — optional so older providers
296
- * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
297
- * small inter-segment cracks (durMs under-covers the span to the next
298
- * startMs by ~11-17 ms) instead of no-opping at a segment head.
299
- */
300
- export declare const LocateSegmentResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
301
- kind: z.ZodLiteral<"segment">;
302
- startMs: z.ZodNumber;
303
- durMs: z.ZodNumber;
304
- bytes: z.ZodNumber;
201
+ localMasterPath: z.ZodNullable<z.ZodString>;
202
+ playbackUrl: z.ZodNullable<z.ZodString>;
203
+ playbackEndpoints: z.ZodArray<z.ZodString>;
204
+ }, z.core.$strip>;
305
205
  }, z.core.$strip>, z.ZodObject<{
306
- kind: z.ZodLiteral<"gap">;
307
- nearestEdgeMs: z.ZodNullable<z.ZodNumber>;
308
- prevEndMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
309
- }, z.core.$strip>], "kind">;
310
- export type LocateSegmentResult = z.infer<typeof LocateSegmentResultSchema>;
311
- /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
312
- export declare const ReadSegmentBytesResultSchema: z.ZodObject<{
313
- data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
314
- }, z.core.$strip>;
315
- export type ReadSegmentBytesResult = z.infer<typeof ReadSegmentBytesResultSchema>;
316
- /**
317
- * One GOP of a finalized segment, cut by byte range through the segment's own
318
- * `mfra` (D31 on the D42 feeder path). `data` is the `ftyp`+`moov` head plus
319
- * the single `moof`+`mdat` covering the requested instant — standalone-
320
- * demuxable, never the whole file. When the segment's index cannot be parsed
321
- * the provider degrades INSIDE the mechanism to the whole segment (still one
322
- * `data`, `gopStartMs` = the segment start) — a worse read, not another path.
323
- */
324
- export declare const ReadGopBytesResultSchema: z.ZodObject<{
325
- data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
326
- gopStartMs: z.ZodNumber;
327
- gopDurMs: z.ZodNumber;
328
- }, z.core.$strip>;
329
- export type ReadGopBytesResult = z.infer<typeof ReadGopBytesResultSchema>;
330
- /**
331
- * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
332
- * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
333
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
334
- * a replay needs several seconds of native pixels, not one frame.
335
- *
336
- * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
337
- * is `false` when the returned bytes were cut short by the read's own safety
338
- * byte cap before covering `[fromMs, toMs)` — a truncation, reported, not a
339
- * silently shorter answer. `spans-multiple-segments` is a REFUSAL, not a
340
- * degradation: a window whose end falls past the covering segment would need
341
- * bytes stitched from a second segment file (its own `ftyp`+`moov`), which is
342
- * not one standalone-demuxable stream — the caller's answer is to request a
343
- * shorter window or one aligned to a single segment, not to receive spliced
344
- * bytes nothing has proven decodable.
345
- */
346
- export declare const ReadWindowBytesResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
347
- kind: z.ZodLiteral<"ok">;
348
- data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
349
- gopStartMs: z.ZodNumber;
350
- gopDurMs: z.ZodNumber;
351
- reachesRequestedEnd: z.ZodBoolean;
206
+ kind: z.ZodLiteral<"clip">;
207
+ source: z.ZodString;
208
+ clipId: z.ZodString;
209
+ startsAtMs: z.ZodNumber;
352
210
  }, z.core.$strip>, z.ZodObject<{
353
- kind: z.ZodLiteral<"spans-multiple-segments">;
354
- segmentEndMs: z.ZodNumber;
211
+ kind: z.ZodLiteral<"none">;
212
+ reason: z.ZodString;
355
213
  }, z.core.$strip>], "kind">;
356
- export type ReadWindowBytesResult = z.infer<typeof ReadWindowBytesResultSchema>;
214
+ export type RecordingPlayback = z.infer<typeof RecordingPlaybackSchema>;
357
215
  export declare const recordingCapability: {
358
216
  readonly name: "recording";
359
- readonly scope: "system";
360
- readonly mode: "singleton";
361
- readonly exposesDeviceSettings: true;
362
- readonly status: {
363
- readonly schema: z.ZodObject<{
364
- deviceId: z.ZodNumber;
365
- enabled: z.ZodBoolean;
366
- activeMode: z.ZodEnum<{
367
- events: "events";
368
- off: "off";
369
- continuous: "continuous";
370
- "on-device-decision": "on-device-decision";
371
- }>;
372
- nodeId: z.ZodString;
373
- storageBytes: z.ZodNumber;
374
- }, z.core.$strip>;
375
- readonly kind: "command-driven";
376
- };
217
+ readonly scope: "device";
218
+ /** Several sources per camera, listed beside each other. The mount stays
219
+ * `device-scoped` — see `resolveCapMount`'s ordering and D554: per-device
220
+ * wins over the global collection fan-out. */
221
+ readonly mode: "collection";
222
+ readonly kind: "wrapper";
223
+ readonly defaultActive: true;
224
+ /** Recorded coverage is a property of a camera — the cap is meaningless on a
225
+ * sensor, a button or an event emitter, and the `defaultActive` auto-bind
226
+ * reads this to decide which devices it may claim. */
227
+ readonly deviceTypes: readonly [DeviceType.Camera];
377
228
  readonly methods: {
378
- readonly getAvailability: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
379
- deviceId: z.ZodNumber;
380
- fromMs: z.ZodNumber;
381
- toMs: z.ZodNumber;
382
- profile: z.ZodOptional<z.ZodString>;
383
- }, z.core.$strip>, z.ZodObject<{
384
- deviceId: z.ZodNumber;
385
- ranges: z.ZodArray<z.ZodObject<{
386
- profile: z.ZodString;
387
- startMs: z.ZodNumber;
388
- endMs: z.ZodNumber;
389
- }, z.core.$strip>>;
390
- profilesWithFootage: z.ZodArray<z.ZodString>;
391
- }, z.core.$strip>, "query">;
392
229
  /**
393
- * `getAvailability` for a SET of cameras, in one round trip.
230
+ * The sources this camera has, WITH the reason any of them cannot answer.
394
231
  *
395
- * A multi-camera timeline re-asks availability for every camera in the grid
396
- * on every day change; fanned out that is one request per camera for N
397
- * independent calendar walks. The per-camera work is IDENTICAL (the same
398
- * `availabilityProfileFor` + `rangesIn`, run concurrently inside the
399
- * recorder) — only the transport collapses.
232
+ * Asked separately from `getAvailability` because an empty bar is
233
+ * ambiguous and this is the only place the ambiguity is resolved: every
234
+ * bound provider contributes its own rows, and a provider that could not be
235
+ * reached at all still produces one row saying so. A surface that draws "no
236
+ * recordings" without reading this is drawing a guess.
400
237
  *
401
- * `protected` for the same reason the singular method is: every id in
402
- * `deviceIds` is a device reference, so the F1 #3 gate refuses any camera
403
- * outside the caller's scope — one id out of scope refuses the CALL, it
404
- * does not quietly drop a row.
238
+ * The ONLY method here without a `provider` — it is the call that tells the
239
+ * caller what to put there.
240
+ */
241
+ readonly listSources: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
242
+ deviceId: z.ZodNumber;
243
+ }, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
244
+ source: z.ZodString;
245
+ label: z.ZodString;
246
+ addonId: z.ZodOptional<z.ZodString>;
247
+ availability: z.ZodObject<{
248
+ state: z.ZodEnum<{
249
+ ok: "ok";
250
+ sleeping: "sleeping";
251
+ unreachable: "unreachable";
252
+ "no-storage": "no-storage";
253
+ "index-empty": "index-empty";
254
+ }>;
255
+ reason: z.ZodOptional<z.ZodString>;
256
+ coverageAsOf: z.ZodOptional<z.ZodNumber>;
257
+ }, z.core.$strip>;
258
+ }, z.core.$strip>>>, "query">;
259
+ /**
260
+ * Recorded coverage of `[fromMs, toMs)` at ONE source — the timeline bar.
405
261
  *
406
- * Every requested id gets a row, marked — see
407
- * {@link RecordingAvailabilityForDeviceSchema}. `deviceIds` is capped at
408
- * {@link RECORDING_TIMELINE_BATCH_MAX} and an over-cap ask is refused.
262
+ * `protected`, not `admin`: a per-camera read is exactly what a camera
263
+ * viewer is FOR, and the device-scoped mount routes through
264
+ * `getProviderForDevice`, so a camera outside the caller's scope is refused
265
+ * before a provider is reached.
409
266
  */
410
- readonly getAvailabilityBatch: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
411
- deviceIds: z.ZodArray<z.ZodNumber>;
267
+ readonly getAvailability: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
268
+ deviceId: z.ZodNumber;
269
+ provider: z.ZodString;
412
270
  fromMs: z.ZodNumber;
413
271
  toMs: z.ZodNumber;
414
- }, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
272
+ profile: z.ZodOptional<z.ZodString>;
273
+ }, z.core.$strip>, z.ZodObject<{
415
274
  deviceId: z.ZodNumber;
416
275
  read: z.ZodEnum<{
417
276
  read: "read";
418
277
  unreadable: "unreadable";
419
278
  }>;
420
- ranges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
279
+ ranges: z.ZodArray<z.ZodObject<{
421
280
  profile: z.ZodString;
422
281
  startMs: z.ZodNumber;
423
282
  endMs: z.ZodNumber;
424
- }, z.core.$strip>>>;
425
- profilesWithFootage: z.ZodReadonly<z.ZodArray<z.ZodString>>;
426
- }, z.core.$strip>>>, "query">;
427
- /** Which calendar days in [fromMs,toMs) have ≥1 recorded segment, bucketed by
428
- * the client's local day (`tzOffsetMinutes` = minutes to add to UTC). Drives
429
- * the theater date-picker's day dots. */
283
+ }, z.core.$strip>>;
284
+ profilesWithFootage: z.ZodArray<z.ZodString>;
285
+ }, z.core.$strip>, "query">;
286
+ /** Which calendar days in [fromMs,toMs) this source has ≥1 recording in,
287
+ * bucketed by the client's local day (`tzOffsetMinutes` = minutes to add
288
+ * to UTC). Drives the theater date-picker's day dots. `provider` is
289
+ * REQUIRED for the reason `getAvailability` states. */
430
290
  readonly getDaysWithRecordings: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
431
291
  deviceId: z.ZodNumber;
292
+ provider: z.ZodString;
432
293
  fromMs: z.ZodNumber;
433
294
  toMs: z.ZodNumber;
434
295
  tzOffsetMinutes: z.ZodNumber;
435
296
  }, z.core.$strip>, z.ZodObject<{
436
- deviceId: z.ZodNumber;
437
- days: z.ZodArray<z.ZodNumber>;
438
- }, z.core.$strip>, "query">;
439
- /**
440
- * `getDaysWithRecordings` for a SET of cameras, in one round trip.
441
- *
442
- * The cheapest question in the product, asked once per camera per month
443
- * change. One directory read per day per camera at the owner, unchanged;
444
- * what collapses is the N requests it took to ask.
445
- *
446
- * Every requested id gets a row, marked — see
447
- * {@link RecordingDaysForDeviceSchema}. `deviceIds` is capped at
448
- * {@link RECORDING_TIMELINE_BATCH_MAX} and an over-cap ask is refused.
449
- */
450
- readonly getDaysWithRecordingsBatch: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
451
- deviceIds: z.ZodArray<z.ZodNumber>;
452
- fromMs: z.ZodNumber;
453
- toMs: z.ZodNumber;
454
- tzOffsetMinutes: z.ZodNumber;
455
- }, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
456
297
  deviceId: z.ZodNumber;
457
298
  read: z.ZodEnum<{
458
299
  read: "read";
459
300
  unreadable: "unreadable";
460
301
  }>;
461
- days: z.ZodReadonly<z.ZodArray<z.ZodNumber>>;
462
- }, z.core.$strip>>>, "query">;
463
- readonly getPlaybackManifest: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
464
- deviceId: z.ZodNumber;
465
- fromMs: z.ZodNumber;
466
- toMs: z.ZodNumber;
467
- }, z.core.$strip>, z.ZodObject<{
468
- deviceId: z.ZodNumber;
469
- localMasterPath: z.ZodNullable<z.ZodString>;
470
- playbackUrl: z.ZodNullable<z.ZodString>;
471
- playbackEndpoints: z.ZodArray<z.ZodString>;
472
- }, z.core.$strip>, "query">;
473
- readonly getStorageUsage: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
474
- nodeId: z.ZodString;
475
- totalUsedBytes: z.ZodNumber;
476
- devices: z.ZodArray<z.ZodObject<{
477
- deviceId: z.ZodNumber;
478
- usedBytes: z.ZodNumber;
479
- oldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
480
- segments: z.ZodOptional<z.ZodNumber>;
481
- residentBytes: z.ZodOptional<z.ZodNumber>;
482
- residentOldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
483
- }, z.core.$strip>>;
484
- devicesRead: z.ZodOptional<z.ZodEnum<{
485
- unavailable: "unavailable";
486
- archive: "archive";
487
- }>>;
488
- locations: z.ZodOptional<z.ZodArray<z.ZodObject<{
489
- locationId: z.ZodNullable<z.ZodString>;
490
- locationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
491
- root: z.ZodOptional<z.ZodString>;
492
- usedBytes: z.ZodNumber;
493
- availableBytes: z.ZodNullable<z.ZodNumber>;
494
- totalBytes: z.ZodNullable<z.ZodNumber>;
495
- }, z.core.$strip>>>;
302
+ days: z.ZodArray<z.ZodNumber>;
496
303
  }, z.core.$strip>, "query">;
497
304
  /**
498
- * READ the camera's recording intent.
305
+ * How to PLAY `[fromMs, toMs)` at this source.
499
306
  *
500
- * `protected`, not `admin`, since 2026-09-21. It is the only per-camera
501
- * source of the recording mode the viewer has, and the camera status dot
502
- * asks for it on a screen every read-only user sees. As `admin` it answered
503
- * FORBIDDEN, the viewer collapsed that to `null` and `null` to `'off'`, and
504
- * a recording camera was drawn GREEN — a failed measurement rendered as a
505
- * value (D315, D393, D590). It carries schedules and retention, no secret,
506
- * and the per-device gate in `scope-access.ts` still applies; `setDeviceConfig`
507
- * stays `admin`.
307
+ * It was `getPlaybackManifest`, and the rename is not cosmetic: a
308
+ * "manifest" is an HLS master playlist, which is a property of OUR recorder
309
+ * and of nothing else. Keeping the name would make every onboard
310
+ * implementation a lie in its signature. The old shape survives verbatim
311
+ * inside the union's `hls` arm, so the recorder's implementation is
312
+ * unchanged behind it.
508
313
  */
509
- readonly getDeviceConfig: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
314
+ readonly getPlayback: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
510
315
  deviceId: z.ZodNumber;
511
- }, z.core.$strip>, z.ZodObject<{
512
- enabled: z.ZodBoolean;
513
- mode: z.ZodOptional<z.ZodEnum<{
514
- events: "events";
515
- off: "off";
516
- continuous: "continuous";
517
- "on-device-decision": "on-device-decision";
518
- }>>;
519
- profiles: z.ZodOptional<z.ZodArray<z.ZodEnum<{
520
- high: "high";
521
- mid: "mid";
522
- low: "low";
523
- }>>>;
524
- segmentSeconds: z.ZodOptional<z.ZodNumber>;
525
- bands: z.ZodDefault<z.ZodArray<z.ZodObject<{
526
- days: z.ZodArray<z.ZodNumber>;
527
- start: z.ZodString;
528
- end: z.ZodString;
529
- mode: z.ZodEnum<{
530
- events: "events";
531
- continuous: "continuous";
532
- }>;
533
- audio: z.ZodOptional<z.ZodEnum<{
534
- muted: "muted";
535
- on: "on";
536
- }>>;
537
- triggers: z.ZodOptional<z.ZodObject<{
538
- motion: z.ZodOptional<z.ZodBoolean>;
539
- audioThresholdDbfs: z.ZodOptional<z.ZodNumber>;
540
- objectClasses: z.ZodOptional<z.ZodArray<z.ZodEnum<{
541
- person: "person";
542
- vehicle: "vehicle";
543
- animal: "animal";
544
- }>>>;
545
- sensorDeviceIds: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
546
- }, z.core.$strip>>;
547
- preBufferSec: z.ZodOptional<z.ZodNumber>;
548
- postBufferSec: z.ZodOptional<z.ZodNumber>;
549
- }, z.core.$strip>>>;
550
- deviceDecision: z.ZodOptional<z.ZodBoolean>;
551
- retention: z.ZodOptional<z.ZodObject<{
552
- maxAgeDays: z.ZodOptional<z.ZodNumber>;
553
- maxSizeGb: z.ZodOptional<z.ZodNumber>;
554
- }, z.core.$strip>>;
555
- }, z.core.$strict>, "query">;
556
- /** Locate footage at a wall-clock instant: the covering segment's window,
557
- * or a gap with the forward nearest covered edge. Used by a feeder running
558
- * in another addon process to seek recorded footage over tRPC. */
559
- readonly locateSegment: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
560
- deviceId: z.ZodNumber;
561
- profile: z.ZodString;
562
- epochMs: z.ZodNumber;
563
- }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
564
- kind: z.ZodLiteral<"segment">;
565
- startMs: z.ZodNumber;
566
- durMs: z.ZodNumber;
567
- bytes: z.ZodNumber;
568
- }, z.core.$strip>, z.ZodObject<{
569
- kind: z.ZodLiteral<"gap">;
570
- nearestEdgeMs: z.ZodNullable<z.ZodNumber>;
571
- prevEndMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
572
- }, z.core.$strip>], "kind">, "query">;
573
- /** Read one finalized segment's raw bytes by its exact `startMs`. Used by a
574
- * feeder running in another addon process to pull recorded footage over tRPC. */
575
- readonly readSegmentBytes: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
576
- deviceId: z.ZodNumber;
577
- profile: z.ZodString;
578
- startMs: z.ZodNumber;
579
- }, z.core.$strip>, z.ZodObject<{
580
- data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
581
- }, z.core.$strip>, "query">;
582
- /** Read the single GOP of segment `startMs` covering `epochMs`, by mfra
583
- * byte range — the scrub-granular read (D31 letter on the feeder path).
584
- * See {@link ReadGopBytesResultSchema} for the degradation contract. */
585
- readonly readGopBytes: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
586
- deviceId: z.ZodNumber;
587
- profile: z.ZodString;
588
- startMs: z.ZodNumber;
589
- epochMs: z.ZodNumber;
590
- }, z.core.$strip>, z.ZodObject<{
591
- data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
592
- gopStartMs: z.ZodNumber;
593
- gopDurMs: z.ZodNumber;
594
- }, z.core.$strip>, "query">;
595
- /** Read a WINDOW `[fromMs, toMs)` of segment `startMs`, by mfra byte
596
- * range — the multi-GOP twin of `readGopBytes`. Refuses (does not
597
- * degrade) when the window runs past the covering segment. Used by the
598
- * replay clip's `recording` source to fetch several seconds of native
599
- * footage for its single ffmpeg decode pass. */
600
- readonly readWindowBytes: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
601
- deviceId: z.ZodNumber;
602
- profile: z.ZodString;
603
- startMs: z.ZodNumber;
316
+ provider: z.ZodString;
604
317
  fromMs: z.ZodNumber;
605
318
  toMs: z.ZodNumber;
606
- }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
607
- kind: z.ZodLiteral<"ok">;
608
- data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
609
- gopStartMs: z.ZodNumber;
610
- gopDurMs: z.ZodNumber;
611
- reachesRequestedEnd: z.ZodBoolean;
612
- }, z.core.$strip>, z.ZodObject<{
613
- kind: z.ZodLiteral<"spans-multiple-segments">;
614
- segmentEndMs: z.ZodNumber;
615
- }, z.core.$strip>], "kind">, "query">;
616
- readonly setDeviceConfig: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
617
- deviceId: z.ZodNumber;
618
- config: z.ZodObject<{
619
- enabled: z.ZodBoolean;
620
- mode: z.ZodOptional<z.ZodEnum<{
621
- events: "events";
622
- off: "off";
623
- continuous: "continuous";
624
- "on-device-decision": "on-device-decision";
625
- }>>;
626
- profiles: z.ZodOptional<z.ZodArray<z.ZodEnum<{
627
- high: "high";
628
- mid: "mid";
629
- low: "low";
630
- }>>>;
631
- segmentSeconds: z.ZodOptional<z.ZodNumber>;
632
- bands: z.ZodDefault<z.ZodArray<z.ZodObject<{
633
- days: z.ZodArray<z.ZodNumber>;
634
- start: z.ZodString;
635
- end: z.ZodString;
636
- mode: z.ZodEnum<{
637
- events: "events";
638
- continuous: "continuous";
639
- }>;
640
- audio: z.ZodOptional<z.ZodEnum<{
641
- muted: "muted";
642
- on: "on";
643
- }>>;
644
- triggers: z.ZodOptional<z.ZodObject<{
645
- motion: z.ZodOptional<z.ZodBoolean>;
646
- audioThresholdDbfs: z.ZodOptional<z.ZodNumber>;
647
- objectClasses: z.ZodOptional<z.ZodArray<z.ZodEnum<{
648
- person: "person";
649
- vehicle: "vehicle";
650
- animal: "animal";
651
- }>>>;
652
- sensorDeviceIds: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
653
- }, z.core.$strip>>;
654
- preBufferSec: z.ZodOptional<z.ZodNumber>;
655
- postBufferSec: z.ZodOptional<z.ZodNumber>;
656
- }, z.core.$strip>>>;
657
- deviceDecision: z.ZodOptional<z.ZodBoolean>;
658
- retention: z.ZodOptional<z.ZodObject<{
659
- maxAgeDays: z.ZodOptional<z.ZodNumber>;
660
- maxSizeGb: z.ZodOptional<z.ZodNumber>;
661
- }, z.core.$strip>>;
662
- }, z.core.$strict>;
663
- }, z.core.$strip>, z.ZodObject<{
664
- enabled: z.ZodBoolean;
665
- mode: z.ZodOptional<z.ZodEnum<{
666
- events: "events";
667
- off: "off";
668
- continuous: "continuous";
669
- "on-device-decision": "on-device-decision";
670
- }>>;
671
- profiles: z.ZodOptional<z.ZodArray<z.ZodEnum<{
319
+ profile: z.ZodOptional<z.ZodEnum<{
672
320
  high: "high";
673
321
  mid: "mid";
674
322
  low: "low";
675
- }>>>;
676
- segmentSeconds: z.ZodOptional<z.ZodNumber>;
677
- bands: z.ZodDefault<z.ZodArray<z.ZodObject<{
678
- days: z.ZodArray<z.ZodNumber>;
679
- start: z.ZodString;
680
- end: z.ZodString;
681
- mode: z.ZodEnum<{
682
- events: "events";
683
- continuous: "continuous";
684
- }>;
685
- audio: z.ZodOptional<z.ZodEnum<{
686
- muted: "muted";
687
- on: "on";
688
- }>>;
689
- triggers: z.ZodOptional<z.ZodObject<{
690
- motion: z.ZodOptional<z.ZodBoolean>;
691
- audioThresholdDbfs: z.ZodOptional<z.ZodNumber>;
692
- objectClasses: z.ZodOptional<z.ZodArray<z.ZodEnum<{
693
- person: "person";
694
- vehicle: "vehicle";
695
- animal: "animal";
696
- }>>>;
697
- sensorDeviceIds: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
698
- }, z.core.$strip>>;
699
- preBufferSec: z.ZodOptional<z.ZodNumber>;
700
- postBufferSec: z.ZodOptional<z.ZodNumber>;
701
- }, z.core.$strip>>>;
702
- deviceDecision: z.ZodOptional<z.ZodBoolean>;
703
- retention: z.ZodOptional<z.ZodObject<{
704
- maxAgeDays: z.ZodOptional<z.ZodNumber>;
705
- maxSizeGb: z.ZodOptional<z.ZodNumber>;
706
- }, z.core.$strip>>;
707
- }, z.core.$strict>, "mutation">;
708
- /** Re-scan this device's footage from disk (stat sizes) and reseed the
709
- * index, then return the fresh status. */
710
- readonly rescanStorage: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
711
- deviceId: z.ZodNumber;
712
- }, z.core.$strip>, z.ZodObject<{
713
- deviceId: z.ZodNumber;
714
- enabled: z.ZodBoolean;
715
- activeMode: z.ZodEnum<{
716
- events: "events";
717
- off: "off";
718
- continuous: "continuous";
719
- "on-device-decision": "on-device-decision";
720
- }>;
721
- nodeId: z.ZodString;
722
- storageBytes: z.ZodNumber;
723
- }, z.core.$strip>, "mutation">;
724
- /** Apply this device's retention policy to footage now; returns the oldest
725
- * surviving footage start (the retention floor) or null if no footage. The
726
- * prune is logged to the recordings ops-log with `reason` (default
727
- * `'retention'` — the policy-driven prune; `'quota'` when disk-pressure
728
- * triggered). */
729
- readonly pruneFootage: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
730
- deviceId: z.ZodNumber;
731
- reason: z.ZodOptional<z.ZodEnum<{
732
- retention: "retention";
733
- quota: "quota";
734
- manual: "manual";
735
- operator: "operator";
736
- maintenance: "maintenance";
737
- "orphaned-device": "orphaned-device";
738
323
  }>>;
324
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
325
+ kind: z.ZodLiteral<"hls">;
326
+ manifest: z.ZodObject<{
327
+ deviceId: z.ZodNumber;
328
+ localMasterPath: z.ZodNullable<z.ZodString>;
329
+ playbackUrl: z.ZodNullable<z.ZodString>;
330
+ playbackEndpoints: z.ZodArray<z.ZodString>;
331
+ }, z.core.$strip>;
739
332
  }, z.core.$strip>, z.ZodObject<{
740
- floorMs: z.ZodNullable<z.ZodNumber>;
741
- deletedBuckets: z.ZodNumber;
742
- reclaimedBytes: z.ZodNumber;
743
- }, z.core.$strip>, "mutation">;
744
- /**
745
- * Manually delete a camera's footage — the whole footprint, or a
746
- * `[fromMs, toMs)` window when either bound is given. Logged to the
747
- * recordings ops-log as `op:'manual-delete', reason:'manual'`. Destructive:
748
- * the admin UI guards it behind a confirm.
749
- */
750
- readonly deleteFootprint: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
751
- deviceId: z.ZodNumber;
752
- fromMs: z.ZodOptional<z.ZodNumber>;
753
- toMs: z.ZodOptional<z.ZodNumber>;
333
+ kind: z.ZodLiteral<"clip">;
334
+ source: z.ZodString;
335
+ clipId: z.ZodString;
336
+ startsAtMs: z.ZodNumber;
754
337
  }, z.core.$strip>, z.ZodObject<{
755
- deletedBuckets: z.ZodNumber;
756
- reclaimedBytes: z.ZodNumber;
757
- }, z.core.$strip>, "mutation">;
758
- /** The recordings ops-log rows (newest-first), optionally scoped to one
759
- * camera. Backed by the recorder's bounded DurableState ring. */
760
- readonly listOpsLog: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
761
- deviceId: z.ZodOptional<z.ZodNumber>;
762
- limit: z.ZodOptional<z.ZodNumber>;
763
- }, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
764
- id: z.ZodString;
765
- at: z.ZodNumber;
766
- domain: z.ZodEnum<{
767
- recording: "recording";
768
- events: "events";
769
- }>;
770
- op: z.ZodEnum<{
771
- prune: "prune";
772
- "manual-delete": "manual-delete";
773
- rescan: "rescan";
774
- "retention-run": "retention-run";
775
- relocate: "relocate";
776
- "orphan-audit": "orphan-audit";
777
- }>;
778
- reason: z.ZodEnum<{
779
- retention: "retention";
780
- quota: "quota";
781
- manual: "manual";
782
- operator: "operator";
783
- maintenance: "maintenance";
784
- "orphaned-device": "orphaned-device";
785
- }>;
786
- deviceId: z.ZodNullable<z.ZodNumber>;
787
- nodeId: z.ZodString;
788
- itemsAffected: z.ZodNumber;
789
- bytesReclaimed: z.ZodNumber;
790
- detail: z.ZodNullable<z.ZodString>;
791
- actor: z.ZodString;
792
- }, z.core.$strip>>>, "query">;
793
- /**
794
- * Render a short GIF from recorded footage around `aroundMs` (low profile,
795
- * palette-free ffmpeg gif). Synchronous — the window is a few seconds of
796
- * `low`, rendering in ~1-2s. Built for notification attachments: the
797
- * caller gets bytes, nothing persists. Fails when no footage covers the
798
- * window (camera not recording → caller skips the attachment).
799
- */
800
- readonly renderGif: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
801
- deviceId: z.ZodNumber;
802
- aroundMs: z.ZodNumber;
803
- preRollSec: z.ZodDefault<z.ZodNumber>;
804
- postRollSec: z.ZodDefault<z.ZodNumber>;
805
- maxWidth: z.ZodDefault<z.ZodNumber>;
806
- fps: z.ZodDefault<z.ZodNumber>;
807
- }, z.core.$strip>, z.ZodObject<{
808
- gifBase64: z.ZodString;
809
- fromMs: z.ZodNumber;
810
- toMs: z.ZodNumber;
811
- }, z.core.$strip>, "mutation">;
338
+ kind: z.ZodLiteral<"none">;
339
+ reason: z.ZodString;
340
+ }, z.core.$strip>], "kind">, "query">;
812
341
  /**
813
- * Render a short MP4 clip from recorded footage around `aroundMs` — the
814
- * "send a clip, not a gif" notification attachment. Same window, source
815
- * and fail-closed contract as {@link renderGif}: no footage covering the
816
- * window ⇒ it throws and the caller ships no attachment. Re-encoded (never
817
- * stream-copied) so a concat across segments with different encoder
818
- * parameters still plays. Silent by contract.
819
- *
820
- * The returned window is SEGMENT-GRANULAR: the source playlist is built
821
- * from whole segments, so the clip starts at or before `fromMs` and ends
822
- * at or after `toMs` — overshoot bounded by one segment per side (an 8 s
823
- * ask over 4 s segments measured 12 s). `fromMs`/`toMs` report the window
824
- * ASKED for, not the encoded duration.
342
+ * What this (camera, source) can actually DO — asked before anything is
343
+ * drawn. See {@link RecordingSourceOptionsSchema}; a constant the surface
344
+ * keeps instead is the second authority D612 exists to end.
825
345
  */
826
- readonly renderClip: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
346
+ readonly getPlaybackOptions: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
827
347
  deviceId: z.ZodNumber;
828
- aroundMs: z.ZodNumber;
829
- preRollSec: z.ZodDefault<z.ZodNumber>;
830
- postRollSec: z.ZodDefault<z.ZodNumber>;
831
- maxWidth: z.ZodDefault<z.ZodNumber>;
348
+ provider: z.ZodString;
832
349
  }, z.core.$strip>, z.ZodObject<{
833
- clipBase64: z.ZodString;
834
- mime: z.ZodString;
835
- fromMs: z.ZodNumber;
836
- toMs: z.ZodNumber;
837
- bytes: z.ZodNumber;
838
- }, z.core.$strip>, "mutation">;
839
- /** Internal migration-participant lease. Blocks new recorder attaches and
840
- * waits for writers to exit while their watchers index final segments. */
841
- readonly pauseForStorageMigration: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
842
- leaseId: z.ZodString;
843
- }, z.core.$strip>, z.ZodObject<{
844
- paused: z.ZodLiteral<true>;
845
- }, z.core.$strip>, "mutation">;
846
- readonly resumeForStorageMigration: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
847
- leaseId: z.ZodString;
848
- }, z.core.$strip>, z.ZodObject<{
849
- resumed: z.ZodLiteral<true>;
850
- }, z.core.$strip>, "mutation">;
851
- /** Re-resolve location roots after the coordinator changes defaults. */
852
- readonly refreshStorageLocationsForMigration: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
853
- leaseId: z.ZodString;
854
- }, z.core.$strip>, z.ZodObject<{
855
- refreshed: z.ZodLiteral<true>;
856
- }, z.core.$strip>, "mutation">;
857
- /** Internal mover, callable only by the storage-migration coordinator. */
858
- readonly startStorageMigrationMove: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
859
- fromLocationId: z.ZodString;
860
- toLocationId: z.ZodString;
861
- entities: z.ZodOptional<z.ZodArray<z.ZodEnum<{
862
- segments: "segments";
863
- }>>>;
864
- footageClass: z.ZodOptional<z.ZodEnum<{
865
- recordings: "recordings";
866
- recordingsLow: "recordingsLow";
867
- }>>;
868
- deviceId: z.ZodOptional<z.ZodNumber>;
869
- profiles: z.ZodOptional<z.ZodArray<z.ZodString>>;
870
- throttleMbps: z.ZodOptional<z.ZodNumber>;
871
- sinceMs: z.ZodOptional<z.ZodNumber>;
872
- leaseId: z.ZodString;
873
- }, z.core.$strip>, z.ZodObject<{
874
- jobId: z.ZodString;
875
- }, z.core.$strip>, "mutation">;
876
- readonly getStorageMigrationMoveStatus: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
877
- jobId: z.ZodString;
878
- }, z.core.$strip>, z.ZodNullable<z.ZodObject<{
879
- jobId: z.ZodString;
880
- state: z.ZodEnum<{
881
- queued: "queued";
882
- running: "running";
883
- done: "done";
884
- failed: "failed";
885
- cancelled: "cancelled";
350
+ transport: z.ZodEnum<{
351
+ archive: "archive";
352
+ stream: "stream";
353
+ realtime: "realtime";
886
354
  }>;
887
- fromLocationId: z.ZodString;
888
- toLocationId: z.ZodString;
889
- deviceId: z.ZodNullable<z.ZodNumber>;
890
- entities: z.ZodArray<z.ZodString>;
891
- filesMoved: z.ZodNumber;
892
- bytesMoved: z.ZodNumber;
893
- filesTotal: z.ZodNullable<z.ZodNumber>;
894
- rowsReconciled: z.ZodOptional<z.ZodNumber>;
895
- rowsForgotten: z.ZodOptional<z.ZodNumber>;
896
- startedAt: z.ZodNumber;
897
- finishedAt: z.ZodNullable<z.ZodNumber>;
898
- error: z.ZodNullable<z.ZodString>;
899
- }, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind>;
900
- readonly cancelStorageMigrationMove: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
901
- jobId: z.ZodString;
902
- }, z.core.$strip>, z.ZodObject<{
903
- cancelled: z.ZodBoolean;
904
- }, z.core.$strip>, "mutation">;
905
- /**
906
- * Move footage between locations — the OPERATOR's mover, scoped to one
907
- * camera (and optionally to specific profiles) rather than a whole disk.
908
- * Queued FIFO behind the single-flight engine, so arming several is safe.
909
- */
910
- readonly relocateFootage: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
911
- fromLocationId: z.ZodString;
912
- toLocationId: z.ZodString;
913
- entities: z.ZodOptional<z.ZodArray<z.ZodEnum<{
914
- segments: "segments";
915
- }>>>;
916
- footageClass: z.ZodOptional<z.ZodEnum<{
917
- recordings: "recordings";
918
- recordingsLow: "recordingsLow";
919
- }>>;
920
- deviceId: z.ZodOptional<z.ZodNumber>;
921
- profiles: z.ZodOptional<z.ZodArray<z.ZodString>>;
922
- throttleMbps: z.ZodOptional<z.ZodNumber>;
923
- sinceMs: z.ZodOptional<z.ZodNumber>;
924
- }, z.core.$strip>, z.ZodObject<{
925
- jobId: z.ZodString;
926
- }, z.core.$strip>, "mutation">;
927
- /** Every relocate job this recorder knows about, newest first (in RAM: the
928
- * move is resumable, so a lost list costs nothing but the display). */
929
- readonly listRelocateJobs: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{}, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
930
- jobId: z.ZodString;
931
- state: z.ZodEnum<{
932
- queued: "queued";
933
- running: "running";
934
- done: "done";
935
- failed: "failed";
936
- cancelled: "cancelled";
355
+ coverage: z.ZodEnum<{
356
+ continuous: "continuous";
357
+ sparse: "sparse";
937
358
  }>;
938
- fromLocationId: z.ZodString;
939
- toLocationId: z.ZodString;
940
- deviceId: z.ZodNullable<z.ZodNumber>;
941
- entities: z.ZodArray<z.ZodString>;
942
- filesMoved: z.ZodNumber;
943
- bytesMoved: z.ZodNumber;
944
- filesTotal: z.ZodNullable<z.ZodNumber>;
945
- rowsReconciled: z.ZodOptional<z.ZodNumber>;
946
- rowsForgotten: z.ZodOptional<z.ZodNumber>;
947
- startedAt: z.ZodNumber;
948
- finishedAt: z.ZodNullable<z.ZodNumber>;
949
- error: z.ZodNullable<z.ZodString>;
950
- }, z.core.$strip>>>, "query">;
951
- /**
952
- * What a location STILL holds, asked of the durable hour ledger.
953
- *
954
- * The number behind "drain remaining": segments and bytes that would still
955
- * have to move off `fromLocationId`. It is a ledger aggregate — the archive
956
- * — because the resident index is not the archive (D295), and a drain sized
957
- * off the index is exactly what reported `done` over 80.3 GB on 2026-08-29.
958
- * `null` means the archive could not be asked (no ledger on this node, or
959
- * the aggregate failed) and is never conflated with an empty source.
960
- */
961
- readonly getRelocateResidue: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
962
- fromLocationId: z.ZodString;
963
- footageClass: z.ZodOptional<z.ZodEnum<{
964
- recordings: "recordings";
965
- recordingsLow: "recordingsLow";
966
- }>>;
967
- }, z.core.$strip>, z.ZodNullable<z.ZodObject<{
968
- segments: z.ZodNumber;
969
- bytes: z.ZodNumber;
970
- }, z.core.$strip>>, "query">;
971
- /**
972
- * Does this location's LEDGER tell the truth about its disk? (D319)
973
- *
974
- * One `readdir` per claimed hour, diffed both ways: durable rows whose file
975
- * is not there, and files no durable row names. `apply` defaults to FALSE —
976
- * the report is the product, and the dry run is how an operator
977
- * sanity-checks the destructive run before authorising it.
978
- *
979
- * REFUSES a source that is still a write target: a listing of a live
980
- * location is a lower bound, which is not the strong evidence that lets
981
- * this pass forget without a budget. A live location is reconciled by the
982
- * mover, under D318's bound.
983
- */
984
- readonly reconcileLedgerAgainstDisk: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
985
- locationId: z.ZodString;
986
- apply: z.ZodOptional<z.ZodBoolean>;
987
- deviceId: z.ZodOptional<z.ZodNumber>;
988
- profiles: z.ZodOptional<z.ZodArray<z.ZodString>>;
989
- }, z.core.$strip>, z.ZodObject<{
990
- locationId: z.ZodString;
991
- applied: z.ZodBoolean;
992
- refused: z.ZodNullable<z.ZodEnum<{
993
- "location-unknown": "location-unknown";
994
- "source-writable": "source-writable";
995
- "no-ledger": "no-ledger";
996
- "archive-unreadable": "archive-unreadable";
997
- "anchor-absent": "anchor-absent";
998
- "anchor-unreadable": "anchor-unreadable";
999
- "anchor-moved": "anchor-moved";
1000
- }>>;
1001
- archiveSegments: z.ZodNullable<z.ZodNumber>;
1002
- archiveBytes: z.ZodNullable<z.ZodNumber>;
1003
- hoursClaimed: z.ZodNumber;
1004
- hoursWalked: z.ZodNumber;
1005
- hoursMissing: z.ZodNumber;
1006
- listings: z.ZodNumber;
1007
- segmentsClaimed: z.ZodNumber;
1008
- ghostSegments: z.ZodNumber;
1009
- ghostBytes: z.ZodNumber;
1010
- ghostHoursWhole: z.ZodNumber;
1011
- forgottenSegments: z.ZodNumber;
1012
- forgottenBytes: z.ZodNumber;
1013
- orphanFiles: z.ZodNumber;
1014
- orphanSample: z.ZodReadonly<z.ZodArray<z.ZodString>>;
1015
- hoursSkipped: z.ZodNumber;
1016
- skippedByReason: z.ZodObject<{
1017
- 'live-tail': z.ZodNumber;
1018
- 'listing-error': z.ZodNumber;
1019
- 'path-mismatch': z.ZodNumber;
1020
- 'durable-refused': z.ZodNumber;
1021
- }, z.core.$strip>;
1022
- bounded: z.ZodBoolean;
1023
- byDevice: z.ZodReadonly<z.ZodArray<z.ZodObject<{
1024
- deviceId: z.ZodNumber;
1025
- hoursWalked: z.ZodNumber;
1026
- hoursMissing: z.ZodNumber;
1027
- ghostSegments: z.ZodNumber;
1028
- ghostBytes: z.ZodNumber;
1029
- forgottenSegments: z.ZodNumber;
1030
- orphanFiles: z.ZodNumber;
1031
- }, z.core.$strip>>>;
1032
- }, z.core.$strip>, "mutation">;
1033
- /** Cancel a running or queued relocate job. A queued job never runs. */
1034
- readonly cancelRelocateJob: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1035
- jobId: z.ZodString;
1036
- }, z.core.$strip>, z.ZodObject<{
1037
- cancelled: z.ZodBoolean;
1038
- }, z.core.$strip>, "mutation">;
1039
- /** What a rebalance WOULD move, and what it would refuse. Moves nothing. */
1040
- readonly planStorageRebalance: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1041
- throttleMbps: z.ZodOptional<z.ZodNumber>;
1042
- minMoveGb: z.ZodOptional<z.ZodNumber>;
1043
- }, z.core.$strip>, z.ZodObject<{
1044
- moves: z.ZodArray<z.ZodObject<{
1045
- deviceId: z.ZodNumber;
1046
- profile: z.ZodString;
1047
- fromLocationId: z.ZodString;
1048
- toLocationId: z.ZodString;
1049
- bytes: z.ZodNumber;
1050
- files: z.ZodNumber;
1051
- }, z.core.$strip>>;
1052
- skipped: z.ZodArray<z.ZodObject<{
1053
- deviceId: z.ZodNumber;
1054
- profile: z.ZodString;
1055
- fromLocationId: z.ZodString;
1056
- toLocationId: z.ZodNullable<z.ZodString>;
1057
- bytes: z.ZodNumber;
1058
- reason: z.ZodEnum<{
1059
- unassigned: "unassigned";
1060
- "below-threshold": "below-threshold";
1061
- "target-not-writable": "target-not-writable";
1062
- "no-headroom": "no-headroom";
1063
- }>;
1064
- }, z.core.$strip>>;
1065
- bytesToMove: z.ZodNumber;
1066
- jobIds: z.ZodArray<z.ZodString>;
1067
- }, z.core.$strip>, "query">;
1068
- /** Arm the rebalance: enqueue one relocate job per planned move. */
1069
- readonly startStorageRebalance: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1070
- throttleMbps: z.ZodOptional<z.ZodNumber>;
1071
- minMoveGb: z.ZodOptional<z.ZodNumber>;
1072
- }, z.core.$strip>, z.ZodObject<{
1073
- moves: z.ZodArray<z.ZodObject<{
1074
- deviceId: z.ZodNumber;
1075
- profile: z.ZodString;
1076
- fromLocationId: z.ZodString;
1077
- toLocationId: z.ZodString;
1078
- bytes: z.ZodNumber;
1079
- files: z.ZodNumber;
1080
- }, z.core.$strip>>;
1081
- skipped: z.ZodArray<z.ZodObject<{
1082
- deviceId: z.ZodNumber;
1083
- profile: z.ZodString;
1084
- fromLocationId: z.ZodString;
1085
- toLocationId: z.ZodNullable<z.ZodString>;
1086
- bytes: z.ZodNumber;
1087
- reason: z.ZodEnum<{
1088
- unassigned: "unassigned";
1089
- "below-threshold": "below-threshold";
1090
- "target-not-writable": "target-not-writable";
1091
- "no-headroom": "no-headroom";
1092
- }>;
1093
- }, z.core.$strip>>;
1094
- bytesToMove: z.ZodNumber;
1095
- jobIds: z.ZodArray<z.ZodString>;
1096
- }, z.core.$strip>, "mutation">;
1097
- /**
1098
- * The placement plan in force plus operator pins. Drives the Locations
1099
- * admin page: Auto vs a named recordings location, per camera.
1100
- */
1101
- readonly getPlacement: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
1102
- assignments: z.ZodArray<z.ZodObject<{
1103
- deviceId: z.ZodNumber;
1104
- profile: z.ZodString;
1105
- locationId: z.ZodString;
1106
- }, z.core.$strip>>;
1107
- pins: z.ZodArray<z.ZodObject<{
1108
- deviceId: z.ZodNumber;
1109
- locationId: z.ZodString;
1110
- }, z.core.$strip>>;
1111
- defaultLocations: z.ZodRecord<z.ZodString, z.ZodString>;
359
+ seek: z.ZodEnum<{
360
+ forward: "forward";
361
+ free: "free";
362
+ segment: "segment";
363
+ }>;
364
+ stepBack: z.ZodBoolean;
365
+ scrub: z.ZodBoolean;
366
+ rates: z.ZodReadonly<z.ZodArray<z.ZodNumber>>;
367
+ exclusive: z.ZodBoolean;
1112
368
  }, z.core.$strip>, "query">;
1113
- /**
1114
- * Pin a camera to a recordings location, or clear the pin (Auto). High and
1115
- * mid follow the pin; low stays with the recordingsLow planner.
1116
- */
1117
- readonly setDevicePlacement: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1118
- deviceId: z.ZodNumber;
1119
- locationId: z.ZodNullable<z.ZodString>;
1120
- }, z.core.$strip>, z.ZodObject<{
1121
- ok: z.ZodLiteral<true>;
1122
- }, z.core.$strip>, "mutation">;
1123
369
  };
1124
370
  };
1125
371
  export type IRecordingProvider = InferProvider<typeof recordingCapability>;