@camstack/addon-provider-dreo 0.2.90 → 0.2.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +246 -22
- package/dist/addon.mjs +246 -22
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -35,7 +35,7 @@ var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["modu
|
|
|
35
35
|
//#endregion
|
|
36
36
|
let crypto$1 = require("crypto");
|
|
37
37
|
let events = require("events");
|
|
38
|
-
//#region ../types/dist/event-category-
|
|
38
|
+
//#region ../types/dist/event-category-DAXzJeTX.mjs
|
|
39
39
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
40
40
|
EventCategory["SystemBoot"] = "system.boot";
|
|
41
41
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -627,7 +627,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
627
627
|
* issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
|
|
628
628
|
*/
|
|
629
629
|
EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
|
|
630
|
-
EventCategory["FrigateLiveEvent"] = "frigate.live-event";
|
|
631
630
|
EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
|
|
632
631
|
/**
|
|
633
632
|
* Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
|
|
@@ -12661,7 +12660,7 @@ DeviceType.Camera;
|
|
|
12661
12660
|
var SourceInfoSchema = object({
|
|
12662
12661
|
/** Live dispatch key — mutable when the source system allows rename. */
|
|
12663
12662
|
id: string(),
|
|
12664
|
-
/** Source system tag — e.g. 'homeassistant' | 'reolink' | '
|
|
12663
|
+
/** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
|
|
12665
12664
|
system: string(),
|
|
12666
12665
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
12667
12666
|
* Used to detect rename when `id` changes. */
|
|
@@ -12674,7 +12673,7 @@ var SourceInfoSchema = object({
|
|
|
12674
12673
|
/**
|
|
12675
12674
|
* Build the synthetic SourceInfo every existing provider falls back to
|
|
12676
12675
|
* when no upstream value has been persisted. Keeps non-migrated providers
|
|
12677
|
-
* (Reolink / Hikvision / ONVIF /
|
|
12676
|
+
* (Reolink / Hikvision / ONVIF / RTSP) functional without code
|
|
12678
12677
|
* changes — `id` reuses the CamStack stableId, `system` reuses the addon
|
|
12679
12678
|
* id. Real upstream identity replaces this once a provider migrates and
|
|
12680
12679
|
* calls `updateSourceInfo()` with concrete values.
|
|
@@ -13353,7 +13352,7 @@ var deviceProviderCapability = {
|
|
|
13353
13352
|
* - `device-management.router.ts` (deleted in Phase 2)
|
|
13354
13353
|
* - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
|
|
13355
13354
|
*
|
|
13356
|
-
* All device provider addons (rtsp, onvif,
|
|
13355
|
+
* All device provider addons (rtsp, onvif, …) are hub-local: they may
|
|
13357
13356
|
* fork into separate processes but never run on remote cluster agents. Therefore:
|
|
13358
13357
|
* - No nodeId routing needed — this is a pure hub singleton.
|
|
13359
13358
|
* - The hub's DeviceRegistry is the single source of truth for all live devices.
|
|
@@ -17401,7 +17400,7 @@ var NcRuleInputSchema = object({
|
|
|
17401
17400
|
* The measured seven-person arrival on device 590 spans 110 s with every
|
|
17402
17401
|
* internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
|
|
17403
17402
|
* idle cutoff holds it as one and ends it when the arrival actually ends.
|
|
17404
|
-
* 30 is
|
|
17403
|
+
* 30 s is a widely shipped value for the same decision.
|
|
17405
17404
|
*
|
|
17406
17405
|
* ### What it replaces
|
|
17407
17406
|
*
|
|
@@ -19483,6 +19482,13 @@ var ZoneCrossingSchema = object({
|
|
|
19483
19482
|
/** Zone display name at crossing time (falls back to the id). */
|
|
19484
19483
|
zoneName: string().optional()
|
|
19485
19484
|
});
|
|
19485
|
+
/** One zone a box was stamped with, and how much of the BOX fell inside it. */
|
|
19486
|
+
var ZoneOverlapSchema = object({
|
|
19487
|
+
zoneId: string(),
|
|
19488
|
+
zoneName: string().optional(),
|
|
19489
|
+
/** Percentage of the BOX area inside the zone, 0–100. */
|
|
19490
|
+
overlapPct: number()
|
|
19491
|
+
});
|
|
19486
19492
|
var ObjectEventSchema = object({
|
|
19487
19493
|
...BaseEventFields,
|
|
19488
19494
|
kind: literal("object"),
|
|
@@ -19507,6 +19513,35 @@ var ObjectEventSchema = object({
|
|
|
19507
19513
|
bbox: BoundingBoxSchema.optional(),
|
|
19508
19514
|
/** Heavy JSON — omitted in slim projection. */
|
|
19509
19515
|
zones: array(string()).readonly().optional(),
|
|
19516
|
+
/**
|
|
19517
|
+
* How far inside each stamped zone the box actually was, as a percentage of
|
|
19518
|
+
* the BOX area.
|
|
19519
|
+
*
|
|
19520
|
+
* Membership alone cannot express "at least a third of it inside", which is
|
|
19521
|
+
* the bar an operator argues with — and the number already existed: the
|
|
19522
|
+
* engine computed it, the pipeline logged it, and then discarded it. It
|
|
19523
|
+
* matters most on the events that carry no track, where a rule has nothing
|
|
19524
|
+
* else to judge by.
|
|
19525
|
+
*/
|
|
19526
|
+
zoneOverlaps: array(ZoneOverlapSchema).readonly().optional(),
|
|
19527
|
+
/**
|
|
19528
|
+
* Present when this event describes a detection the TRACKER refused, so it
|
|
19529
|
+
* has no track and never will.
|
|
19530
|
+
*
|
|
19531
|
+
* A zone-scoped immediate rule asks "is there an animal in the flowerbed
|
|
19532
|
+
* NOW?"; tracking answers a different question ("is this the same subject as
|
|
19533
|
+
* before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
|
|
19534
|
+
* dog at 0.7729, 100% inside a watched zone, was refused three times in six
|
|
19535
|
+
* seconds with three different candidate ids — seven analysed frames in the
|
|
19536
|
+
* window, the subject in a handful of them, metres apart — and produced no
|
|
19537
|
+
* event at all.
|
|
19538
|
+
*
|
|
19539
|
+
* It is NAMED rather than merely implied by a missing `trackId`: an event
|
|
19540
|
+
* with no track and no reason is indistinguishable from a track whose media
|
|
19541
|
+
* went missing, and a consumer that asks this one for a best shot or a
|
|
19542
|
+
* history is asking for something that never existed.
|
|
19543
|
+
*/
|
|
19544
|
+
spawnRefused: string().optional(),
|
|
19510
19545
|
/** Omitted in slim projection. */
|
|
19511
19546
|
state: TrackStateSchema.optional(),
|
|
19512
19547
|
/**
|
|
@@ -19933,7 +19968,17 @@ var EventDensityBucketSchema = object({
|
|
|
19933
19968
|
bucketStart: number(),
|
|
19934
19969
|
motion: number().int(),
|
|
19935
19970
|
object: number().int(),
|
|
19936
|
-
audio: number().int()
|
|
19971
|
+
audio: number().int(),
|
|
19972
|
+
/**
|
|
19973
|
+
* Energy-weighted mean dBFS of the audio events in this bucket — the LEVEL,
|
|
19974
|
+
* as opposed to `audio`, which is their COUNT (D431).
|
|
19975
|
+
*
|
|
19976
|
+
* ABSENT when the bucket holds no audio event. Absence means "nothing was
|
|
19977
|
+
* measured", which is not the same claim as silence, and a lane that cannot
|
|
19978
|
+
* tell them apart paints a quiet hour at full scale — which is exactly what
|
|
19979
|
+
* the count-on-a-level-meter did.
|
|
19980
|
+
*/
|
|
19981
|
+
audioDbfs: number().optional()
|
|
19937
19982
|
});
|
|
19938
19983
|
/**
|
|
19939
19984
|
* One camera's row in a `getEventDensityBatch` answer.
|
|
@@ -20580,6 +20625,60 @@ var NativeCropResultSchema = object({
|
|
|
20580
20625
|
*/
|
|
20581
20626
|
tier: _enum(["native", "ram-fullframe"]).optional()
|
|
20582
20627
|
});
|
|
20628
|
+
/**
|
|
20629
|
+
* What a PARKED frame is for — the `kind` half of the `(deviceId, trackId,
|
|
20630
|
+
* kind)` key ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
|
|
20631
|
+
*
|
|
20632
|
+
* - `keyFrame` — the track's clean best FULL frame at native width (capped by
|
|
20633
|
+
* the caller's `maxWidth`). What `keyFrame` + `keyFrameSmall` are written
|
|
20634
|
+
* from, and what the detail plane's full-frame rung cuts from.
|
|
20635
|
+
* - `thumbnail` — the best-shot subject slab: the caller's 16:9 central-square
|
|
20636
|
+
* window, cut by the runner at uncapped native resolution.
|
|
20637
|
+
*
|
|
20638
|
+
* The runner never interprets `trackId`; it is an opaque key the hub owns.
|
|
20639
|
+
*/
|
|
20640
|
+
var ParkedFrameKindSchema = _enum(["keyFrame", "thumbnail"]);
|
|
20641
|
+
/**
|
|
20642
|
+
* Why a park did NOT happen. Every one is logged on the runner with
|
|
20643
|
+
* `tags: { deviceId }` and the handle's measured age, because a handle already
|
|
20644
|
+
* gone at park time IS the defect the 150–500 ms window exists to prevent —
|
|
20645
|
+
* never a reason to retry in a loop.
|
|
20646
|
+
*
|
|
20647
|
+
* - `handle-gone` — the native surface no longer resolves this handle (never
|
|
20648
|
+
* registered, past the lease bound, or the worker released it). `detail`
|
|
20649
|
+
* carries the runner's own miss reason.
|
|
20650
|
+
* - `encode-failed` — pixels resolved and the JPEG encode threw.
|
|
20651
|
+
*/
|
|
20652
|
+
var ParkRefusalSchema = _enum(["handle-gone", "encode-failed"]);
|
|
20653
|
+
/** Answer to `parkTrackFrame` — a discriminated union, so "not parked" always names why. */
|
|
20654
|
+
var ParkTrackFrameResultSchema = discriminatedUnion("parked", [object({
|
|
20655
|
+
parked: literal(true),
|
|
20656
|
+
/** The node holding the parcel — what a later retrieval must be pinned to. */
|
|
20657
|
+
nodeId: string(),
|
|
20658
|
+
width: number().int().positive(),
|
|
20659
|
+
height: number().int().positive(),
|
|
20660
|
+
/** JPEG bytes the parcel costs on the node. */
|
|
20661
|
+
bytes: number().int().nonnegative(),
|
|
20662
|
+
/** Whether this park replaced a parcel already held for the key. */
|
|
20663
|
+
replaced: boolean()
|
|
20664
|
+
}), object({
|
|
20665
|
+
parked: literal(false),
|
|
20666
|
+
nodeId: string(),
|
|
20667
|
+
reason: ParkRefusalSchema,
|
|
20668
|
+
/** Age of the handle at the park, on the runner's clock; null if unknown. */
|
|
20669
|
+
handleAgeMs: number().nullable(),
|
|
20670
|
+
detail: string().optional()
|
|
20671
|
+
})]);
|
|
20672
|
+
/** A retrieved parcel — the runner's own JPEG, base64 for the wire. */
|
|
20673
|
+
var ParkedTrackFrameSchema = object({
|
|
20674
|
+
jpeg: string(),
|
|
20675
|
+
width: number().int().positive(),
|
|
20676
|
+
height: number().int().positive(),
|
|
20677
|
+
/** The frame instant the parcel shows (the caller's clock, echoed back). */
|
|
20678
|
+
timestamp: number(),
|
|
20679
|
+
/** When the node stored it (the node's clock). */
|
|
20680
|
+
parkedAt: number()
|
|
20681
|
+
});
|
|
20583
20682
|
/** Parent detection context passed to `runDetailSubtree` — the crop's
|
|
20584
20683
|
* originating detection, in FRAME-space coordinates. Reuses
|
|
20585
20684
|
* `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
|
|
@@ -20969,7 +21068,7 @@ var RunnerCameraConfigSchema = object({
|
|
|
20969
21068
|
* - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
|
|
20970
21069
|
* analyzer providers) running on decoded frames in this runner.
|
|
20971
21070
|
* - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
|
|
20972
|
-
* analytics
|
|
21071
|
+
* analytics). The provider emits ProviderMotion
|
|
20973
21072
|
* events; the orchestrator forwards to `reportMotion`.
|
|
20974
21073
|
*/
|
|
20975
21074
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
@@ -21211,7 +21310,26 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
|
|
|
21211
21310
|
className: string(),
|
|
21212
21311
|
/** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
|
|
21213
21312
|
sourceDeviceId: number()
|
|
21214
|
-
}), RunStatelessStepResultSchema, { kind: "mutation" })
|
|
21313
|
+
}), RunStatelessStepResultSchema, { kind: "mutation" }), method(object({
|
|
21314
|
+
deviceId: number(),
|
|
21315
|
+
/** Opaque to the runner — the hub's track id. */
|
|
21316
|
+
trackId: string(),
|
|
21317
|
+
kind: ParkedFrameKindSchema,
|
|
21318
|
+
handle: FrameHandleSchema,
|
|
21319
|
+
/** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
|
|
21320
|
+
bbox: NativeCropBboxSchema,
|
|
21321
|
+
/** Width cap for a full-frame park (the `keyFrame` native cap). */
|
|
21322
|
+
maxWidth: number().int().positive().optional(),
|
|
21323
|
+
/** The frame instant (caller's clock) — orders parks for one key. */
|
|
21324
|
+
timestamp: number()
|
|
21325
|
+
}), ParkTrackFrameResultSchema, { kind: "mutation" }), method(object({
|
|
21326
|
+
deviceId: number(),
|
|
21327
|
+
trackId: string(),
|
|
21328
|
+
kind: ParkedFrameKindSchema
|
|
21329
|
+
}), ParkedTrackFrameSchema.nullable()), method(object({
|
|
21330
|
+
deviceId: number(),
|
|
21331
|
+
trackId: string()
|
|
21332
|
+
}), object({ released: number().int().nonnegative() }), { kind: "mutation" });
|
|
21215
21333
|
var CameraPipelineConfigSchema = object({
|
|
21216
21334
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
21217
21335
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -24281,8 +24399,8 @@ onStatusChanged: { data: object({
|
|
|
24281
24399
|
/**
|
|
24282
24400
|
* Runtime-state slice — every provider that registers this cap
|
|
24283
24401
|
* stores the same shape under `device.runtimeState[battery]`.
|
|
24284
|
-
* Cross-provider uniformity: a Reolink Argus, a
|
|
24285
|
-
*
|
|
24402
|
+
* Cross-provider uniformity: a Reolink Argus, a sensor proxy,
|
|
24403
|
+
* an ONVIF battery cam all read/write the same keys.
|
|
24286
24404
|
* Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
|
|
24287
24405
|
* via `device.runtimeState.getCapState('battery')` regardless of
|
|
24288
24406
|
* the underlying driver.
|
|
@@ -24415,7 +24533,7 @@ DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _v
|
|
|
24415
24533
|
*
|
|
24416
24534
|
* Implementations:
|
|
24417
24535
|
* - Each camera-providing addon registers this cap natively per
|
|
24418
|
-
* device (Reolink, Hikvision, RTSP,
|
|
24536
|
+
* device (Reolink, Hikvision, RTSP, ONVIF self).
|
|
24419
24537
|
* - Returns a snapshot from the persisted device config blob — no
|
|
24420
24538
|
* extra round-trip to the camera, no probing.
|
|
24421
24539
|
* - The cap is admin-only (`auth: 'admin'`) — credentials must not
|
|
@@ -26515,7 +26633,7 @@ var AvailableIntegrationTypeSchema = object({
|
|
|
26515
26633
|
* Which integration-marker cap the addon declared, so the wizard can
|
|
26516
26634
|
* branch on CAP — never on addon name. `device-adoption` integrations
|
|
26517
26635
|
* (Home Assistant, …) route through the broker step (Approach A);
|
|
26518
|
-
* `device-provider` integrations (Reolink/
|
|
26636
|
+
* `device-provider` integrations (Reolink/ONVIF) keep the
|
|
26519
26637
|
* legacy config → discovery flow.
|
|
26520
26638
|
*/
|
|
26521
26639
|
kind: _enum(["device-adoption", "device-provider"]),
|
|
@@ -29883,7 +30001,23 @@ var RecordingRangeSchema = object({
|
|
|
29883
30001
|
});
|
|
29884
30002
|
var RecordingAvailabilitySchema = object({
|
|
29885
30003
|
deviceId: number(),
|
|
29886
|
-
ranges: array(RecordingRangeSchema)
|
|
30004
|
+
ranges: array(RecordingRangeSchema),
|
|
30005
|
+
/**
|
|
30006
|
+
* Every profile this camera has footage in — not only the one `ranges`
|
|
30007
|
+
* describes (D433).
|
|
30008
|
+
*
|
|
30009
|
+
* `ranges` answers for ONE profile by design: the timeline is a single bar,
|
|
30010
|
+
* and enumerating all of them triples the directory reads for a bar that
|
|
30011
|
+
* would look identical. But the answer used to say nothing about that, so a
|
|
30012
|
+
* caller asking "what can I export?" read the single preferred profile as
|
|
30013
|
+
* the only one that exists — on this deployment every camera records `high`
|
|
30014
|
+
* AND `low`, the low tree holding 14 GB for camera 615 alone, and the export
|
|
30015
|
+
* UI could not see it.
|
|
30016
|
+
*
|
|
30017
|
+
* Cheap: it is the same shallow directory read the profile CHOICE already
|
|
30018
|
+
* makes. Ask for a specific profile's ranges with the `profile` input.
|
|
30019
|
+
*/
|
|
30020
|
+
profilesWithFootage: array(string())
|
|
29887
30021
|
});
|
|
29888
30022
|
var RecordingDaysSchema = object({
|
|
29889
30023
|
deviceId: number(),
|
|
@@ -29909,7 +30043,11 @@ var RecordingDaysSchema = object({
|
|
|
29909
30043
|
var RecordingAvailabilityForDeviceSchema = object({
|
|
29910
30044
|
deviceId: number(),
|
|
29911
30045
|
read: _enum(["read", "unreadable"]),
|
|
29912
|
-
ranges: array(RecordingRangeSchema).readonly()
|
|
30046
|
+
ranges: array(RecordingRangeSchema).readonly(),
|
|
30047
|
+
/** Same field, same meaning, as the singular answer (D433). A row that
|
|
30048
|
+
* dropped it would tell a grid caller the archive holds one profile.
|
|
30049
|
+
* Empty on an `'unreadable'` row: nobody looked. */
|
|
30050
|
+
profilesWithFootage: array(string()).readonly()
|
|
29913
30051
|
});
|
|
29914
30052
|
/**
|
|
29915
30053
|
* One camera's row in a `getDaysWithRecordingsBatch` answer. Same rule as
|
|
@@ -29939,13 +30077,31 @@ var RecordingManifestSchema = object({
|
|
|
29939
30077
|
*/
|
|
29940
30078
|
playbackEndpoints: array(string())
|
|
29941
30079
|
});
|
|
29942
|
-
/**
|
|
29943
|
-
*
|
|
30080
|
+
/**
|
|
30081
|
+
* Recording storage usage for one camera — what the ARCHIVE holds for it,
|
|
30082
|
+
* across every profile and every resolvable location on this node.
|
|
30083
|
+
*
|
|
30084
|
+
* ## Archive vs residency, which is the whole point of this shape (D418)
|
|
30085
|
+
*
|
|
30086
|
+
* `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
|
|
30087
|
+
* the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
|
|
30088
|
+
* this camera writes to, so the two can be added up and compared.
|
|
30089
|
+
*
|
|
30090
|
+
* They were not always. Until D418 this row came from the recorder's in-RAM
|
|
30091
|
+
* `RecordingIndex`, which since D287 holds only the live tail plus the hours
|
|
30092
|
+
* somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
|
|
30093
|
+
* 60.5 GB and "oldest: three hours ago" on the same page as the volume row
|
|
30094
|
+
* that said otherwise, and two people read it as retention eating recent
|
|
30095
|
+
* footage. Residency is still reported, under `residentBytes` /
|
|
30096
|
+
* `residentOldestMs`, which answer a different question and say so.
|
|
30097
|
+
*/
|
|
29944
30098
|
var RecordingDeviceUsageSchema = object({
|
|
29945
30099
|
deviceId: number(),
|
|
30100
|
+
/** Bytes the ARCHIVE holds for this camera on this node's resolvable
|
|
30101
|
+
* recordings locations. */
|
|
29946
30102
|
usedBytes: number(),
|
|
29947
30103
|
/**
|
|
29948
|
-
* Start of this camera's OLDEST
|
|
30104
|
+
* Start of this camera's OLDEST ARCHIVED segment, across every profile and
|
|
29949
30105
|
* location — the "Oldest footage" column in Recordings → Storage, and the
|
|
29950
30106
|
* only honest answer to "is retention actually holding?" per camera.
|
|
29951
30107
|
*
|
|
@@ -29955,7 +30111,24 @@ var RecordingDeviceUsageSchema = object({
|
|
|
29955
30111
|
* (types) and the addon ship on different trains, and the addon is usually
|
|
29956
30112
|
* the later of the two.
|
|
29957
30113
|
*/
|
|
29958
|
-
oldestMs: number().nullable().optional()
|
|
30114
|
+
oldestMs: number().nullable().optional(),
|
|
30115
|
+
/** Segments the archive holds for this camera — the "M" beside `usedBytes`.
|
|
30116
|
+
* OPTIONAL for the same train-skew reason as `oldestMs`. */
|
|
30117
|
+
segments: number().optional(),
|
|
30118
|
+
/**
|
|
30119
|
+
* RESIDENCY, not the archive: bytes the recorder process currently holds in
|
|
30120
|
+
* its RAM index — the live tail plus the hours a reader hydrated.
|
|
30121
|
+
*
|
|
30122
|
+
* It answers "what can be served without touching the disk", never "how much
|
|
30123
|
+
* footage this camera has". A UI that renders it must label it as such, and
|
|
30124
|
+
* must never total it as storage. OPTIONAL: a recorder predating D418 omits
|
|
30125
|
+
* it, and so does a node whose ledger could not answer.
|
|
30126
|
+
*/
|
|
30127
|
+
residentBytes: number().optional(),
|
|
30128
|
+
/** The residency counterpart of `oldestMs` — the oldest segment currently in
|
|
30129
|
+
* RAM, which on a healthy recorder is minutes ago and means nothing about
|
|
30130
|
+
* retention. `null` = nothing resident. */
|
|
30131
|
+
residentOldestMs: number().nullable().optional()
|
|
29959
30132
|
});
|
|
29960
30133
|
/** Recording storage usage + capacity for one storage location. */
|
|
29961
30134
|
var RecordingLocationUsageSchema = object({
|
|
@@ -29993,6 +30166,17 @@ var RecordingStorageUsageSchema = object({
|
|
|
29993
30166
|
totalUsedBytes: number(),
|
|
29994
30167
|
devices: array(RecordingDeviceUsageSchema),
|
|
29995
30168
|
/**
|
|
30169
|
+
* WHERE `devices[]` came from, so an empty table is never mistaken for empty
|
|
30170
|
+
* disks (D418).
|
|
30171
|
+
*
|
|
30172
|
+
* `archive` = the durable hour ledger answered. `unavailable` = this node
|
|
30173
|
+
* declared no ledger and the recorder REFUSED rather than answering the
|
|
30174
|
+
* question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
|
|
30175
|
+
* zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
|
|
30176
|
+
* and its rows are residency.
|
|
30177
|
+
*/
|
|
30178
|
+
devicesRead: _enum(["archive", "unavailable"]).optional(),
|
|
30179
|
+
/**
|
|
29996
30180
|
* Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
|
|
29997
30181
|
* of the payload without it: the hub serves this method through a BAKED
|
|
29998
30182
|
* router, so a hub whose framework train predates a change to this array
|
|
@@ -30153,7 +30337,14 @@ var ReadWindowBytesResultSchema = discriminatedUnion("kind", [object({
|
|
|
30153
30337
|
method(object({
|
|
30154
30338
|
deviceId: number(),
|
|
30155
30339
|
fromMs: number(),
|
|
30156
|
-
toMs: number()
|
|
30340
|
+
toMs: number(),
|
|
30341
|
+
/**
|
|
30342
|
+
* Answer for THIS profile instead of the preferred one (D433). Absent
|
|
30343
|
+
* keeps the timeline's behaviour — one bar, one profile, one set of
|
|
30344
|
+
* reads. `profilesWithFootage` on the answer says what may be asked
|
|
30345
|
+
* for.
|
|
30346
|
+
*/
|
|
30347
|
+
profile: string().optional()
|
|
30157
30348
|
}), RecordingAvailabilitySchema, {
|
|
30158
30349
|
kind: "query",
|
|
30159
30350
|
auth: "protected"
|
|
@@ -33872,7 +34063,7 @@ function toDeviceSummary(device, addonId) {
|
|
|
33872
34063
|
};
|
|
33873
34064
|
}
|
|
33874
34065
|
/**
|
|
33875
|
-
* Base class for device-provider addons (rtsp, onvif
|
|
34066
|
+
* Base class for device-provider addons (rtsp, onvif).
|
|
33876
34067
|
*
|
|
33877
34068
|
* Provides default implementations for the common device-provider cap
|
|
33878
34069
|
* methods (`start`, `stop`, `getStatus`, `getDevices`, `supportsDiscovery`,
|
|
@@ -38528,6 +38719,24 @@ Object.freeze({
|
|
|
38528
38719
|
addonId: null,
|
|
38529
38720
|
access: "view"
|
|
38530
38721
|
},
|
|
38722
|
+
"pipelineRunner.getParkedTrackFrame": {
|
|
38723
|
+
capName: "pipeline-runner",
|
|
38724
|
+
capScope: "system",
|
|
38725
|
+
addonId: null,
|
|
38726
|
+
access: "view"
|
|
38727
|
+
},
|
|
38728
|
+
"pipelineRunner.parkTrackFrame": {
|
|
38729
|
+
capName: "pipeline-runner",
|
|
38730
|
+
capScope: "system",
|
|
38731
|
+
addonId: null,
|
|
38732
|
+
access: "create"
|
|
38733
|
+
},
|
|
38734
|
+
"pipelineRunner.releaseParkedTrackFrames": {
|
|
38735
|
+
capName: "pipeline-runner",
|
|
38736
|
+
capScope: "system",
|
|
38737
|
+
addonId: null,
|
|
38738
|
+
access: "create"
|
|
38739
|
+
},
|
|
38531
38740
|
"pipelineRunner.reportMotion": {
|
|
38532
38741
|
capName: "pipeline-runner",
|
|
38533
38742
|
capScope: "system",
|
|
@@ -41805,6 +42014,21 @@ Object.freeze({
|
|
|
41805
42014
|
form: "single",
|
|
41806
42015
|
optional: false
|
|
41807
42016
|
}],
|
|
42017
|
+
"pipelineRunner.getParkedTrackFrame": [{
|
|
42018
|
+
name: "deviceId",
|
|
42019
|
+
form: "single",
|
|
42020
|
+
optional: false
|
|
42021
|
+
}],
|
|
42022
|
+
"pipelineRunner.parkTrackFrame": [{
|
|
42023
|
+
name: "deviceId",
|
|
42024
|
+
form: "single",
|
|
42025
|
+
optional: false
|
|
42026
|
+
}],
|
|
42027
|
+
"pipelineRunner.releaseParkedTrackFrames": [{
|
|
42028
|
+
name: "deviceId",
|
|
42029
|
+
form: "single",
|
|
42030
|
+
optional: false
|
|
42031
|
+
}],
|
|
41808
42032
|
"pipelineRunner.reportMotion": [{
|
|
41809
42033
|
name: "deviceId",
|
|
41810
42034
|
form: "single",
|
|
@@ -42496,7 +42720,7 @@ var PreviewTextField = string().max(200);
|
|
|
42496
42720
|
* Whether the notification's preview is a STILL or a short animation.
|
|
42497
42721
|
*
|
|
42498
42722
|
* The operator's ask, verbatim: *"inviato come gif o video (come per le altre
|
|
42499
|
-
* rule)"* —
|
|
42723
|
+
* rule)"* — the other rules already offer an animated preview, and a ten-hour
|
|
42500
42724
|
* night reads better as three seconds of motion than as one frame of it. Both
|
|
42501
42725
|
* modes get the SAME treatment (blurred frame, large centred title); `'gif'`
|
|
42502
42726
|
* simply applies it to a dozen frames sampled across the render and assembles
|
package/dist/addon.mjs
CHANGED
|
@@ -36,7 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
36
36
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
37
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
38
38
|
//#endregion
|
|
39
|
-
//#region ../types/dist/event-category-
|
|
39
|
+
//#region ../types/dist/event-category-DAXzJeTX.mjs
|
|
40
40
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
41
41
|
EventCategory["SystemBoot"] = "system.boot";
|
|
42
42
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -628,7 +628,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
628
628
|
* issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
|
|
629
629
|
*/
|
|
630
630
|
EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
|
|
631
|
-
EventCategory["FrigateLiveEvent"] = "frigate.live-event";
|
|
632
631
|
EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
|
|
633
632
|
/**
|
|
634
633
|
* Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
|
|
@@ -12662,7 +12661,7 @@ DeviceType.Camera;
|
|
|
12662
12661
|
var SourceInfoSchema = object({
|
|
12663
12662
|
/** Live dispatch key — mutable when the source system allows rename. */
|
|
12664
12663
|
id: string(),
|
|
12665
|
-
/** Source system tag — e.g. 'homeassistant' | 'reolink' | '
|
|
12664
|
+
/** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
|
|
12666
12665
|
system: string(),
|
|
12667
12666
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
12668
12667
|
* Used to detect rename when `id` changes. */
|
|
@@ -12675,7 +12674,7 @@ var SourceInfoSchema = object({
|
|
|
12675
12674
|
/**
|
|
12676
12675
|
* Build the synthetic SourceInfo every existing provider falls back to
|
|
12677
12676
|
* when no upstream value has been persisted. Keeps non-migrated providers
|
|
12678
|
-
* (Reolink / Hikvision / ONVIF /
|
|
12677
|
+
* (Reolink / Hikvision / ONVIF / RTSP) functional without code
|
|
12679
12678
|
* changes — `id` reuses the CamStack stableId, `system` reuses the addon
|
|
12680
12679
|
* id. Real upstream identity replaces this once a provider migrates and
|
|
12681
12680
|
* calls `updateSourceInfo()` with concrete values.
|
|
@@ -13354,7 +13353,7 @@ var deviceProviderCapability = {
|
|
|
13354
13353
|
* - `device-management.router.ts` (deleted in Phase 2)
|
|
13355
13354
|
* - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
|
|
13356
13355
|
*
|
|
13357
|
-
* All device provider addons (rtsp, onvif,
|
|
13356
|
+
* All device provider addons (rtsp, onvif, …) are hub-local: they may
|
|
13358
13357
|
* fork into separate processes but never run on remote cluster agents. Therefore:
|
|
13359
13358
|
* - No nodeId routing needed — this is a pure hub singleton.
|
|
13360
13359
|
* - The hub's DeviceRegistry is the single source of truth for all live devices.
|
|
@@ -17402,7 +17401,7 @@ var NcRuleInputSchema = object({
|
|
|
17402
17401
|
* The measured seven-person arrival on device 590 spans 110 s with every
|
|
17403
17402
|
* internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
|
|
17404
17403
|
* idle cutoff holds it as one and ends it when the arrival actually ends.
|
|
17405
|
-
* 30 is
|
|
17404
|
+
* 30 s is a widely shipped value for the same decision.
|
|
17406
17405
|
*
|
|
17407
17406
|
* ### What it replaces
|
|
17408
17407
|
*
|
|
@@ -19484,6 +19483,13 @@ var ZoneCrossingSchema = object({
|
|
|
19484
19483
|
/** Zone display name at crossing time (falls back to the id). */
|
|
19485
19484
|
zoneName: string().optional()
|
|
19486
19485
|
});
|
|
19486
|
+
/** One zone a box was stamped with, and how much of the BOX fell inside it. */
|
|
19487
|
+
var ZoneOverlapSchema = object({
|
|
19488
|
+
zoneId: string(),
|
|
19489
|
+
zoneName: string().optional(),
|
|
19490
|
+
/** Percentage of the BOX area inside the zone, 0–100. */
|
|
19491
|
+
overlapPct: number()
|
|
19492
|
+
});
|
|
19487
19493
|
var ObjectEventSchema = object({
|
|
19488
19494
|
...BaseEventFields,
|
|
19489
19495
|
kind: literal("object"),
|
|
@@ -19508,6 +19514,35 @@ var ObjectEventSchema = object({
|
|
|
19508
19514
|
bbox: BoundingBoxSchema.optional(),
|
|
19509
19515
|
/** Heavy JSON — omitted in slim projection. */
|
|
19510
19516
|
zones: array(string()).readonly().optional(),
|
|
19517
|
+
/**
|
|
19518
|
+
* How far inside each stamped zone the box actually was, as a percentage of
|
|
19519
|
+
* the BOX area.
|
|
19520
|
+
*
|
|
19521
|
+
* Membership alone cannot express "at least a third of it inside", which is
|
|
19522
|
+
* the bar an operator argues with — and the number already existed: the
|
|
19523
|
+
* engine computed it, the pipeline logged it, and then discarded it. It
|
|
19524
|
+
* matters most on the events that carry no track, where a rule has nothing
|
|
19525
|
+
* else to judge by.
|
|
19526
|
+
*/
|
|
19527
|
+
zoneOverlaps: array(ZoneOverlapSchema).readonly().optional(),
|
|
19528
|
+
/**
|
|
19529
|
+
* Present when this event describes a detection the TRACKER refused, so it
|
|
19530
|
+
* has no track and never will.
|
|
19531
|
+
*
|
|
19532
|
+
* A zone-scoped immediate rule asks "is there an animal in the flowerbed
|
|
19533
|
+
* NOW?"; tracking answers a different question ("is this the same subject as
|
|
19534
|
+
* before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
|
|
19535
|
+
* dog at 0.7729, 100% inside a watched zone, was refused three times in six
|
|
19536
|
+
* seconds with three different candidate ids — seven analysed frames in the
|
|
19537
|
+
* window, the subject in a handful of them, metres apart — and produced no
|
|
19538
|
+
* event at all.
|
|
19539
|
+
*
|
|
19540
|
+
* It is NAMED rather than merely implied by a missing `trackId`: an event
|
|
19541
|
+
* with no track and no reason is indistinguishable from a track whose media
|
|
19542
|
+
* went missing, and a consumer that asks this one for a best shot or a
|
|
19543
|
+
* history is asking for something that never existed.
|
|
19544
|
+
*/
|
|
19545
|
+
spawnRefused: string().optional(),
|
|
19511
19546
|
/** Omitted in slim projection. */
|
|
19512
19547
|
state: TrackStateSchema.optional(),
|
|
19513
19548
|
/**
|
|
@@ -19934,7 +19969,17 @@ var EventDensityBucketSchema = object({
|
|
|
19934
19969
|
bucketStart: number(),
|
|
19935
19970
|
motion: number().int(),
|
|
19936
19971
|
object: number().int(),
|
|
19937
|
-
audio: number().int()
|
|
19972
|
+
audio: number().int(),
|
|
19973
|
+
/**
|
|
19974
|
+
* Energy-weighted mean dBFS of the audio events in this bucket — the LEVEL,
|
|
19975
|
+
* as opposed to `audio`, which is their COUNT (D431).
|
|
19976
|
+
*
|
|
19977
|
+
* ABSENT when the bucket holds no audio event. Absence means "nothing was
|
|
19978
|
+
* measured", which is not the same claim as silence, and a lane that cannot
|
|
19979
|
+
* tell them apart paints a quiet hour at full scale — which is exactly what
|
|
19980
|
+
* the count-on-a-level-meter did.
|
|
19981
|
+
*/
|
|
19982
|
+
audioDbfs: number().optional()
|
|
19938
19983
|
});
|
|
19939
19984
|
/**
|
|
19940
19985
|
* One camera's row in a `getEventDensityBatch` answer.
|
|
@@ -20581,6 +20626,60 @@ var NativeCropResultSchema = object({
|
|
|
20581
20626
|
*/
|
|
20582
20627
|
tier: _enum(["native", "ram-fullframe"]).optional()
|
|
20583
20628
|
});
|
|
20629
|
+
/**
|
|
20630
|
+
* What a PARKED frame is for — the `kind` half of the `(deviceId, trackId,
|
|
20631
|
+
* kind)` key ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
|
|
20632
|
+
*
|
|
20633
|
+
* - `keyFrame` — the track's clean best FULL frame at native width (capped by
|
|
20634
|
+
* the caller's `maxWidth`). What `keyFrame` + `keyFrameSmall` are written
|
|
20635
|
+
* from, and what the detail plane's full-frame rung cuts from.
|
|
20636
|
+
* - `thumbnail` — the best-shot subject slab: the caller's 16:9 central-square
|
|
20637
|
+
* window, cut by the runner at uncapped native resolution.
|
|
20638
|
+
*
|
|
20639
|
+
* The runner never interprets `trackId`; it is an opaque key the hub owns.
|
|
20640
|
+
*/
|
|
20641
|
+
var ParkedFrameKindSchema = _enum(["keyFrame", "thumbnail"]);
|
|
20642
|
+
/**
|
|
20643
|
+
* Why a park did NOT happen. Every one is logged on the runner with
|
|
20644
|
+
* `tags: { deviceId }` and the handle's measured age, because a handle already
|
|
20645
|
+
* gone at park time IS the defect the 150–500 ms window exists to prevent —
|
|
20646
|
+
* never a reason to retry in a loop.
|
|
20647
|
+
*
|
|
20648
|
+
* - `handle-gone` — the native surface no longer resolves this handle (never
|
|
20649
|
+
* registered, past the lease bound, or the worker released it). `detail`
|
|
20650
|
+
* carries the runner's own miss reason.
|
|
20651
|
+
* - `encode-failed` — pixels resolved and the JPEG encode threw.
|
|
20652
|
+
*/
|
|
20653
|
+
var ParkRefusalSchema = _enum(["handle-gone", "encode-failed"]);
|
|
20654
|
+
/** Answer to `parkTrackFrame` — a discriminated union, so "not parked" always names why. */
|
|
20655
|
+
var ParkTrackFrameResultSchema = discriminatedUnion("parked", [object({
|
|
20656
|
+
parked: literal(true),
|
|
20657
|
+
/** The node holding the parcel — what a later retrieval must be pinned to. */
|
|
20658
|
+
nodeId: string(),
|
|
20659
|
+
width: number().int().positive(),
|
|
20660
|
+
height: number().int().positive(),
|
|
20661
|
+
/** JPEG bytes the parcel costs on the node. */
|
|
20662
|
+
bytes: number().int().nonnegative(),
|
|
20663
|
+
/** Whether this park replaced a parcel already held for the key. */
|
|
20664
|
+
replaced: boolean()
|
|
20665
|
+
}), object({
|
|
20666
|
+
parked: literal(false),
|
|
20667
|
+
nodeId: string(),
|
|
20668
|
+
reason: ParkRefusalSchema,
|
|
20669
|
+
/** Age of the handle at the park, on the runner's clock; null if unknown. */
|
|
20670
|
+
handleAgeMs: number().nullable(),
|
|
20671
|
+
detail: string().optional()
|
|
20672
|
+
})]);
|
|
20673
|
+
/** A retrieved parcel — the runner's own JPEG, base64 for the wire. */
|
|
20674
|
+
var ParkedTrackFrameSchema = object({
|
|
20675
|
+
jpeg: string(),
|
|
20676
|
+
width: number().int().positive(),
|
|
20677
|
+
height: number().int().positive(),
|
|
20678
|
+
/** The frame instant the parcel shows (the caller's clock, echoed back). */
|
|
20679
|
+
timestamp: number(),
|
|
20680
|
+
/** When the node stored it (the node's clock). */
|
|
20681
|
+
parkedAt: number()
|
|
20682
|
+
});
|
|
20584
20683
|
/** Parent detection context passed to `runDetailSubtree` — the crop's
|
|
20585
20684
|
* originating detection, in FRAME-space coordinates. Reuses
|
|
20586
20685
|
* `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
|
|
@@ -20970,7 +21069,7 @@ var RunnerCameraConfigSchema = object({
|
|
|
20970
21069
|
* - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
|
|
20971
21070
|
* analyzer providers) running on decoded frames in this runner.
|
|
20972
21071
|
* - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
|
|
20973
|
-
* analytics
|
|
21072
|
+
* analytics). The provider emits ProviderMotion
|
|
20974
21073
|
* events; the orchestrator forwards to `reportMotion`.
|
|
20975
21074
|
*/
|
|
20976
21075
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
@@ -21212,7 +21311,26 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
|
|
|
21212
21311
|
className: string(),
|
|
21213
21312
|
/** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
|
|
21214
21313
|
sourceDeviceId: number()
|
|
21215
|
-
}), RunStatelessStepResultSchema, { kind: "mutation" })
|
|
21314
|
+
}), RunStatelessStepResultSchema, { kind: "mutation" }), method(object({
|
|
21315
|
+
deviceId: number(),
|
|
21316
|
+
/** Opaque to the runner — the hub's track id. */
|
|
21317
|
+
trackId: string(),
|
|
21318
|
+
kind: ParkedFrameKindSchema,
|
|
21319
|
+
handle: FrameHandleSchema,
|
|
21320
|
+
/** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
|
|
21321
|
+
bbox: NativeCropBboxSchema,
|
|
21322
|
+
/** Width cap for a full-frame park (the `keyFrame` native cap). */
|
|
21323
|
+
maxWidth: number().int().positive().optional(),
|
|
21324
|
+
/** The frame instant (caller's clock) — orders parks for one key. */
|
|
21325
|
+
timestamp: number()
|
|
21326
|
+
}), ParkTrackFrameResultSchema, { kind: "mutation" }), method(object({
|
|
21327
|
+
deviceId: number(),
|
|
21328
|
+
trackId: string(),
|
|
21329
|
+
kind: ParkedFrameKindSchema
|
|
21330
|
+
}), ParkedTrackFrameSchema.nullable()), method(object({
|
|
21331
|
+
deviceId: number(),
|
|
21332
|
+
trackId: string()
|
|
21333
|
+
}), object({ released: number().int().nonnegative() }), { kind: "mutation" });
|
|
21216
21334
|
var CameraPipelineConfigSchema = object({
|
|
21217
21335
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
21218
21336
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -24282,8 +24400,8 @@ onStatusChanged: { data: object({
|
|
|
24282
24400
|
/**
|
|
24283
24401
|
* Runtime-state slice — every provider that registers this cap
|
|
24284
24402
|
* stores the same shape under `device.runtimeState[battery]`.
|
|
24285
|
-
* Cross-provider uniformity: a Reolink Argus, a
|
|
24286
|
-
*
|
|
24403
|
+
* Cross-provider uniformity: a Reolink Argus, a sensor proxy,
|
|
24404
|
+
* an ONVIF battery cam all read/write the same keys.
|
|
24287
24405
|
* Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
|
|
24288
24406
|
* via `device.runtimeState.getCapState('battery')` regardless of
|
|
24289
24407
|
* the underlying driver.
|
|
@@ -24416,7 +24534,7 @@ DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _v
|
|
|
24416
24534
|
*
|
|
24417
24535
|
* Implementations:
|
|
24418
24536
|
* - Each camera-providing addon registers this cap natively per
|
|
24419
|
-
* device (Reolink, Hikvision, RTSP,
|
|
24537
|
+
* device (Reolink, Hikvision, RTSP, ONVIF self).
|
|
24420
24538
|
* - Returns a snapshot from the persisted device config blob — no
|
|
24421
24539
|
* extra round-trip to the camera, no probing.
|
|
24422
24540
|
* - The cap is admin-only (`auth: 'admin'`) — credentials must not
|
|
@@ -26516,7 +26634,7 @@ var AvailableIntegrationTypeSchema = object({
|
|
|
26516
26634
|
* Which integration-marker cap the addon declared, so the wizard can
|
|
26517
26635
|
* branch on CAP — never on addon name. `device-adoption` integrations
|
|
26518
26636
|
* (Home Assistant, …) route through the broker step (Approach A);
|
|
26519
|
-
* `device-provider` integrations (Reolink/
|
|
26637
|
+
* `device-provider` integrations (Reolink/ONVIF) keep the
|
|
26520
26638
|
* legacy config → discovery flow.
|
|
26521
26639
|
*/
|
|
26522
26640
|
kind: _enum(["device-adoption", "device-provider"]),
|
|
@@ -29884,7 +30002,23 @@ var RecordingRangeSchema = object({
|
|
|
29884
30002
|
});
|
|
29885
30003
|
var RecordingAvailabilitySchema = object({
|
|
29886
30004
|
deviceId: number(),
|
|
29887
|
-
ranges: array(RecordingRangeSchema)
|
|
30005
|
+
ranges: array(RecordingRangeSchema),
|
|
30006
|
+
/**
|
|
30007
|
+
* Every profile this camera has footage in — not only the one `ranges`
|
|
30008
|
+
* describes (D433).
|
|
30009
|
+
*
|
|
30010
|
+
* `ranges` answers for ONE profile by design: the timeline is a single bar,
|
|
30011
|
+
* and enumerating all of them triples the directory reads for a bar that
|
|
30012
|
+
* would look identical. But the answer used to say nothing about that, so a
|
|
30013
|
+
* caller asking "what can I export?" read the single preferred profile as
|
|
30014
|
+
* the only one that exists — on this deployment every camera records `high`
|
|
30015
|
+
* AND `low`, the low tree holding 14 GB for camera 615 alone, and the export
|
|
30016
|
+
* UI could not see it.
|
|
30017
|
+
*
|
|
30018
|
+
* Cheap: it is the same shallow directory read the profile CHOICE already
|
|
30019
|
+
* makes. Ask for a specific profile's ranges with the `profile` input.
|
|
30020
|
+
*/
|
|
30021
|
+
profilesWithFootage: array(string())
|
|
29888
30022
|
});
|
|
29889
30023
|
var RecordingDaysSchema = object({
|
|
29890
30024
|
deviceId: number(),
|
|
@@ -29910,7 +30044,11 @@ var RecordingDaysSchema = object({
|
|
|
29910
30044
|
var RecordingAvailabilityForDeviceSchema = object({
|
|
29911
30045
|
deviceId: number(),
|
|
29912
30046
|
read: _enum(["read", "unreadable"]),
|
|
29913
|
-
ranges: array(RecordingRangeSchema).readonly()
|
|
30047
|
+
ranges: array(RecordingRangeSchema).readonly(),
|
|
30048
|
+
/** Same field, same meaning, as the singular answer (D433). A row that
|
|
30049
|
+
* dropped it would tell a grid caller the archive holds one profile.
|
|
30050
|
+
* Empty on an `'unreadable'` row: nobody looked. */
|
|
30051
|
+
profilesWithFootage: array(string()).readonly()
|
|
29914
30052
|
});
|
|
29915
30053
|
/**
|
|
29916
30054
|
* One camera's row in a `getDaysWithRecordingsBatch` answer. Same rule as
|
|
@@ -29940,13 +30078,31 @@ var RecordingManifestSchema = object({
|
|
|
29940
30078
|
*/
|
|
29941
30079
|
playbackEndpoints: array(string())
|
|
29942
30080
|
});
|
|
29943
|
-
/**
|
|
29944
|
-
*
|
|
30081
|
+
/**
|
|
30082
|
+
* Recording storage usage for one camera — what the ARCHIVE holds for it,
|
|
30083
|
+
* across every profile and every resolvable location on this node.
|
|
30084
|
+
*
|
|
30085
|
+
* ## Archive vs residency, which is the whole point of this shape (D418)
|
|
30086
|
+
*
|
|
30087
|
+
* `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
|
|
30088
|
+
* the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
|
|
30089
|
+
* this camera writes to, so the two can be added up and compared.
|
|
30090
|
+
*
|
|
30091
|
+
* They were not always. Until D418 this row came from the recorder's in-RAM
|
|
30092
|
+
* `RecordingIndex`, which since D287 holds only the live tail plus the hours
|
|
30093
|
+
* somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
|
|
30094
|
+
* 60.5 GB and "oldest: three hours ago" on the same page as the volume row
|
|
30095
|
+
* that said otherwise, and two people read it as retention eating recent
|
|
30096
|
+
* footage. Residency is still reported, under `residentBytes` /
|
|
30097
|
+
* `residentOldestMs`, which answer a different question and say so.
|
|
30098
|
+
*/
|
|
29945
30099
|
var RecordingDeviceUsageSchema = object({
|
|
29946
30100
|
deviceId: number(),
|
|
30101
|
+
/** Bytes the ARCHIVE holds for this camera on this node's resolvable
|
|
30102
|
+
* recordings locations. */
|
|
29947
30103
|
usedBytes: number(),
|
|
29948
30104
|
/**
|
|
29949
|
-
* Start of this camera's OLDEST
|
|
30105
|
+
* Start of this camera's OLDEST ARCHIVED segment, across every profile and
|
|
29950
30106
|
* location — the "Oldest footage" column in Recordings → Storage, and the
|
|
29951
30107
|
* only honest answer to "is retention actually holding?" per camera.
|
|
29952
30108
|
*
|
|
@@ -29956,7 +30112,24 @@ var RecordingDeviceUsageSchema = object({
|
|
|
29956
30112
|
* (types) and the addon ship on different trains, and the addon is usually
|
|
29957
30113
|
* the later of the two.
|
|
29958
30114
|
*/
|
|
29959
|
-
oldestMs: number().nullable().optional()
|
|
30115
|
+
oldestMs: number().nullable().optional(),
|
|
30116
|
+
/** Segments the archive holds for this camera — the "M" beside `usedBytes`.
|
|
30117
|
+
* OPTIONAL for the same train-skew reason as `oldestMs`. */
|
|
30118
|
+
segments: number().optional(),
|
|
30119
|
+
/**
|
|
30120
|
+
* RESIDENCY, not the archive: bytes the recorder process currently holds in
|
|
30121
|
+
* its RAM index — the live tail plus the hours a reader hydrated.
|
|
30122
|
+
*
|
|
30123
|
+
* It answers "what can be served without touching the disk", never "how much
|
|
30124
|
+
* footage this camera has". A UI that renders it must label it as such, and
|
|
30125
|
+
* must never total it as storage. OPTIONAL: a recorder predating D418 omits
|
|
30126
|
+
* it, and so does a node whose ledger could not answer.
|
|
30127
|
+
*/
|
|
30128
|
+
residentBytes: number().optional(),
|
|
30129
|
+
/** The residency counterpart of `oldestMs` — the oldest segment currently in
|
|
30130
|
+
* RAM, which on a healthy recorder is minutes ago and means nothing about
|
|
30131
|
+
* retention. `null` = nothing resident. */
|
|
30132
|
+
residentOldestMs: number().nullable().optional()
|
|
29960
30133
|
});
|
|
29961
30134
|
/** Recording storage usage + capacity for one storage location. */
|
|
29962
30135
|
var RecordingLocationUsageSchema = object({
|
|
@@ -29994,6 +30167,17 @@ var RecordingStorageUsageSchema = object({
|
|
|
29994
30167
|
totalUsedBytes: number(),
|
|
29995
30168
|
devices: array(RecordingDeviceUsageSchema),
|
|
29996
30169
|
/**
|
|
30170
|
+
* WHERE `devices[]` came from, so an empty table is never mistaken for empty
|
|
30171
|
+
* disks (D418).
|
|
30172
|
+
*
|
|
30173
|
+
* `archive` = the durable hour ledger answered. `unavailable` = this node
|
|
30174
|
+
* declared no ledger and the recorder REFUSED rather than answering the
|
|
30175
|
+
* question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
|
|
30176
|
+
* zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
|
|
30177
|
+
* and its rows are residency.
|
|
30178
|
+
*/
|
|
30179
|
+
devicesRead: _enum(["archive", "unavailable"]).optional(),
|
|
30180
|
+
/**
|
|
29997
30181
|
* Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
|
|
29998
30182
|
* of the payload without it: the hub serves this method through a BAKED
|
|
29999
30183
|
* router, so a hub whose framework train predates a change to this array
|
|
@@ -30154,7 +30338,14 @@ var ReadWindowBytesResultSchema = discriminatedUnion("kind", [object({
|
|
|
30154
30338
|
method(object({
|
|
30155
30339
|
deviceId: number(),
|
|
30156
30340
|
fromMs: number(),
|
|
30157
|
-
toMs: number()
|
|
30341
|
+
toMs: number(),
|
|
30342
|
+
/**
|
|
30343
|
+
* Answer for THIS profile instead of the preferred one (D433). Absent
|
|
30344
|
+
* keeps the timeline's behaviour — one bar, one profile, one set of
|
|
30345
|
+
* reads. `profilesWithFootage` on the answer says what may be asked
|
|
30346
|
+
* for.
|
|
30347
|
+
*/
|
|
30348
|
+
profile: string().optional()
|
|
30158
30349
|
}), RecordingAvailabilitySchema, {
|
|
30159
30350
|
kind: "query",
|
|
30160
30351
|
auth: "protected"
|
|
@@ -33873,7 +34064,7 @@ function toDeviceSummary(device, addonId) {
|
|
|
33873
34064
|
};
|
|
33874
34065
|
}
|
|
33875
34066
|
/**
|
|
33876
|
-
* Base class for device-provider addons (rtsp, onvif
|
|
34067
|
+
* Base class for device-provider addons (rtsp, onvif).
|
|
33877
34068
|
*
|
|
33878
34069
|
* Provides default implementations for the common device-provider cap
|
|
33879
34070
|
* methods (`start`, `stop`, `getStatus`, `getDevices`, `supportsDiscovery`,
|
|
@@ -38529,6 +38720,24 @@ Object.freeze({
|
|
|
38529
38720
|
addonId: null,
|
|
38530
38721
|
access: "view"
|
|
38531
38722
|
},
|
|
38723
|
+
"pipelineRunner.getParkedTrackFrame": {
|
|
38724
|
+
capName: "pipeline-runner",
|
|
38725
|
+
capScope: "system",
|
|
38726
|
+
addonId: null,
|
|
38727
|
+
access: "view"
|
|
38728
|
+
},
|
|
38729
|
+
"pipelineRunner.parkTrackFrame": {
|
|
38730
|
+
capName: "pipeline-runner",
|
|
38731
|
+
capScope: "system",
|
|
38732
|
+
addonId: null,
|
|
38733
|
+
access: "create"
|
|
38734
|
+
},
|
|
38735
|
+
"pipelineRunner.releaseParkedTrackFrames": {
|
|
38736
|
+
capName: "pipeline-runner",
|
|
38737
|
+
capScope: "system",
|
|
38738
|
+
addonId: null,
|
|
38739
|
+
access: "create"
|
|
38740
|
+
},
|
|
38532
38741
|
"pipelineRunner.reportMotion": {
|
|
38533
38742
|
capName: "pipeline-runner",
|
|
38534
38743
|
capScope: "system",
|
|
@@ -41806,6 +42015,21 @@ Object.freeze({
|
|
|
41806
42015
|
form: "single",
|
|
41807
42016
|
optional: false
|
|
41808
42017
|
}],
|
|
42018
|
+
"pipelineRunner.getParkedTrackFrame": [{
|
|
42019
|
+
name: "deviceId",
|
|
42020
|
+
form: "single",
|
|
42021
|
+
optional: false
|
|
42022
|
+
}],
|
|
42023
|
+
"pipelineRunner.parkTrackFrame": [{
|
|
42024
|
+
name: "deviceId",
|
|
42025
|
+
form: "single",
|
|
42026
|
+
optional: false
|
|
42027
|
+
}],
|
|
42028
|
+
"pipelineRunner.releaseParkedTrackFrames": [{
|
|
42029
|
+
name: "deviceId",
|
|
42030
|
+
form: "single",
|
|
42031
|
+
optional: false
|
|
42032
|
+
}],
|
|
41809
42033
|
"pipelineRunner.reportMotion": [{
|
|
41810
42034
|
name: "deviceId",
|
|
41811
42035
|
form: "single",
|
|
@@ -42497,7 +42721,7 @@ var PreviewTextField = string().max(200);
|
|
|
42497
42721
|
* Whether the notification's preview is a STILL or a short animation.
|
|
42498
42722
|
*
|
|
42499
42723
|
* The operator's ask, verbatim: *"inviato come gif o video (come per le altre
|
|
42500
|
-
* rule)"* —
|
|
42724
|
+
* rule)"* — the other rules already offer an animated preview, and a ten-hour
|
|
42501
42725
|
* night reads better as three seconds of motion than as one frame of it. Both
|
|
42502
42726
|
* modes get the SAME treatment (blurred frame, large centred title); `'gif'`
|
|
42503
42727
|
* 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-provider-dreo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.93",
|
|
4
4
|
"description": "Dreo smart-device (fan / air-circulator / purifier / heater / humidifier) device-provider addon for CamStack — wraps the @apocaliss92/nodedreo Dreo cloud client (REST + WebSocket)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|