@camstack/addon-provider-dreame 0.2.89 → 0.2.92

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 (3) hide show
  1. package/dist/addon.js +208 -21
  2. package/dist/addon.mjs +208 -21
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -52672,7 +52672,7 @@ var DreameCameraStream = class extends TypedEmitter {
52672
52672
  }
52673
52673
  };
52674
52674
  //#endregion
52675
- //#region ../types/dist/event-category-CnLqLOKs.mjs
52675
+ //#region ../types/dist/event-category-DAXzJeTX.mjs
52676
52676
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
52677
52677
  EventCategory["SystemBoot"] = "system.boot";
52678
52678
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -53264,7 +53264,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
53264
53264
  * issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
53265
53265
  */
53266
53266
  EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
53267
- EventCategory["FrigateLiveEvent"] = "frigate.live-event";
53268
53267
  EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
53269
53268
  /**
53270
53269
  * Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
@@ -65298,7 +65297,7 @@ DeviceType.Camera;
65298
65297
  var SourceInfoSchema = object({
65299
65298
  /** Live dispatch key — mutable when the source system allows rename. */
65300
65299
  id: string(),
65301
- /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'frigate'. */
65300
+ /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
65302
65301
  system: string(),
65303
65302
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
65304
65303
  * Used to detect rename when `id` changes. */
@@ -65311,7 +65310,7 @@ var SourceInfoSchema = object({
65311
65310
  /**
65312
65311
  * Build the synthetic SourceInfo every existing provider falls back to
65313
65312
  * when no upstream value has been persisted. Keeps non-migrated providers
65314
- * (Reolink / Hikvision / ONVIF / Frigate / RTSP) functional without code
65313
+ * (Reolink / Hikvision / ONVIF / RTSP) functional without code
65315
65314
  * changes — `id` reuses the CamStack stableId, `system` reuses the addon
65316
65315
  * id. Real upstream identity replaces this once a provider migrates and
65317
65316
  * calls `updateSourceInfo()` with concrete values.
@@ -65990,7 +65989,7 @@ var deviceProviderCapability = {
65990
65989
  * - `device-management.router.ts` (deleted in Phase 2)
65991
65990
  * - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
65992
65991
  *
65993
- * All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
65992
+ * All device provider addons (rtsp, onvif, …) are hub-local: they may
65994
65993
  * fork into separate processes but never run on remote cluster agents. Therefore:
65995
65994
  * - No nodeId routing needed — this is a pure hub singleton.
65996
65995
  * - The hub's DeviceRegistry is the single source of truth for all live devices.
@@ -70038,7 +70037,7 @@ var NcRuleInputSchema = object({
70038
70037
  * The measured seven-person arrival on device 590 spans 110 s with every
70039
70038
  * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
70040
70039
  * idle cutoff holds it as one and ends it when the arrival actually ends.
70041
- * 30 is Frigate's shipped value for the same decision.
70040
+ * 30 s is a widely shipped value for the same decision.
70042
70041
  *
70043
70042
  * ### What it replaces
70044
70043
  *
@@ -72120,6 +72119,13 @@ var ZoneCrossingSchema = object({
72120
72119
  /** Zone display name at crossing time (falls back to the id). */
72121
72120
  zoneName: string().optional()
72122
72121
  });
72122
+ /** One zone a box was stamped with, and how much of the BOX fell inside it. */
72123
+ var ZoneOverlapSchema = object({
72124
+ zoneId: string(),
72125
+ zoneName: string().optional(),
72126
+ /** Percentage of the BOX area inside the zone, 0–100. */
72127
+ overlapPct: number()
72128
+ });
72123
72129
  var ObjectEventSchema = object({
72124
72130
  ...BaseEventFields,
72125
72131
  kind: literal("object"),
@@ -72144,6 +72150,35 @@ var ObjectEventSchema = object({
72144
72150
  bbox: BoundingBoxSchema.optional(),
72145
72151
  /** Heavy JSON — omitted in slim projection. */
72146
72152
  zones: array(string()).readonly().optional(),
72153
+ /**
72154
+ * How far inside each stamped zone the box actually was, as a percentage of
72155
+ * the BOX area.
72156
+ *
72157
+ * Membership alone cannot express "at least a third of it inside", which is
72158
+ * the bar an operator argues with — and the number already existed: the
72159
+ * engine computed it, the pipeline logged it, and then discarded it. It
72160
+ * matters most on the events that carry no track, where a rule has nothing
72161
+ * else to judge by.
72162
+ */
72163
+ zoneOverlaps: array(ZoneOverlapSchema).readonly().optional(),
72164
+ /**
72165
+ * Present when this event describes a detection the TRACKER refused, so it
72166
+ * has no track and never will.
72167
+ *
72168
+ * A zone-scoped immediate rule asks "is there an animal in the flowerbed
72169
+ * NOW?"; tracking answers a different question ("is this the same subject as
72170
+ * before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
72171
+ * dog at 0.7729, 100% inside a watched zone, was refused three times in six
72172
+ * seconds with three different candidate ids — seven analysed frames in the
72173
+ * window, the subject in a handful of them, metres apart — and produced no
72174
+ * event at all.
72175
+ *
72176
+ * It is NAMED rather than merely implied by a missing `trackId`: an event
72177
+ * with no track and no reason is indistinguishable from a track whose media
72178
+ * went missing, and a consumer that asks this one for a best shot or a
72179
+ * history is asking for something that never existed.
72180
+ */
72181
+ spawnRefused: string().optional(),
72147
72182
  /** Omitted in slim projection. */
72148
72183
  state: TrackStateSchema.optional(),
72149
72184
  /**
@@ -73217,6 +73252,60 @@ var NativeCropResultSchema = object({
73217
73252
  */
73218
73253
  tier: _enum(["native", "ram-fullframe"]).optional()
73219
73254
  });
73255
+ /**
73256
+ * What a PARKED frame is for — the `kind` half of the `(deviceId, trackId,
73257
+ * kind)` key ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
73258
+ *
73259
+ * - `keyFrame` — the track's clean best FULL frame at native width (capped by
73260
+ * the caller's `maxWidth`). What `keyFrame` + `keyFrameSmall` are written
73261
+ * from, and what the detail plane's full-frame rung cuts from.
73262
+ * - `thumbnail` — the best-shot subject slab: the caller's 16:9 central-square
73263
+ * window, cut by the runner at uncapped native resolution.
73264
+ *
73265
+ * The runner never interprets `trackId`; it is an opaque key the hub owns.
73266
+ */
73267
+ var ParkedFrameKindSchema = _enum(["keyFrame", "thumbnail"]);
73268
+ /**
73269
+ * Why a park did NOT happen. Every one is logged on the runner with
73270
+ * `tags: { deviceId }` and the handle's measured age, because a handle already
73271
+ * gone at park time IS the defect the 150–500 ms window exists to prevent —
73272
+ * never a reason to retry in a loop.
73273
+ *
73274
+ * - `handle-gone` — the native surface no longer resolves this handle (never
73275
+ * registered, past the lease bound, or the worker released it). `detail`
73276
+ * carries the runner's own miss reason.
73277
+ * - `encode-failed` — pixels resolved and the JPEG encode threw.
73278
+ */
73279
+ var ParkRefusalSchema = _enum(["handle-gone", "encode-failed"]);
73280
+ /** Answer to `parkTrackFrame` — a discriminated union, so "not parked" always names why. */
73281
+ var ParkTrackFrameResultSchema = discriminatedUnion("parked", [object({
73282
+ parked: literal(true),
73283
+ /** The node holding the parcel — what a later retrieval must be pinned to. */
73284
+ nodeId: string(),
73285
+ width: number().int().positive(),
73286
+ height: number().int().positive(),
73287
+ /** JPEG bytes the parcel costs on the node. */
73288
+ bytes: number().int().nonnegative(),
73289
+ /** Whether this park replaced a parcel already held for the key. */
73290
+ replaced: boolean()
73291
+ }), object({
73292
+ parked: literal(false),
73293
+ nodeId: string(),
73294
+ reason: ParkRefusalSchema,
73295
+ /** Age of the handle at the park, on the runner's clock; null if unknown. */
73296
+ handleAgeMs: number().nullable(),
73297
+ detail: string().optional()
73298
+ })]);
73299
+ /** A retrieved parcel — the runner's own JPEG, base64 for the wire. */
73300
+ var ParkedTrackFrameSchema = object({
73301
+ jpeg: string(),
73302
+ width: number().int().positive(),
73303
+ height: number().int().positive(),
73304
+ /** The frame instant the parcel shows (the caller's clock, echoed back). */
73305
+ timestamp: number(),
73306
+ /** When the node stored it (the node's clock). */
73307
+ parkedAt: number()
73308
+ });
73220
73309
  /** Parent detection context passed to `runDetailSubtree` — the crop's
73221
73310
  * originating detection, in FRAME-space coordinates. Reuses
73222
73311
  * `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
@@ -73606,7 +73695,7 @@ var RunnerCameraConfigSchema = object({
73606
73695
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
73607
73696
  * analyzer providers) running on decoded frames in this runner.
73608
73697
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
73609
- * analytics, Frigate motion). The provider emits ProviderMotion
73698
+ * analytics). The provider emits ProviderMotion
73610
73699
  * events; the orchestrator forwards to `reportMotion`.
73611
73700
  */
73612
73701
  motionSources: MotionSourcesSchema.default(["analyzer"]),
@@ -73848,7 +73937,26 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
73848
73937
  className: string(),
73849
73938
  /** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
73850
73939
  sourceDeviceId: number()
73851
- }), RunStatelessStepResultSchema, { kind: "mutation" });
73940
+ }), RunStatelessStepResultSchema, { kind: "mutation" }), method(object({
73941
+ deviceId: number(),
73942
+ /** Opaque to the runner — the hub's track id. */
73943
+ trackId: string(),
73944
+ kind: ParkedFrameKindSchema,
73945
+ handle: FrameHandleSchema,
73946
+ /** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
73947
+ bbox: NativeCropBboxSchema,
73948
+ /** Width cap for a full-frame park (the `keyFrame` native cap). */
73949
+ maxWidth: number().int().positive().optional(),
73950
+ /** The frame instant (caller's clock) — orders parks for one key. */
73951
+ timestamp: number()
73952
+ }), ParkTrackFrameResultSchema, { kind: "mutation" }), method(object({
73953
+ deviceId: number(),
73954
+ trackId: string(),
73955
+ kind: ParkedFrameKindSchema
73956
+ }), ParkedTrackFrameSchema.nullable()), method(object({
73957
+ deviceId: number(),
73958
+ trackId: string()
73959
+ }), object({ released: number().int().nonnegative() }), { kind: "mutation" });
73852
73960
  var CameraPipelineConfigSchema = object({
73853
73961
  engine: PipelineEngineChoiceSchema.optional(),
73854
73962
  steps: array(PipelineStepInputSchema).readonly(),
@@ -76918,8 +77026,8 @@ onStatusChanged: { data: object({
76918
77026
  /**
76919
77027
  * Runtime-state slice — every provider that registers this cap
76920
77028
  * stores the same shape under `device.runtimeState[battery]`.
76921
- * Cross-provider uniformity: a Reolink Argus, a Frigate sensor
76922
- * proxy, an ONVIF battery cam all read/write the same keys.
77029
+ * Cross-provider uniformity: a Reolink Argus, a sensor proxy,
77030
+ * an ONVIF battery cam all read/write the same keys.
76923
77031
  * Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
76924
77032
  * via `device.runtimeState.getCapState('battery')` regardless of
76925
77033
  * the underlying driver.
@@ -77069,7 +77177,7 @@ var buttonCapability = {
77069
77177
  *
77070
77178
  * Implementations:
77071
77179
  * - Each camera-providing addon registers this cap natively per
77072
- * device (Reolink, Hikvision, RTSP, Frigate, ONVIF self).
77180
+ * device (Reolink, Hikvision, RTSP, ONVIF self).
77073
77181
  * - Returns a snapshot from the persisted device config blob — no
77074
77182
  * extra round-trip to the camera, no probing.
77075
77183
  * - The cap is admin-only (`auth: 'admin'`) — credentials must not
@@ -79169,7 +79277,7 @@ var AvailableIntegrationTypeSchema = object({
79169
79277
  * Which integration-marker cap the addon declared, so the wizard can
79170
79278
  * branch on CAP — never on addon name. `device-adoption` integrations
79171
79279
  * (Home Assistant, …) route through the broker step (Approach A);
79172
- * `device-provider` integrations (Reolink/Frigate/ONVIF) keep the
79280
+ * `device-provider` integrations (Reolink/ONVIF) keep the
79173
79281
  * legacy config → discovery flow.
79174
79282
  */
79175
79283
  kind: _enum(["device-adoption", "device-provider"]),
@@ -82741,13 +82849,31 @@ var RecordingManifestSchema = object({
82741
82849
  */
82742
82850
  playbackEndpoints: array(string())
82743
82851
  });
82744
- /** Recording storage usage for one camera (bytes on disk across all its
82745
- * profiles/subtrees/locations on this node). */
82852
+ /**
82853
+ * Recording storage usage for one camera — what the ARCHIVE holds for it,
82854
+ * across every profile and every resolvable location on this node.
82855
+ *
82856
+ * ## Archive vs residency, which is the whole point of this shape (D418)
82857
+ *
82858
+ * `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
82859
+ * the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
82860
+ * this camera writes to, so the two can be added up and compared.
82861
+ *
82862
+ * They were not always. Until D418 this row came from the recorder's in-RAM
82863
+ * `RecordingIndex`, which since D287 holds only the live tail plus the hours
82864
+ * somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
82865
+ * 60.5 GB and "oldest: three hours ago" on the same page as the volume row
82866
+ * that said otherwise, and two people read it as retention eating recent
82867
+ * footage. Residency is still reported, under `residentBytes` /
82868
+ * `residentOldestMs`, which answer a different question and say so.
82869
+ */
82746
82870
  var RecordingDeviceUsageSchema = object({
82747
82871
  deviceId: number(),
82872
+ /** Bytes the ARCHIVE holds for this camera on this node's resolvable
82873
+ * recordings locations. */
82748
82874
  usedBytes: number(),
82749
82875
  /**
82750
- * Start of this camera's OLDEST indexed segment, across every profile and
82876
+ * Start of this camera's OLDEST ARCHIVED segment, across every profile and
82751
82877
  * location — the "Oldest footage" column in Recordings → Storage, and the
82752
82878
  * only honest answer to "is retention actually holding?" per camera.
82753
82879
  *
@@ -82757,7 +82883,24 @@ var RecordingDeviceUsageSchema = object({
82757
82883
  * (types) and the addon ship on different trains, and the addon is usually
82758
82884
  * the later of the two.
82759
82885
  */
82760
- oldestMs: number().nullable().optional()
82886
+ oldestMs: number().nullable().optional(),
82887
+ /** Segments the archive holds for this camera — the "M" beside `usedBytes`.
82888
+ * OPTIONAL for the same train-skew reason as `oldestMs`. */
82889
+ segments: number().optional(),
82890
+ /**
82891
+ * RESIDENCY, not the archive: bytes the recorder process currently holds in
82892
+ * its RAM index — the live tail plus the hours a reader hydrated.
82893
+ *
82894
+ * It answers "what can be served without touching the disk", never "how much
82895
+ * footage this camera has". A UI that renders it must label it as such, and
82896
+ * must never total it as storage. OPTIONAL: a recorder predating D418 omits
82897
+ * it, and so does a node whose ledger could not answer.
82898
+ */
82899
+ residentBytes: number().optional(),
82900
+ /** The residency counterpart of `oldestMs` — the oldest segment currently in
82901
+ * RAM, which on a healthy recorder is minutes ago and means nothing about
82902
+ * retention. `null` = nothing resident. */
82903
+ residentOldestMs: number().nullable().optional()
82761
82904
  });
82762
82905
  /** Recording storage usage + capacity for one storage location. */
82763
82906
  var RecordingLocationUsageSchema = object({
@@ -82795,6 +82938,17 @@ var RecordingStorageUsageSchema = object({
82795
82938
  totalUsedBytes: number(),
82796
82939
  devices: array(RecordingDeviceUsageSchema),
82797
82940
  /**
82941
+ * WHERE `devices[]` came from, so an empty table is never mistaken for empty
82942
+ * disks (D418).
82943
+ *
82944
+ * `archive` = the durable hour ledger answered. `unavailable` = this node
82945
+ * declared no ledger and the recorder REFUSED rather than answering the
82946
+ * question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
82947
+ * zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
82948
+ * and its rows are residency.
82949
+ */
82950
+ devicesRead: _enum(["archive", "unavailable"]).optional(),
82951
+ /**
82798
82952
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
82799
82953
  * of the payload without it: the hub serves this method through a BAKED
82800
82954
  * router, so a hub whose framework train predates a change to this array
@@ -86674,7 +86828,7 @@ function toDeviceSummary(device, addonId) {
86674
86828
  };
86675
86829
  }
86676
86830
  /**
86677
- * Base class for device-provider addons (rtsp, onvif, frigate).
86831
+ * Base class for device-provider addons (rtsp, onvif).
86678
86832
  *
86679
86833
  * Provides default implementations for the common device-provider cap
86680
86834
  * methods (`start`, `stop`, `getStatus`, `getDevices`, `supportsDiscovery`,
@@ -91330,6 +91484,24 @@ Object.freeze({
91330
91484
  addonId: null,
91331
91485
  access: "view"
91332
91486
  },
91487
+ "pipelineRunner.getParkedTrackFrame": {
91488
+ capName: "pipeline-runner",
91489
+ capScope: "system",
91490
+ addonId: null,
91491
+ access: "view"
91492
+ },
91493
+ "pipelineRunner.parkTrackFrame": {
91494
+ capName: "pipeline-runner",
91495
+ capScope: "system",
91496
+ addonId: null,
91497
+ access: "create"
91498
+ },
91499
+ "pipelineRunner.releaseParkedTrackFrames": {
91500
+ capName: "pipeline-runner",
91501
+ capScope: "system",
91502
+ addonId: null,
91503
+ access: "create"
91504
+ },
91333
91505
  "pipelineRunner.reportMotion": {
91334
91506
  capName: "pipeline-runner",
91335
91507
  capScope: "system",
@@ -94607,6 +94779,21 @@ Object.freeze({
94607
94779
  form: "single",
94608
94780
  optional: false
94609
94781
  }],
94782
+ "pipelineRunner.getParkedTrackFrame": [{
94783
+ name: "deviceId",
94784
+ form: "single",
94785
+ optional: false
94786
+ }],
94787
+ "pipelineRunner.parkTrackFrame": [{
94788
+ name: "deviceId",
94789
+ form: "single",
94790
+ optional: false
94791
+ }],
94792
+ "pipelineRunner.releaseParkedTrackFrames": [{
94793
+ name: "deviceId",
94794
+ form: "single",
94795
+ optional: false
94796
+ }],
94610
94797
  "pipelineRunner.reportMotion": [{
94611
94798
  name: "deviceId",
94612
94799
  form: "single",
@@ -95298,7 +95485,7 @@ var PreviewTextField = string().max(200);
95298
95485
  * Whether the notification's preview is a STILL or a short animation.
95299
95486
  *
95300
95487
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
95301
- * rule)"* — his Scrypted advanced-notifier has a `gifRule`, and a ten-hour
95488
+ * rule)"* — the other rules already offer an animated preview, and a ten-hour
95302
95489
  * night reads better as three seconds of motion than as one frame of it. Both
95303
95490
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
95304
95491
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -143943,9 +144130,9 @@ var { mulaw, alaw } = resolveAlawmulaw();
143943
144130
  //#endregion
143944
144131
  //#region src/devices/dreame-rfc4571-server.ts
143945
144132
  /**
143946
- * RFC 4571 (framed RTP over TCP) output for the robot camera — the shape the
143947
- * Scrypted plugin (`scrypted-dreame-native/src/rfc4571.ts`) proved on this
143948
- * robot, ported: nodedreame's `DreameCameraStream` speaks the LinkVisual relay
144133
+ * RFC 4571 (framed RTP over TCP) output for the robot camera — the shape
144134
+ * already proven on this robot: nodedreame's `DreameCameraStream` speaks the
144135
+ * LinkVisual relay
143949
144136
  * and emits H.264 access units + AAC (ADTS); nodelink's `Rfc4571Muxer` frames
143950
144137
  * them as RTP on a local TCP server the stream-broker dials as a
143951
144138
  * `pull-rfc4571` source, exactly like a Reolink Baichuan camera.
package/dist/addon.mjs CHANGED
@@ -52669,7 +52669,7 @@ var DreameCameraStream = class extends TypedEmitter {
52669
52669
  }
52670
52670
  };
52671
52671
  //#endregion
52672
- //#region ../types/dist/event-category-CnLqLOKs.mjs
52672
+ //#region ../types/dist/event-category-DAXzJeTX.mjs
52673
52673
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
52674
52674
  EventCategory["SystemBoot"] = "system.boot";
52675
52675
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -53261,7 +53261,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
53261
53261
  * issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
53262
53262
  */
53263
53263
  EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
53264
- EventCategory["FrigateLiveEvent"] = "frigate.live-event";
53265
53264
  EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
53266
53265
  /**
53267
53266
  * Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
@@ -65295,7 +65294,7 @@ DeviceType.Camera;
65295
65294
  var SourceInfoSchema = object({
65296
65295
  /** Live dispatch key — mutable when the source system allows rename. */
65297
65296
  id: string(),
65298
- /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'frigate'. */
65297
+ /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
65299
65298
  system: string(),
65300
65299
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
65301
65300
  * Used to detect rename when `id` changes. */
@@ -65308,7 +65307,7 @@ var SourceInfoSchema = object({
65308
65307
  /**
65309
65308
  * Build the synthetic SourceInfo every existing provider falls back to
65310
65309
  * when no upstream value has been persisted. Keeps non-migrated providers
65311
- * (Reolink / Hikvision / ONVIF / Frigate / RTSP) functional without code
65310
+ * (Reolink / Hikvision / ONVIF / RTSP) functional without code
65312
65311
  * changes — `id` reuses the CamStack stableId, `system` reuses the addon
65313
65312
  * id. Real upstream identity replaces this once a provider migrates and
65314
65313
  * calls `updateSourceInfo()` with concrete values.
@@ -65987,7 +65986,7 @@ var deviceProviderCapability = {
65987
65986
  * - `device-management.router.ts` (deleted in Phase 2)
65988
65987
  * - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
65989
65988
  *
65990
- * All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
65989
+ * All device provider addons (rtsp, onvif, …) are hub-local: they may
65991
65990
  * fork into separate processes but never run on remote cluster agents. Therefore:
65992
65991
  * - No nodeId routing needed — this is a pure hub singleton.
65993
65992
  * - The hub's DeviceRegistry is the single source of truth for all live devices.
@@ -70035,7 +70034,7 @@ var NcRuleInputSchema = object({
70035
70034
  * The measured seven-person arrival on device 590 spans 110 s with every
70036
70035
  * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
70037
70036
  * idle cutoff holds it as one and ends it when the arrival actually ends.
70038
- * 30 is Frigate's shipped value for the same decision.
70037
+ * 30 s is a widely shipped value for the same decision.
70039
70038
  *
70040
70039
  * ### What it replaces
70041
70040
  *
@@ -72117,6 +72116,13 @@ var ZoneCrossingSchema = object({
72117
72116
  /** Zone display name at crossing time (falls back to the id). */
72118
72117
  zoneName: string().optional()
72119
72118
  });
72119
+ /** One zone a box was stamped with, and how much of the BOX fell inside it. */
72120
+ var ZoneOverlapSchema = object({
72121
+ zoneId: string(),
72122
+ zoneName: string().optional(),
72123
+ /** Percentage of the BOX area inside the zone, 0–100. */
72124
+ overlapPct: number()
72125
+ });
72120
72126
  var ObjectEventSchema = object({
72121
72127
  ...BaseEventFields,
72122
72128
  kind: literal("object"),
@@ -72141,6 +72147,35 @@ var ObjectEventSchema = object({
72141
72147
  bbox: BoundingBoxSchema.optional(),
72142
72148
  /** Heavy JSON — omitted in slim projection. */
72143
72149
  zones: array(string()).readonly().optional(),
72150
+ /**
72151
+ * How far inside each stamped zone the box actually was, as a percentage of
72152
+ * the BOX area.
72153
+ *
72154
+ * Membership alone cannot express "at least a third of it inside", which is
72155
+ * the bar an operator argues with — and the number already existed: the
72156
+ * engine computed it, the pipeline logged it, and then discarded it. It
72157
+ * matters most on the events that carry no track, where a rule has nothing
72158
+ * else to judge by.
72159
+ */
72160
+ zoneOverlaps: array(ZoneOverlapSchema).readonly().optional(),
72161
+ /**
72162
+ * Present when this event describes a detection the TRACKER refused, so it
72163
+ * has no track and never will.
72164
+ *
72165
+ * A zone-scoped immediate rule asks "is there an animal in the flowerbed
72166
+ * NOW?"; tracking answers a different question ("is this the same subject as
72167
+ * before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
72168
+ * dog at 0.7729, 100% inside a watched zone, was refused three times in six
72169
+ * seconds with three different candidate ids — seven analysed frames in the
72170
+ * window, the subject in a handful of them, metres apart — and produced no
72171
+ * event at all.
72172
+ *
72173
+ * It is NAMED rather than merely implied by a missing `trackId`: an event
72174
+ * with no track and no reason is indistinguishable from a track whose media
72175
+ * went missing, and a consumer that asks this one for a best shot or a
72176
+ * history is asking for something that never existed.
72177
+ */
72178
+ spawnRefused: string().optional(),
72144
72179
  /** Omitted in slim projection. */
72145
72180
  state: TrackStateSchema.optional(),
72146
72181
  /**
@@ -73214,6 +73249,60 @@ var NativeCropResultSchema = object({
73214
73249
  */
73215
73250
  tier: _enum(["native", "ram-fullframe"]).optional()
73216
73251
  });
73252
+ /**
73253
+ * What a PARKED frame is for — the `kind` half of the `(deviceId, trackId,
73254
+ * kind)` key ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
73255
+ *
73256
+ * - `keyFrame` — the track's clean best FULL frame at native width (capped by
73257
+ * the caller's `maxWidth`). What `keyFrame` + `keyFrameSmall` are written
73258
+ * from, and what the detail plane's full-frame rung cuts from.
73259
+ * - `thumbnail` — the best-shot subject slab: the caller's 16:9 central-square
73260
+ * window, cut by the runner at uncapped native resolution.
73261
+ *
73262
+ * The runner never interprets `trackId`; it is an opaque key the hub owns.
73263
+ */
73264
+ var ParkedFrameKindSchema = _enum(["keyFrame", "thumbnail"]);
73265
+ /**
73266
+ * Why a park did NOT happen. Every one is logged on the runner with
73267
+ * `tags: { deviceId }` and the handle's measured age, because a handle already
73268
+ * gone at park time IS the defect the 150–500 ms window exists to prevent —
73269
+ * never a reason to retry in a loop.
73270
+ *
73271
+ * - `handle-gone` — the native surface no longer resolves this handle (never
73272
+ * registered, past the lease bound, or the worker released it). `detail`
73273
+ * carries the runner's own miss reason.
73274
+ * - `encode-failed` — pixels resolved and the JPEG encode threw.
73275
+ */
73276
+ var ParkRefusalSchema = _enum(["handle-gone", "encode-failed"]);
73277
+ /** Answer to `parkTrackFrame` — a discriminated union, so "not parked" always names why. */
73278
+ var ParkTrackFrameResultSchema = discriminatedUnion("parked", [object({
73279
+ parked: literal(true),
73280
+ /** The node holding the parcel — what a later retrieval must be pinned to. */
73281
+ nodeId: string(),
73282
+ width: number().int().positive(),
73283
+ height: number().int().positive(),
73284
+ /** JPEG bytes the parcel costs on the node. */
73285
+ bytes: number().int().nonnegative(),
73286
+ /** Whether this park replaced a parcel already held for the key. */
73287
+ replaced: boolean()
73288
+ }), object({
73289
+ parked: literal(false),
73290
+ nodeId: string(),
73291
+ reason: ParkRefusalSchema,
73292
+ /** Age of the handle at the park, on the runner's clock; null if unknown. */
73293
+ handleAgeMs: number().nullable(),
73294
+ detail: string().optional()
73295
+ })]);
73296
+ /** A retrieved parcel — the runner's own JPEG, base64 for the wire. */
73297
+ var ParkedTrackFrameSchema = object({
73298
+ jpeg: string(),
73299
+ width: number().int().positive(),
73300
+ height: number().int().positive(),
73301
+ /** The frame instant the parcel shows (the caller's clock, echoed back). */
73302
+ timestamp: number(),
73303
+ /** When the node stored it (the node's clock). */
73304
+ parkedAt: number()
73305
+ });
73217
73306
  /** Parent detection context passed to `runDetailSubtree` — the crop's
73218
73307
  * originating detection, in FRAME-space coordinates. Reuses
73219
73308
  * `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
@@ -73603,7 +73692,7 @@ var RunnerCameraConfigSchema = object({
73603
73692
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
73604
73693
  * analyzer providers) running on decoded frames in this runner.
73605
73694
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
73606
- * analytics, Frigate motion). The provider emits ProviderMotion
73695
+ * analytics). The provider emits ProviderMotion
73607
73696
  * events; the orchestrator forwards to `reportMotion`.
73608
73697
  */
73609
73698
  motionSources: MotionSourcesSchema.default(["analyzer"]),
@@ -73845,7 +73934,26 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
73845
73934
  className: string(),
73846
73935
  /** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
73847
73936
  sourceDeviceId: number()
73848
- }), RunStatelessStepResultSchema, { kind: "mutation" });
73937
+ }), RunStatelessStepResultSchema, { kind: "mutation" }), method(object({
73938
+ deviceId: number(),
73939
+ /** Opaque to the runner — the hub's track id. */
73940
+ trackId: string(),
73941
+ kind: ParkedFrameKindSchema,
73942
+ handle: FrameHandleSchema,
73943
+ /** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
73944
+ bbox: NativeCropBboxSchema,
73945
+ /** Width cap for a full-frame park (the `keyFrame` native cap). */
73946
+ maxWidth: number().int().positive().optional(),
73947
+ /** The frame instant (caller's clock) — orders parks for one key. */
73948
+ timestamp: number()
73949
+ }), ParkTrackFrameResultSchema, { kind: "mutation" }), method(object({
73950
+ deviceId: number(),
73951
+ trackId: string(),
73952
+ kind: ParkedFrameKindSchema
73953
+ }), ParkedTrackFrameSchema.nullable()), method(object({
73954
+ deviceId: number(),
73955
+ trackId: string()
73956
+ }), object({ released: number().int().nonnegative() }), { kind: "mutation" });
73849
73957
  var CameraPipelineConfigSchema = object({
73850
73958
  engine: PipelineEngineChoiceSchema.optional(),
73851
73959
  steps: array(PipelineStepInputSchema).readonly(),
@@ -76915,8 +77023,8 @@ onStatusChanged: { data: object({
76915
77023
  /**
76916
77024
  * Runtime-state slice — every provider that registers this cap
76917
77025
  * stores the same shape under `device.runtimeState[battery]`.
76918
- * Cross-provider uniformity: a Reolink Argus, a Frigate sensor
76919
- * proxy, an ONVIF battery cam all read/write the same keys.
77026
+ * Cross-provider uniformity: a Reolink Argus, a sensor proxy,
77027
+ * an ONVIF battery cam all read/write the same keys.
76920
77028
  * Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
76921
77029
  * via `device.runtimeState.getCapState('battery')` regardless of
76922
77030
  * the underlying driver.
@@ -77066,7 +77174,7 @@ var buttonCapability = {
77066
77174
  *
77067
77175
  * Implementations:
77068
77176
  * - Each camera-providing addon registers this cap natively per
77069
- * device (Reolink, Hikvision, RTSP, Frigate, ONVIF self).
77177
+ * device (Reolink, Hikvision, RTSP, ONVIF self).
77070
77178
  * - Returns a snapshot from the persisted device config blob — no
77071
77179
  * extra round-trip to the camera, no probing.
77072
77180
  * - The cap is admin-only (`auth: 'admin'`) — credentials must not
@@ -79166,7 +79274,7 @@ var AvailableIntegrationTypeSchema = object({
79166
79274
  * Which integration-marker cap the addon declared, so the wizard can
79167
79275
  * branch on CAP — never on addon name. `device-adoption` integrations
79168
79276
  * (Home Assistant, …) route through the broker step (Approach A);
79169
- * `device-provider` integrations (Reolink/Frigate/ONVIF) keep the
79277
+ * `device-provider` integrations (Reolink/ONVIF) keep the
79170
79278
  * legacy config → discovery flow.
79171
79279
  */
79172
79280
  kind: _enum(["device-adoption", "device-provider"]),
@@ -82738,13 +82846,31 @@ var RecordingManifestSchema = object({
82738
82846
  */
82739
82847
  playbackEndpoints: array(string())
82740
82848
  });
82741
- /** Recording storage usage for one camera (bytes on disk across all its
82742
- * profiles/subtrees/locations on this node). */
82849
+ /**
82850
+ * Recording storage usage for one camera — what the ARCHIVE holds for it,
82851
+ * across every profile and every resolvable location on this node.
82852
+ *
82853
+ * ## Archive vs residency, which is the whole point of this shape (D418)
82854
+ *
82855
+ * `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
82856
+ * the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
82857
+ * this camera writes to, so the two can be added up and compared.
82858
+ *
82859
+ * They were not always. Until D418 this row came from the recorder's in-RAM
82860
+ * `RecordingIndex`, which since D287 holds only the live tail plus the hours
82861
+ * somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
82862
+ * 60.5 GB and "oldest: three hours ago" on the same page as the volume row
82863
+ * that said otherwise, and two people read it as retention eating recent
82864
+ * footage. Residency is still reported, under `residentBytes` /
82865
+ * `residentOldestMs`, which answer a different question and say so.
82866
+ */
82743
82867
  var RecordingDeviceUsageSchema = object({
82744
82868
  deviceId: number(),
82869
+ /** Bytes the ARCHIVE holds for this camera on this node's resolvable
82870
+ * recordings locations. */
82745
82871
  usedBytes: number(),
82746
82872
  /**
82747
- * Start of this camera's OLDEST indexed segment, across every profile and
82873
+ * Start of this camera's OLDEST ARCHIVED segment, across every profile and
82748
82874
  * location — the "Oldest footage" column in Recordings → Storage, and the
82749
82875
  * only honest answer to "is retention actually holding?" per camera.
82750
82876
  *
@@ -82754,7 +82880,24 @@ var RecordingDeviceUsageSchema = object({
82754
82880
  * (types) and the addon ship on different trains, and the addon is usually
82755
82881
  * the later of the two.
82756
82882
  */
82757
- oldestMs: number().nullable().optional()
82883
+ oldestMs: number().nullable().optional(),
82884
+ /** Segments the archive holds for this camera — the "M" beside `usedBytes`.
82885
+ * OPTIONAL for the same train-skew reason as `oldestMs`. */
82886
+ segments: number().optional(),
82887
+ /**
82888
+ * RESIDENCY, not the archive: bytes the recorder process currently holds in
82889
+ * its RAM index — the live tail plus the hours a reader hydrated.
82890
+ *
82891
+ * It answers "what can be served without touching the disk", never "how much
82892
+ * footage this camera has". A UI that renders it must label it as such, and
82893
+ * must never total it as storage. OPTIONAL: a recorder predating D418 omits
82894
+ * it, and so does a node whose ledger could not answer.
82895
+ */
82896
+ residentBytes: number().optional(),
82897
+ /** The residency counterpart of `oldestMs` — the oldest segment currently in
82898
+ * RAM, which on a healthy recorder is minutes ago and means nothing about
82899
+ * retention. `null` = nothing resident. */
82900
+ residentOldestMs: number().nullable().optional()
82758
82901
  });
82759
82902
  /** Recording storage usage + capacity for one storage location. */
82760
82903
  var RecordingLocationUsageSchema = object({
@@ -82792,6 +82935,17 @@ var RecordingStorageUsageSchema = object({
82792
82935
  totalUsedBytes: number(),
82793
82936
  devices: array(RecordingDeviceUsageSchema),
82794
82937
  /**
82938
+ * WHERE `devices[]` came from, so an empty table is never mistaken for empty
82939
+ * disks (D418).
82940
+ *
82941
+ * `archive` = the durable hour ledger answered. `unavailable` = this node
82942
+ * declared no ledger and the recorder REFUSED rather than answering the
82943
+ * question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
82944
+ * zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
82945
+ * and its rows are residency.
82946
+ */
82947
+ devicesRead: _enum(["archive", "unavailable"]).optional(),
82948
+ /**
82795
82949
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
82796
82950
  * of the payload without it: the hub serves this method through a BAKED
82797
82951
  * router, so a hub whose framework train predates a change to this array
@@ -86671,7 +86825,7 @@ function toDeviceSummary(device, addonId) {
86671
86825
  };
86672
86826
  }
86673
86827
  /**
86674
- * Base class for device-provider addons (rtsp, onvif, frigate).
86828
+ * Base class for device-provider addons (rtsp, onvif).
86675
86829
  *
86676
86830
  * Provides default implementations for the common device-provider cap
86677
86831
  * methods (`start`, `stop`, `getStatus`, `getDevices`, `supportsDiscovery`,
@@ -91327,6 +91481,24 @@ Object.freeze({
91327
91481
  addonId: null,
91328
91482
  access: "view"
91329
91483
  },
91484
+ "pipelineRunner.getParkedTrackFrame": {
91485
+ capName: "pipeline-runner",
91486
+ capScope: "system",
91487
+ addonId: null,
91488
+ access: "view"
91489
+ },
91490
+ "pipelineRunner.parkTrackFrame": {
91491
+ capName: "pipeline-runner",
91492
+ capScope: "system",
91493
+ addonId: null,
91494
+ access: "create"
91495
+ },
91496
+ "pipelineRunner.releaseParkedTrackFrames": {
91497
+ capName: "pipeline-runner",
91498
+ capScope: "system",
91499
+ addonId: null,
91500
+ access: "create"
91501
+ },
91330
91502
  "pipelineRunner.reportMotion": {
91331
91503
  capName: "pipeline-runner",
91332
91504
  capScope: "system",
@@ -94604,6 +94776,21 @@ Object.freeze({
94604
94776
  form: "single",
94605
94777
  optional: false
94606
94778
  }],
94779
+ "pipelineRunner.getParkedTrackFrame": [{
94780
+ name: "deviceId",
94781
+ form: "single",
94782
+ optional: false
94783
+ }],
94784
+ "pipelineRunner.parkTrackFrame": [{
94785
+ name: "deviceId",
94786
+ form: "single",
94787
+ optional: false
94788
+ }],
94789
+ "pipelineRunner.releaseParkedTrackFrames": [{
94790
+ name: "deviceId",
94791
+ form: "single",
94792
+ optional: false
94793
+ }],
94607
94794
  "pipelineRunner.reportMotion": [{
94608
94795
  name: "deviceId",
94609
94796
  form: "single",
@@ -95295,7 +95482,7 @@ var PreviewTextField = string().max(200);
95295
95482
  * Whether the notification's preview is a STILL or a short animation.
95296
95483
  *
95297
95484
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
95298
- * rule)"* — his Scrypted advanced-notifier has a `gifRule`, and a ten-hour
95485
+ * rule)"* — the other rules already offer an animated preview, and a ten-hour
95299
95486
  * night reads better as three seconds of motion than as one frame of it. Both
95300
95487
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
95301
95488
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -143940,9 +144127,9 @@ var { mulaw, alaw } = resolveAlawmulaw();
143940
144127
  //#endregion
143941
144128
  //#region src/devices/dreame-rfc4571-server.ts
143942
144129
  /**
143943
- * RFC 4571 (framed RTP over TCP) output for the robot camera — the shape the
143944
- * Scrypted plugin (`scrypted-dreame-native/src/rfc4571.ts`) proved on this
143945
- * robot, ported: nodedreame's `DreameCameraStream` speaks the LinkVisual relay
144130
+ * RFC 4571 (framed RTP over TCP) output for the robot camera — the shape
144131
+ * already proven on this robot: nodedreame's `DreameCameraStream` speaks the
144132
+ * LinkVisual relay
143946
144133
  * and emits H.264 access units + AAC (ADTS); nodelink's `Rfc4571Muxer` frames
143947
144134
  * them as RTP on a local TCP server the stream-broker dials as a
143948
144135
  * `pull-rfc4571` source, exactly like a Reolink Baichuan camera.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-dreame",
3
- "version": "0.2.89",
3
+ "version": "0.2.92",
4
4
  "description": "Dreame robot-vacuum / lawn-mower device-provider addon for CamStack — wraps the @apocaliss92/nodedreame Dreamehome cloud client",
5
5
  "keywords": [
6
6
  "camstack",