@camstack/types 1.2.172 → 1.2.175

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 (39) hide show
  1. package/dist/addon/mint-once.d.ts +73 -0
  2. package/dist/addon.js +2 -2
  3. package/dist/addon.mjs +2 -2
  4. package/dist/capabilities/battery.cap.d.ts +2 -2
  5. package/dist/capabilities/camera-credentials.cap.d.ts +1 -1
  6. package/dist/capabilities/capability-definition.d.ts +2 -2
  7. package/dist/capabilities/device-manager.cap.d.ts +1 -1
  8. package/dist/capabilities/index.d.ts +2 -2
  9. package/dist/capabilities/notification-rules.cap.d.ts +11 -11
  10. package/dist/capabilities/pipeline-analytics.cap.d.ts +31 -0
  11. package/dist/capabilities/pipeline-runner.cap.d.ts +162 -0
  12. package/dist/capabilities/recording.cap.d.ts +35 -2
  13. package/dist/device/base-device-provider.d.ts +1 -1
  14. package/dist/device/device-runtime-state.d.ts +2 -2
  15. package/dist/device/device.d.ts +1 -1
  16. package/dist/device/source-info.d.ts +1 -1
  17. package/dist/enums/event-category.d.ts +0 -1
  18. package/dist/enums.js +1 -1
  19. package/dist/enums.mjs +1 -1
  20. package/dist/{event-category-BVo6ta6_.js → event-category-BNJ9EE5B.js} +0 -1
  21. package/dist/{event-category-CnLqLOKs.mjs → event-category-DAXzJeTX.mjs} +0 -1
  22. package/dist/generated/addon-api.d.ts +21 -0
  23. package/dist/generated/device-proxy.d.ts +1 -1
  24. package/dist/generated/method-access-map.d.ts +1 -1
  25. package/dist/generated/method-device-selectors.d.ts +2 -2
  26. package/dist/index.js +247 -18
  27. package/dist/index.mjs +244 -19
  28. package/dist/interfaces/addon.d.ts +1 -1
  29. package/dist/interfaces/config-ui.d.ts +1 -1
  30. package/dist/interfaces/context.d.ts +2 -2
  31. package/dist/interfaces/device-provider.d.ts +1 -1
  32. package/dist/interfaces/event-bus.d.ts +16 -1
  33. package/dist/interfaces/pipeline-runner-capability.d.ts +28 -0
  34. package/dist/interfaces/stream-broker.d.ts +7 -7
  35. package/dist/notification/timelapse-rule.d.ts +1 -1
  36. package/dist/{sleep-Bo9cUOXp.js → sleep-CTHjJilA.js} +5 -2
  37. package/dist/{sleep-DMghvp8F.mjs → sleep-ox21Ig4I.mjs} +5 -2
  38. package/dist/types/detection.d.ts +3 -5
  39. package/package.json +1 -1
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Mint-on-empty, with the read-back that makes it safe.
3
+ *
4
+ * ## The shape, and why it is a trap
5
+ *
6
+ * ```ts
7
+ * let secret = await state.get()
8
+ * if (secret === '') {
9
+ * secret = randomUUID()
10
+ * await state.set(secret)
11
+ * }
12
+ * ```
13
+ *
14
+ * `state.get()` cannot distinguish "never minted" from "the store could not be
15
+ * read": `readAddonStoreWithRetry` gives up and answers `{}`, so a store that
16
+ * is merely unreachable reads as EMPTY and this mints a SECOND secret over a
17
+ * perfectly good first one. For a signing secret that invalidates every link
18
+ * already handed out. For the HomeKit bridge identity it is irreversible —
19
+ * every paired iPhone loses the bridge, and no later write of the store brings
20
+ * it back.
21
+ *
22
+ * The read-back is the only evidence available at this layer that the store is
23
+ * actually answering. `snapshot.addon.ts` (`ensureLinkSecret`) has done this
24
+ * since 2026-08-14 and was the only site that did.
25
+ *
26
+ * ## What it does NOT fix
27
+ *
28
+ * If the write genuinely lands, the read-back confirms it and the old value is
29
+ * already gone — a read-back cannot undo a write. It is a gate on USING the
30
+ * minted value, and it is load-bearing only because the settings view refuses
31
+ * to write at all when the last read of the addon store failed
32
+ * (`writeAddonStore`'s refusal). The two together are what close the window;
33
+ * the durable fix is a discriminated read result carried all the way up —
34
+ * `docs/design/plans/2026-08-27-lettura-fallita-non-diventa-un-default.md`.
35
+ */
36
+ /** Why a mint was refused. Both mean: the store is not answering. */
37
+ export type MintRefusalReason = 'read-back-empty' | 'read-back-mismatch';
38
+ export interface MintRefusalDetail {
39
+ readonly reason: MintRefusalReason;
40
+ /** True when the read-back answered the fallback — the usual store-down shape. */
41
+ readonly readBackEmpty: boolean;
42
+ }
43
+ export type MintOnceOutcome<TValue> = {
44
+ readonly kind: 'existing';
45
+ readonly value: TValue;
46
+ } | {
47
+ readonly kind: 'minted';
48
+ readonly value: TValue;
49
+ } | {
50
+ readonly kind: 'refused';
51
+ };
52
+ export interface MintOnceReadBackInput<TValue> {
53
+ /** Read the persisted value. MUST answer the fallback (not throw) when absent. */
54
+ readonly read: () => Promise<TValue>;
55
+ /** Is this the fallback — i.e. "nothing persisted, or nothing readable"? */
56
+ readonly isEmpty: (value: TValue) => boolean;
57
+ /** Produce a fresh value. Called at most once, and only when `isEmpty` holds. */
58
+ readonly mint: () => TValue;
59
+ /** Persist the freshly minted value. */
60
+ readonly write: (value: TValue) => Promise<void>;
61
+ /** Value equality for the read-back. Defaults to `Object.is`. */
62
+ readonly equals?: (a: TValue, b: TValue) => boolean;
63
+ /** Always log this: a refusal means a feature is deliberately not starting. */
64
+ readonly onRefused: (detail: MintRefusalDetail) => void;
65
+ }
66
+ /**
67
+ * Resolve a mint-once secret/identity: reuse what is stored, or mint, persist
68
+ * and READ BACK — refusing the minted value when the read-back disagrees.
69
+ *
70
+ * A `refused` outcome is never cached by this function; the caller may retry on
71
+ * the next tick, when the store may be answering again.
72
+ */
73
+ export declare function mintOnceWithReadBack<TValue>(input: MintOnceReadBackInput<TValue>): Promise<MintOnceOutcome<TValue>>;
package/dist/addon.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_event_category = require("./event-category-BVo6ta6_.js");
3
- const require_sleep = require("./sleep-Bo9cUOXp.js");
2
+ const require_event_category = require("./event-category-BNJ9EE5B.js");
3
+ const require_sleep = require("./sleep-CTHjJilA.js");
4
4
  const require_err_msg = require("./err-msg-COpsHMw2.js");
5
5
  //#region src/generated/cap-input-defaults.ts
6
6
  /**
package/dist/addon.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { t as EventCategory } from "./event-category-CnLqLOKs.mjs";
2
- import { D as adminUiCapability, E as DeviceType, G as scopeKey, H as ReadinessTimeoutError, M as expandCapMethods, R as nodePin, S as DEVICE_CHILDREN_BATCH_MAX, V as ReadinessRegistry, _t as DATAPLANE_SECRET_HEADER, a as asJsonObject, b as deviceOpsCapability, bt as BaseAddon, d as BOOT_RECOVERY_BACKOFF_MS, f as DEVICE_SCOPED_CAPS, h as createEventBusSliceSource, m as createDeviceProxy, p as isDeviceScopedCap, s as asString, t as sleep, u as parseJsonUnknown, wt as emitReadiness, x as viewerUiCapability, xt as normalizeAddonInitResult, yt as DisposerChain, z as readNodePin } from "./sleep-DMghvp8F.mjs";
1
+ import { t as EventCategory } from "./event-category-DAXzJeTX.mjs";
2
+ import { D as adminUiCapability, E as DeviceType, G as scopeKey, H as ReadinessTimeoutError, M as expandCapMethods, R as nodePin, S as DEVICE_CHILDREN_BATCH_MAX, V as ReadinessRegistry, _t as DATAPLANE_SECRET_HEADER, a as asJsonObject, b as deviceOpsCapability, bt as BaseAddon, d as BOOT_RECOVERY_BACKOFF_MS, f as DEVICE_SCOPED_CAPS, h as createEventBusSliceSource, m as createDeviceProxy, p as isDeviceScopedCap, s as asString, t as sleep, u as parseJsonUnknown, wt as emitReadiness, x as viewerUiCapability, xt as normalizeAddonInitResult, yt as DisposerChain, z as readNodePin } from "./sleep-ox21Ig4I.mjs";
3
3
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
4
4
  //#region src/generated/cap-input-defaults.ts
5
5
  /**
@@ -104,8 +104,8 @@ export declare const batteryCapability: {
104
104
  /**
105
105
  * Runtime-state slice — every provider that registers this cap
106
106
  * stores the same shape under `device.runtimeState[battery]`.
107
- * Cross-provider uniformity: a Reolink Argus, a Frigate sensor
108
- * proxy, an ONVIF battery cam all read/write the same keys.
107
+ * Cross-provider uniformity: a Reolink Argus, a sensor proxy,
108
+ * an ONVIF battery cam all read/write the same keys.
109
109
  * Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
110
110
  * via `device.runtimeState.getCapState('battery')` regardless of
111
111
  * the underlying driver.
@@ -14,7 +14,7 @@ import { DeviceType } from '../device/device-type.js';
14
14
  *
15
15
  * Implementations:
16
16
  * - Each camera-providing addon registers this cap natively per
17
- * device (Reolink, Hikvision, RTSP, Frigate, ONVIF self).
17
+ * device (Reolink, Hikvision, RTSP, ONVIF self).
18
18
  * - Returns a snapshot from the persisted device config blob — no
19
19
  * extra round-trip to the camera, no probing.
20
20
  * - The cap is admin-only (`auth: 'admin'`) — credentials must not
@@ -406,8 +406,8 @@ export interface CapabilityDefinition<TName extends string = string, TMethods ex
406
406
  * .setCapState('<capName>', value)`. Examples:
407
407
  *
408
408
  * - `batteryCapability.runtimeState`: `{ percentage, charging,
409
- * sleeping, lastUpdated }`. A Reolink Argus, a Frigate sensor
410
- * proxy, an ONVIF battery cam — every provider stores the
409
+ * sleeping, lastUpdated }`. A Reolink Argus, a sensor proxy,
410
+ * an ONVIF battery cam — every provider stores the
411
411
  * same shape under `state.battery`.
412
412
  * - `ptzCapability.runtimeState`: `{ pan, tilt, zoom }`.
413
413
  *
@@ -7,7 +7,7 @@
7
7
  * - `device-management.router.ts` (deleted in Phase 2)
8
8
  * - `device-ops.router.ts` (compat layer — deleted; device-provider ops absorbed here)
9
9
  *
10
- * All device provider addons (rtsp, onvif, frigate, …) are hub-local: they may
10
+ * All device provider addons (rtsp, onvif, …) are hub-local: they may
11
11
  * fork into separate processes but never run on remote cluster agents. Therefore:
12
12
  * - No nodeId routing needed — this is a pure hub singleton.
13
13
  * - The hub's DeviceRegistry is the single source of truth for all live devices.
@@ -87,8 +87,8 @@ export type { NativeCropRef, PipelineStepInputOutput, PipelineValidationIssue, P
87
87
  export { ModelSubstitutionSchema, NativeCropRefSchema, PipelineDefaultStepSchema, PipelineEngineChoiceSchema, PipelineRunResultBridge, PipelineStepInputSchema, PipelineValidationIssueSchema, PipelineValidationResultSchema, pipelineExecutorCapability, } from './pipeline-executor.cap.js';
88
88
  export type { CameraAssignmentStatus, CameraAudioStatus, CameraBrokerProfile, CameraBrokerStatus, CameraDecoderShm, CameraDecoderStatus, CameraDetectionPhase, CameraDetectionProvisioning, CameraDetectionProvisioningState, CameraDetectionStatus, CameraMotionStatus, CameraRecordingMode, CameraRecordingStatus, CameraSourceStatus, CameraSourceStream, CameraStatus, CameraStatusDegradation, CameraStatusDegradationReason, CameraStatusStage, DiskReconcileJob, InferenceDeviceExclusionReason, IngestOwner, NodeInferenceDevice, NodeInferenceDevices, } from './pipeline-orchestrator.cap.js';
89
89
  export { AgentLoadSummarySchema, CameraAssignmentStatusSchema, CameraAudioStatusSchema, CameraBrokerProfileSchema, CameraBrokerStatusSchema, CameraDecoderShmSchema, CameraDecoderStatusSchema, CameraDetectionPhaseSchema, CameraDetectionProvisioningSchema, CameraDetectionProvisioningStateSchema, CameraDetectionStatusSchema, CameraMotionStatusSchema, CameraRecordingModeSchema, CameraRecordingStatusSchema, CameraSourceStatusSchema, CameraSourceStreamSchema, CameraStatusDegradationReasonSchema, CameraStatusDegradationSchema, CameraStatusSchema, CameraStatusStageSchema, CapabilityBindingsSchema, DiskReconcileJobSchema, GlobalMetricsSchema, INFERENCE_DEVICE_EXCLUSION_REASONS, InferenceDeviceExclusionReasonSchema, IngestOwnerSchema, PipelineAssignmentSchema, pipelineOrchestratorCapability, } from './pipeline-orchestrator.cap.js';
90
- export type { DetailParent, DetailResult, MotionSource, MotionSources, ReportMotionInput, RunDetailSubtreeInput, RunDetailSubtreeResult, RunnerFrameSource, RunnerInferenceDevice, RunStatelessStepInput, RunStatelessStepResult, StatelessStepRefusal, } from './pipeline-runner.cap.js';
91
- export { FrameLazyCountersSchema, FrameLazyMetricsSchema, MotionSourceEnum, MotionSourcesSchema, type NativeCropBbox, NativeCropBboxSchema, NativeCropResultSchema, pipelineRunnerCapability, ReportMotionInputSchema, RunnerCameraConfigSchema, RunnerCameraDeviceUIFields, RunnerFrameSourceSchema, RunnerInferenceDeviceSchema, RunnerLocalLoadSchema, RunnerLocalMetricsSchema, } from './pipeline-runner.cap.js';
90
+ export type { DetailParent, DetailResult, MotionSource, MotionSources, ParkedFrameKind, ParkedTrackFrame, ParkRefusal, ParkTrackFrameResult, ReportMotionInput, RunDetailSubtreeInput, RunDetailSubtreeResult, RunnerFrameSource, RunnerInferenceDevice, RunStatelessStepInput, RunStatelessStepResult, StatelessStepRefusal, } from './pipeline-runner.cap.js';
91
+ export { FrameLazyCountersSchema, FrameLazyMetricsSchema, MotionSourceEnum, MotionSourcesSchema, type NativeCropBbox, NativeCropBboxSchema, NativeCropResultSchema, ParkedFrameKindSchema, ParkedTrackFrameSchema, ParkRefusalSchema, ParkTrackFrameResultSchema, pipelineRunnerCapability, ReportMotionInputSchema, RunnerCameraConfigSchema, RunnerCameraDeviceUIFields, RunnerFrameSourceSchema, RunnerInferenceDeviceSchema, RunnerLocalLoadSchema, RunnerLocalMetricsSchema, } from './pipeline-runner.cap.js';
92
92
  export { AudioChunkInputSchema, AudioClassificationLabelSchema, AudioLevelSchema, BoundingBoxSchema, FrameInputSchema, SpatialDetectionSchema, } from './schemas/detection-shared.js';
93
93
  export { CameraMetricsSchema, CameraMetricsWithDeviceIdSchema, OrchestratorMetricsSchema, } from './schemas/orchestrator-metrics.js';
94
94
  export type { CameraStream, CamProfile, CamStreamKind, DecodedAudioChunkWire, FrameHandleFormat, ProfileRtspEntry, ProfileSlot, ProfileSlotStatus, SubscribeAudioChunksInput, SubscribeAudioChunksResult, SubscribeFramesInput, SubscribeFramesResult, } from './schemas/streaming-shared.js';
@@ -697,9 +697,9 @@ export type NcMediaFrame = z.infer<typeof NcMediaFrameSchema>;
697
697
  export declare const NcMediaPolicySchema: z.ZodObject<{
698
698
  attach: z.ZodDefault<z.ZodEnum<{
699
699
  none: "none";
700
+ keyFrame: "keyFrame";
700
701
  best: "best";
701
702
  "best-matching": "best-matching";
702
- keyFrame: "keyFrame";
703
703
  }>>;
704
704
  frame: z.ZodOptional<z.ZodEnum<{
705
705
  full: "full";
@@ -961,9 +961,9 @@ export declare const NcRuleInputSchema: z.ZodObject<{
961
961
  media: z.ZodDefault<z.ZodObject<{
962
962
  attach: z.ZodDefault<z.ZodEnum<{
963
963
  none: "none";
964
+ keyFrame: "keyFrame";
964
965
  best: "best";
965
966
  "best-matching": "best-matching";
966
- keyFrame: "keyFrame";
967
967
  }>>;
968
968
  frame: z.ZodOptional<z.ZodEnum<{
969
969
  full: "full";
@@ -1297,9 +1297,9 @@ export declare const NcRulePatchSchema: z.ZodObject<{
1297
1297
  media: z.ZodOptional<z.ZodObject<{
1298
1298
  attach: z.ZodDefault<z.ZodEnum<{
1299
1299
  none: "none";
1300
+ keyFrame: "keyFrame";
1300
1301
  best: "best";
1301
1302
  "best-matching": "best-matching";
1302
- keyFrame: "keyFrame";
1303
1303
  }>>;
1304
1304
  frame: z.ZodOptional<z.ZodEnum<{
1305
1305
  full: "full";
@@ -1478,9 +1478,9 @@ export declare const NcRuleSchema: z.ZodObject<{
1478
1478
  media: z.ZodDefault<z.ZodObject<{
1479
1479
  attach: z.ZodDefault<z.ZodEnum<{
1480
1480
  none: "none";
1481
+ keyFrame: "keyFrame";
1481
1482
  best: "best";
1482
1483
  "best-matching": "best-matching";
1483
- keyFrame: "keyFrame";
1484
1484
  }>>;
1485
1485
  frame: z.ZodOptional<z.ZodEnum<{
1486
1486
  full: "full";
@@ -2174,9 +2174,9 @@ export declare const notificationRulesCapability: {
2174
2174
  media: z.ZodDefault<z.ZodObject<{
2175
2175
  attach: z.ZodDefault<z.ZodEnum<{
2176
2176
  none: "none";
2177
+ keyFrame: "keyFrame";
2177
2178
  best: "best";
2178
2179
  "best-matching": "best-matching";
2179
- keyFrame: "keyFrame";
2180
2180
  }>>;
2181
2181
  frame: z.ZodOptional<z.ZodEnum<{
2182
2182
  full: "full";
@@ -2435,9 +2435,9 @@ export declare const notificationRulesCapability: {
2435
2435
  media: z.ZodDefault<z.ZodObject<{
2436
2436
  attach: z.ZodDefault<z.ZodEnum<{
2437
2437
  none: "none";
2438
+ keyFrame: "keyFrame";
2438
2439
  best: "best";
2439
2440
  "best-matching": "best-matching";
2440
- keyFrame: "keyFrame";
2441
2441
  }>>;
2442
2442
  frame: z.ZodOptional<z.ZodEnum<{
2443
2443
  full: "full";
@@ -2694,9 +2694,9 @@ export declare const notificationRulesCapability: {
2694
2694
  media: z.ZodDefault<z.ZodObject<{
2695
2695
  attach: z.ZodDefault<z.ZodEnum<{
2696
2696
  none: "none";
2697
+ keyFrame: "keyFrame";
2697
2698
  best: "best";
2698
2699
  "best-matching": "best-matching";
2699
- keyFrame: "keyFrame";
2700
2700
  }>>;
2701
2701
  frame: z.ZodOptional<z.ZodEnum<{
2702
2702
  full: "full";
@@ -2947,9 +2947,9 @@ export declare const notificationRulesCapability: {
2947
2947
  media: z.ZodDefault<z.ZodObject<{
2948
2948
  attach: z.ZodDefault<z.ZodEnum<{
2949
2949
  none: "none";
2950
+ keyFrame: "keyFrame";
2950
2951
  best: "best";
2951
2952
  "best-matching": "best-matching";
2952
- keyFrame: "keyFrame";
2953
2953
  }>>;
2954
2954
  frame: z.ZodOptional<z.ZodEnum<{
2955
2955
  full: "full";
@@ -3283,9 +3283,9 @@ export declare const notificationRulesCapability: {
3283
3283
  media: z.ZodOptional<z.ZodObject<{
3284
3284
  attach: z.ZodDefault<z.ZodEnum<{
3285
3285
  none: "none";
3286
+ keyFrame: "keyFrame";
3286
3287
  best: "best";
3287
3288
  "best-matching": "best-matching";
3288
- keyFrame: "keyFrame";
3289
3289
  }>>;
3290
3290
  frame: z.ZodOptional<z.ZodEnum<{
3291
3291
  full: "full";
@@ -3463,9 +3463,9 @@ export declare const notificationRulesCapability: {
3463
3463
  media: z.ZodDefault<z.ZodObject<{
3464
3464
  attach: z.ZodDefault<z.ZodEnum<{
3465
3465
  none: "none";
3466
+ keyFrame: "keyFrame";
3466
3467
  best: "best";
3467
3468
  "best-matching": "best-matching";
3468
- keyFrame: "keyFrame";
3469
3469
  }>>;
3470
3470
  frame: z.ZodOptional<z.ZodEnum<{
3471
3471
  full: "full";
@@ -3770,9 +3770,9 @@ export declare const notificationRulesCapability: {
3770
3770
  media: z.ZodDefault<z.ZodObject<{
3771
3771
  attach: z.ZodDefault<z.ZodEnum<{
3772
3772
  none: "none";
3773
+ keyFrame: "keyFrame";
3773
3774
  best: "best";
3774
3775
  "best-matching": "best-matching";
3775
- keyFrame: "keyFrame";
3776
3776
  }>>;
3777
3777
  frame: z.ZodOptional<z.ZodEnum<{
3778
3778
  full: "full";
@@ -594,6 +594,13 @@ export declare const ZoneCrossingSchema: z.ZodObject<{
594
594
  zoneName: z.ZodOptional<z.ZodString>;
595
595
  }, z.core.$strip>;
596
596
  export type ZoneCrossing = z.infer<typeof ZoneCrossingSchema>;
597
+ /** One zone a box was stamped with, and how much of the BOX fell inside it. */
598
+ export declare const ZoneOverlapSchema: z.ZodObject<{
599
+ zoneId: z.ZodString;
600
+ zoneName: z.ZodOptional<z.ZodString>;
601
+ overlapPct: z.ZodNumber;
602
+ }, z.core.$strip>;
603
+ export type ZoneOverlap = z.infer<typeof ZoneOverlapSchema>;
597
604
  declare const ObjectEventSchema: z.ZodObject<{
598
605
  confidence: z.ZodOptional<z.ZodNumber>;
599
606
  bbox: z.ZodOptional<z.ZodObject<{
@@ -603,6 +610,12 @@ declare const ObjectEventSchema: z.ZodObject<{
603
610
  h: z.ZodNumber;
604
611
  }, z.core.$strip>>;
605
612
  zones: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
613
+ zoneOverlaps: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodObject<{
614
+ zoneId: z.ZodString;
615
+ zoneName: z.ZodOptional<z.ZodString>;
616
+ overlapPct: z.ZodNumber;
617
+ }, z.core.$strip>>>>;
618
+ spawnRefused: z.ZodOptional<z.ZodString>;
606
619
  state: z.ZodOptional<z.ZodEnum<{
607
620
  moving: "moving";
608
621
  left: "left";
@@ -1495,6 +1508,12 @@ export declare const ScoredObjectEventSchema: z.ZodObject<{
1495
1508
  h: z.ZodNumber;
1496
1509
  }, z.core.$strip>>;
1497
1510
  zones: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
1511
+ zoneOverlaps: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodObject<{
1512
+ zoneId: z.ZodString;
1513
+ zoneName: z.ZodOptional<z.ZodString>;
1514
+ overlapPct: z.ZodNumber;
1515
+ }, z.core.$strip>>>>;
1516
+ spawnRefused: z.ZodOptional<z.ZodString>;
1498
1517
  state: z.ZodOptional<z.ZodEnum<{
1499
1518
  moving: "moving";
1500
1519
  left: "left";
@@ -2269,6 +2288,12 @@ export declare const pipelineAnalyticsCapability: {
2269
2288
  h: z.ZodNumber;
2270
2289
  }, z.core.$strip>>;
2271
2290
  zones: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
2291
+ zoneOverlaps: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodObject<{
2292
+ zoneId: z.ZodString;
2293
+ zoneName: z.ZodOptional<z.ZodString>;
2294
+ overlapPct: z.ZodNumber;
2295
+ }, z.core.$strip>>>>;
2296
+ spawnRefused: z.ZodOptional<z.ZodString>;
2272
2297
  state: z.ZodOptional<z.ZodEnum<{
2273
2298
  moving: "moving";
2274
2299
  left: "left";
@@ -3938,6 +3963,12 @@ export declare const pipelineAnalyticsCapability: {
3938
3963
  h: z.ZodNumber;
3939
3964
  }, z.core.$strip>>;
3940
3965
  zones: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
3966
+ zoneOverlaps: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodObject<{
3967
+ zoneId: z.ZodString;
3968
+ zoneName: z.ZodOptional<z.ZodString>;
3969
+ overlapPct: z.ZodNumber;
3970
+ }, z.core.$strip>>>>;
3971
+ spawnRefused: z.ZodOptional<z.ZodString>;
3941
3972
  state: z.ZodOptional<z.ZodEnum<{
3942
3973
  moving: "moving";
3943
3974
  left: "left";
@@ -26,6 +26,67 @@ export declare const NativeCropResultSchema: z.ZodObject<{
26
26
  }, z.core.$strip>;
27
27
  export type NativeCropBbox = z.infer<typeof NativeCropBboxSchema>;
28
28
  export type NativeCropCapResult = z.infer<typeof NativeCropResultSchema>;
29
+ /**
30
+ * What a PARKED frame is for — the `kind` half of the `(deviceId, trackId,
31
+ * kind)` key ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
32
+ *
33
+ * - `keyFrame` — the track's clean best FULL frame at native width (capped by
34
+ * the caller's `maxWidth`). What `keyFrame` + `keyFrameSmall` are written
35
+ * from, and what the detail plane's full-frame rung cuts from.
36
+ * - `thumbnail` — the best-shot subject slab: the caller's 16:9 central-square
37
+ * window, cut by the runner at uncapped native resolution.
38
+ *
39
+ * The runner never interprets `trackId`; it is an opaque key the hub owns.
40
+ */
41
+ export declare const ParkedFrameKindSchema: z.ZodEnum<{
42
+ keyFrame: "keyFrame";
43
+ thumbnail: "thumbnail";
44
+ }>;
45
+ export type ParkedFrameKind = z.infer<typeof ParkedFrameKindSchema>;
46
+ /**
47
+ * Why a park did NOT happen. Every one is logged on the runner with
48
+ * `tags: { deviceId }` and the handle's measured age, because a handle already
49
+ * gone at park time IS the defect the 150–500 ms window exists to prevent —
50
+ * never a reason to retry in a loop.
51
+ *
52
+ * - `handle-gone` — the native surface no longer resolves this handle (never
53
+ * registered, past the lease bound, or the worker released it). `detail`
54
+ * carries the runner's own miss reason.
55
+ * - `encode-failed` — pixels resolved and the JPEG encode threw.
56
+ */
57
+ export declare const ParkRefusalSchema: z.ZodEnum<{
58
+ "handle-gone": "handle-gone";
59
+ "encode-failed": "encode-failed";
60
+ }>;
61
+ export type ParkRefusal = z.infer<typeof ParkRefusalSchema>;
62
+ /** Answer to `parkTrackFrame` — a discriminated union, so "not parked" always names why. */
63
+ export declare const ParkTrackFrameResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
64
+ parked: z.ZodLiteral<true>;
65
+ nodeId: z.ZodString;
66
+ width: z.ZodNumber;
67
+ height: z.ZodNumber;
68
+ bytes: z.ZodNumber;
69
+ replaced: z.ZodBoolean;
70
+ }, z.core.$strip>, z.ZodObject<{
71
+ parked: z.ZodLiteral<false>;
72
+ nodeId: z.ZodString;
73
+ reason: z.ZodEnum<{
74
+ "handle-gone": "handle-gone";
75
+ "encode-failed": "encode-failed";
76
+ }>;
77
+ handleAgeMs: z.ZodNullable<z.ZodNumber>;
78
+ detail: z.ZodOptional<z.ZodString>;
79
+ }, z.core.$strip>], "parked">;
80
+ export type ParkTrackFrameResult = z.infer<typeof ParkTrackFrameResultSchema>;
81
+ /** A retrieved parcel — the runner's own JPEG, base64 for the wire. */
82
+ export declare const ParkedTrackFrameSchema: z.ZodObject<{
83
+ jpeg: z.ZodString;
84
+ width: z.ZodNumber;
85
+ height: z.ZodNumber;
86
+ timestamp: z.ZodNumber;
87
+ parkedAt: z.ZodNumber;
88
+ }, z.core.$strip>;
89
+ export type ParkedTrackFrame = z.infer<typeof ParkedTrackFrameSchema>;
29
90
  /** Parent detection context passed to `runDetailSubtree` — the crop's
30
91
  * originating detection, in FRAME-space coordinates. Reuses
31
92
  * `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
@@ -927,6 +988,107 @@ export declare const pipelineRunnerCapability: {
927
988
  }>;
928
989
  detail: z.ZodString;
929
990
  }, z.core.$strip>], "kind">, "mutation">;
991
+ /**
992
+ * PARK a frame for a track at the instant it is judged to matter
993
+ * ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
994
+ *
995
+ * The hub's `BestDetectionTracker` — the single "best per track" policy —
996
+ * concludes a frame is a track's best and calls this on the node that
997
+ * owns `handle` (`nodePin(handle.nodeId)`), while the handle is young. The
998
+ * runner cuts `bbox` from the native surface it already holds (a full
999
+ * frame for `keyFrame`, the caller's subject window for `thumbnail`),
1000
+ * encodes ONE JPEG, and keeps it under `(deviceId, trackId, kind)`. Every
1001
+ * later consumer retrieves by that key (`getParkedTrackFrame`) — a lookup
1002
+ * that cannot miss on age. D52 holds: the rectangle is cut by the runner,
1003
+ * never a pre-cut tile the caller decided. D9/D18 hold: one compressed
1004
+ * encode at a decision point, never a stream.
1005
+ *
1006
+ * Idempotent per `(trackId, kind)`: a later park replaces (the ranking is
1007
+ * the hub's; this adds no second opinion), an out-of-order older instant
1008
+ * is ignored. Bounded per device and per node on the runner
1009
+ * (`parked-frame-store.ts`), oldest-first eviction, never a refusal for
1010
+ * space. A refusal names its reason and is logged on the runner with the
1011
+ * handle's measured age — it is never retried into a loop.
1012
+ */
1013
+ readonly parkTrackFrame: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1014
+ deviceId: z.ZodNumber;
1015
+ trackId: z.ZodString;
1016
+ kind: z.ZodEnum<{
1017
+ keyFrame: "keyFrame";
1018
+ thumbnail: "thumbnail";
1019
+ }>;
1020
+ handle: z.ZodObject<{
1021
+ shmId: z.ZodString;
1022
+ slot: z.ZodNumber;
1023
+ seq: z.ZodNumber;
1024
+ width: z.ZodNumber;
1025
+ height: z.ZodNumber;
1026
+ format: z.ZodEnum<{
1027
+ jpeg: "jpeg";
1028
+ rgb: "rgb";
1029
+ bgr: "bgr";
1030
+ yuv420: "yuv420";
1031
+ gray: "gray";
1032
+ }>;
1033
+ pts: z.ZodNumber;
1034
+ byteLength: z.ZodNumber;
1035
+ nodeId: z.ZodString;
1036
+ slotCount: z.ZodNumber;
1037
+ }, z.core.$strip>;
1038
+ bbox: z.ZodObject<{
1039
+ x: z.ZodNumber;
1040
+ y: z.ZodNumber;
1041
+ w: z.ZodNumber;
1042
+ h: z.ZodNumber;
1043
+ }, z.core.$strip>;
1044
+ maxWidth: z.ZodOptional<z.ZodNumber>;
1045
+ timestamp: z.ZodNumber;
1046
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
1047
+ parked: z.ZodLiteral<true>;
1048
+ nodeId: z.ZodString;
1049
+ width: z.ZodNumber;
1050
+ height: z.ZodNumber;
1051
+ bytes: z.ZodNumber;
1052
+ replaced: z.ZodBoolean;
1053
+ }, z.core.$strip>, z.ZodObject<{
1054
+ parked: z.ZodLiteral<false>;
1055
+ nodeId: z.ZodString;
1056
+ reason: z.ZodEnum<{
1057
+ "handle-gone": "handle-gone";
1058
+ "encode-failed": "encode-failed";
1059
+ }>;
1060
+ handleAgeMs: z.ZodNullable<z.ZodNumber>;
1061
+ detail: z.ZodOptional<z.ZodString>;
1062
+ }, z.core.$strip>], "parked">, "mutation">;
1063
+ /**
1064
+ * Retrieve a parked parcel by `(deviceId, trackId, kind)`. Pinned to the
1065
+ * node that answered the park (`ParkTrackFrameResult.nodeId`). `null` means
1066
+ * nothing was parked under that key on this node — never "too old".
1067
+ */
1068
+ readonly getParkedTrackFrame: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1069
+ deviceId: z.ZodNumber;
1070
+ trackId: z.ZodString;
1071
+ kind: z.ZodEnum<{
1072
+ keyFrame: "keyFrame";
1073
+ thumbnail: "thumbnail";
1074
+ }>;
1075
+ }, z.core.$strip>, z.ZodNullable<z.ZodObject<{
1076
+ jpeg: z.ZodString;
1077
+ width: z.ZodNumber;
1078
+ height: z.ZodNumber;
1079
+ timestamp: z.ZodNumber;
1080
+ parkedAt: z.ZodNumber;
1081
+ }, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind>;
1082
+ /**
1083
+ * Drop every parcel of a track — the hub closed it. Idempotent. A track
1084
+ * whose release is lost ages out on the runner under a hard ceiling.
1085
+ */
1086
+ readonly releaseParkedTrackFrames: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1087
+ deviceId: z.ZodNumber;
1088
+ trackId: z.ZodString;
1089
+ }, z.core.$strip>, z.ZodObject<{
1090
+ released: z.ZodNumber;
1091
+ }, z.core.$strip>, "mutation">;
930
1092
  };
931
1093
  };
932
1094
  export type IPipelineRunnerProvider = InferProvider<typeof pipelineRunnerCapability>;
@@ -108,12 +108,31 @@ export declare const RecordingManifestSchema: z.ZodObject<{
108
108
  playbackEndpoints: z.ZodArray<z.ZodString>;
109
109
  }, z.core.$strip>;
110
110
  export type RecordingManifest = z.infer<typeof RecordingManifestSchema>;
111
- /** Recording storage usage for one camera (bytes on disk across all its
112
- * profiles/subtrees/locations on this node). */
111
+ /**
112
+ * Recording storage usage for one camera — what the ARCHIVE holds for it,
113
+ * across every profile and every resolvable location on this node.
114
+ *
115
+ * ## Archive vs residency, which is the whole point of this shape (D418)
116
+ *
117
+ * `usedBytes` / `oldestMs` / `segments` are the durable hour ledger's numbers:
118
+ * the same quantity `RecordingLocationUsage.usedBytes` reports for the volume
119
+ * this camera writes to, so the two can be added up and compared.
120
+ *
121
+ * They were not always. Until D418 this row came from the recorder's in-RAM
122
+ * `RecordingIndex`, which since D287 holds only the live tail plus the hours
123
+ * somebody hydrated — so a hub with 1.9 TB and 3.3 days of footage reported
124
+ * 60.5 GB and "oldest: three hours ago" on the same page as the volume row
125
+ * that said otherwise, and two people read it as retention eating recent
126
+ * footage. Residency is still reported, under `residentBytes` /
127
+ * `residentOldestMs`, which answer a different question and say so.
128
+ */
113
129
  export declare const RecordingDeviceUsageSchema: z.ZodObject<{
114
130
  deviceId: z.ZodNumber;
115
131
  usedBytes: z.ZodNumber;
116
132
  oldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
133
+ segments: z.ZodOptional<z.ZodNumber>;
134
+ residentBytes: z.ZodOptional<z.ZodNumber>;
135
+ residentOldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
117
136
  }, z.core.$strip>;
118
137
  export type RecordingDeviceUsage = z.infer<typeof RecordingDeviceUsageSchema>;
119
138
  /** Recording storage usage + capacity for one storage location. */
@@ -136,7 +155,14 @@ export declare const RecordingStorageUsageSchema: z.ZodObject<{
136
155
  deviceId: z.ZodNumber;
137
156
  usedBytes: z.ZodNumber;
138
157
  oldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
158
+ segments: z.ZodOptional<z.ZodNumber>;
159
+ residentBytes: z.ZodOptional<z.ZodNumber>;
160
+ residentOldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
139
161
  }, z.core.$strip>>;
162
+ devicesRead: z.ZodOptional<z.ZodEnum<{
163
+ unavailable: "unavailable";
164
+ archive: "archive";
165
+ }>>;
140
166
  locations: z.ZodOptional<z.ZodArray<z.ZodObject<{
141
167
  locationId: z.ZodNullable<z.ZodString>;
142
168
  locationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -446,7 +472,14 @@ export declare const recordingCapability: {
446
472
  deviceId: z.ZodNumber;
447
473
  usedBytes: z.ZodNumber;
448
474
  oldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
475
+ segments: z.ZodOptional<z.ZodNumber>;
476
+ residentBytes: z.ZodOptional<z.ZodNumber>;
477
+ residentOldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
449
478
  }, z.core.$strip>>;
479
+ devicesRead: z.ZodOptional<z.ZodEnum<{
480
+ unavailable: "unavailable";
481
+ archive: "archive";
482
+ }>>;
450
483
  locations: z.ZodOptional<z.ZodArray<z.ZodObject<{
451
484
  locationId: z.ZodNullable<z.ZodString>;
452
485
  locationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -81,7 +81,7 @@ export interface FieldProbeResult {
81
81
  */
82
82
  export declare function toDeviceSummary(device: IDevice, addonId: string): DeviceSummary;
83
83
  /**
84
- * Base class for device-provider addons (rtsp, onvif, frigate).
84
+ * Base class for device-provider addons (rtsp, onvif).
85
85
  *
86
86
  * Provides default implementations for the common device-provider cap
87
87
  * methods (`start`, `stop`, `getStatus`, `getDevices`, `supportsDiscovery`,
@@ -7,8 +7,8 @@ import { z } from 'zod';
7
7
  * Shape: `Record<capName, capStateSlice>`. Each slice's schema is
8
8
  * declared by the capability itself (`CapabilityDefinition.runtimeState`)
9
9
  * so that any provider implementing the cap inherits the same shape —
10
- * the BatteryStatus shape a Reolink cam emits is the same a Frigate or
11
- * ONVIF cam emits, no driver-specific re-declaration.
10
+ * the BatteryStatus shape a Reolink cam emits is the same an ONVIF cam
11
+ * emits, no driver-specific re-declaration.
12
12
  *
13
13
  * Schemas are registered DYNAMICALLY as the device's caps are
14
14
  * installed (see `BaseDevice.registerNativeCap`). A slice without a
@@ -61,7 +61,7 @@ export interface IDevice {
61
61
  * Kernel-managed per-device runtime-state surface (cap-keyed slices:
62
62
  * `device-status`, `feature-probe`, `battery`, …). Present on every
63
63
  * `BaseDevice` subclass; optional here because a handful of direct
64
- * `IDevice` implementors (legacy Onvif/Frigate camera classes) predate
64
+ * `IDevice` implementors (legacy Onvif camera classes) predate
65
65
  * the runtime-state machinery and don't carry one. Consumers that read
66
66
  * it (e.g. the device-manager's `probed`-flag derivation) tolerate
67
67
  * `undefined` as "no slice".
@@ -38,7 +38,7 @@ export type SourceInfo = z.infer<typeof SourceInfoSchema>;
38
38
  /**
39
39
  * Build the synthetic SourceInfo every existing provider falls back to
40
40
  * when no upstream value has been persisted. Keeps non-migrated providers
41
- * (Reolink / Hikvision / ONVIF / Frigate / RTSP) functional without code
41
+ * (Reolink / Hikvision / ONVIF / RTSP) functional without code
42
42
  * changes — `id` reuses the CamStack stableId, `system` reuses the addon
43
43
  * id. Real upstream identity replaces this once a provider migrates and
44
44
  * calls `updateSourceInfo()` with concrete values.
@@ -589,7 +589,6 @@ export declare enum EventCategory {
589
589
  * issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
590
590
  */
591
591
  PipelineAnalyticsPlateGalleryChanged = "pipeline-analytics.plate-gallery-changed",
592
- FrigateLiveEvent = "frigate.live-event",
593
592
  CameraStreamsProfileSlotsChanged = "camera-streams.onProfileSlotsChanged",
594
593
  /**
595
594
  * Stream-broker health watchdog. Per-broker (deviceId/profile) emission.
package/dist/enums.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_event_category = require("./event-category-BVo6ta6_.js");
2
+ const require_event_category = require("./event-category-BNJ9EE5B.js");
3
3
  //#region src/enums/event-source-type.ts
4
4
  var EventSourceType = /* @__PURE__ */ function(EventSourceType) {
5
5
  EventSourceType["Addon"] = "addon";
package/dist/enums.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as EventCategory } from "./event-category-CnLqLOKs.mjs";
1
+ import { t as EventCategory } from "./event-category-DAXzJeTX.mjs";
2
2
  //#region src/enums/event-source-type.ts
3
3
  var EventSourceType = /* @__PURE__ */ function(EventSourceType) {
4
4
  EventSourceType["Addon"] = "addon";