@camstack/addon-matter-broker 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 +246 -22
  2. package/dist/addon.mjs +246 -22
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -13,7 +13,7 @@ let node_stream_promises = require("node:stream/promises");
13
13
  let node_net = require("node:net");
14
14
  let node_dgram = require("node:dgram");
15
15
  node_dgram = require_esm.__toESM(node_dgram, 1);
16
- //#region ../types/dist/event-category-CnLqLOKs.mjs
16
+ //#region ../types/dist/event-category-DAXzJeTX.mjs
17
17
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
18
18
  EventCategory["SystemBoot"] = "system.boot";
19
19
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -605,7 +605,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
605
605
  * issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
606
606
  */
607
607
  EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
608
- EventCategory["FrigateLiveEvent"] = "frigate.live-event";
609
608
  EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
610
609
  /**
611
610
  * Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
@@ -12688,7 +12687,7 @@ DeviceType.Camera;
12688
12687
  var SourceInfoSchema = object({
12689
12688
  /** Live dispatch key — mutable when the source system allows rename. */
12690
12689
  id: string$2(),
12691
- /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'frigate'. */
12690
+ /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
12692
12691
  system: string$2(),
12693
12692
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
12694
12693
  * Used to detect rename when `id` changes. */
@@ -12701,7 +12700,7 @@ var SourceInfoSchema = object({
12701
12700
  /**
12702
12701
  * Build the synthetic SourceInfo every existing provider falls back to
12703
12702
  * when no upstream value has been persisted. Keeps non-migrated providers
12704
- * (Reolink / Hikvision / ONVIF / Frigate / RTSP) functional without code
12703
+ * (Reolink / Hikvision / ONVIF / RTSP) functional without code
12705
12704
  * changes — `id` reuses the CamStack stableId, `system` reuses the addon
12706
12705
  * id. Real upstream identity replaces this once a provider migrates and
12707
12706
  * calls `updateSourceInfo()` with concrete values.
@@ -13380,7 +13379,7 @@ var deviceProviderCapability = {
13380
13379
  * - `device-management.router.ts` (deleted in Phase 2)
13381
13380
  * - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
13382
13381
  *
13383
- * All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
13382
+ * All device provider addons (rtsp, onvif, …) are hub-local: they may
13384
13383
  * fork into separate processes but never run on remote cluster agents. Therefore:
13385
13384
  * - No nodeId routing needed — this is a pure hub singleton.
13386
13385
  * - The hub's DeviceRegistry is the single source of truth for all live devices.
@@ -17428,7 +17427,7 @@ var NcRuleInputSchema = object({
17428
17427
  * The measured seven-person arrival on device 590 spans 110 s with every
17429
17428
  * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
17430
17429
  * idle cutoff holds it as one and ends it when the arrival actually ends.
17431
- * 30 is Frigate's shipped value for the same decision.
17430
+ * 30 s is a widely shipped value for the same decision.
17432
17431
  *
17433
17432
  * ### What it replaces
17434
17433
  *
@@ -19510,6 +19509,13 @@ var ZoneCrossingSchema = object({
19510
19509
  /** Zone display name at crossing time (falls back to the id). */
19511
19510
  zoneName: string$2().optional()
19512
19511
  });
19512
+ /** One zone a box was stamped with, and how much of the BOX fell inside it. */
19513
+ var ZoneOverlapSchema = object({
19514
+ zoneId: string$2(),
19515
+ zoneName: string$2().optional(),
19516
+ /** Percentage of the BOX area inside the zone, 0–100. */
19517
+ overlapPct: number()
19518
+ });
19513
19519
  var ObjectEventSchema = object({
19514
19520
  ...BaseEventFields,
19515
19521
  kind: literal("object"),
@@ -19534,6 +19540,35 @@ var ObjectEventSchema = object({
19534
19540
  bbox: BoundingBoxSchema.optional(),
19535
19541
  /** Heavy JSON — omitted in slim projection. */
19536
19542
  zones: array(string$2()).readonly().optional(),
19543
+ /**
19544
+ * How far inside each stamped zone the box actually was, as a percentage of
19545
+ * the BOX area.
19546
+ *
19547
+ * Membership alone cannot express "at least a third of it inside", which is
19548
+ * the bar an operator argues with — and the number already existed: the
19549
+ * engine computed it, the pipeline logged it, and then discarded it. It
19550
+ * matters most on the events that carry no track, where a rule has nothing
19551
+ * else to judge by.
19552
+ */
19553
+ zoneOverlaps: array(ZoneOverlapSchema).readonly().optional(),
19554
+ /**
19555
+ * Present when this event describes a detection the TRACKER refused, so it
19556
+ * has no track and never will.
19557
+ *
19558
+ * A zone-scoped immediate rule asks "is there an animal in the flowerbed
19559
+ * NOW?"; tracking answers a different question ("is this the same subject as
19560
+ * before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
19561
+ * dog at 0.7729, 100% inside a watched zone, was refused three times in six
19562
+ * seconds with three different candidate ids — seven analysed frames in the
19563
+ * window, the subject in a handful of them, metres apart — and produced no
19564
+ * event at all.
19565
+ *
19566
+ * It is NAMED rather than merely implied by a missing `trackId`: an event
19567
+ * with no track and no reason is indistinguishable from a track whose media
19568
+ * went missing, and a consumer that asks this one for a best shot or a
19569
+ * history is asking for something that never existed.
19570
+ */
19571
+ spawnRefused: string$2().optional(),
19537
19572
  /** Omitted in slim projection. */
19538
19573
  state: TrackStateSchema.optional(),
19539
19574
  /**
@@ -19960,7 +19995,17 @@ var EventDensityBucketSchema = object({
19960
19995
  bucketStart: number(),
19961
19996
  motion: number().int(),
19962
19997
  object: number().int(),
19963
- audio: number().int()
19998
+ audio: number().int(),
19999
+ /**
20000
+ * Energy-weighted mean dBFS of the audio events in this bucket — the LEVEL,
20001
+ * as opposed to `audio`, which is their COUNT (D431).
20002
+ *
20003
+ * ABSENT when the bucket holds no audio event. Absence means "nothing was
20004
+ * measured", which is not the same claim as silence, and a lane that cannot
20005
+ * tell them apart paints a quiet hour at full scale — which is exactly what
20006
+ * the count-on-a-level-meter did.
20007
+ */
20008
+ audioDbfs: number().optional()
19964
20009
  });
19965
20010
  /**
19966
20011
  * One camera's row in a `getEventDensityBatch` answer.
@@ -20607,6 +20652,60 @@ var NativeCropResultSchema = object({
20607
20652
  */
20608
20653
  tier: _enum(["native", "ram-fullframe"]).optional()
20609
20654
  });
20655
+ /**
20656
+ * What a PARKED frame is for — the `kind` half of the `(deviceId, trackId,
20657
+ * kind)` key ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
20658
+ *
20659
+ * - `keyFrame` — the track's clean best FULL frame at native width (capped by
20660
+ * the caller's `maxWidth`). What `keyFrame` + `keyFrameSmall` are written
20661
+ * from, and what the detail plane's full-frame rung cuts from.
20662
+ * - `thumbnail` — the best-shot subject slab: the caller's 16:9 central-square
20663
+ * window, cut by the runner at uncapped native resolution.
20664
+ *
20665
+ * The runner never interprets `trackId`; it is an opaque key the hub owns.
20666
+ */
20667
+ var ParkedFrameKindSchema = _enum(["keyFrame", "thumbnail"]);
20668
+ /**
20669
+ * Why a park did NOT happen. Every one is logged on the runner with
20670
+ * `tags: { deviceId }` and the handle's measured age, because a handle already
20671
+ * gone at park time IS the defect the 150–500 ms window exists to prevent —
20672
+ * never a reason to retry in a loop.
20673
+ *
20674
+ * - `handle-gone` — the native surface no longer resolves this handle (never
20675
+ * registered, past the lease bound, or the worker released it). `detail`
20676
+ * carries the runner's own miss reason.
20677
+ * - `encode-failed` — pixels resolved and the JPEG encode threw.
20678
+ */
20679
+ var ParkRefusalSchema = _enum(["handle-gone", "encode-failed"]);
20680
+ /** Answer to `parkTrackFrame` — a discriminated union, so "not parked" always names why. */
20681
+ var ParkTrackFrameResultSchema = discriminatedUnion("parked", [object({
20682
+ parked: literal(true),
20683
+ /** The node holding the parcel — what a later retrieval must be pinned to. */
20684
+ nodeId: string$2(),
20685
+ width: number().int().positive(),
20686
+ height: number().int().positive(),
20687
+ /** JPEG bytes the parcel costs on the node. */
20688
+ bytes: number().int().nonnegative(),
20689
+ /** Whether this park replaced a parcel already held for the key. */
20690
+ replaced: boolean()
20691
+ }), object({
20692
+ parked: literal(false),
20693
+ nodeId: string$2(),
20694
+ reason: ParkRefusalSchema,
20695
+ /** Age of the handle at the park, on the runner's clock; null if unknown. */
20696
+ handleAgeMs: number().nullable(),
20697
+ detail: string$2().optional()
20698
+ })]);
20699
+ /** A retrieved parcel — the runner's own JPEG, base64 for the wire. */
20700
+ var ParkedTrackFrameSchema = object({
20701
+ jpeg: string$2(),
20702
+ width: number().int().positive(),
20703
+ height: number().int().positive(),
20704
+ /** The frame instant the parcel shows (the caller's clock, echoed back). */
20705
+ timestamp: number(),
20706
+ /** When the node stored it (the node's clock). */
20707
+ parkedAt: number()
20708
+ });
20610
20709
  /** Parent detection context passed to `runDetailSubtree` — the crop's
20611
20710
  * originating detection, in FRAME-space coordinates. Reuses
20612
20711
  * `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
@@ -20996,7 +21095,7 @@ var RunnerCameraConfigSchema = object({
20996
21095
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
20997
21096
  * analyzer providers) running on decoded frames in this runner.
20998
21097
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
20999
- * analytics, Frigate motion). The provider emits ProviderMotion
21098
+ * analytics). The provider emits ProviderMotion
21000
21099
  * events; the orchestrator forwards to `reportMotion`.
21001
21100
  */
21002
21101
  motionSources: MotionSourcesSchema.default(["analyzer"]),
@@ -21238,7 +21337,26 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
21238
21337
  className: string$2(),
21239
21338
  /** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
21240
21339
  sourceDeviceId: number()
21241
- }), RunStatelessStepResultSchema, { kind: "mutation" });
21340
+ }), RunStatelessStepResultSchema, { kind: "mutation" }), method(object({
21341
+ deviceId: number(),
21342
+ /** Opaque to the runner — the hub's track id. */
21343
+ trackId: string$2(),
21344
+ kind: ParkedFrameKindSchema,
21345
+ handle: FrameHandleSchema,
21346
+ /** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
21347
+ bbox: NativeCropBboxSchema,
21348
+ /** Width cap for a full-frame park (the `keyFrame` native cap). */
21349
+ maxWidth: number().int().positive().optional(),
21350
+ /** The frame instant (caller's clock) — orders parks for one key. */
21351
+ timestamp: number()
21352
+ }), ParkTrackFrameResultSchema, { kind: "mutation" }), method(object({
21353
+ deviceId: number(),
21354
+ trackId: string$2(),
21355
+ kind: ParkedFrameKindSchema
21356
+ }), ParkedTrackFrameSchema.nullable()), method(object({
21357
+ deviceId: number(),
21358
+ trackId: string$2()
21359
+ }), object({ released: number().int().nonnegative() }), { kind: "mutation" });
21242
21360
  var CameraPipelineConfigSchema = object({
21243
21361
  engine: PipelineEngineChoiceSchema.optional(),
21244
21362
  steps: array(PipelineStepInputSchema).readonly(),
@@ -24308,8 +24426,8 @@ onStatusChanged: { data: object({
24308
24426
  /**
24309
24427
  * Runtime-state slice — every provider that registers this cap
24310
24428
  * stores the same shape under `device.runtimeState[battery]`.
24311
- * Cross-provider uniformity: a Reolink Argus, a Frigate sensor
24312
- * proxy, an ONVIF battery cam all read/write the same keys.
24429
+ * Cross-provider uniformity: a Reolink Argus, a sensor proxy,
24430
+ * an ONVIF battery cam all read/write the same keys.
24313
24431
  * Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
24314
24432
  * via `device.runtimeState.getCapState('battery')` regardless of
24315
24433
  * the underlying driver.
@@ -24459,7 +24577,7 @@ var buttonCapability = {
24459
24577
  *
24460
24578
  * Implementations:
24461
24579
  * - Each camera-providing addon registers this cap natively per
24462
- * device (Reolink, Hikvision, RTSP, Frigate, ONVIF self).
24580
+ * device (Reolink, Hikvision, RTSP, ONVIF self).
24463
24581
  * - Returns a snapshot from the persisted device config blob — no
24464
24582
  * extra round-trip to the camera, no probing.
24465
24583
  * - The cap is admin-only (`auth: 'admin'`) — credentials must not
@@ -26551,7 +26669,7 @@ var AvailableIntegrationTypeSchema = object({
26551
26669
  * Which integration-marker cap the addon declared, so the wizard can
26552
26670
  * branch on CAP — never on addon name. `device-adoption` integrations
26553
26671
  * (Home Assistant, …) route through the broker step (Approach A);
26554
- * `device-provider` integrations (Reolink/Frigate/ONVIF) keep the
26672
+ * `device-provider` integrations (Reolink/ONVIF) keep the
26555
26673
  * legacy config → discovery flow.
26556
26674
  */
26557
26675
  kind: _enum(["device-adoption", "device-provider"]),
@@ -29919,7 +30037,23 @@ var RecordingRangeSchema = object({
29919
30037
  });
29920
30038
  var RecordingAvailabilitySchema = object({
29921
30039
  deviceId: number(),
29922
- ranges: array(RecordingRangeSchema)
30040
+ ranges: array(RecordingRangeSchema),
30041
+ /**
30042
+ * Every profile this camera has footage in — not only the one `ranges`
30043
+ * describes (D433).
30044
+ *
30045
+ * `ranges` answers for ONE profile by design: the timeline is a single bar,
30046
+ * and enumerating all of them triples the directory reads for a bar that
30047
+ * would look identical. But the answer used to say nothing about that, so a
30048
+ * caller asking "what can I export?" read the single preferred profile as
30049
+ * the only one that exists — on this deployment every camera records `high`
30050
+ * AND `low`, the low tree holding 14 GB for camera 615 alone, and the export
30051
+ * UI could not see it.
30052
+ *
30053
+ * Cheap: it is the same shallow directory read the profile CHOICE already
30054
+ * makes. Ask for a specific profile's ranges with the `profile` input.
30055
+ */
30056
+ profilesWithFootage: array(string$2())
29923
30057
  });
29924
30058
  var RecordingDaysSchema = object({
29925
30059
  deviceId: number(),
@@ -29945,7 +30079,11 @@ var RecordingDaysSchema = object({
29945
30079
  var RecordingAvailabilityForDeviceSchema = object({
29946
30080
  deviceId: number(),
29947
30081
  read: _enum(["read", "unreadable"]),
29948
- ranges: array(RecordingRangeSchema).readonly()
30082
+ ranges: array(RecordingRangeSchema).readonly(),
30083
+ /** Same field, same meaning, as the singular answer (D433). A row that
30084
+ * dropped it would tell a grid caller the archive holds one profile.
30085
+ * Empty on an `'unreadable'` row: nobody looked. */
30086
+ profilesWithFootage: array(string$2()).readonly()
29949
30087
  });
29950
30088
  /**
29951
30089
  * One camera's row in a `getDaysWithRecordingsBatch` answer. Same rule as
@@ -29975,13 +30113,31 @@ var RecordingManifestSchema = object({
29975
30113
  */
29976
30114
  playbackEndpoints: array(string$2())
29977
30115
  });
29978
- /** Recording storage usage for one camera (bytes on disk across all its
29979
- * profiles/subtrees/locations on this node). */
30116
+ /**
30117
+ * Recording storage usage for one camera — what the ARCHIVE holds for it,
30118
+ * across every profile and every resolvable location on this node.
30119
+ *
30120
+ * ## Archive vs residency, which is the whole point of this shape (D418)
30121
+ *
30122
+ * `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
30123
+ * the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
30124
+ * this camera writes to, so the two can be added up and compared.
30125
+ *
30126
+ * They were not always. Until D418 this row came from the recorder's in-RAM
30127
+ * `RecordingIndex`, which since D287 holds only the live tail plus the hours
30128
+ * somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
30129
+ * 60.5 GB and "oldest: three hours ago" on the same page as the volume row
30130
+ * that said otherwise, and two people read it as retention eating recent
30131
+ * footage. Residency is still reported, under `residentBytes` /
30132
+ * `residentOldestMs`, which answer a different question and say so.
30133
+ */
29980
30134
  var RecordingDeviceUsageSchema = object({
29981
30135
  deviceId: number(),
30136
+ /** Bytes the ARCHIVE holds for this camera on this node's resolvable
30137
+ * recordings locations. */
29982
30138
  usedBytes: number(),
29983
30139
  /**
29984
- * Start of this camera's OLDEST indexed segment, across every profile and
30140
+ * Start of this camera's OLDEST ARCHIVED segment, across every profile and
29985
30141
  * location — the "Oldest footage" column in Recordings → Storage, and the
29986
30142
  * only honest answer to "is retention actually holding?" per camera.
29987
30143
  *
@@ -29991,7 +30147,24 @@ var RecordingDeviceUsageSchema = object({
29991
30147
  * (types) and the addon ship on different trains, and the addon is usually
29992
30148
  * the later of the two.
29993
30149
  */
29994
- oldestMs: number().nullable().optional()
30150
+ oldestMs: number().nullable().optional(),
30151
+ /** Segments the archive holds for this camera — the "M" beside `usedBytes`.
30152
+ * OPTIONAL for the same train-skew reason as `oldestMs`. */
30153
+ segments: number().optional(),
30154
+ /**
30155
+ * RESIDENCY, not the archive: bytes the recorder process currently holds in
30156
+ * its RAM index — the live tail plus the hours a reader hydrated.
30157
+ *
30158
+ * It answers "what can be served without touching the disk", never "how much
30159
+ * footage this camera has". A UI that renders it must label it as such, and
30160
+ * must never total it as storage. OPTIONAL: a recorder predating D418 omits
30161
+ * it, and so does a node whose ledger could not answer.
30162
+ */
30163
+ residentBytes: number().optional(),
30164
+ /** The residency counterpart of `oldestMs` — the oldest segment currently in
30165
+ * RAM, which on a healthy recorder is minutes ago and means nothing about
30166
+ * retention. `null` = nothing resident. */
30167
+ residentOldestMs: number().nullable().optional()
29995
30168
  });
29996
30169
  /** Recording storage usage + capacity for one storage location. */
29997
30170
  var RecordingLocationUsageSchema = object({
@@ -30029,6 +30202,17 @@ var RecordingStorageUsageSchema = object({
30029
30202
  totalUsedBytes: number(),
30030
30203
  devices: array(RecordingDeviceUsageSchema),
30031
30204
  /**
30205
+ * WHERE `devices[]` came from, so an empty table is never mistaken for empty
30206
+ * disks (D418).
30207
+ *
30208
+ * `archive` = the durable hour ledger answered. `unavailable` = this node
30209
+ * declared no ledger and the recorder REFUSED rather than answering the
30210
+ * question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
30211
+ * zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
30212
+ * and its rows are residency.
30213
+ */
30214
+ devicesRead: _enum(["archive", "unavailable"]).optional(),
30215
+ /**
30032
30216
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
30033
30217
  * of the payload without it: the hub serves this method through a BAKED
30034
30218
  * router, so a hub whose framework train predates a change to this array
@@ -30189,7 +30373,14 @@ var ReadWindowBytesResultSchema = discriminatedUnion("kind", [object({
30189
30373
  method(object({
30190
30374
  deviceId: number(),
30191
30375
  fromMs: number(),
30192
- toMs: number()
30376
+ toMs: number(),
30377
+ /**
30378
+ * Answer for THIS profile instead of the preferred one (D433). Absent
30379
+ * keeps the timeline's behaviour — one bar, one profile, one set of
30380
+ * reads. `profilesWithFootage` on the answer says what may be asked
30381
+ * for.
30382
+ */
30383
+ profile: string$2().optional()
30193
30384
  }), RecordingAvailabilitySchema, {
30194
30385
  kind: "query",
30195
30386
  auth: "protected"
@@ -33908,7 +34099,7 @@ function toDeviceSummary(device, addonId) {
33908
34099
  };
33909
34100
  }
33910
34101
  /**
33911
- * Base class for device-provider addons (rtsp, onvif, frigate).
34102
+ * Base class for device-provider addons (rtsp, onvif).
33912
34103
  *
33913
34104
  * Provides default implementations for the common device-provider cap
33914
34105
  * methods (`start`, `stop`, `getStatus`, `getDevices`, `supportsDiscovery`,
@@ -38564,6 +38755,24 @@ Object.freeze({
38564
38755
  addonId: null,
38565
38756
  access: "view"
38566
38757
  },
38758
+ "pipelineRunner.getParkedTrackFrame": {
38759
+ capName: "pipeline-runner",
38760
+ capScope: "system",
38761
+ addonId: null,
38762
+ access: "view"
38763
+ },
38764
+ "pipelineRunner.parkTrackFrame": {
38765
+ capName: "pipeline-runner",
38766
+ capScope: "system",
38767
+ addonId: null,
38768
+ access: "create"
38769
+ },
38770
+ "pipelineRunner.releaseParkedTrackFrames": {
38771
+ capName: "pipeline-runner",
38772
+ capScope: "system",
38773
+ addonId: null,
38774
+ access: "create"
38775
+ },
38567
38776
  "pipelineRunner.reportMotion": {
38568
38777
  capName: "pipeline-runner",
38569
38778
  capScope: "system",
@@ -41841,6 +42050,21 @@ Object.freeze({
41841
42050
  form: "single",
41842
42051
  optional: false
41843
42052
  }],
42053
+ "pipelineRunner.getParkedTrackFrame": [{
42054
+ name: "deviceId",
42055
+ form: "single",
42056
+ optional: false
42057
+ }],
42058
+ "pipelineRunner.parkTrackFrame": [{
42059
+ name: "deviceId",
42060
+ form: "single",
42061
+ optional: false
42062
+ }],
42063
+ "pipelineRunner.releaseParkedTrackFrames": [{
42064
+ name: "deviceId",
42065
+ form: "single",
42066
+ optional: false
42067
+ }],
41844
42068
  "pipelineRunner.reportMotion": [{
41845
42069
  name: "deviceId",
41846
42070
  form: "single",
@@ -42532,7 +42756,7 @@ var PreviewTextField = string$2().max(200);
42532
42756
  * Whether the notification's preview is a STILL or a short animation.
42533
42757
  *
42534
42758
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
42535
- * rule)"* — his Scrypted advanced-notifier has a `gifRule`, and a ten-hour
42759
+ * rule)"* — the other rules already offer an animated preview, and a ten-hour
42536
42760
  * night reads better as three seconds of motion than as one frame of it. Both
42537
42761
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
42538
42762
  * simply applies it to a dozen frames sampled across the render and assembles
package/dist/addon.mjs CHANGED
@@ -11,7 +11,7 @@ import { networkInterfaces, tmpdir, uptime } from "node:os";
11
11
  import { finished } from "node:stream/promises";
12
12
  import { createConnection, createServer as createServer$2 } from "node:net";
13
13
  import * as dgram from "node:dgram";
14
- //#region ../types/dist/event-category-CnLqLOKs.mjs
14
+ //#region ../types/dist/event-category-DAXzJeTX.mjs
15
15
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
16
16
  EventCategory["SystemBoot"] = "system.boot";
17
17
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -603,7 +603,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
603
603
  * issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
604
604
  */
605
605
  EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
606
- EventCategory["FrigateLiveEvent"] = "frigate.live-event";
607
606
  EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
608
607
  /**
609
608
  * Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
@@ -12686,7 +12685,7 @@ DeviceType.Camera;
12686
12685
  var SourceInfoSchema = object({
12687
12686
  /** Live dispatch key — mutable when the source system allows rename. */
12688
12687
  id: string$2(),
12689
- /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'frigate'. */
12688
+ /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
12690
12689
  system: string$2(),
12691
12690
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
12692
12691
  * Used to detect rename when `id` changes. */
@@ -12699,7 +12698,7 @@ var SourceInfoSchema = object({
12699
12698
  /**
12700
12699
  * Build the synthetic SourceInfo every existing provider falls back to
12701
12700
  * when no upstream value has been persisted. Keeps non-migrated providers
12702
- * (Reolink / Hikvision / ONVIF / Frigate / RTSP) functional without code
12701
+ * (Reolink / Hikvision / ONVIF / RTSP) functional without code
12703
12702
  * changes — `id` reuses the CamStack stableId, `system` reuses the addon
12704
12703
  * id. Real upstream identity replaces this once a provider migrates and
12705
12704
  * calls `updateSourceInfo()` with concrete values.
@@ -13378,7 +13377,7 @@ var deviceProviderCapability = {
13378
13377
  * - `device-management.router.ts` (deleted in Phase 2)
13379
13378
  * - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
13380
13379
  *
13381
- * All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
13380
+ * All device provider addons (rtsp, onvif, …) are hub-local: they may
13382
13381
  * fork into separate processes but never run on remote cluster agents. Therefore:
13383
13382
  * - No nodeId routing needed — this is a pure hub singleton.
13384
13383
  * - The hub's DeviceRegistry is the single source of truth for all live devices.
@@ -17426,7 +17425,7 @@ var NcRuleInputSchema = object({
17426
17425
  * The measured seven-person arrival on device 590 spans 110 s with every
17427
17426
  * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
17428
17427
  * idle cutoff holds it as one and ends it when the arrival actually ends.
17429
- * 30 is Frigate's shipped value for the same decision.
17428
+ * 30 s is a widely shipped value for the same decision.
17430
17429
  *
17431
17430
  * ### What it replaces
17432
17431
  *
@@ -19508,6 +19507,13 @@ var ZoneCrossingSchema = object({
19508
19507
  /** Zone display name at crossing time (falls back to the id). */
19509
19508
  zoneName: string$2().optional()
19510
19509
  });
19510
+ /** One zone a box was stamped with, and how much of the BOX fell inside it. */
19511
+ var ZoneOverlapSchema = object({
19512
+ zoneId: string$2(),
19513
+ zoneName: string$2().optional(),
19514
+ /** Percentage of the BOX area inside the zone, 0–100. */
19515
+ overlapPct: number()
19516
+ });
19511
19517
  var ObjectEventSchema = object({
19512
19518
  ...BaseEventFields,
19513
19519
  kind: literal("object"),
@@ -19532,6 +19538,35 @@ var ObjectEventSchema = object({
19532
19538
  bbox: BoundingBoxSchema.optional(),
19533
19539
  /** Heavy JSON — omitted in slim projection. */
19534
19540
  zones: array(string$2()).readonly().optional(),
19541
+ /**
19542
+ * How far inside each stamped zone the box actually was, as a percentage of
19543
+ * the BOX area.
19544
+ *
19545
+ * Membership alone cannot express "at least a third of it inside", which is
19546
+ * the bar an operator argues with — and the number already existed: the
19547
+ * engine computed it, the pipeline logged it, and then discarded it. It
19548
+ * matters most on the events that carry no track, where a rule has nothing
19549
+ * else to judge by.
19550
+ */
19551
+ zoneOverlaps: array(ZoneOverlapSchema).readonly().optional(),
19552
+ /**
19553
+ * Present when this event describes a detection the TRACKER refused, so it
19554
+ * has no track and never will.
19555
+ *
19556
+ * A zone-scoped immediate rule asks "is there an animal in the flowerbed
19557
+ * NOW?"; tracking answers a different question ("is this the same subject as
19558
+ * before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
19559
+ * dog at 0.7729, 100% inside a watched zone, was refused three times in six
19560
+ * seconds with three different candidate ids — seven analysed frames in the
19561
+ * window, the subject in a handful of them, metres apart — and produced no
19562
+ * event at all.
19563
+ *
19564
+ * It is NAMED rather than merely implied by a missing `trackId`: an event
19565
+ * with no track and no reason is indistinguishable from a track whose media
19566
+ * went missing, and a consumer that asks this one for a best shot or a
19567
+ * history is asking for something that never existed.
19568
+ */
19569
+ spawnRefused: string$2().optional(),
19535
19570
  /** Omitted in slim projection. */
19536
19571
  state: TrackStateSchema.optional(),
19537
19572
  /**
@@ -19958,7 +19993,17 @@ var EventDensityBucketSchema = object({
19958
19993
  bucketStart: number(),
19959
19994
  motion: number().int(),
19960
19995
  object: number().int(),
19961
- audio: number().int()
19996
+ audio: number().int(),
19997
+ /**
19998
+ * Energy-weighted mean dBFS of the audio events in this bucket — the LEVEL,
19999
+ * as opposed to `audio`, which is their COUNT (D431).
20000
+ *
20001
+ * ABSENT when the bucket holds no audio event. Absence means "nothing was
20002
+ * measured", which is not the same claim as silence, and a lane that cannot
20003
+ * tell them apart paints a quiet hour at full scale — which is exactly what
20004
+ * the count-on-a-level-meter did.
20005
+ */
20006
+ audioDbfs: number().optional()
19962
20007
  });
19963
20008
  /**
19964
20009
  * One camera's row in a `getEventDensityBatch` answer.
@@ -20605,6 +20650,60 @@ var NativeCropResultSchema = object({
20605
20650
  */
20606
20651
  tier: _enum(["native", "ram-fullframe"]).optional()
20607
20652
  });
20653
+ /**
20654
+ * What a PARKED frame is for — the `kind` half of the `(deviceId, trackId,
20655
+ * kind)` key ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
20656
+ *
20657
+ * - `keyFrame` — the track's clean best FULL frame at native width (capped by
20658
+ * the caller's `maxWidth`). What `keyFrame` + `keyFrameSmall` are written
20659
+ * from, and what the detail plane's full-frame rung cuts from.
20660
+ * - `thumbnail` — the best-shot subject slab: the caller's 16:9 central-square
20661
+ * window, cut by the runner at uncapped native resolution.
20662
+ *
20663
+ * The runner never interprets `trackId`; it is an opaque key the hub owns.
20664
+ */
20665
+ var ParkedFrameKindSchema = _enum(["keyFrame", "thumbnail"]);
20666
+ /**
20667
+ * Why a park did NOT happen. Every one is logged on the runner with
20668
+ * `tags: { deviceId }` and the handle's measured age, because a handle already
20669
+ * gone at park time IS the defect the 150–500 ms window exists to prevent —
20670
+ * never a reason to retry in a loop.
20671
+ *
20672
+ * - `handle-gone` — the native surface no longer resolves this handle (never
20673
+ * registered, past the lease bound, or the worker released it). `detail`
20674
+ * carries the runner's own miss reason.
20675
+ * - `encode-failed` — pixels resolved and the JPEG encode threw.
20676
+ */
20677
+ var ParkRefusalSchema = _enum(["handle-gone", "encode-failed"]);
20678
+ /** Answer to `parkTrackFrame` — a discriminated union, so "not parked" always names why. */
20679
+ var ParkTrackFrameResultSchema = discriminatedUnion("parked", [object({
20680
+ parked: literal(true),
20681
+ /** The node holding the parcel — what a later retrieval must be pinned to. */
20682
+ nodeId: string$2(),
20683
+ width: number().int().positive(),
20684
+ height: number().int().positive(),
20685
+ /** JPEG bytes the parcel costs on the node. */
20686
+ bytes: number().int().nonnegative(),
20687
+ /** Whether this park replaced a parcel already held for the key. */
20688
+ replaced: boolean()
20689
+ }), object({
20690
+ parked: literal(false),
20691
+ nodeId: string$2(),
20692
+ reason: ParkRefusalSchema,
20693
+ /** Age of the handle at the park, on the runner's clock; null if unknown. */
20694
+ handleAgeMs: number().nullable(),
20695
+ detail: string$2().optional()
20696
+ })]);
20697
+ /** A retrieved parcel — the runner's own JPEG, base64 for the wire. */
20698
+ var ParkedTrackFrameSchema = object({
20699
+ jpeg: string$2(),
20700
+ width: number().int().positive(),
20701
+ height: number().int().positive(),
20702
+ /** The frame instant the parcel shows (the caller's clock, echoed back). */
20703
+ timestamp: number(),
20704
+ /** When the node stored it (the node's clock). */
20705
+ parkedAt: number()
20706
+ });
20608
20707
  /** Parent detection context passed to `runDetailSubtree` — the crop's
20609
20708
  * originating detection, in FRAME-space coordinates. Reuses
20610
20709
  * `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
@@ -20994,7 +21093,7 @@ var RunnerCameraConfigSchema = object({
20994
21093
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
20995
21094
  * analyzer providers) running on decoded frames in this runner.
20996
21095
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
20997
- * analytics, Frigate motion). The provider emits ProviderMotion
21096
+ * analytics). The provider emits ProviderMotion
20998
21097
  * events; the orchestrator forwards to `reportMotion`.
20999
21098
  */
21000
21099
  motionSources: MotionSourcesSchema.default(["analyzer"]),
@@ -21236,7 +21335,26 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
21236
21335
  className: string$2(),
21237
21336
  /** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
21238
21337
  sourceDeviceId: number()
21239
- }), RunStatelessStepResultSchema, { kind: "mutation" });
21338
+ }), RunStatelessStepResultSchema, { kind: "mutation" }), method(object({
21339
+ deviceId: number(),
21340
+ /** Opaque to the runner — the hub's track id. */
21341
+ trackId: string$2(),
21342
+ kind: ParkedFrameKindSchema,
21343
+ handle: FrameHandleSchema,
21344
+ /** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
21345
+ bbox: NativeCropBboxSchema,
21346
+ /** Width cap for a full-frame park (the `keyFrame` native cap). */
21347
+ maxWidth: number().int().positive().optional(),
21348
+ /** The frame instant (caller's clock) — orders parks for one key. */
21349
+ timestamp: number()
21350
+ }), ParkTrackFrameResultSchema, { kind: "mutation" }), method(object({
21351
+ deviceId: number(),
21352
+ trackId: string$2(),
21353
+ kind: ParkedFrameKindSchema
21354
+ }), ParkedTrackFrameSchema.nullable()), method(object({
21355
+ deviceId: number(),
21356
+ trackId: string$2()
21357
+ }), object({ released: number().int().nonnegative() }), { kind: "mutation" });
21240
21358
  var CameraPipelineConfigSchema = object({
21241
21359
  engine: PipelineEngineChoiceSchema.optional(),
21242
21360
  steps: array(PipelineStepInputSchema).readonly(),
@@ -24306,8 +24424,8 @@ onStatusChanged: { data: object({
24306
24424
  /**
24307
24425
  * Runtime-state slice — every provider that registers this cap
24308
24426
  * stores the same shape under `device.runtimeState[battery]`.
24309
- * Cross-provider uniformity: a Reolink Argus, a Frigate sensor
24310
- * proxy, an ONVIF battery cam all read/write the same keys.
24427
+ * Cross-provider uniformity: a Reolink Argus, a sensor proxy,
24428
+ * an ONVIF battery cam all read/write the same keys.
24311
24429
  * Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
24312
24430
  * via `device.runtimeState.getCapState('battery')` regardless of
24313
24431
  * the underlying driver.
@@ -24457,7 +24575,7 @@ var buttonCapability = {
24457
24575
  *
24458
24576
  * Implementations:
24459
24577
  * - Each camera-providing addon registers this cap natively per
24460
- * device (Reolink, Hikvision, RTSP, Frigate, ONVIF self).
24578
+ * device (Reolink, Hikvision, RTSP, ONVIF self).
24461
24579
  * - Returns a snapshot from the persisted device config blob — no
24462
24580
  * extra round-trip to the camera, no probing.
24463
24581
  * - The cap is admin-only (`auth: 'admin'`) — credentials must not
@@ -26549,7 +26667,7 @@ var AvailableIntegrationTypeSchema = object({
26549
26667
  * Which integration-marker cap the addon declared, so the wizard can
26550
26668
  * branch on CAP — never on addon name. `device-adoption` integrations
26551
26669
  * (Home Assistant, …) route through the broker step (Approach A);
26552
- * `device-provider` integrations (Reolink/Frigate/ONVIF) keep the
26670
+ * `device-provider` integrations (Reolink/ONVIF) keep the
26553
26671
  * legacy config → discovery flow.
26554
26672
  */
26555
26673
  kind: _enum(["device-adoption", "device-provider"]),
@@ -29917,7 +30035,23 @@ var RecordingRangeSchema = object({
29917
30035
  });
29918
30036
  var RecordingAvailabilitySchema = object({
29919
30037
  deviceId: number(),
29920
- ranges: array(RecordingRangeSchema)
30038
+ ranges: array(RecordingRangeSchema),
30039
+ /**
30040
+ * Every profile this camera has footage in — not only the one `ranges`
30041
+ * describes (D433).
30042
+ *
30043
+ * `ranges` answers for ONE profile by design: the timeline is a single bar,
30044
+ * and enumerating all of them triples the directory reads for a bar that
30045
+ * would look identical. But the answer used to say nothing about that, so a
30046
+ * caller asking "what can I export?" read the single preferred profile as
30047
+ * the only one that exists — on this deployment every camera records `high`
30048
+ * AND `low`, the low tree holding 14 GB for camera 615 alone, and the export
30049
+ * UI could not see it.
30050
+ *
30051
+ * Cheap: it is the same shallow directory read the profile CHOICE already
30052
+ * makes. Ask for a specific profile's ranges with the `profile` input.
30053
+ */
30054
+ profilesWithFootage: array(string$2())
29921
30055
  });
29922
30056
  var RecordingDaysSchema = object({
29923
30057
  deviceId: number(),
@@ -29943,7 +30077,11 @@ var RecordingDaysSchema = object({
29943
30077
  var RecordingAvailabilityForDeviceSchema = object({
29944
30078
  deviceId: number(),
29945
30079
  read: _enum(["read", "unreadable"]),
29946
- ranges: array(RecordingRangeSchema).readonly()
30080
+ ranges: array(RecordingRangeSchema).readonly(),
30081
+ /** Same field, same meaning, as the singular answer (D433). A row that
30082
+ * dropped it would tell a grid caller the archive holds one profile.
30083
+ * Empty on an `'unreadable'` row: nobody looked. */
30084
+ profilesWithFootage: array(string$2()).readonly()
29947
30085
  });
29948
30086
  /**
29949
30087
  * One camera's row in a `getDaysWithRecordingsBatch` answer. Same rule as
@@ -29973,13 +30111,31 @@ var RecordingManifestSchema = object({
29973
30111
  */
29974
30112
  playbackEndpoints: array(string$2())
29975
30113
  });
29976
- /** Recording storage usage for one camera (bytes on disk across all its
29977
- * profiles/subtrees/locations on this node). */
30114
+ /**
30115
+ * Recording storage usage for one camera — what the ARCHIVE holds for it,
30116
+ * across every profile and every resolvable location on this node.
30117
+ *
30118
+ * ## Archive vs residency, which is the whole point of this shape (D418)
30119
+ *
30120
+ * `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
30121
+ * the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
30122
+ * this camera writes to, so the two can be added up and compared.
30123
+ *
30124
+ * They were not always. Until D418 this row came from the recorder's in-RAM
30125
+ * `RecordingIndex`, which since D287 holds only the live tail plus the hours
30126
+ * somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
30127
+ * 60.5 GB and "oldest: three hours ago" on the same page as the volume row
30128
+ * that said otherwise, and two people read it as retention eating recent
30129
+ * footage. Residency is still reported, under `residentBytes` /
30130
+ * `residentOldestMs`, which answer a different question and say so.
30131
+ */
29978
30132
  var RecordingDeviceUsageSchema = object({
29979
30133
  deviceId: number(),
30134
+ /** Bytes the ARCHIVE holds for this camera on this node's resolvable
30135
+ * recordings locations. */
29980
30136
  usedBytes: number(),
29981
30137
  /**
29982
- * Start of this camera's OLDEST indexed segment, across every profile and
30138
+ * Start of this camera's OLDEST ARCHIVED segment, across every profile and
29983
30139
  * location — the "Oldest footage" column in Recordings → Storage, and the
29984
30140
  * only honest answer to "is retention actually holding?" per camera.
29985
30141
  *
@@ -29989,7 +30145,24 @@ var RecordingDeviceUsageSchema = object({
29989
30145
  * (types) and the addon ship on different trains, and the addon is usually
29990
30146
  * the later of the two.
29991
30147
  */
29992
- oldestMs: number().nullable().optional()
30148
+ oldestMs: number().nullable().optional(),
30149
+ /** Segments the archive holds for this camera — the "M" beside `usedBytes`.
30150
+ * OPTIONAL for the same train-skew reason as `oldestMs`. */
30151
+ segments: number().optional(),
30152
+ /**
30153
+ * RESIDENCY, not the archive: bytes the recorder process currently holds in
30154
+ * its RAM index — the live tail plus the hours a reader hydrated.
30155
+ *
30156
+ * It answers "what can be served without touching the disk", never "how much
30157
+ * footage this camera has". A UI that renders it must label it as such, and
30158
+ * must never total it as storage. OPTIONAL: a recorder predating D418 omits
30159
+ * it, and so does a node whose ledger could not answer.
30160
+ */
30161
+ residentBytes: number().optional(),
30162
+ /** The residency counterpart of `oldestMs` — the oldest segment currently in
30163
+ * RAM, which on a healthy recorder is minutes ago and means nothing about
30164
+ * retention. `null` = nothing resident. */
30165
+ residentOldestMs: number().nullable().optional()
29993
30166
  });
29994
30167
  /** Recording storage usage + capacity for one storage location. */
29995
30168
  var RecordingLocationUsageSchema = object({
@@ -30027,6 +30200,17 @@ var RecordingStorageUsageSchema = object({
30027
30200
  totalUsedBytes: number(),
30028
30201
  devices: array(RecordingDeviceUsageSchema),
30029
30202
  /**
30203
+ * WHERE `devices[]` came from, so an empty table is never mistaken for empty
30204
+ * disks (D418).
30205
+ *
30206
+ * `archive` = the durable hour ledger answered. `unavailable` = this node
30207
+ * declared no ledger and the recorder REFUSED rather than answering the
30208
+ * question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
30209
+ * zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
30210
+ * and its rows are residency.
30211
+ */
30212
+ devicesRead: _enum(["archive", "unavailable"]).optional(),
30213
+ /**
30030
30214
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
30031
30215
  * of the payload without it: the hub serves this method through a BAKED
30032
30216
  * router, so a hub whose framework train predates a change to this array
@@ -30187,7 +30371,14 @@ var ReadWindowBytesResultSchema = discriminatedUnion("kind", [object({
30187
30371
  method(object({
30188
30372
  deviceId: number(),
30189
30373
  fromMs: number(),
30190
- toMs: number()
30374
+ toMs: number(),
30375
+ /**
30376
+ * Answer for THIS profile instead of the preferred one (D433). Absent
30377
+ * keeps the timeline's behaviour — one bar, one profile, one set of
30378
+ * reads. `profilesWithFootage` on the answer says what may be asked
30379
+ * for.
30380
+ */
30381
+ profile: string$2().optional()
30191
30382
  }), RecordingAvailabilitySchema, {
30192
30383
  kind: "query",
30193
30384
  auth: "protected"
@@ -33906,7 +34097,7 @@ function toDeviceSummary(device, addonId) {
33906
34097
  };
33907
34098
  }
33908
34099
  /**
33909
- * Base class for device-provider addons (rtsp, onvif, frigate).
34100
+ * Base class for device-provider addons (rtsp, onvif).
33910
34101
  *
33911
34102
  * Provides default implementations for the common device-provider cap
33912
34103
  * methods (`start`, `stop`, `getStatus`, `getDevices`, `supportsDiscovery`,
@@ -38562,6 +38753,24 @@ Object.freeze({
38562
38753
  addonId: null,
38563
38754
  access: "view"
38564
38755
  },
38756
+ "pipelineRunner.getParkedTrackFrame": {
38757
+ capName: "pipeline-runner",
38758
+ capScope: "system",
38759
+ addonId: null,
38760
+ access: "view"
38761
+ },
38762
+ "pipelineRunner.parkTrackFrame": {
38763
+ capName: "pipeline-runner",
38764
+ capScope: "system",
38765
+ addonId: null,
38766
+ access: "create"
38767
+ },
38768
+ "pipelineRunner.releaseParkedTrackFrames": {
38769
+ capName: "pipeline-runner",
38770
+ capScope: "system",
38771
+ addonId: null,
38772
+ access: "create"
38773
+ },
38565
38774
  "pipelineRunner.reportMotion": {
38566
38775
  capName: "pipeline-runner",
38567
38776
  capScope: "system",
@@ -41839,6 +42048,21 @@ Object.freeze({
41839
42048
  form: "single",
41840
42049
  optional: false
41841
42050
  }],
42051
+ "pipelineRunner.getParkedTrackFrame": [{
42052
+ name: "deviceId",
42053
+ form: "single",
42054
+ optional: false
42055
+ }],
42056
+ "pipelineRunner.parkTrackFrame": [{
42057
+ name: "deviceId",
42058
+ form: "single",
42059
+ optional: false
42060
+ }],
42061
+ "pipelineRunner.releaseParkedTrackFrames": [{
42062
+ name: "deviceId",
42063
+ form: "single",
42064
+ optional: false
42065
+ }],
41842
42066
  "pipelineRunner.reportMotion": [{
41843
42067
  name: "deviceId",
41844
42068
  form: "single",
@@ -42530,7 +42754,7 @@ var PreviewTextField = string$2().max(200);
42530
42754
  * Whether the notification's preview is a STILL or a short animation.
42531
42755
  *
42532
42756
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
42533
- * rule)"* — his Scrypted advanced-notifier has a `gifRule`, and a ten-hour
42757
+ * rule)"* — the other rules already offer an animated preview, and a ten-hour
42534
42758
  * night reads better as three seconds of motion than as one frame of it. Both
42535
42759
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
42536
42760
  * simply applies it to a dozen frames sampled across the render and assembles
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-matter-broker",
3
- "version": "0.2.89",
3
+ "version": "0.2.92",
4
4
  "description": "Matter broker addon for CamStack — owns a Matter fabric (commissioning + the long-lived controller) via the matter.js controller and brokers commissioned Matter nodes into CamStack",
5
5
  "keywords": [
6
6
  "camstack",