@camstack/addon-pipeline 1.2.272 → 1.2.274

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.
Files changed (33) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/{default-detection-model-DqrqHCuw.mjs → default-detection-model-BXwE-Dvo.mjs} +1 -1
  4. package/dist/{default-detection-model-kQnvoRyv.js → default-detection-model-CAWhHQo2.js} +1 -1
  5. package/dist/detection-pipeline/index.js +4 -4
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-DBHsAlUE.mjs → dist-g5MfpiBh.mjs} +363 -20
  8. package/dist/{dist-DygcLvgG.js → dist-k6Vu-AhZ.js} +386 -19
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/{node-CACCuE7t.js → node--u_jUObS.js} +1 -1
  12. package/dist/{node-j_3VvNQJ.mjs → node-BXsHQH5h.mjs} +1 -1
  13. package/dist/pipeline-runner/index.js +3 -3
  14. package/dist/pipeline-runner/index.mjs +3 -3
  15. package/dist/{process-memory-fse8NnRi.js → process-memory-DN7opum2.js} +1 -1
  16. package/dist/{process-memory-DcoIQGG5.mjs → process-memory-Gl3EowL-.mjs} +1 -1
  17. package/dist/recorder/index.js +572 -3
  18. package/dist/recorder/index.mjs +572 -3
  19. package/dist/{segment-demux-js-Ce24Y2G0.js → segment-demux-js-DHX8o8pI.js} +1 -1
  20. package/dist/{segment-demux-js-DSgNEMf6.mjs → segment-demux-js-sYP_jndp.mjs} +1 -1
  21. package/dist/stream-broker/_stub.js +2 -2
  22. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BSZUBMBY.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CEy8IryH.mjs} +2 -2
  23. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BlXyfeXU.mjs +26 -0
  24. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-MU3_q1MX.mjs +26 -0
  25. package/dist/stream-broker/demux-worker-child.js +1 -1
  26. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  27. package/dist/stream-broker/{hostInit-lVR0hopj.mjs → hostInit-UKNN4qes.mjs} +2 -2
  28. package/dist/stream-broker/index.js +3 -3
  29. package/dist/stream-broker/index.mjs +3 -3
  30. package/dist/stream-broker/remoteEntry.js +1 -1
  31. package/package.json +5 -1
  32. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-_bHa4uUp.mjs +0 -26
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CeR_IxxU.mjs +0 -26
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-DygcLvgG.js");
7
- const require_process_memory = require("../process-memory-fse8NnRi.js");
6
+ const require_dist = require("../dist-k6Vu-AhZ.js");
7
+ const require_process_memory = require("../process-memory-DN7opum2.js");
8
8
  let node_fs = require("node:fs");
9
9
  node_fs = require_chunk.__toESM(node_fs);
10
10
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-DBHsAlUE.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DcoIQGG5.mjs";
2
+ import { E as PoolMemoryWatchdog, I as audioAnalysisCapability, Jt as BaseAddon, L as audioAnalyzerCapability, Qt as audioChunkBytesPerSample, Vt as errMsg, jt as resolvePoolMemoryPolicy, lt as mapAudioLabelToMacro, n as AUDIO_BACKEND_CHOICES, nn as expandAudioChunkToF32le, rn as hydrateSchema, s as DEFAULT_AUDIO_ANALYZER_CONFIG, sn as nodePin, wn as EventCategory, x as HF_BASE_URL } from "../dist-g5MfpiBh.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-Gl3EowL-.mjs";
4
4
  import * as fs from "node:fs";
5
5
  import * as path$1 from "node:path";
6
6
  import { downloadFile } from "@camstack/system/addon-utils";
@@ -1,4 +1,4 @@
1
- import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-DBHsAlUE.mjs";
1
+ import { R as audioKindId, a as COCO_80_LABELS, it as hfModelUrl, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-g5MfpiBh.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DygcLvgG.js");
1
+ const require_dist = require("./dist-k6Vu-AhZ.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-DygcLvgG.js");
7
- const require_node = require("../node-CACCuE7t.js");
8
- const require_default_detection_model = require("../default-detection-model-kQnvoRyv.js");
6
+ const require_dist = require("../dist-k6Vu-AhZ.js");
7
+ const require_node = require("../node--u_jUObS.js");
8
+ const require_default_detection_model = require("../default-detection-model-CAWhHQo2.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-fse8NnRi.js");
10
+ const require_process_memory = require("../process-memory-DN7opum2.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-DBHsAlUE.mjs";
3
- import { s as readProcessCost } from "../node-j_3VvNQJ.mjs";
4
- import { a as localFrameRegistry, c as ALL_STEPS, d as getStepDefinition, f as resolveModelForFormat, l as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as landmarkPrecisionVerdict, r as macroGateVerdict, s as ALL_PIPELINE_STEPS, u as getStep } from "../default-detection-model-DqrqHCuw.mjs";
2
+ import { $ as evaluateZoneRules, $t as createEvent, Cn as union, E as PoolMemoryWatchdog, J as detectionPipelineCapability, Jt as BaseAddon, Nt as runtimeDevices$1, Ot as resolveClusterStepModelId, P as YAMNET_TO_MACRO, Rt as supportedRuntimes$1, Sn as string, St as pipelineExecutorCapability, Vt as errMsg, W as defaultDeviceFor$1, Z as enumerateInferenceDevices, at as inferModelProvider, c as DEFAULT_CLUSTER_STEP_MODELS, cn as parseJsonUnknown, dn as sleep, gt as overlayClusterStepSettings, jt as resolvePoolMemoryPolicy, l as DEFAULT_CLUSTER_STEP_SETTINGS, m as DEVICE_BACKEND_TO_FORMAT, pn as array, rn as hydrateSchema, sn as nodePin, st as loadContributionCapability, t as APPLE_SA_TO_MACRO, vt as pickClusterStepModels, wn as EventCategory, yn as object, yt as pickClusterStepSettings } from "../dist-g5MfpiBh.mjs";
3
+ import { s as readProcessCost } from "../node-BXsHQH5h.mjs";
4
+ import { a as localFrameRegistry, c as ALL_STEPS, d as getStepDefinition, f as resolveModelForFormat, l as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as landmarkPrecisionVerdict, r as macroGateVerdict, s as ALL_PIPELINE_STEPS, u as getStep } from "../default-detection-model-BXwE-Dvo.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DcoIQGG5.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-Gl3EowL-.mjs";
7
7
  import * as os from "node:os";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
@@ -5360,7 +5360,7 @@ var ZodIssueCode = {
5360
5360
  var ZodFirstPartyTypeKind;
5361
5361
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5362
5362
  //#endregion
5363
- //#region ../types/dist/sleep-CiR4z7r9.mjs
5363
+ //#region ../types/dist/sleep-CaB_hL5g.mjs
5364
5364
  /**
5365
5365
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5366
5366
  * window to float samples (D455).
@@ -8341,6 +8341,8 @@ var EVENT_OWNER_TYPES = [
8341
8341
  * nothing failing until a caller asked.
8342
8342
  */
8343
8343
  var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
8344
+ /** The same list as a Zod enum, for the cap input that carries it. */
8345
+ var MediaPresenceOwnerKindSchema = _enum([...EVENT_OWNER_TYPES, "track"]);
8344
8346
  new Set(EVENT_OWNER_TYPES);
8345
8347
  var EncodeProfileSchema = object({
8346
8348
  video: object({
@@ -9321,6 +9323,24 @@ var DetectionCatalogClassMapSchema = object({
9321
9323
  preserveOriginal: boolean()
9322
9324
  });
9323
9325
  /**
9326
+ * THE canonical event-clip pad: the time window a single-timestamp analytics
9327
+ * event expands to when joined with footage (clip window = `[timestamp - preMs,
9328
+ * timestamp + postMs]`). Matches the admin-ui clip window (−5s/+10s).
9329
+ *
9330
+ * Every consumer derives from this ONE constant so event↔footage boundaries
9331
+ * agree everywhere (C1): today that is the `videoclips` default provider
9332
+ * (addon-post-analysis), which pads its clip windows with it. The recorder used
9333
+ * to pad in-RAM playback markers with it too; those markers had no reader
9334
+ * anywhere in the repo and were deleted on 2026-08-29.
9335
+ *
9336
+ * NOTE: this is a UI/JOIN convention, NOT the `events`-band keep/discard gate —
9337
+ * that uses the per-device `preBufferSec`/`postBufferSec` config.
9338
+ */
9339
+ var EVENT_PAD_MS = {
9340
+ preMs: 5e3,
9341
+ postMs: 1e4
9342
+ };
9343
+ /**
9324
9344
  * Numeric day-of-week: 0 = Sunday … 6 = Saturday (matches `Date.getDay`).
9325
9345
  * Named `RecordingWeekday` to avoid collision with the string-union
9326
9346
  * `Weekday` exported from `interfaces/timezones.ts`.
@@ -9537,7 +9557,20 @@ function stripRetiredBandPreBufferSec(config) {
9537
9557
  strippedBands
9538
9558
  };
9539
9559
  }
9540
- DEFAULT_EVENTS_BAND_BUFFER_SEC.postBufferSec * 1e3;
9560
+ /**
9561
+ * Adjacent recorded ranges closer than this belong to the SAME videoclip visit.
9562
+ *
9563
+ * This is NOT the recorder calendar merge (`RANGE_MERGE_GAP_MS = 5s`). That
9564
+ * threshold is for the timeline bar, which must show exact holes — including
9565
+ * the ~8s GOP/keyframe rolls measured on events-mode cameras (dispensa 1438,
9566
+ * 2026-08-16). A videoclip is the events-mode keep-window (writer session),
9567
+ * whose idle bound is `postBufferSec`. Using that default (30s) glues those
9568
+ * intra-visit holes without joining visits hours apart.
9569
+ *
9570
+ * Segments stay the source of truth on disk (`startMs-durMs-bytes.m4s`); a
9571
+ * visit is derived, not a second copy of the files.
9572
+ */
9573
+ var VISIT_MERGE_GAP_MS = DEFAULT_EVENTS_BAND_BUFFER_SEC.postBufferSec * 1e3;
9541
9574
  /**
9542
9575
  * Per-device retention overrides. Every field is optional; an unset or `0`
9543
9576
  * value inherits the node-wide recorder default. Only footage-lifetime limits
@@ -23927,7 +23960,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
23927
23960
  ownerType: EventOwnerTypeSchema,
23928
23961
  eventId: number().int(),
23929
23962
  deviceId: number()
23930
- }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
23963
+ }), array(MediaFileInfoSchema).readonly()), method(object({
23964
+ deviceId: number(),
23965
+ ownerKind: MediaPresenceOwnerKindSchema,
23966
+ ownerIds: array(string()).max(5e3)
23967
+ }), array(string()).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
23931
23968
  kind: "mutation",
23932
23969
  auth: "admin"
23933
23970
  }), method(RebuildObjectEmbeddingsInput, RebuildObjectEmbeddingsResultSchema, {
@@ -27155,6 +27192,18 @@ method(VectorDeclareIndexInputSchema, _void(), {
27155
27192
  kind: "mutation",
27156
27193
  auth: "admin"
27157
27194
  }), method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" });
27195
+ _enum([
27196
+ "queue-full",
27197
+ "camera-backoff",
27198
+ "sleeping",
27199
+ "camera-refused",
27200
+ "no-keyframe",
27201
+ "no-catalog-row",
27202
+ "unsupported",
27203
+ "unknown-device",
27204
+ "uid-missing"
27205
+ ]);
27206
+ _enum(["deferred", "final"]);
27158
27207
  var ClipSchema = object({
27159
27208
  /** Opaque, provider-namespaced id. The default provider encodes the time
27160
27209
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -27229,31 +27278,303 @@ var ClipSchema = object({
27229
27278
  holes: array(object({
27230
27279
  startMs: number(),
27231
27280
  endMs: number()
27232
- })).optional()
27281
+ })).optional(),
27282
+ /**
27283
+ * A URL that MAY produce this clip's still, asked only for rows actually on
27284
+ * screen. The opposite of {@link ClipSchema.thumbnail}: that one is VOUCHED
27285
+ * (a JPEG is already on disk), this one is an offer. The route answers 200
27286
+ * with the image, or 204 with `x-camstack-reason` when it could not mint one
27287
+ * — a surface latches that refusal to the instant rather than retrying.
27288
+ *
27289
+ * Never both: a clip with a vouched `thumbnail` needs no mint.
27290
+ */
27291
+ thumbnailMint: string().optional(),
27292
+ /**
27293
+ * Why no still will be produced for this clip RIGHT NOW — set when the
27294
+ * provider already knows, so the surface draws the glyph and the reason
27295
+ * instead of firing a mint that cannot succeed.
27296
+ *
27297
+ * `sleeping` — a standalone battery camera; a read would be a wake (D549 4).
27298
+ * `camera-refused` — the camera answered the CoverPreview with a refusal.
27299
+ * `no-keyframe` — the window holds no decodable I-frame (an event that sits
27300
+ * inside no file is the measured case).
27301
+ * `unsupported` — this source cannot mint stills at all.
27302
+ */
27303
+ thumbnailUnavailable: object({ reason: _enum([
27304
+ "sleeping",
27305
+ "camera-refused",
27306
+ "no-keyframe",
27307
+ "unsupported"
27308
+ ]) }).optional(),
27309
+ /**
27310
+ * When the catalog this row came from was last CONFIRMED against the device.
27311
+ * Absent means "this row was read live". A persisted catalog served while a
27312
+ * camera sleeps carries the age it really has — a cached list is never drawn
27313
+ * as current (D549 13).
27314
+ */
27315
+ catalogAsOf: number().optional(),
27316
+ /**
27317
+ * The camera's OWN type strings for this clip, all of them, unmapped
27318
+ * (`md`, `people`, `dog_cat`, `sched`, …). Kept beside {@link labels}
27319
+ * because a firmware inventing a type must not vanish: the mapping into our
27320
+ * filter vocabulary is lossy on purpose and this is the lossless copy
27321
+ * (D549 20).
27322
+ */
27323
+ nativeTypes: array(string()).optional(),
27324
+ /**
27325
+ * What the subject DID — `crossline`, `intrude`, `loitering`. A behaviour
27326
+ * travels BESIDE a class, never instead of one, and the class filter ignores
27327
+ * it: "a person crossed a line" is still a person (D549 20).
27328
+ */
27329
+ behaviours: array(string()).optional(),
27330
+ /**
27331
+ * The same recording as two files — the sub twin (what the row and its
27332
+ * thumbnail are) and its main twin, matched at listing time so a quality
27333
+ * change never re-searches the camera (D549 15). `getClipPlayback`'s
27334
+ * `profile` picks between them: `low | mid` → sub, `high` → main.
27335
+ */
27336
+ streams: object({
27337
+ sub: object({
27338
+ id: string(),
27339
+ bytes: number().optional()
27340
+ }).optional(),
27341
+ main: object({
27342
+ id: string(),
27343
+ bytes: number().optional()
27344
+ }).optional()
27345
+ }).optional(),
27346
+ /** The camera says it holds a sub-stream copy of this recording. */
27347
+ supportSub: boolean().optional(),
27348
+ /**
27349
+ * Whether this row has bytes behind it. ABSENT means yes — every clip that
27350
+ * IS a file is playable, and only a source that lists EVENTS can produce a
27351
+ * row with nothing to play (the measured case: 1 of 29 hub events on 3628
27352
+ * fell inside no file). Such a row is shown, never dropped and never offered
27353
+ * as playable-then-failing (D549 19).
27354
+ */
27355
+ playable: boolean().optional(),
27356
+ /** Why {@link playable} is false, verbatim (`no-file-for-window`). */
27357
+ unplayableReason: string().optional(),
27358
+ /**
27359
+ * This clip is STILL BEING WRITTEN, so {@link ClipSchema.timeRange}`.endMs`
27360
+ * is not its end.
27361
+ *
27362
+ * Absent — the common case — means the row is closed and its `endMs` is the
27363
+ * end of the recording. Present and `true` means the source told us the file
27364
+ * has no end yet, and the `endMs` we carry is whatever the camera's index
27365
+ * entry happened to hold: on a Reolink E1 Outdoor PoE (592, measured
27366
+ * 2026-09-20) the newest file `…_192927_000000_…_0.mp4` reported an `endTime`
27367
+ * of 19:29:56 and STILL reported it eight minutes later, while the file went
27368
+ * on growing. A surface that drew 29 s there was lying about a clip that
27369
+ * plays for minutes, on the one row the operator looks at first.
27370
+ *
27371
+ * `endMs` is deliberately still a number: it is the best bound anything has
27372
+ * for a mint window or a byte fetch, and every consumer already requires it.
27373
+ * This flag says what it is WORTH, and a duration is not drawn from it.
27374
+ */
27375
+ inProgress: boolean().optional()
27233
27376
  });
27234
27377
  var ClipPlaybackSchema = object({
27235
- /** HLS master URL through the hub data-plane (Range + token in path). */
27378
+ /**
27379
+ * A media URL through the hub data-plane. {@link ClipPlaybackSchema.format}
27380
+ * says what kind — an HLS master playlist for a recording-derived clip, a
27381
+ * progressive MP4 for a native file the vendor addon muxed and serves with
27382
+ * `Range`. The URL is NOT a credential: both planes are registered
27383
+ * `access: 'authenticated'` and the hub's `/addon/<id>/<prefix>` proxy takes
27384
+ * the session cookie, so nothing is appended to it (D549 22).
27385
+ */
27236
27386
  playbackUrl: string(),
27387
+ /**
27388
+ * How to play {@link playbackUrl}. Absent means `hls` — the shape every
27389
+ * existing consumer already assumes. A player that branches on this is the
27390
+ * one change a native clip needs; a player that ignores it will hand an MP4
27391
+ * to hls.js and fail parsing it as a manifest.
27392
+ */
27393
+ format: _enum(["hls", "mp4"]).optional(),
27394
+ /**
27395
+ * Which twin was actually served. A clip that holds only one stream answers
27396
+ * with the one it has, and the surface SAYS so — a missing main twin is
27397
+ * never served silently as if it were the asked-for quality (D549 15).
27398
+ */
27399
+ served: CamProfileSchema.optional(),
27237
27400
  /** Optional LAN/remote alternates for the same clip. */
27238
27401
  playbackEndpoints: array(string()).optional(),
27239
27402
  token: string().optional()
27240
27403
  });
27241
- DeviceType.Camera, method(object({
27242
- deviceId: number(),
27243
- since: number(),
27244
- until: number(),
27245
- limit: number().int().positive().optional()
27246
- }), array(ClipSchema).readonly(), {
27247
- kind: "query",
27248
- auth: "admin"
27249
- }), method(object({
27250
- deviceId: number(),
27251
- clipId: string()
27252
- }), ClipPlaybackSchema, {
27253
- kind: "query",
27254
- auth: "admin"
27404
+ /**
27405
+ * Why a source cannot answer right now — per SOURCE, never fleet-wide.
27406
+ *
27407
+ * `ok` is the only state whose clip list may be read as complete. The other
27408
+ * three exist because an empty list from a sleeping camera reads as "this
27409
+ * camera has no recordings", which is the defect this whole line of work is
27410
+ * about: a battery camera nobody woke (`sleeping`), a camera that could not be
27411
+ * reached at all (`unreachable`, also what a provider that THREW reports), a
27412
+ * camera whose SD card is not mounted (`no-storage`, measured on 640 —
27413
+ * `HddInfo mount 0`, honestly nothing to list rather than "no clips"), and a
27414
+ * camera whose OWN index disagrees with its OWN calendar (`index-empty`,
27415
+ * measured on 618: the calendar marks 3–20 September, days 6–20 list zero
27416
+ * files on both streams and both filters, with 177 GB free). That last one is
27417
+ * a defect ON THE CAMERA, and the only honest thing a provider can do is say
27418
+ * which days it asked for and got nothing — "no clips" would be a lie about a
27419
+ * card that is full of them.
27420
+ */
27421
+ var ClipSourceAvailabilitySchema = object({
27422
+ state: _enum([
27423
+ "ok",
27424
+ "sleeping",
27425
+ "unreachable",
27426
+ "no-storage",
27427
+ "index-empty"
27428
+ ]),
27429
+ /** Free text, shown verbatim. Names the camera's own refusal when there is one. */
27430
+ reason: string().optional(),
27431
+ /** When this source's catalog was last CONFIRMED. A cached list is never
27432
+ * drawn as current: the surface shows the age whenever it is older than the
27433
+ * refresh interval. */
27434
+ catalogAsOf: number().optional()
27255
27435
  });
27256
27436
  /**
27437
+ * One SOURCE of clips for a camera — a row of the picker, and the namespace
27438
+ * every clip id from it is prefixed with (`analytics`,
27439
+ * `native:reolink:onboard`, `hksv`, …).
27440
+ *
27441
+ * A provider lists the sources IT serves for that device, and answers for each
27442
+ * of them whether it can answer at all. A provider with nothing to offer on a
27443
+ * camera returns `[]` — it is not that camera's business.
27444
+ */
27445
+ var ClipSourceSchema = object({
27446
+ /** The value this source stamps on {@link ClipSchema.source}, and the prefix
27447
+ * of every clip id it mints. `getClipPlayback` routes on it. */
27448
+ source: string(),
27449
+ /** Operator-facing name of the source ("CamStack recordings", "SD card"). */
27450
+ label: string(),
27451
+ /**
27452
+ * The addon that SERVES this row.
27453
+ *
27454
+ * A surface cannot otherwise resolve a source to who answers it, and the
27455
+ * alternative — a `native:reolink:* → provider-reolink` table inside the
27456
+ * widget — is a second authority on provider identity living in the one
27457
+ * package with no business knowing it, wrong the day a third source appears
27458
+ * (D557). One addon may serve SEVERAL sources, which is why the per-device
27459
+ * switch is keyed by SOURCE and not by this (D555) — `addon-provider-reolink`
27460
+ * served a hub child two of them until the two views were measured to be one
27461
+ * store read twice (D555) and then read ONE way (D565).
27462
+ *
27463
+ * Optional for version skew only. The collection dispatcher stamps it from
27464
+ * the registry, so a row that travelled through the fan-out carries the
27465
+ * authoritative id whatever the provider filled in.
27466
+ */
27467
+ addonId: string().optional(),
27468
+ availability: ClipSourceAvailabilitySchema
27469
+ });
27470
+ var videoclipsCapability = {
27471
+ name: "videoclips",
27472
+ scope: "device",
27473
+ mode: "collection",
27474
+ kind: "wrapper",
27475
+ defaultActive: true,
27476
+ /** A clip is a window over a camera's footage — the cap is meaningless on a
27477
+ * sensor, a button or an event emitter, and the `defaultActive` auto-bind
27478
+ * reads this to decide which devices it may claim. */
27479
+ deviceTypes: [DeviceType.Camera],
27480
+ /**
27481
+ * The Clips section of a camera's device details is FRAMEWORK-DERIVED (D14):
27482
+ * the aggregator turns this declaration into the `type:'widget'` section and
27483
+ * `DeviceDetail.tsx` is never edited. `videoclips` is the first WRAPPER cap
27484
+ * to declare one — every previous `host/` widget cap is `deviceNative` — so
27485
+ * `device-config-widget-wrapped-binding.spec.ts` pins that a `kind:'wrapped'`
27486
+ * binding entry derives the same section a native one does.
27487
+ *
27488
+ * **It is a SECTION of the Recording tab, at the end of it — not a tab of
27489
+ * its own.** It shipped as a `clips` top-tab and the operator rejected the
27490
+ * placement: *"utilizzerei la stessa tab recordings, lì abbiamo già tutto il
27491
+ * necessario, una nuova sezione alla fine per le clips"*. The Recording tab
27492
+ * already holds the recorder's panel, the schedule bands and the unified
27493
+ * retention policy; footage the camera itself holds is the same question,
27494
+ * asked of a different store. `order: 100` puts it after all of them with
27495
+ * room left in front. The `clips` entry in `WELL_KNOWN_TABS` went with it —
27496
+ * a well-known id nobody declares is an invitation to mint the tab again.
27497
+ *
27498
+ * `topTab` stays: the browser owns a pane (a day's tiles, a source list and
27499
+ * a player) and the Config tab's inner bar has no room for one. The widget
27500
+ * itself is `host/clips-browser` in ui-library's `HOST_WIDGETS`, and because
27501
+ * the admin Recordings page renders every `location:'top-tab'` +
27502
+ * `tab:'recording'` section behind its camera picker
27503
+ * (`CameraRecordingSettingsSection`), this declaration lands the section on
27504
+ * BOTH surfaces with no second wiring.
27505
+ */
27506
+ deviceConfig: { ui: {
27507
+ kind: "widget",
27508
+ widgetId: "host/clips-browser",
27509
+ tab: "recording",
27510
+ topTab: true,
27511
+ label: "Clips",
27512
+ order: 100
27513
+ } },
27514
+ methods: {
27515
+ listClips: method(object({
27516
+ deviceId: number(),
27517
+ since: number(),
27518
+ until: number(),
27519
+ limit: number().int().positive().optional(),
27520
+ /**
27521
+ * WHICH provider to ask — the `addonId` a {@link ClipSourceSchema} row
27522
+ * carries, never a source id and never a list.
27523
+ *
27524
+ * Absent means the device's BOUND provider, which is CamStack on every
27525
+ * camera today because that is what `deviceManager.getBindings`
27526
+ * answers with. A provider the device is not bound to is refused by
27527
+ * name rather than answered by another one (D552's
27528
+ * `rejectUnresolvedAddonPin` rule).
27529
+ *
27530
+ * It replaced `sources?: string[]`, a VIEW filter over source ids that
27531
+ * assumed the answer was a fan-out over everything a camera has. The
27532
+ * operator settled otherwise on 2026-09-20 — *"il get videoclips
27533
+ * prendere un provider opzionale, di default va su camstack"*,
27534
+ * *"l'utilizzatore è uno solo"* — so the list is asked of one provider
27535
+ * at a time and there is nothing to filter out of it.
27536
+ */
27537
+ provider: string().optional()
27538
+ }), array(ClipSchema).readonly(), {
27539
+ kind: "query",
27540
+ auth: "protected"
27541
+ }),
27542
+ /**
27543
+ * The sources this camera has, WITH the reason any of them cannot answer.
27544
+ *
27545
+ * Asked separately from `listClips` because an empty clip list is
27546
+ * ambiguous and this is the only place the ambiguity is resolved: every
27547
+ * bound provider contributes its own rows, and a provider that could not
27548
+ * be reached at all still produces one row saying so. A surface that draws
27549
+ * "no clips" without reading this is drawing a guess.
27550
+ */
27551
+ listSources: method(object({ deviceId: number() }), array(ClipSourceSchema).readonly(), {
27552
+ kind: "query",
27553
+ auth: "protected"
27554
+ }),
27555
+ getClipPlayback: method(object({
27556
+ deviceId: number(),
27557
+ clipId: string(),
27558
+ /**
27559
+ * Which twin to serve, on the ONE quality scale the system already has
27560
+ * (`CamProfileSchema`). `low | mid` → the sub file, `high` → the main
27561
+ * twin; both ids are already on the row so this never re-searches the
27562
+ * camera. Absent means the provider's own default (the sub file, which
27563
+ * every source is measured to hold).
27564
+ *
27565
+ * `auto` is deliberately NOT accepted here: a stored file has no
27566
+ * broker session, so the adaptive tier cannot be resolved for it. The
27567
+ * viewer resolves `auto` to a profile the same way live does, before
27568
+ * it calls (D549 15).
27569
+ */
27570
+ profile: CamProfileSchema.optional()
27571
+ }), ClipPlaybackSchema, {
27572
+ kind: "query",
27573
+ auth: "protected"
27574
+ })
27575
+ }
27576
+ };
27577
+ /**
27257
27578
  * Optional client-side hints sent at session creation to help the provider
27258
27579
  * pick the best native source. All fields optional — a viewer that knows
27259
27580
  * nothing still gets a sane default. (Relocated from the retired `webrtc`
@@ -39233,6 +39554,12 @@ Object.freeze({
39233
39554
  addonId: null,
39234
39555
  access: "view"
39235
39556
  },
39557
+ "pipelineAnalytics.ownersWithMedia": {
39558
+ capName: "pipeline-analytics",
39559
+ capScope: "device",
39560
+ addonId: null,
39561
+ access: "view"
39562
+ },
39236
39563
  "pipelineAnalytics.pauseForStorageMigration": {
39237
39564
  capName: "pipeline-analytics",
39238
39565
  capScope: "device",
@@ -41825,6 +42152,12 @@ Object.freeze({
41825
42152
  addonId: null,
41826
42153
  access: "view"
41827
42154
  },
42155
+ "videoclips.listSources": {
42156
+ capName: "videoclips",
42157
+ capScope: "device",
42158
+ addonId: null,
42159
+ access: "view"
42160
+ },
41828
42161
  "viewerUi.getStaticDir": {
41829
42162
  capName: "viewer-ui",
41830
42163
  capScope: "system",
@@ -43127,6 +43460,11 @@ Object.freeze({
43127
43460
  form: "single",
43128
43461
  optional: false
43129
43462
  }],
43463
+ "pipelineAnalytics.ownersWithMedia": [{
43464
+ name: "deviceId",
43465
+ form: "single",
43466
+ optional: false
43467
+ }],
43130
43468
  "pipelineAnalytics.proposeRetrainAnnotations": [{
43131
43469
  name: "deviceId",
43132
43470
  form: "single",
@@ -43833,6 +44171,11 @@ Object.freeze({
43833
44171
  form: "single",
43834
44172
  optional: false
43835
44173
  }],
44174
+ "videoclips.listSources": [{
44175
+ name: "deviceId",
44176
+ form: "single",
44177
+ optional: false
44178
+ }],
43836
44179
  "waterHeater.setAway": [{
43837
44180
  name: "deviceId",
43838
44181
  form: "single",
@@ -45592,4 +45935,4 @@ function enumerateInferenceDevices(hw) {
45592
45935
  return out;
45593
45936
  }
45594
45937
  //#endregion
45595
- export { failureContributionCapability as $, hydrateSchema as $t, RingBuffer as A, runtimeDevices as At, declareLogChannel as B, buildFfmpegArgs as Bt, OpsLogEntrySchema as C, recordingExportCapability as Ct, RECORDING_EXPORT_MAX_READ_BYTES as D, resolveLocationMode as Dt, RATE_CONTROL_TIGHT as E, resolveEgressDecodeHwAccel as Et, audioKindId as F, supportedRuntimes as Ft, detectionPipelineCapability as G, CAM_PROFILE_ORDER as Gt, deriveBatteryPresence as H, isSoftwareDecode as Ht, batteryCapability as I, webrtcSessionCapability as It, enumerateInferenceDevices as J, audioChunkBytesPerSample as Jt, egressTranscodeSharingKey as K, DeviceFeature as Kt, cameraStreamsCapability as L, errMsg as Lt, addonWidgetsSourceCapability as M, storageOccupancyCapability as Mt, audioAnalysisCapability as N, streamBrokerCapability as Nt, RecordingConfigSchema as O, resolvePoolMemoryPolicy as Ot, audioAnalyzerCapability as P, stripRetiredBandPreBufferSec as Pt, evictionPolicyOfLocation as Q, expandAudioChunkToF32le as Qt, createHwAccelCache as R, AUDIO_PRESETS as Rt, NativeLeaseSettingsSchema as S, recordingCapability as St, RATE_CONTROL_RELAXED as T, resolveClusterStepModelId as Tt, deriveDetailCropRect as U, BOOT_RECOVERY_BACKOFF_MS as Ut, defaultDeviceFor as V, invocationFromEncodeProfile as Vt, deriveRecordingMode as W, BaseAddon as Wt, evaluateZoneRules as X, customAction as Xt, evaluateSensorEdge as Y, createEvent as Yt, evictionPolicyForMode as Z, defineCustomActions as Zt, FailureCounters as _, record as _n, pickDetailCropConvention as _t, COCO_80_LABELS as a, parseProfileBrokerId as an, logChannelsCapability as at, MOTION_CLOSE_AFTER_MS as b, EventCategory as bn, pipelineRunnerCapability as bt, DEFAULT_CLUSTER_STEP_MODELS as c, _enum as cn, mayReadLocation as ct, DEFAULT_EVENTS_BAND_BUFFER_SEC as d, discriminatedUnion as dn, modeMayWrite as dt, isEvent as en, gbToBytes as et, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as f, lazy as fn, motionDetectionCapability as ft, ExportRecordSchema as g, preprocess as gn, pickClusterStepSettings as gt, EncodeProfileSchema as h, object as hn, pickClusterStepModels as ht, BatteryStatusSchema as i, parseJsonUnknown as in, loadContributionCapability as it, YAMNET_TO_MACRO as j, storageEvictableCapability as jt, RecordingSignalStatusSchema as k, resolveRecordingProfiles as kt, DEFAULT_CLUSTER_STEP_SETTINGS as l, array as ln, mayWriteToLocation as lt, DEVICE_BACKEND_TO_FORMAT as m, number as mn, parseProcStatus as mt, AUDIO_BACKEND_CHOICES as n, makeSourceBrokerId as nn, inferModelProvider as nt, COCO_TO_MACRO as o, selectAssignedProfileSlots as on, mapAudioLabelToMacro as ot, DEFAULT_NATIVE_LEASE_SETTINGS as p, literal as pn, overlayClusterStepSettings as pt, egressTransportFromRequest as q, DeviceType as qt, AUDIO_MACRO_LABELS as r, nodePin as rn, isFirstLevelMacroClass as rt, DEFAULT_AUDIO_ANALYZER_CONFIG as s, sleep as sn, maskUrlCredentials as st, APPLE_SA_TO_MACRO as t, makeProfileBrokerId as tn, hfModelUrl as tt, DEFAULT_DETAIL_CROP_CONVENTION as u, boolean as un, migrateLegacyDeviceSignalConfig as ut, G711_SCALE_CORRECTION_DB as v, string as vn, pickNativeLeaseOverride as vt, PoolMemoryWatchdog as w, recordingSignalCapability as wt, NativeLeaseAdmissionSchema as x, rankStreams as xt, HF_BASE_URL as y, union as yn, pipelineExecutorCapability as yt, createLogChannelsProvider as z, Fmp4BoxSplitter as zt };
45938
+ export { evaluateZoneRules as $, createEvent as $t, RecordingConfigSchema as A, resolveLocationMode as At, cameraStreamsCapability as B, webrtcSessionCapability as Bt, NativeLeaseAdmissionSchema as C, union as Cn, pipelineRunnerCapability as Ct, RATE_CONTROL_RELAXED as D, recordingSignalCapability as Dt, PoolMemoryWatchdog as E, recordingExportCapability as Et, addonWidgetsSourceCapability as F, storageOccupancyCapability as Ft, deriveBatteryPresence as G, invocationFromEncodeProfile as Gt, createLogChannelsProvider as H, AUDIO_PRESETS as Ht, audioAnalysisCapability as I, streamBrokerCapability as It, detectionPipelineCapability as J, BaseAddon as Jt, deriveDetailCropRect as K, isSoftwareDecode as Kt, audioAnalyzerCapability as L, stripRetiredBandPreBufferSec as Lt, RingBuffer as M, resolveRecordingProfiles as Mt, VISIT_MERGE_GAP_MS as N, runtimeDevices as Nt, RATE_CONTROL_TIGHT as O, resolveClusterStepModelId as Ot, YAMNET_TO_MACRO as P, storageEvictableCapability as Pt, evaluateSensorEdge as Q, audioChunkBytesPerSample as Qt, audioKindId as R, supportedRuntimes as Rt, MOTION_CLOSE_AFTER_MS as S, string as Sn, pipelineExecutorCapability as St, OpsLogEntrySchema as T, recordingCapability as Tt, declareLogChannel as U, Fmp4BoxSplitter as Ut, createHwAccelCache as V, errMsg as Vt, defaultDeviceFor as W, buildFfmpegArgs as Wt, egressTransportFromRequest as X, DeviceFeature as Xt, egressTranscodeSharingKey as Y, CAM_PROFILE_ORDER as Yt, enumerateInferenceDevices as Z, DeviceType as Zt, EncodeProfileSchema as _, literal as _n, parseProcStatus as _t, COCO_80_LABELS as a, makeProfileBrokerId as an, inferModelProvider as at, G711_SCALE_CORRECTION_DB as b, preprocess as bn, pickDetailCropConvention as bt, DEFAULT_CLUSTER_STEP_MODELS as c, parseJsonUnknown as cn, logChannelsCapability as ct, DEFAULT_EVENTS_BAND_BUFFER_SEC as d, sleep as dn, mayReadLocation as dt, customAction as en, evictionPolicyForMode as et, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as f, _enum as fn, mayWriteToLocation as ft, EVENT_PAD_MS as g, lazy as gn, overlayClusterStepSettings as gt, EVENT_OWNER_TYPES as h, discriminatedUnion as hn, motionDetectionCapability as ht, BatteryStatusSchema as i, isEvent as in, hfModelUrl as it, RecordingSignalStatusSchema as j, resolvePoolMemoryPolicy as jt, RECORDING_EXPORT_MAX_READ_BYTES as k, resolveEgressDecodeHwAccel as kt, DEFAULT_CLUSTER_STEP_SETTINGS as l, parseProfileBrokerId as ln, mapAudioLabelToMacro as lt, DEVICE_BACKEND_TO_FORMAT as m, boolean as mn, modeMayWrite as mt, AUDIO_BACKEND_CHOICES as n, expandAudioChunkToF32le as nn, failureContributionCapability as nt, COCO_TO_MACRO as o, makeSourceBrokerId as on, isFirstLevelMacroClass as ot, DEFAULT_NATIVE_LEASE_SETTINGS as p, array as pn, migrateLegacyDeviceSignalConfig as pt, deriveRecordingMode as q, BOOT_RECOVERY_BACKOFF_MS as qt, AUDIO_MACRO_LABELS as r, hydrateSchema as rn, gbToBytes as rt, DEFAULT_AUDIO_ANALYZER_CONFIG as s, nodePin as sn, loadContributionCapability as st, APPLE_SA_TO_MACRO as t, defineCustomActions as tn, evictionPolicyOfLocation as tt, DEFAULT_DETAIL_CROP_CONVENTION as u, selectAssignedProfileSlots as un, maskUrlCredentials as ut, ExportRecordSchema as v, number as vn, pickClusterStepModels as vt, NativeLeaseSettingsSchema as w, EventCategory as wn, rankStreams as wt, HF_BASE_URL as x, record as xn, pickNativeLeaseOverride as xt, FailureCounters as y, object as yn, pickClusterStepSettings as yt, batteryCapability as z, videoclipsCapability as zt };