@camstack/types 1.2.233 → 1.2.235

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-D7DPSeiv.js");
2
+ const require_sleep = require("./sleep-CsgPITp-.js");
3
3
  const require_event_category = require("./event-category-BVfsrBYA.js");
4
4
  const require_err_msg = require("./err-msg-COpsHMw2.js");
5
5
  //#region src/generated/cap-input-defaults.ts
@@ -297,7 +297,7 @@ function materialise(defaults) {
297
297
  * barrel (`ALL_CAPABILITY_DEFINITIONS`), which would cost ~144MB RSS per
298
298
  * forked runner. See docs/decisions/adr-0028.md.
299
299
  *
300
- * Coverage: 21 collection caps, 34 array methods.
300
+ * Coverage: 22 collection caps, 36 array methods.
301
301
  */
302
302
  var COLLECTION_ARRAY_METHODS = Object.freeze({
303
303
  "addon-pages-source": ["listPages"],
@@ -333,7 +333,8 @@ var COLLECTION_ARRAY_METHODS = Object.freeze({
333
333
  "storage-occupancy": ["getOccupancy"],
334
334
  "storage-provider": ["list"],
335
335
  "turn-provider": ["getTurnServers"],
336
- "user-passkeys": ["listPasskeys"]
336
+ "user-passkeys": ["listPasskeys"],
337
+ "videoclips": ["listClips", "listSources"]
337
338
  });
338
339
  /**
339
340
  * True when `method` on cap `capName` is a COLLECTION cap's array-returning
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as DeviceType, At as emitReadiness, Ct as DATAPLANE_SECRET_HEADER, Dt as normalizeAddonInitResult, Et as BaseAddon, G as ReadinessRegistry, H as nodePin, I as expandCapMethods, K as ReadinessTimeoutError, S as DEVICE_CHILDREN_BATCH_MAX, T as describeCustomActions, Tt as DisposerChain, U as readNodePin, Y as scopeKey, a as asJsonObject, b as deviceOpsCapability, d as BOOT_RECOVERY_BACKOFF_MS, f as DEVICE_SCOPED_CAPS, h as createEventBusSliceSource, j as adminUiCapability, m as createDeviceProxy, p as isDeviceScopedCap, s as asString, t as sleep, u as parseJsonUnknown, x as viewerUiCapability } from "./sleep-CiR4z7r9.mjs";
1
+ import { A as DeviceType, At as emitReadiness, Ct as DATAPLANE_SECRET_HEADER, Dt as normalizeAddonInitResult, Et as BaseAddon, G as ReadinessRegistry, H as nodePin, I as expandCapMethods, K as ReadinessTimeoutError, S as DEVICE_CHILDREN_BATCH_MAX, T as describeCustomActions, Tt as DisposerChain, U as readNodePin, Y as scopeKey, a as asJsonObject, b as deviceOpsCapability, d as BOOT_RECOVERY_BACKOFF_MS, f as DEVICE_SCOPED_CAPS, h as createEventBusSliceSource, j as adminUiCapability, m as createDeviceProxy, p as isDeviceScopedCap, s as asString, t as sleep, u as parseJsonUnknown, x as viewerUiCapability } from "./sleep-7AN_Txmu.mjs";
2
2
  import { t as EventCategory } from "./event-category-BVDXG4tB.mjs";
3
3
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
4
4
  //#region src/generated/cap-input-defaults.ts
@@ -296,7 +296,7 @@ function materialise(defaults) {
296
296
  * barrel (`ALL_CAPABILITY_DEFINITIONS`), which would cost ~144MB RSS per
297
297
  * forked runner. See docs/decisions/adr-0028.md.
298
298
  *
299
- * Coverage: 21 collection caps, 34 array methods.
299
+ * Coverage: 22 collection caps, 36 array methods.
300
300
  */
301
301
  var COLLECTION_ARRAY_METHODS = Object.freeze({
302
302
  "addon-pages-source": ["listPages"],
@@ -332,7 +332,8 @@ var COLLECTION_ARRAY_METHODS = Object.freeze({
332
332
  "storage-occupancy": ["getOccupancy"],
333
333
  "storage-provider": ["list"],
334
334
  "turn-provider": ["getTurnServers"],
335
- "user-passkeys": ["listPasskeys"]
335
+ "user-passkeys": ["listPasskeys"],
336
+ "videoclips": ["listClips", "listSources"]
336
337
  });
337
338
  /**
338
339
  * True when `method` on cap `capName` is a COLLECTION cap's array-returning
@@ -11,6 +11,25 @@
11
11
  * (`_def.type`) and legacy Zod 3 (`_def.typeName` / `constructor.name`) shapes.
12
12
  */
13
13
  import type { CapabilityDefinition, CapabilityMethodAuth } from './capability-definition.js';
14
+ /**
15
+ * True when a cap's generated router carries the COLLECTION `addonId`
16
+ * selector — "which provider of this collection answers".
17
+ *
18
+ * `resolveCapMount` is the authority, not `mode`: since D554 a device-scoped
19
+ * wrapper that is a collection (`videoclips`) keeps the PER-DEVICE mount, and
20
+ * its sources are resolved from the device, never picked by an addonId the
21
+ * caller supplies. Emitting the selector for it would advertise a routing key
22
+ * the runtime builder does not read — the exact type/runtime disagreement
23
+ * D552 removed from `generate-cap-mounts.ts`.
24
+ *
25
+ * The one exception is preserved deliberately, and it is the same one
26
+ * `generate-cap-mounts.ts` documents: a cap declaring `mount: { kind: 'skip' }`
27
+ * keeps its mode-derived shape. The builder never mounts it, so the emitted
28
+ * value is never called — four inert caps (`log-channels`, `login-method`,
29
+ * `load-contribution`, `failure-contribution`) that would otherwise change
30
+ * shape inside a slice that is about something else.
31
+ */
32
+ export declare function emitsCollectionSelector(def: CapabilityDefinition): boolean;
14
33
  /** `z.void()` — input carries no data. */
15
34
  export declare function isVoidInput(schema: unknown): boolean;
16
35
  /** `z.object()` — supports `.loose()` for out-of-band `nodeId`/`addonId` keys. */
@@ -86,6 +105,24 @@ export declare function extractNestedAddonId(input: unknown): string | undefined
86
105
  * for non-object schemas.
87
106
  */
88
107
  export declare function objectInputDeclaresAddonId(schema: unknown): boolean;
108
+ /**
109
+ * True when an OBJECT input schema declares a top-level, REQUIRED, numeric
110
+ * `deviceId` — i.e. the method names exactly one device on every call.
111
+ *
112
+ * This is the question the per-device dispatcher asks at runtime
113
+ * (`requireDeviceScoped`: `typeof input.deviceId !== 'number'` → BAD_REQUEST),
114
+ * asked once at build time instead. A `device-scoped` cap's method that cannot
115
+ * answer it has no device to resolve for and therefore resolves through the
116
+ * cap's SYSTEM provider (`cap-router-builder.ts`) — the same destination
117
+ * `systemOnly` names explicitly. Without this, flipping the mount would 400
118
+ * every batch (`deviceIds`), fleet-wide (`z.void()`) and job-keyed method on
119
+ * the eight device-scoped wrapper caps.
120
+ *
121
+ * Structural, never a name heuristic over source text: the field must resolve
122
+ * to `z.number()` and must NOT be wrapped in `optional` / `nullable` /
123
+ * `default` — an absent value is exactly the input the dispatcher rejects.
124
+ */
125
+ export declare function objectInputDeclaresRequiredDeviceId(schema: unknown): boolean;
89
126
  /**
90
127
  * Effective auth for a cap method — the `internal: true` floor (Task 7.5c).
91
128
  *
@@ -612,7 +612,23 @@ export interface CapabilityDefinition<TName extends string = string, TMethods ex
612
612
  * `device-native` are the auto-derivable defaults; the rest are explicit
613
613
  * opt-ins for caps that today need a hand-written override.
614
614
  */
615
- export type CapabilityMountKind = 'singleton' | 'collection' | 'device-native' | 'server-provided' | 'hub-only' | 'skip'
615
+ export type CapabilityMountKind = 'singleton' | 'collection' | 'device-native'
616
+ /**
617
+ * `scope: 'device'` + `kind: 'wrapper'` — ONE active provider PER DEVICE,
618
+ * substitutable through `deviceManager.setWrapperActive`. NOT
619
+ * `device-native`: there is no native provider (the provider is an addon,
620
+ * not the device), so resolution goes through the D13 resolver
621
+ * `CapabilityRegistry.getProviderForDevice(cap, deviceId)`, which falls back
622
+ * to the global active singleton for a device with no binding.
623
+ *
624
+ * Only a method that NAMES a device can be dispatched per device — the
625
+ * per-device dispatcher demands a numeric `deviceId` on every call. A method
626
+ * whose input carries no required numeric `deviceId` (a batch over
627
+ * `deviceIds`, a fleet-wide count, a job id) resolves through the cap's
628
+ * SYSTEM provider instead, exactly as `systemOnly` does; the builder makes
629
+ * that call per method (`cap-router-builder.ts`).
630
+ */
631
+ | 'device-scoped' | 'server-provided' | 'hub-only' | 'skip'
616
632
  /**
617
633
  * @deprecated Legacy alias for `server-provided` (renamed in SP1). Retained
618
634
  * ONLY so the runtime tolerates version skew across the framework-live-update
@@ -1361,14 +1361,29 @@ export declare const deviceManagerCapability: {
1361
1361
  }, z.core.$strip>>;
1362
1362
  }, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind>;
1363
1363
  /**
1364
- * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
1365
- * Persists the binding via ctx.settings. active=false clears the wrapper
1366
- * (falls back to native if registered).
1364
+ * Activate (or deactivate) a wrapper addon — or ONE of its sources — for a
1365
+ * (device, cap) pair.
1366
+ *
1367
+ * Persists the binding via ctx.settings; `active: false` on a SINGLETON cap
1368
+ * clears the wrapper (falling back to native if one is registered). On a
1369
+ * COLLECTION cap it adds to the per-device DENY set instead, and the
1370
+ * wrapper binding is left exactly as it was — a cap with several sources
1371
+ * has no "which one" for `getBindings` to answer (D556).
1372
+ *
1373
+ * `sourceId` is what makes the switch match its label. One addon can serve
1374
+ * several of a device's sources (`addon-provider-reolink` answers a hub
1375
+ * child with `native:reolink:onboard` AND `native:reolink:hub`), so a
1376
+ * toggle keyed by addon would turn off both while saying it turned off one
1377
+ * — the D62 defect with the polarity reversed (D557). Naming the source
1378
+ * denies exactly that source. OMITTING it keeps the cap-wide meaning
1379
+ * D556 shipped: every source this addon serves for this device, which is
1380
+ * also how a deny entry persisted before the re-key is still read.
1367
1381
  */
1368
1382
  readonly setWrapperActive: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1369
1383
  deviceId: z.ZodNumber;
1370
1384
  capName: z.ZodString;
1371
1385
  wrapperAddonId: z.ZodString;
1386
+ sourceId: z.ZodOptional<z.ZodString>;
1372
1387
  active: z.ZodBoolean;
1373
1388
  }, z.core.$strip>, z.ZodVoid, "mutation">;
1374
1389
  /**
@@ -36,7 +36,7 @@ export { BrokerAddInputSchema, BrokerGetStateInputSchema, type BrokerInfo as Uni
36
36
  export { cameraPipelineConfigCapability, type ICameraPipelineConfigProvider, } from './camera-pipeline-config.cap.js';
37
37
  export { streamSignalsCapability, type IStreamSignalsProvider, type StreamSignal, StreamSignalSchema, type StreamSignalsStatus, StreamSignalsStatusSchema, } from './stream-signals.cap.js';
38
38
  export { cameraStreamsCapability, type ICameraStreamsProvider, type PickedCamStream, PickedCamStreamSchema, type PickStreamPreferences, PickStreamPreferencesSchema, type PickStreamRequirements, PickStreamRequirementsSchema, type StreamCodec, StreamCodecSchema, } from './camera-streams.cap.js';
39
- export { extractNestedAddonId, isArrayOutputSchema, isCollectionArrayMethod, isObjectInput, isVoidInput, kebabToCamel, looseSchema, objectInputDeclaresAddonId, procedureAuthKey, resolveMethodAuth, } from './cap-router-predicates.js';
39
+ export { emitsCollectionSelector, extractNestedAddonId, isArrayOutputSchema, isCollectionArrayMethod, isObjectInput, isVoidInput, kebabToCamel, looseSchema, objectInputDeclaresAddonId, objectInputDeclaresRequiredDeviceId, procedureAuthKey, resolveMethodAuth, } from './cap-router-predicates.js';
40
40
  export type { CapabilityDefinition, CapabilityEventSchema, CapabilityMethodAuth, CapabilityMethodCaller, CapabilityMethodKind, CapabilityMethodOptions, CapabilityMethodSchema, CapabilityMountHint, CapabilityMountKind, CapabilityStatusItemArray, CapabilityStatusKind, CapabilityStatusSchema, CapCaller, DeviceConfigDerivedFormUi, DeviceConfigSpec, DeviceConfigUiSpec, DeviceConfigWidgetUi, DeviceSettingsContribution, InferDeviceProxyCap, InferEvents, InferName, InferNativeProvider, InferProvider, InferRuntimeState, ProviderKind, RuntimeStateDurability, UiContribution, UiContributionKind, UiContributionRemote, } from './capability-definition.js';
41
41
  export { DEFAULT_RUNTIME_STATE_DURABILITY, DEVICE_SETTINGS_CONTRIBUTION_METHODS, DEVICE_STATUS_METHOD, event, expandCapMethods, isDeviceConfigCap, method, resolveCapMount, } from './capability-definition.js';
42
42
  export { CORE_BLOCK_ADDON_PREFIX, CORE_BLOCKS_ADDON_ID, type CoreBlock, type CoreBlockCompileResult, CoreBlockCompileResultSchema, type CoreBlockInput, CoreBlockInputSchema, type CoreBlockPlacement, CoreBlockPlacementSchema, CoreBlockSchema, type CoreBlockStatus, CoreBlockStatusSchema, coreBlockAddonId, coreBlockIdFromAddonId, coreBlocksCapability, type ICoreBlocksProvider, } from './core-blocks.cap.js';
@@ -116,8 +116,8 @@ export type { IUserPasskeysProvider, PasskeySummary } from './user-passkeys.cap.
116
116
  export { PasskeySummarySchema, userPasskeysCapability } from './user-passkeys.cap.js';
117
117
  export type { IVectorStoreProvider } from './vector-store.cap.js';
118
118
  export { VectorDeclareIndexInputSchema, VectorDeleteByFilterInputSchema, VectorDeleteInputSchema, VectorDeleteResultSchema, type VectorFilter, VectorFilterSchema, VectorGetInputSchema, VectorGetResultSchema, type VectorItem, VectorItemSchema, type VectorMatch, VectorMatchSchema, type VectorMetadata, VectorMetadataSchema, type VectorMetric, VectorMetricSchema, VectorQueryInputSchema, VectorQueryResultSchema, VectorStatsInputSchema, VectorStatsResultSchema, VectorUpsertInputSchema, VectorUpsertResultSchema, vectorStoreCapability, } from './vector-store.cap.js';
119
- export type { Clip, ClipPlayback, IVideoclipsProvider } from './videoclips.cap.js';
120
- export { ClipPlaybackSchema, ClipSchema, MAX_CLIP_EVENT_IDS, MAX_CLIP_LABELS, videoclipsCapability, } from './videoclips.cap.js';
119
+ export type { Clip, ClipPlayback, ClipSource, ClipSourceAvailability, IVideoclipsProvider, } from './videoclips.cap.js';
120
+ export { ClipPlaybackSchema, ClipSchema, ClipSourceAvailabilitySchema, ClipSourceSchema, MAX_CLIP_EVENT_IDS, MAX_CLIP_LABELS, videoclipsCapability, } from './videoclips.cap.js';
121
121
  export type { IViewerUiProvider } from './viewer-ui.cap.js';
122
122
  export { viewerUiCapability } from './viewer-ui.cap.js';
123
123
  export { type IWebrtcSessionProvider, type WebrtcClientHints, type WebrtcLadderDecision, WebrtcLadderDecisionSchema, type WebrtcSessionDebug, WebrtcSessionDebugSchema, type WebrtcStreamChoice, WebrtcStreamChoiceSchema, type WebrtcStreamTarget, WebrtcStreamTargetSchema, type WebrtcTierFailure, WebrtcTierFailureSchema, webrtcClientHintsSchema, webrtcSessionCapability, } from './webrtc-session.cap.js';
@@ -4,13 +4,29 @@ import { type InferProvider } from './capability-definition.js';
4
4
  /**
5
5
  * `videoclips` — the unified, navigable-clip surface for a camera.
6
6
  *
7
- * A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
8
- * provider per device, substitutable. The DEFAULT provider (registered by
7
+ * A device-scoped wrapper COLLECTION (D549 decision 2, D554): every provider a
8
+ * camera has is a SOURCE, and they are listed beside each other — never one
9
+ * substituted for another. The DEFAULT provider (registered by
9
10
  * `addon-post-analysis`, `defaultActive: true`) composes the analytics event
10
11
  * log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
11
12
  * is a time-WINDOW over existing footage, never a separate file. A camera that
12
- * exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
13
- * wrapper provider for its device and serve its own clip catalog + URLs.
13
+ * exposes NATIVE onboard clips (Reolink SD card, a hub's storage, HKSV) adds
14
+ * its own catalog ALONGSIDE that one.
15
+ *
16
+ * The mount stays per-device (`resolveCapMount` → `device-scoped`), and a
17
+ * device's SOURCES are its BINDINGS: `deviceManager.getBindings(deviceId)` is
18
+ * what says a provider serves this camera, never the set of addons that
19
+ * happen to have registered the capability somewhere in the cluster. That is
20
+ * what stopped one addon appearing three times on 592 — as the device's
21
+ * native provider, as the hub-local registration and as
22
+ * `pipeline-analytics@little-unraid` (D554 amended 2026-09-20).
23
+ *
24
+ * `listClips` is asked of ONE provider at a time
25
+ * ({@link videoclipsCapability.methods.listClips} `provider`), defaulting to
26
+ * the bound one, which is CamStack on every camera today. It is NOT a union
27
+ * over everything a camera has: *"l'utilizzatore è uno solo"*.
28
+ * {@link videoclipsCapability.methods.getClipPlayback} dispatches by the
29
+ * source namespace inside the clip id, which is why ids are self-contained.
14
30
  *
15
31
  * A `Clip` is purely time-based (subtree-blind): playback resolves segments by
16
32
  * temporal overlap, so the API never decides `continuous` vs `events`.
@@ -46,30 +62,158 @@ export declare const ClipSchema: z.ZodObject<{
46
62
  startMs: z.ZodNumber;
47
63
  endMs: z.ZodNumber;
48
64
  }, z.core.$strip>>>;
65
+ thumbnailMint: z.ZodOptional<z.ZodString>;
66
+ thumbnailUnavailable: z.ZodOptional<z.ZodObject<{
67
+ reason: z.ZodEnum<{
68
+ sleeping: "sleeping";
69
+ unsupported: "unsupported";
70
+ "camera-refused": "camera-refused";
71
+ "no-keyframe": "no-keyframe";
72
+ }>;
73
+ }, z.core.$strip>>;
74
+ catalogAsOf: z.ZodOptional<z.ZodNumber>;
75
+ nativeTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
76
+ behaviours: z.ZodOptional<z.ZodArray<z.ZodString>>;
77
+ streams: z.ZodOptional<z.ZodObject<{
78
+ sub: z.ZodOptional<z.ZodObject<{
79
+ id: z.ZodString;
80
+ bytes: z.ZodOptional<z.ZodNumber>;
81
+ }, z.core.$strip>>;
82
+ main: z.ZodOptional<z.ZodObject<{
83
+ id: z.ZodString;
84
+ bytes: z.ZodOptional<z.ZodNumber>;
85
+ }, z.core.$strip>>;
86
+ }, z.core.$strip>>;
87
+ supportSub: z.ZodOptional<z.ZodBoolean>;
88
+ playable: z.ZodOptional<z.ZodBoolean>;
89
+ unplayableReason: z.ZodOptional<z.ZodString>;
49
90
  }, z.core.$strip>;
50
91
  export type Clip = z.infer<typeof ClipSchema>;
51
92
  export declare const ClipPlaybackSchema: z.ZodObject<{
52
93
  playbackUrl: z.ZodString;
94
+ format: z.ZodOptional<z.ZodEnum<{
95
+ hls: "hls";
96
+ mp4: "mp4";
97
+ }>>;
98
+ served: z.ZodOptional<z.ZodEnum<{
99
+ high: "high";
100
+ mid: "mid";
101
+ low: "low";
102
+ }>>;
53
103
  playbackEndpoints: z.ZodOptional<z.ZodArray<z.ZodString>>;
54
104
  token: z.ZodOptional<z.ZodString>;
55
105
  }, z.core.$strip>;
56
106
  export type ClipPlayback = z.infer<typeof ClipPlaybackSchema>;
107
+ /**
108
+ * Why a source cannot answer right now — per SOURCE, never fleet-wide.
109
+ *
110
+ * `ok` is the only state whose clip list may be read as complete. The other
111
+ * three exist because an empty list from a sleeping camera reads as "this
112
+ * camera has no recordings", which is the defect this whole line of work is
113
+ * about: a battery camera nobody woke (`sleeping`), a camera that could not be
114
+ * reached at all (`unreachable`, also what a provider that THREW reports), a
115
+ * camera whose SD card is not mounted (`no-storage`, measured on 640 —
116
+ * `HddInfo mount 0`, honestly nothing to list rather than "no clips"), and a
117
+ * camera whose OWN index disagrees with its OWN calendar (`index-empty`,
118
+ * measured on 618: the calendar marks 3–20 September, days 6–20 list zero
119
+ * files on both streams and both filters, with 177 GB free). That last one is
120
+ * a defect ON THE CAMERA, and the only honest thing a provider can do is say
121
+ * which days it asked for and got nothing — "no clips" would be a lie about a
122
+ * card that is full of them.
123
+ */
124
+ export declare const ClipSourceAvailabilitySchema: z.ZodObject<{
125
+ state: z.ZodEnum<{
126
+ ok: "ok";
127
+ sleeping: "sleeping";
128
+ unreachable: "unreachable";
129
+ "no-storage": "no-storage";
130
+ "index-empty": "index-empty";
131
+ }>;
132
+ reason: z.ZodOptional<z.ZodString>;
133
+ catalogAsOf: z.ZodOptional<z.ZodNumber>;
134
+ }, z.core.$strip>;
135
+ export type ClipSourceAvailability = z.infer<typeof ClipSourceAvailabilitySchema>;
136
+ /**
137
+ * One SOURCE of clips for a camera — a row of the picker, and the namespace
138
+ * every clip id from it is prefixed with (`analytics`,
139
+ * `native:reolink:onboard`, `hksv`, …).
140
+ *
141
+ * A provider lists the sources IT serves for that device, and answers for each
142
+ * of them whether it can answer at all. A provider with nothing to offer on a
143
+ * camera returns `[]` — it is not that camera's business.
144
+ */
145
+ export declare const ClipSourceSchema: z.ZodObject<{
146
+ source: z.ZodString;
147
+ label: z.ZodString;
148
+ addonId: z.ZodOptional<z.ZodString>;
149
+ via: z.ZodOptional<z.ZodString>;
150
+ availability: z.ZodObject<{
151
+ state: z.ZodEnum<{
152
+ ok: "ok";
153
+ sleeping: "sleeping";
154
+ unreachable: "unreachable";
155
+ "no-storage": "no-storage";
156
+ "index-empty": "index-empty";
157
+ }>;
158
+ reason: z.ZodOptional<z.ZodString>;
159
+ catalogAsOf: z.ZodOptional<z.ZodNumber>;
160
+ }, z.core.$strip>;
161
+ switchedOff: z.ZodOptional<z.ZodBoolean>;
162
+ }, z.core.$strip>;
163
+ export type ClipSource = z.infer<typeof ClipSourceSchema>;
57
164
  export declare const videoclipsCapability: {
58
165
  readonly name: "videoclips";
59
166
  readonly scope: "device";
60
- readonly mode: "singleton";
167
+ readonly mode: "collection";
61
168
  readonly kind: "wrapper";
62
169
  readonly defaultActive: true;
63
170
  /** A clip is a window over a camera's footage — the cap is meaningless on a
64
171
  * sensor, a button or an event emitter, and the `defaultActive` auto-bind
65
172
  * reads this to decide which devices it may claim. */
66
173
  readonly deviceTypes: readonly [DeviceType.Camera];
174
+ /**
175
+ * The Clips section of a camera's device details is FRAMEWORK-DERIVED (D14):
176
+ * the aggregator turns this declaration into the `type:'widget'` section and
177
+ * `DeviceDetail.tsx` is never edited. `videoclips` is the first WRAPPER cap
178
+ * to declare one — every previous `host/` widget cap is `deviceNative` — so
179
+ * `device-config-widget-wrapped-binding.spec.ts` pins that a `kind:'wrapped'`
180
+ * binding entry derives the same section a native one does.
181
+ *
182
+ * **It is a SECTION of the Recording tab, at the end of it — not a tab of
183
+ * its own.** It shipped as a `clips` top-tab and the operator rejected the
184
+ * placement: *"utilizzerei la stessa tab recordings, lì abbiamo già tutto il
185
+ * necessario, una nuova sezione alla fine per le clips"*. The Recording tab
186
+ * already holds the recorder's panel, the schedule bands and the unified
187
+ * retention policy; footage the camera itself holds is the same question,
188
+ * asked of a different store. `order: 100` puts it after all of them with
189
+ * room left in front. The `clips` entry in `WELL_KNOWN_TABS` went with it —
190
+ * a well-known id nobody declares is an invitation to mint the tab again.
191
+ *
192
+ * `topTab` stays: the browser owns a pane (a day's tiles, a source list and
193
+ * a player) and the Config tab's inner bar has no room for one. The widget
194
+ * itself is `host/clips-browser` in ui-library's `HOST_WIDGETS`, and because
195
+ * the admin Recordings page renders every `location:'top-tab'` +
196
+ * `tab:'recording'` section behind its camera picker
197
+ * (`CameraRecordingSettingsSection`), this declaration lands the section on
198
+ * BOTH surfaces with no second wiring.
199
+ */
200
+ readonly deviceConfig: {
201
+ readonly ui: {
202
+ readonly kind: "widget";
203
+ readonly widgetId: "host/clips-browser";
204
+ readonly tab: "recording";
205
+ readonly topTab: true;
206
+ readonly label: "Clips";
207
+ readonly order: 100;
208
+ };
209
+ };
67
210
  readonly methods: {
68
211
  readonly listClips: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
69
212
  deviceId: z.ZodNumber;
70
213
  since: z.ZodNumber;
71
214
  until: z.ZodNumber;
72
215
  limit: z.ZodOptional<z.ZodNumber>;
216
+ provider: z.ZodOptional<z.ZodString>;
73
217
  }, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
74
218
  id: z.ZodString;
75
219
  source: z.ZodString;
@@ -92,12 +236,80 @@ export declare const videoclipsCapability: {
92
236
  startMs: z.ZodNumber;
93
237
  endMs: z.ZodNumber;
94
238
  }, z.core.$strip>>>;
239
+ thumbnailMint: z.ZodOptional<z.ZodString>;
240
+ thumbnailUnavailable: z.ZodOptional<z.ZodObject<{
241
+ reason: z.ZodEnum<{
242
+ sleeping: "sleeping";
243
+ unsupported: "unsupported";
244
+ "camera-refused": "camera-refused";
245
+ "no-keyframe": "no-keyframe";
246
+ }>;
247
+ }, z.core.$strip>>;
248
+ catalogAsOf: z.ZodOptional<z.ZodNumber>;
249
+ nativeTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
250
+ behaviours: z.ZodOptional<z.ZodArray<z.ZodString>>;
251
+ streams: z.ZodOptional<z.ZodObject<{
252
+ sub: z.ZodOptional<z.ZodObject<{
253
+ id: z.ZodString;
254
+ bytes: z.ZodOptional<z.ZodNumber>;
255
+ }, z.core.$strip>>;
256
+ main: z.ZodOptional<z.ZodObject<{
257
+ id: z.ZodString;
258
+ bytes: z.ZodOptional<z.ZodNumber>;
259
+ }, z.core.$strip>>;
260
+ }, z.core.$strip>>;
261
+ supportSub: z.ZodOptional<z.ZodBoolean>;
262
+ playable: z.ZodOptional<z.ZodBoolean>;
263
+ unplayableReason: z.ZodOptional<z.ZodString>;
264
+ }, z.core.$strip>>>, "query">;
265
+ /**
266
+ * The sources this camera has, WITH the reason any of them cannot answer.
267
+ *
268
+ * Asked separately from `listClips` because an empty clip list is
269
+ * ambiguous and this is the only place the ambiguity is resolved: every
270
+ * bound provider contributes its own rows, and a provider that could not
271
+ * be reached at all still produces one row saying so. A surface that draws
272
+ * "no clips" without reading this is drawing a guess.
273
+ */
274
+ readonly listSources: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
275
+ deviceId: z.ZodNumber;
276
+ }, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
277
+ source: z.ZodString;
278
+ label: z.ZodString;
279
+ addonId: z.ZodOptional<z.ZodString>;
280
+ via: z.ZodOptional<z.ZodString>;
281
+ availability: z.ZodObject<{
282
+ state: z.ZodEnum<{
283
+ ok: "ok";
284
+ sleeping: "sleeping";
285
+ unreachable: "unreachable";
286
+ "no-storage": "no-storage";
287
+ "index-empty": "index-empty";
288
+ }>;
289
+ reason: z.ZodOptional<z.ZodString>;
290
+ catalogAsOf: z.ZodOptional<z.ZodNumber>;
291
+ }, z.core.$strip>;
292
+ switchedOff: z.ZodOptional<z.ZodBoolean>;
95
293
  }, z.core.$strip>>>, "query">;
96
294
  readonly getClipPlayback: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
97
295
  deviceId: z.ZodNumber;
98
296
  clipId: z.ZodString;
297
+ profile: z.ZodOptional<z.ZodEnum<{
298
+ high: "high";
299
+ mid: "mid";
300
+ low: "low";
301
+ }>>;
99
302
  }, z.core.$strip>, z.ZodObject<{
100
303
  playbackUrl: z.ZodString;
304
+ format: z.ZodOptional<z.ZodEnum<{
305
+ hls: "hls";
306
+ mp4: "mp4";
307
+ }>>;
308
+ served: z.ZodOptional<z.ZodEnum<{
309
+ high: "high";
310
+ mid: "mid";
311
+ low: "low";
312
+ }>>;
101
313
  playbackEndpoints: z.ZodOptional<z.ZodArray<z.ZodString>>;
102
314
  token: z.ZodOptional<z.ZodString>;
103
315
  }, z.core.$strip>, "query">;
@@ -9059,6 +9059,13 @@ export type AppRouter = TrpcCoreRouter<{
9059
9059
  output: z.infer<typeof videoclipsCapability.methods.listClips.output>;
9060
9060
  meta: object;
9061
9061
  }>;
9062
+ listSources: TRPCQueryProcedure<{
9063
+ input: {
9064
+ [x: string]: unknown;
9065
+ } & z.input<typeof videoclipsCapability.methods.listSources.input>;
9066
+ output: z.infer<typeof videoclipsCapability.methods.listSources.output>;
9067
+ meta: object;
9068
+ }>;
9062
9069
  getClipPlayback: TRPCQueryProcedure<{
9063
9070
  input: {
9064
9071
  [x: string]: unknown;
@@ -9791,23 +9798,6 @@ export type AppRouter = TrpcCoreRouter<{
9791
9798
  output: Record<string, string>;
9792
9799
  meta: object;
9793
9800
  }>;
9794
- setDeviceCollectionFilter: import("@trpc/server").TRPCMutationProcedure<{
9795
- input: {
9796
- deviceId: string;
9797
- capability: string;
9798
- addonIds: string[];
9799
- };
9800
- output: void;
9801
- meta: object;
9802
- }>;
9803
- clearDeviceCollectionFilter: import("@trpc/server").TRPCMutationProcedure<{
9804
- input: {
9805
- deviceId: string;
9806
- capability: string;
9807
- };
9808
- output: void;
9809
- meta: object;
9810
- }>;
9811
9801
  }>> & import("@trpc/server").TRPCDecorateCreateRouterOptions<{
9812
9802
  listCapabilities: import("@trpc/server").TRPCQueryProcedure<{
9813
9803
  input: void;
@@ -9870,23 +9860,6 @@ export type AppRouter = TrpcCoreRouter<{
9870
9860
  output: Record<string, string>;
9871
9861
  meta: object;
9872
9862
  }>;
9873
- setDeviceCollectionFilter: import("@trpc/server").TRPCMutationProcedure<{
9874
- input: {
9875
- deviceId: string;
9876
- capability: string;
9877
- addonIds: string[];
9878
- };
9879
- output: void;
9880
- meta: object;
9881
- }>;
9882
- clearDeviceCollectionFilter: import("@trpc/server").TRPCMutationProcedure<{
9883
- input: {
9884
- deviceId: string;
9885
- capability: string;
9886
- };
9887
- output: void;
9888
- meta: object;
9889
- }>;
9890
9863
  }>;
9891
9864
  logs: import("@trpc/server/unstable-core-do-not-import").Router<{
9892
9865
  ctx: any;
@@ -488,12 +488,12 @@ export interface CapabilityRouterMap<TRouter = unknown> {
488
488
  readonly zoneRules: TRouter;
489
489
  readonly zones: TRouter;
490
490
  }
491
- /** Capability names whose mode is `singleton` (130 caps). */
492
- export declare const SINGLETON_CAPABILITY_NAMES: readonly ["accessories", "addon-pages", "addon-settings", "addon-widgets", "addons", "admin-ui", "air-quality-sensor", "alarm-panel", "alerts", "ambient-light-sensor", "audio-analysis", "audio-analyzer", "audio-codec", "audio-metrics", "automation-control", "backup", "battery", "binary", "brightness", "button", "camera-credentials", "camera-grid-layout", "camera-pipeline-config", "camera-streams", "carbon-monoxide", "climate-control", "color", "connectivity", "consumables", "contact", "control", "core-blocks", "cover", "day-night", "decoder", "detection-pipeline", "device-adoption", "device-discovery", "device-manager", "device-ops", "device-state", "device-status", "doorbell", "enum-sensor", "event-emitter", "events", "face-gallery", "fan-control", "feature-probe", "filesystem-browse", "flood", "gas", "humidifier", "humidity-sensor", "image", "image-settings", "integrations", "intercom", "lawn-mower-control", "llm-runtime", "local-network", "lock-control", "media-player", "metrics-provider", "model-convert", "model-distributor", "motion", "motion-detection", "motion-trigger", "motion-zones", "native-object-detection", "navigation", "network-link", "network-quality", "nodes", "notification-rules", "notifier", "numeric-sensor", "osd", "osd-manager", "pet-feeder", "pipeline-analytics", "pipeline-executor", "pipeline-orchestrator", "pipeline-runner", "plate-gallery", "platform-probe", "power-meter", "presence", "pressure-sensor", "privacy-mask", "ptz", "ptz-autotrack", "reboot", "recording", "recording-export", "recording-signal", "scene-monitor", "script-runner", "server-management", "settings-store", "smoke", "snapshot", "sso-bridge", "storage", "storage-migration", "stream-broker", "stream-catalog", "stream-params", "stream-signals", "switch", "system", "tamper", "temperature-sensor", "terminal-session", "toast", "update", "user-management", "vacuum-control", "valve", "vector-store", "vibration", "videoclips", "viewer-ui", "water-heater", "weather", "webrtc-session", "zone-analytics", "zone-rules", "zones"];
491
+ /** Capability names whose mode is `singleton` (129 caps). */
492
+ export declare const SINGLETON_CAPABILITY_NAMES: readonly ["accessories", "addon-pages", "addon-settings", "addon-widgets", "addons", "admin-ui", "air-quality-sensor", "alarm-panel", "alerts", "ambient-light-sensor", "audio-analysis", "audio-analyzer", "audio-codec", "audio-metrics", "automation-control", "backup", "battery", "binary", "brightness", "button", "camera-credentials", "camera-grid-layout", "camera-pipeline-config", "camera-streams", "carbon-monoxide", "climate-control", "color", "connectivity", "consumables", "contact", "control", "core-blocks", "cover", "day-night", "decoder", "detection-pipeline", "device-adoption", "device-discovery", "device-manager", "device-ops", "device-state", "device-status", "doorbell", "enum-sensor", "event-emitter", "events", "face-gallery", "fan-control", "feature-probe", "filesystem-browse", "flood", "gas", "humidifier", "humidity-sensor", "image", "image-settings", "integrations", "intercom", "lawn-mower-control", "llm-runtime", "local-network", "lock-control", "media-player", "metrics-provider", "model-convert", "model-distributor", "motion", "motion-detection", "motion-trigger", "motion-zones", "native-object-detection", "navigation", "network-link", "network-quality", "nodes", "notification-rules", "notifier", "numeric-sensor", "osd", "osd-manager", "pet-feeder", "pipeline-analytics", "pipeline-executor", "pipeline-orchestrator", "pipeline-runner", "plate-gallery", "platform-probe", "power-meter", "presence", "pressure-sensor", "privacy-mask", "ptz", "ptz-autotrack", "reboot", "recording", "recording-export", "recording-signal", "scene-monitor", "script-runner", "server-management", "settings-store", "smoke", "snapshot", "sso-bridge", "storage", "storage-migration", "stream-broker", "stream-catalog", "stream-params", "stream-signals", "switch", "system", "tamper", "temperature-sensor", "terminal-session", "toast", "update", "user-management", "vacuum-control", "valve", "vector-store", "vibration", "viewer-ui", "water-heater", "weather", "webrtc-session", "zone-analytics", "zone-rules", "zones"];
493
493
  /** Union of singleton capability names (literal string union). */
494
494
  export type SingletonCapabilityName = typeof SINGLETON_CAPABILITY_NAMES[number];
495
- /** Capability names whose mode is `collection` (28 caps). */
496
- export declare const COLLECTION_CAPABILITY_NAMES: readonly ["addon-pages-source", "addon-routes", "addon-widgets-source", "auth-provider", "broker", "connection-test", "custom-model-registry", "data-store-provider", "device-export", "device-provider", "embedding-encoder", "failure-contribution", "llm", "load-contribution", "log-channels", "log-destination", "login-method", "mesh-network", "mqtt-broker", "network-access", "notification-output", "oauth-integration", "smtp-provider", "storage-evictable", "storage-occupancy", "storage-provider", "turn-provider", "user-passkeys"];
495
+ /** Capability names whose mode is `collection` (29 caps). */
496
+ export declare const COLLECTION_CAPABILITY_NAMES: readonly ["addon-pages-source", "addon-routes", "addon-widgets-source", "auth-provider", "broker", "connection-test", "custom-model-registry", "data-store-provider", "device-export", "device-provider", "embedding-encoder", "failure-contribution", "llm", "load-contribution", "log-channels", "log-destination", "login-method", "mesh-network", "mqtt-broker", "network-access", "notification-output", "oauth-integration", "smtp-provider", "storage-evictable", "storage-occupancy", "storage-provider", "turn-provider", "user-passkeys", "videoclips"];
497
497
  /** Union of collection capability names (literal string union). */
498
498
  export type CollectionCapabilityName = typeof COLLECTION_CAPABILITY_NAMES[number];
499
499
  /** Capability mode lookup at runtime — mirrors the `.cap.ts` definitions. */
@@ -8,7 +8,7 @@
8
8
  * barrel (`ALL_CAPABILITY_DEFINITIONS`), which would cost ~144MB RSS per
9
9
  * forked runner. See docs/decisions/adr-0028.md.
10
10
  *
11
- * Coverage: 21 collection caps, 34 array methods.
11
+ * Coverage: 22 collection caps, 36 array methods.
12
12
  */
13
13
  export declare const COLLECTION_ARRAY_METHODS: Readonly<Record<string, readonly string[]>>;
14
14
  /**
@@ -6,7 +6,7 @@
6
6
  * scope+access check inside `protectedProcedure` (see
7
7
  * `server/backend/src/api/trpc/trpc.middleware.ts`).
8
8
  *
9
- * Coverage: 1056 method paths across 131 capabilities.
9
+ * Coverage: 1057 method paths across 131 capabilities.
10
10
  */
11
11
  import type { CapabilityMethodAccess } from '../capabilities/capability-definition.js';
12
12
  export interface MethodAccessRecord {
@@ -6,7 +6,7 @@
6
6
  * system-scope cap that takes a deviceId was previously never device-filtered
7
7
  * — see the generator header).
8
8
  *
9
- * Coverage: 388 methods carry a device reference, of which
9
+ * Coverage: 389 methods carry a device reference, of which
10
10
  * 141 are on SYSTEM-scope caps.
11
11
  *
12
12
  * Top-level fields, number arrays, and one-level arrays of objects carrying