@camstack/types 1.2.245 → 1.2.247
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.
- package/dist/addon.d.ts +2 -0
- package/dist/addon.js +8 -3
- package/dist/addon.mjs +5 -4
- package/dist/capabilities/index.d.ts +22 -21
- package/dist/capabilities/recording-archive.cap.d.ts +1123 -0
- package/dist/capabilities/recording.cap.d.ts +268 -1022
- package/dist/capabilities/reserved-collection-sources.d.ts +46 -0
- package/dist/capabilities/videoclips.cap.d.ts +340 -11
- package/dist/generated/addon-api.d.ts +117 -110
- package/dist/generated/cap-status-types.d.ts +3 -3
- package/dist/generated/capability-router-map.d.ts +7 -7
- package/dist/generated/collection-array-methods.d.ts +1 -1
- package/dist/generated/device-proxy.d.ts +4 -4
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/method-device-selectors.d.ts +2 -2
- package/dist/generated/system-proxy.d.ts +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2874 -2166
- package/dist/index.mjs +2853 -2165
- package/dist/interfaces/addon-peer-bytes.d.ts +244 -0
- package/dist/interfaces/addon.d.ts +19 -0
- package/dist/interfaces/camera-switches.d.ts +2 -2
- package/dist/interfaces/capability.d.ts +0 -1
- package/dist/{sleep-Da9UCU5_.js → sleep-9gM_dS-5.js} +107 -26
- package/dist/{sleep-i3eUVc-d.mjs → sleep-PEo0-Fz9.mjs} +78 -27
- package/package.json +1 -1
- package/dist/capabilities/events.cap.d.ts +0 -47
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source ids of a device COLLECTION that exactly one addon may mint (D625).
|
|
3
|
+
*
|
|
4
|
+
* A collection cap's picker treats its rows as peers, and that is right almost
|
|
5
|
+
* everywhere. It is wrong for exactly one thing: a DEFAULT that must be
|
|
6
|
+
* impossible to express otherwise.
|
|
7
|
+
*
|
|
8
|
+
* `recording`'s default is ours, always (the operator's ruling, 2026-09-24).
|
|
9
|
+
* The way that is made structural rather than a sort order is a RESERVED id:
|
|
10
|
+
* the absence of an operator choice MEANS `camstack`, so a surface never needs
|
|
11
|
+
* a "first row" fallback and there is nowhere to put one. `clip-sources.ts`
|
|
12
|
+
* ends with `?? sources[0]`, and `videoclips.listSources` on 592 answers the
|
|
13
|
+
* ONBOARD row first — for clips that fallback was argued for, for a timeline it
|
|
14
|
+
* would silently swap an 85 362 s bar for a 21 388 s one.
|
|
15
|
+
*
|
|
16
|
+
* A reserved id is only worth anything if nothing else can spell it, so it is
|
|
17
|
+
* enforced twice and neither is a paragraph:
|
|
18
|
+
*
|
|
19
|
+
* 1. `device-collection-dispatch.ts` DROPS a `listSources` row carrying a
|
|
20
|
+
* reserved id from any addon but its owner, naming the impostor in a log
|
|
21
|
+
* line with `tags: { deviceId }`. It drops the row rather than throwing:
|
|
22
|
+
* one lying provider must not empty a camera's picker.
|
|
23
|
+
* 2. `scripts/check-reserved-collection-sources.ts` fails CI on any package
|
|
24
|
+
* but the owner's that spells the id at all. It reads THIS table, so a new
|
|
25
|
+
* reservation is guarded the moment it is added here.
|
|
26
|
+
*/
|
|
27
|
+
/** One reservation: `sourceId` on `capName` may be served only by `addonId`. */
|
|
28
|
+
export interface ReservedCollectionSource {
|
|
29
|
+
readonly capName: string;
|
|
30
|
+
readonly sourceId: string;
|
|
31
|
+
readonly addonId: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Every reserved (cap, source) pair in the system.
|
|
35
|
+
*
|
|
36
|
+
* KEEP THE LITERALS INLINE. The CI guard parses this array textually — it
|
|
37
|
+
* cannot execute TypeScript — so an entry built from an imported constant
|
|
38
|
+
* would be invisible to it, and a guard that reads the wrong surface is worse
|
|
39
|
+
* than none.
|
|
40
|
+
*/
|
|
41
|
+
export declare const RESERVED_COLLECTION_SOURCES: readonly ReservedCollectionSource[];
|
|
42
|
+
/**
|
|
43
|
+
* The addon allowed to serve `sourceId` on `capName`, or `null` when the id is
|
|
44
|
+
* not reserved at all (which is the common case — most sources are peers).
|
|
45
|
+
*/
|
|
46
|
+
export declare function reservedSourceOwner(capName: string, sourceId: string): string | null;
|
|
@@ -67,6 +67,7 @@ export declare const ClipStillRefusalCodeSchema: z.ZodEnum<{
|
|
|
67
67
|
"no-keyframe": "no-keyframe";
|
|
68
68
|
"queue-full": "queue-full";
|
|
69
69
|
"camera-backoff": "camera-backoff";
|
|
70
|
+
"decode-failed": "decode-failed";
|
|
70
71
|
"no-catalog-row": "no-catalog-row";
|
|
71
72
|
"unknown-device": "unknown-device";
|
|
72
73
|
"uid-missing": "uid-missing";
|
|
@@ -249,11 +250,36 @@ export type ClipWake = z.infer<typeof ClipWakeSchema>;
|
|
|
249
250
|
* the size in the message, never truncates. Half a video is worse than an
|
|
250
251
|
* honest refusal.
|
|
251
252
|
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
253
|
+
* **Superseded as the way a clip export gets its bytes** (D613). The bound is
|
|
254
|
+
* a property of the ENVELOPE, not of clips, so the cure was a transport with
|
|
255
|
+
* no envelope: {@link videoclipsCapability.methods.offerClipBytes} hands back
|
|
256
|
+
* a one-shot `peerBytes` ticket and the consumer streams it straight to disk,
|
|
257
|
+
* holding nothing. This method stays for a consumer that genuinely wants the
|
|
258
|
+
* bytes in hand, and for a provider not yet redeployed — with this bound,
|
|
259
|
+
* which for an inline read is not going to move.
|
|
255
260
|
*/
|
|
256
261
|
export declare const VIDEOCLIPS_MAX_READ_BYTES: number;
|
|
262
|
+
/**
|
|
263
|
+
* Hard ceiling on ONE {@link videoclipsCapability.methods.offerClipBytes}
|
|
264
|
+
* transfer — ten times {@link VIDEOCLIPS_MAX_READ_BYTES}, and the reasoning is
|
|
265
|
+
* not "ten times more comfortable".
|
|
266
|
+
*
|
|
267
|
+
* The inline bound is set by what is HELD: a base64 envelope is the payload at
|
|
268
|
+
* ~1.33× in the provider AND the same again in the caller, so 50 MiB of clip
|
|
269
|
+
* is ~133 MiB of heap across two processes. Over `peerBytes` the consumer
|
|
270
|
+
* holds one socket chunk at a time and writes straight through to the export
|
|
271
|
+
* file, so its contribution is flat whatever the clip weighs. What is left is
|
|
272
|
+
* the PRODUCER's own copy, and that is a property of how each provider makes a
|
|
273
|
+
* clip rather than of this transport: Hikvision's fetch writes to a scratch
|
|
274
|
+
* FILE and offers it (nothing is held), Reolink's cmd-5 transfer is collected
|
|
275
|
+
* in memory and offered from there (one copy, the one it already had).
|
|
276
|
+
*
|
|
277
|
+
* So this number bounds the worst provider, not the transport, and it is named
|
|
278
|
+
* separately so that lifting it is a statement about a provider rather than
|
|
279
|
+
* about clips. Above it the provider REFUSES with the size in the message and
|
|
280
|
+
* never truncates: half a video is worse than an honest refusal.
|
|
281
|
+
*/
|
|
282
|
+
export declare const VIDEOCLIPS_MAX_OFFER_BYTES: number;
|
|
257
283
|
/**
|
|
258
284
|
* A clip's finished bytes, inline — the twin of `recordingExport.readExportBytes`.
|
|
259
285
|
*
|
|
@@ -273,6 +299,34 @@ export declare const ClipBytesSchema: z.ZodObject<{
|
|
|
273
299
|
durationMs: z.ZodOptional<z.ZodNumber>;
|
|
274
300
|
}, z.core.$strip>;
|
|
275
301
|
export type ClipBytes = z.infer<typeof ClipBytesSchema>;
|
|
302
|
+
/**
|
|
303
|
+
* Where a clip's finished bytes can be TAKEN (D613) — the answer to
|
|
304
|
+
* {@link videoclipsCapability.methods.offerClipBytes}.
|
|
305
|
+
*
|
|
306
|
+
* Everything {@link ClipBytesSchema} carries except the bytes themselves, plus
|
|
307
|
+
* the one-shot ticket that leads to them. The metadata is answered BEFORE the
|
|
308
|
+
* transfer on purpose: a consumer learns which twin it got, what to call the
|
|
309
|
+
* file and how long the clip runs without having to read a byte, so a decision
|
|
310
|
+
* it would make on that metadata (a wrong twin, an implausible duration) costs
|
|
311
|
+
* no transfer at all.
|
|
312
|
+
*/
|
|
313
|
+
export declare const ClipBytesOfferSchema: z.ZodObject<{
|
|
314
|
+
ticket: z.ZodObject<{
|
|
315
|
+
url: z.ZodString;
|
|
316
|
+
hostNodeId: z.ZodString;
|
|
317
|
+
expiresAtMs: z.ZodNumber;
|
|
318
|
+
declaredBytes: z.ZodNullable<z.ZodNumber>;
|
|
319
|
+
}, z.core.$strip>;
|
|
320
|
+
contentType: z.ZodString;
|
|
321
|
+
name: z.ZodString;
|
|
322
|
+
served: z.ZodEnum<{
|
|
323
|
+
high: "high";
|
|
324
|
+
mid: "mid";
|
|
325
|
+
low: "low";
|
|
326
|
+
}>;
|
|
327
|
+
durationMs: z.ZodOptional<z.ZodNumber>;
|
|
328
|
+
}, z.core.$strip>;
|
|
329
|
+
export type ClipBytesOffer = z.infer<typeof ClipBytesOfferSchema>;
|
|
276
330
|
/**
|
|
277
331
|
* Where a clip's STREAM can be dialled (D597) — the answer to
|
|
278
332
|
* {@link videoclipsCapability.methods.dialClipStream}.
|
|
@@ -338,6 +392,125 @@ export declare const ClipStreamDialSchema: z.ZodObject<{
|
|
|
338
392
|
}>>;
|
|
339
393
|
}, z.core.$strip>;
|
|
340
394
|
export type ClipStreamDial = z.infer<typeof ClipStreamDialSchema>;
|
|
395
|
+
/**
|
|
396
|
+
* The playback rates the broker can pace over media it HOLDS, ascending,
|
|
397
|
+
* always with `1` — and the WIDEST ladder there is. It is the domain the
|
|
398
|
+
* broker's `clampPlaybackRate` is derived from, at both ends.
|
|
399
|
+
*
|
|
400
|
+
* These are the BROKER's: it re-paces frames it has already demuxed — the
|
|
401
|
+
* `MonotonicClock` divides source elapsed time by the factor and the pacer
|
|
402
|
+
* pushes that much faster. `1.5` is in it because a re-pacer has no reason to
|
|
403
|
+
* refuse it.
|
|
404
|
+
*
|
|
405
|
+
* **`8` is here since D621, and it is the pacer's, not a camera's.** D620
|
|
406
|
+
* measured the thing that was assumed for a year and was never true: a
|
|
407
|
+
* Reolink `<playSpeed>` does not time-compress anything. At 1, 2, 4 and 8 the
|
|
408
|
+
* transfer is byte-identical — same 947 472 bytes, same 594 access units,
|
|
409
|
+
* same 39.855 s presentation span, same 624 AAC frames — and only the wall
|
|
410
|
+
* clock moves. It buys SUPPLY, never speed. So there was never a second
|
|
411
|
+
* mechanism to wire for 8×: there is one, this one, and what it needs is
|
|
412
|
+
* media in hand and a clamp that does not move the number.
|
|
413
|
+
*
|
|
414
|
+
* **`16` is deliberately NOT here, and will not join by widening this array.**
|
|
415
|
+
* The camera's `playSpeed 16` is not a rate at all but an I-frame-only MODE —
|
|
416
|
+
* measured on 592: 10 access units for a whole 36.3 s sub clip, 20 for the
|
|
417
|
+
* main twin at a 2 025 ms median spacing, and no audio track. That is
|
|
418
|
+
* different CONTENT, a stream of its own, and the honest broker-side twin of
|
|
419
|
+
* it would be a pacer that DROPS whole GOPs rather than one that pushes 16×
|
|
420
|
+
* the bitrate at a live WebRTC track. Neither exists. A `16` in this array
|
|
421
|
+
* today would be a rate accepted and delivered at 8 — D612's defect, which
|
|
422
|
+
* this list exists to end, one number further along.
|
|
423
|
+
*
|
|
424
|
+
* Every entry must survive the broker's `clampPlaybackRate` unchanged. Since
|
|
425
|
+
* D621 that is structural rather than a discipline: the clamp reads this
|
|
426
|
+
* array's own ends. What still has to be proved behaviourally — and is, in
|
|
427
|
+
* the broker's `clip-stream-feeder.spec` — is that the PACER really empties a
|
|
428
|
+
* clip `rate` times faster, because a clamp agreeing with a ladder is a
|
|
429
|
+
* constant compared against itself.
|
|
430
|
+
*
|
|
431
|
+
* Narrower ladders exist for transports whose SUPPLY is bounded; they are
|
|
432
|
+
* subsets of this one ({@link CLIP_STREAM_SOURCE_RATES},
|
|
433
|
+
* {@link CLIP_REALTIME_SOURCE_RATES}).
|
|
434
|
+
*/
|
|
435
|
+
export declare const CLIP_BROKER_PACED_RATES: readonly number[];
|
|
436
|
+
/**
|
|
437
|
+
* The rates a provider-STREAMED clip can be delivered at — a subset of
|
|
438
|
+
* {@link CLIP_BROKER_PACED_RATES}, and frozen below it on purpose (D621).
|
|
439
|
+
*
|
|
440
|
+
* A `stream` clip's media does not exist yet: it arrives on a socket from the
|
|
441
|
+
* camera while the pacer consumes it. The pacer takes `rate` seconds of media
|
|
442
|
+
* per second of wall clock, so the ceiling is whatever the SOURCE supplies,
|
|
443
|
+
* and that is a measurement per vendor rather than a preference.
|
|
444
|
+
*
|
|
445
|
+
* Reolink, the one provider on this envelope, was measured on 592
|
|
446
|
+
* (2026-09-23, D620): with the `<ReplaySeek>` that 0.11.1 sends before every
|
|
447
|
+
* replay, a sub clip arrives at **1.2×** and a main twin at **1.37×**. The
|
|
448
|
+
* ladder below is therefore ALREADY beyond this transport above 1 — the D612
|
|
449
|
+
* defect returned through a door nobody opened — and D620 fixed the repair
|
|
450
|
+
* order: the supply first, the ladder after. So this array does not move with
|
|
451
|
+
* the broker's, and it does not gain `8`; what it gains, when the library
|
|
452
|
+
* forwards a `<playSpeed>` large enough to feed the rate being paced over it,
|
|
453
|
+
* is the right to be widened on a measurement rather than shortened on one.
|
|
454
|
+
*/
|
|
455
|
+
export declare const CLIP_STREAM_SOURCE_RATES: readonly number[];
|
|
456
|
+
/**
|
|
457
|
+
* The rates a REALTIME-BOUND stream can be delivered at.
|
|
458
|
+
*
|
|
459
|
+
* **Measured, and it is the whole reason this second ladder exists.** A
|
|
460
|
+
* Hikvision RTSP replay is not a fast fetch: it delivers the recording at the
|
|
461
|
+
* speed it was recorded. On 1436, 2026-09-23, one stream carried 176 access
|
|
462
|
+
* units in 14 274 ms of wall clock at a measured 12.5 fps — 14.08 s of media
|
|
463
|
+
* in 14.27 s, **1.01× realtime** — and a whole 18 s clip took 22.3 s to fetch
|
|
464
|
+
* end to end. Reolink's cmd-5 transfer, which {@link CLIP_BROKER_PACED_RATES}
|
|
465
|
+
* was written for, lands the same bytes at 49–62× and therefore has the entire
|
|
466
|
+
* clip in hand within the first second.
|
|
467
|
+
*
|
|
468
|
+
* The broker's pacer consumes `rate` seconds of media per second of wall
|
|
469
|
+
* clock while the socket supplies one. So at any rate above 1 the buffer
|
|
470
|
+
* drains at `(rate − 1)×` and a stream that is only seconds old runs dry
|
|
471
|
+
* almost at once — the viewer stops, the queue empties, and the provider's
|
|
472
|
+
* own drain gate eventually reports `peer-stalled`. Nothing about that is a
|
|
473
|
+
* bug to be fixed with a bigger buffer: there is no buffer, because the bytes
|
|
474
|
+
* do not exist yet.
|
|
475
|
+
*
|
|
476
|
+
* So the honest answer is the DECLARATION (D612's own rule, applied to the
|
|
477
|
+
* case it did not yet have): a rate this transport cannot deliver is never
|
|
478
|
+
* offered. Below 1 is free — a slower pacer only lets the buffer grow.
|
|
479
|
+
*
|
|
480
|
+
* When a clip is served from a FILE the constraint is gone with the transport,
|
|
481
|
+
* which is why `file` keeps the full ladder.
|
|
482
|
+
*/
|
|
483
|
+
export declare const CLIP_REALTIME_SOURCE_RATES: readonly number[];
|
|
484
|
+
/**
|
|
485
|
+
* What a surface may DRAW for this provider's clips — the answer to
|
|
486
|
+
* {@link videoclipsCapability.methods.getPlaybackOptions} (D612).
|
|
487
|
+
*
|
|
488
|
+
* The envelope is a PROVIDER fact, not a clip fact, and that is measured, not
|
|
489
|
+
* assumed: the broker's `chooseClipPath` reads exactly two inputs — whether
|
|
490
|
+
* `dialClipStream` and `readClipBytes` are wired — and both are constants of
|
|
491
|
+
* the broker's own closure over the provider's methods. The `profile` it is
|
|
492
|
+
* handed is explicitly not read. So every clip of a provider is served the
|
|
493
|
+
* same way, and a per-clip channel carried a value that could not vary. The
|
|
494
|
+
* per-clip `clipTransport` server message was removed for exactly that reason.
|
|
495
|
+
*
|
|
496
|
+
* Queried per camera, before a clip is picked, so a control is rendered or
|
|
497
|
+
* DISABLED rather than offered and refused at play time (D62: a disabled
|
|
498
|
+
* control reads as unavailable, one that undoes the gesture reads as broken).
|
|
499
|
+
*/
|
|
500
|
+
export declare const ClipPlaybackOptionsSchema: z.ZodObject<{
|
|
501
|
+
transport: z.ZodEnum<{
|
|
502
|
+
file: "file";
|
|
503
|
+
stream: "stream";
|
|
504
|
+
}>;
|
|
505
|
+
seek: z.ZodEnum<{
|
|
506
|
+
forward: "forward";
|
|
507
|
+
free: "free";
|
|
508
|
+
}>;
|
|
509
|
+
stepBack: z.ZodBoolean;
|
|
510
|
+
scrub: z.ZodBoolean;
|
|
511
|
+
rates: z.ZodReadonly<z.ZodArray<z.ZodNumber>>;
|
|
512
|
+
}, z.core.$strip>;
|
|
513
|
+
export type ClipPlaybackOptions = z.infer<typeof ClipPlaybackOptionsSchema>;
|
|
341
514
|
export declare const ClipSourceAvailabilitySchema: z.ZodObject<{
|
|
342
515
|
state: z.ZodEnum<{
|
|
343
516
|
ok: "ok";
|
|
@@ -533,14 +706,18 @@ export declare const videoclipsCapability: {
|
|
|
533
706
|
*
|
|
534
707
|
* `getClipPlayback` is the right answer for a player: it hands back a URL
|
|
535
708
|
* on a plane the hub serves `access:'authenticated'`, which a browser and a
|
|
536
|
-
* viewer session satisfy. It is the wrong answer for another ADDON
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
709
|
+
* viewer session satisfy. It is the wrong answer for another ADDON: the
|
|
710
|
+
* hub's proxy in front of that plane takes only a user credential, which
|
|
711
|
+
* an addon does not hold, so a recorder that wants a camera's clip cannot
|
|
712
|
+
* fetch that URL. This method is the shape that answer forced — the same
|
|
713
|
+
* one (and the same bound) as `recordingExport.readExportBytes`.
|
|
714
|
+
*
|
|
715
|
+
* **It is no longer the only seam.** Until D613 there was no addon→addon
|
|
716
|
+
* byte transport at all; there is now
|
|
717
|
+
* ({@link offerClipBytes}, over `ctx.peerBytes`), it holds nothing on
|
|
718
|
+
* either side, and it is what a clip EXPORT uses. This method remains for
|
|
719
|
+
* a consumer that genuinely wants the bytes in hand, and as the named
|
|
720
|
+
* fallback for a provider not yet redeployed.
|
|
544
721
|
*
|
|
545
722
|
* Routing needs no `provider` pin: the id is source-prefixed and
|
|
546
723
|
* self-contained, so `device-collection-dispatch.ts` rule 3 hands the call
|
|
@@ -588,6 +765,72 @@ export declare const videoclipsCapability: {
|
|
|
588
765
|
}, z.core.$strip>, "query"> & {
|
|
589
766
|
readonly providerOptional: true;
|
|
590
767
|
};
|
|
768
|
+
/**
|
|
769
|
+
* Where this clip's finished bytes can be TAKEN — the by-handle read a
|
|
770
|
+
* clip EXPORT pulls, over the addon→addon byte transport (D613).
|
|
771
|
+
*
|
|
772
|
+
* This is {@link readClipBytes} with the envelope removed. Same gates,
|
|
773
|
+
* same vocabulary, same completion rules, same `served` contract — the
|
|
774
|
+
* only difference is that the bytes travel over a one-shot loopback
|
|
775
|
+
* socket instead of inside a base64 field, so neither side holds the
|
|
776
|
+
* payload whole and the 50 MiB refusal on a long `high` twin stops
|
|
777
|
+
* existing. The bound that remains is
|
|
778
|
+
* {@link VIDEOCLIPS_MAX_OFFER_BYTES}, and it bounds the PRODUCER's own
|
|
779
|
+
* copy rather than the transport.
|
|
780
|
+
*
|
|
781
|
+
* **The ticket is loopback and same-host.** A provider on an agent mints a
|
|
782
|
+
* URL that means nothing on the hub, and `ctx.peerBytes.open` refuses it
|
|
783
|
+
* `cross-node` by name rather than dialling whatever else holds that port
|
|
784
|
+
* here. A consumer that can be on the other side of a node boundary from
|
|
785
|
+
* its provider must be able to read that refusal and say so; it must not
|
|
786
|
+
* treat it as "no bytes".
|
|
787
|
+
*
|
|
788
|
+
* **A ticket is a one-shot bearer credential with a seconds-long life.**
|
|
789
|
+
* Take it immediately, never persist it, never log its `url`. An untaken
|
|
790
|
+
* ticket costs the provider one map entry until its TTL, and outstanding
|
|
791
|
+
* tickets are bounded — which is also what makes a per-frame misuse of
|
|
792
|
+
* this method refuse by name rather than work slowly (D9/D18: this is a
|
|
793
|
+
* by-handle fetch of finished media, not a frame pipe).
|
|
794
|
+
*
|
|
795
|
+
* Optional on the provider for the same reason `readClipBytes` is: a
|
|
796
|
+
* source with no camera socket behind it has no bytes. A provider that
|
|
797
|
+
* predates this method answers `NOT_IMPLEMENTED`, and a consumer may fall
|
|
798
|
+
* back to `readClipBytes` — but it says so in the log, with the deploy
|
|
799
|
+
* hint, because that fallback re-imposes the 50 MiB refusal and an
|
|
800
|
+
* operator who sees `too-large-to-transfer` after this shipped is looking
|
|
801
|
+
* at a stale addon, not at a clip that cannot be exported.
|
|
802
|
+
*/
|
|
803
|
+
readonly offerClipBytes: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
|
|
804
|
+
deviceId: z.ZodNumber;
|
|
805
|
+
clipId: z.ZodString;
|
|
806
|
+
provider: z.ZodString;
|
|
807
|
+
profile: z.ZodOptional<z.ZodEnum<{
|
|
808
|
+
high: "high";
|
|
809
|
+
mid: "mid";
|
|
810
|
+
low: "low";
|
|
811
|
+
}>>;
|
|
812
|
+
maxBytes: z.ZodOptional<z.ZodNumber>;
|
|
813
|
+
wake: z.ZodOptional<z.ZodEnum<{
|
|
814
|
+
authorised: "authorised";
|
|
815
|
+
}>>;
|
|
816
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
817
|
+
ticket: z.ZodObject<{
|
|
818
|
+
url: z.ZodString;
|
|
819
|
+
hostNodeId: z.ZodString;
|
|
820
|
+
expiresAtMs: z.ZodNumber;
|
|
821
|
+
declaredBytes: z.ZodNullable<z.ZodNumber>;
|
|
822
|
+
}, z.core.$strip>;
|
|
823
|
+
contentType: z.ZodString;
|
|
824
|
+
name: z.ZodString;
|
|
825
|
+
served: z.ZodEnum<{
|
|
826
|
+
high: "high";
|
|
827
|
+
mid: "mid";
|
|
828
|
+
low: "low";
|
|
829
|
+
}>;
|
|
830
|
+
durationMs: z.ZodOptional<z.ZodNumber>;
|
|
831
|
+
}, z.core.$strip>, "query"> & {
|
|
832
|
+
readonly providerOptional: true;
|
|
833
|
+
};
|
|
591
834
|
/**
|
|
592
835
|
* Where this clip's STREAM can be dialled (D597) — the forward-only
|
|
593
836
|
* fMP4 the provider writes from the first muxed byte, for the broker to
|
|
@@ -639,6 +882,92 @@ export declare const videoclipsCapability: {
|
|
|
639
882
|
}, z.core.$strip>, "query"> & {
|
|
640
883
|
readonly providerOptional: true;
|
|
641
884
|
};
|
|
885
|
+
/**
|
|
886
|
+
* What a surface may DRAW for this provider's clips: the rates it can be
|
|
887
|
+
* played at, whether scrub is served, how far a position may be moved,
|
|
888
|
+
* and whether a backward frame-step means anything (D612).
|
|
889
|
+
*
|
|
890
|
+
* **The only authority.** The per-clip `clipTransport` server message
|
|
891
|
+
* that used to carry the same answer was removed: the broker's transport
|
|
892
|
+
* choice reads nothing that varies per clip, so the clip level had no
|
|
893
|
+
* information the provider does not already have, and two channels that
|
|
894
|
+
* can disagree are worse than one (D62).
|
|
895
|
+
*
|
|
896
|
+
* Asked per camera and per provider, so it must stay CHEAP — it is a
|
|
897
|
+
* statement about wiring, answered from a constant, never a call to the
|
|
898
|
+
* camera. A provider answers with one of {@link CLIP_PLAYBACK_OPTIONS}
|
|
899
|
+
* and never composes an envelope of its own.
|
|
900
|
+
*
|
|
901
|
+
* Optional, and absence is load-bearing: a provider that has not answered
|
|
902
|
+
* has not restricted anything, and a viewer reads it as the freedom it
|
|
903
|
+
* always had. See D612 on the rollout order that absence implies.
|
|
904
|
+
*/
|
|
905
|
+
readonly getPlaybackOptions: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
|
|
906
|
+
deviceId: z.ZodNumber;
|
|
907
|
+
provider: z.ZodString;
|
|
908
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
909
|
+
transport: z.ZodEnum<{
|
|
910
|
+
file: "file";
|
|
911
|
+
stream: "stream";
|
|
912
|
+
}>;
|
|
913
|
+
seek: z.ZodEnum<{
|
|
914
|
+
forward: "forward";
|
|
915
|
+
free: "free";
|
|
916
|
+
}>;
|
|
917
|
+
stepBack: z.ZodBoolean;
|
|
918
|
+
scrub: z.ZodBoolean;
|
|
919
|
+
rates: z.ZodReadonly<z.ZodArray<z.ZodNumber>>;
|
|
920
|
+
}, z.core.$strip>, "query"> & {
|
|
921
|
+
readonly providerOptional: true;
|
|
922
|
+
};
|
|
642
923
|
};
|
|
643
924
|
};
|
|
644
925
|
export type IVideoclipsProvider = InferProvider<typeof videoclipsCapability>;
|
|
926
|
+
/**
|
|
927
|
+
* NOTE ON PLACEMENT: this block lives AFTER the capability definition on
|
|
928
|
+
* purpose. `scripts/lib/parse-cap.ts` finds a cap by the FIRST
|
|
929
|
+
* `export const <X> = {` in the file, so an object literal declared above
|
|
930
|
+
* `videoclipsCapability` is silently taken for the capability itself and
|
|
931
|
+
* codegen emits a `DeviceProxy` entry that does not type-check. Found the
|
|
932
|
+
* hard way, 2026-09-23.
|
|
933
|
+
*/
|
|
934
|
+
/**
|
|
935
|
+
* The two envelopes, spelled ONCE.
|
|
936
|
+
*
|
|
937
|
+
* A provider answers with the entry for the transport its own wiring buys —
|
|
938
|
+
* `stream` if it implements `dialClipStream`, `file` if it implements only
|
|
939
|
+
* `readClipBytes` — and never composes one of its own. One table is what
|
|
940
|
+
* makes "the provider may not promise what no clip can be given" structural
|
|
941
|
+
* instead of a discipline: there is nothing else to promise.
|
|
942
|
+
*/
|
|
943
|
+
export declare const CLIP_PLAYBACK_OPTIONS: {
|
|
944
|
+
readonly stream: {
|
|
945
|
+
readonly transport: "stream";
|
|
946
|
+
readonly seek: "forward";
|
|
947
|
+
readonly stepBack: false;
|
|
948
|
+
readonly scrub: false;
|
|
949
|
+
readonly rates: readonly number[];
|
|
950
|
+
};
|
|
951
|
+
/**
|
|
952
|
+
* A `stream` whose SOURCE runs at realtime — a Hikvision RTSP replay.
|
|
953
|
+
*
|
|
954
|
+
* Same verbs as `stream`, a shorter rate ladder, and the difference is a
|
|
955
|
+
* measurement rather than a preference: see
|
|
956
|
+
* {@link CLIP_REALTIME_SOURCE_RATES}. A third entry rather than a parameter,
|
|
957
|
+
* because a provider must still be able to do nothing but NAME one of these.
|
|
958
|
+
*/
|
|
959
|
+
readonly realtimeStream: {
|
|
960
|
+
readonly transport: "stream";
|
|
961
|
+
readonly seek: "forward";
|
|
962
|
+
readonly stepBack: false;
|
|
963
|
+
readonly scrub: false;
|
|
964
|
+
readonly rates: readonly number[];
|
|
965
|
+
};
|
|
966
|
+
readonly file: {
|
|
967
|
+
readonly transport: "file";
|
|
968
|
+
readonly seek: "free";
|
|
969
|
+
readonly stepBack: true;
|
|
970
|
+
readonly scrub: true;
|
|
971
|
+
readonly rates: readonly number[];
|
|
972
|
+
};
|
|
973
|
+
};
|