@camstack/addon-provider-reolink 1.2.14 → 1.2.16

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 CHANGED
@@ -26,7 +26,7 @@ let fs_promises = require("fs/promises");
26
26
  fs_promises = require_chunk.__toESM(fs_promises, 1);
27
27
  let node_os = require("node:os");
28
28
  node_os = require_chunk.__toESM(node_os);
29
- //#region ../types/dist/event-category-BLcNejAE.mjs
29
+ //#region ../types/dist/event-category-Bz24uP1U.mjs
30
30
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
31
31
  EventCategory["SystemBoot"] = "system.boot";
32
32
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -297,6 +297,19 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
297
297
  */
298
298
  EventCategory["DeviceStateChanged"] = "device.state-changed";
299
299
  /**
300
+ * Frame occupancy for a camera CHANGED — a tracked object was gained or
301
+ * lost. Carries `{ deviceId, totalObjects, byClass, zones }`.
302
+ *
303
+ * Emitted only on a change, so a steady scene is silent. It exists so a
304
+ * client can stop polling `zoneAnalytics.getCurrentSnapshot`: that was the
305
+ * one live badge with no push signal at all, and it cost a request every
306
+ * four seconds per visible camera.
307
+ *
308
+ * Like every event it is telemetry and may be dropped ([D8]) — a consumer
309
+ * keeps a slow reconcile rather than trusting it alone.
310
+ */
311
+ EventCategory["ZoneAnalyticsOccupancyChanged"] = "zone-analytics.occupancy-changed";
312
+ /**
300
313
  * Cap event fired by every device that registers the `battery`
301
314
  * capability. Mirrors the cap definition's `onStatusChanged`. Carries
302
315
  * `{ deviceId, status: BatteryStatus }`. Subscribers (alert center,
@@ -9567,6 +9580,29 @@ var NcOccupancyConditionSchema = object({
9567
9580
  count: number().int().min(0).default(1),
9568
9581
  sustainSeconds: number().int().min(0).max(3600).default(15)
9569
9582
  });
9583
+ /**
9584
+ * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
9585
+ *
9586
+ * The values are not symmetric, and deliberately so — the absent value has to
9587
+ * mean exactly what every rule authored before this condition existed already
9588
+ * does:
9589
+ * - `enter` — entries and every NON-crossing record (movement state,
9590
+ * package, sensor). Exits are rejected. **This is the absent behaviour**:
9591
+ * an operator who never asked for exits must not start receiving them.
9592
+ * - `exit` — ONLY an exit crossing. A record that is not a crossing at all
9593
+ * fails closed, because "the car left the drive" is a question about a
9594
+ * boundary, not about a detection.
9595
+ * - `any` — no direction filter; entries, exits and non-crossings alike.
9596
+ *
9597
+ * A rule asking for a direction should normally also scope `zones`, which the
9598
+ * engine evaluates against the crossed zone as well as the current membership
9599
+ * (an exit's membership no longer contains the zone it just left).
9600
+ */
9601
+ var NcCrossingSchema = _enum([
9602
+ "enter",
9603
+ "exit",
9604
+ "any"
9605
+ ]);
9570
9606
  /** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
9571
9607
  var NcZoneConditionSchema = object({
9572
9608
  ids: array(string().min(1)).min(1),
@@ -9591,6 +9627,13 @@ var NcConditionsSchema = object({
9591
9627
  /** Veto zones — any hit fails the rule. */
9592
9628
  zonesExclude: array(string().min(1)).optional(),
9593
9629
  /**
9630
+ * Zone-crossing direction. IMMEDIATE only — a crossing is a per-event fact
9631
+ * and a closed track carries none, so a `track-end` rule asking for one
9632
+ * fails closed (use `zones`, which tests `zonesVisited`). ABSENT = `enter`,
9633
+ * which is exactly today's behaviour. See {@link NcCrossingSchema}.
9634
+ */
9635
+ crossing: NcCrossingSchema.optional(),
9636
+ /**
9594
9637
  * Exact (case-insensitive) match on the record's collapsed `label`
9595
9638
  * (identity name / plate text / subclass).
9596
9639
  */
@@ -9779,11 +9822,31 @@ var NcMediaPolicySchema = object({
9779
9822
  */
9780
9823
  profile: CamProfileSchema.optional()
9781
9824
  });
9825
+ /**
9826
+ * Cooldown GRANULARITY over the subject's class — how much a fired
9827
+ * notification suppresses.
9828
+ * - `shared` (default, and the absent value) — one window for the whole
9829
+ * rule/scope: a cat silences the next dog for `cooldownSec`.
9830
+ * - `per-class` — an independent window per detected class, so cat→dog fires
9831
+ * at once and cat→cat still waits.
9832
+ *
9833
+ * AUDIO subjects are ALWAYS per-class regardless of this setting: a scream
9834
+ * must not be swallowed by a bark's window (the precedent this generalizes —
9835
+ * see `cooldownKey` in the rule engine).
9836
+ */
9837
+ var NcThrottleGranularitySchema = _enum(["shared", "per-class"]);
9782
9838
  /** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
9783
9839
  var NcThrottleSchema = object({
9784
9840
  cooldownSec: number().int().min(0).max(86400).default(60),
9785
9841
  /** `rule` = one shared cooldown; `rule-device` = per-camera cooldown. */
9786
- scope: _enum(["rule", "rule-device"]).default("rule-device")
9842
+ scope: _enum(["rule", "rule-device"]).default("rule-device"),
9843
+ /**
9844
+ * Class granularity of the cooldown key. Optional rather than defaulted:
9845
+ * a Zod default does NOT run on the addon→addon cap path, so a persisted
9846
+ * rule authored before this field simply carries none — and the engine
9847
+ * reads absent as `shared`, the pre-existing behaviour.
9848
+ */
9849
+ granularity: NcThrottleGranularitySchema.optional()
9787
9850
  });
9788
9851
  /** Client-supplied rule fields (server stamps id/createdBy/createdAt/updatedAt). */
9789
9852
  var NcRuleInputSchema = object({
@@ -9891,6 +9954,7 @@ var NcConditionDescriptorSchema = object({
9891
9954
  "schedule",
9892
9955
  "plateMatcher",
9893
9956
  "packagePhase",
9957
+ "crossingSelect",
9894
9958
  "polygonDraw",
9895
9959
  "occupancy"
9896
9960
  ]),
@@ -14181,6 +14245,18 @@ var motionCapability = {
14181
14245
  name: "motion",
14182
14246
  scope: "device",
14183
14247
  mode: "singleton",
14248
+ /**
14249
+ * Providers register per-device natives via `ctx.registerNativeCap`
14250
+ * (Hikvision/Reolink/Amcrest/Wyze/HA/Homematic/Alexa/Matter) — there is
14251
+ * NO system singleton provider. Without this flag `resolveCapMount`
14252
+ * derived `{ kind: 'singleton' }`, so `motion.getStatus`/`isDetected`
14253
+ * resolved via `registry.getSingleton('motion')` (always null) and every
14254
+ * call 412'd "provider not available" while bindings listed a live
14255
+ * `motion` native (2026-08-02). The flag routes the router through
14256
+ * `requireDeviceScoped` → `getProviderForDevice`, like `motion-trigger`,
14257
+ * `snapshot` and every other per-device native cap.
14258
+ */
14259
+ deviceNative: true,
14184
14260
  deviceTypes: [DeviceType.Camera, DeviceType.Sensor],
14185
14261
  methods: {
14186
14262
  /**
@@ -19125,7 +19201,10 @@ method(object({
19125
19201
  }), method(object({
19126
19202
  deviceId: number(),
19127
19203
  caps: array(string()).readonly().optional()
19128
- }), record(string(), unknown().nullable()));
19204
+ }), record(string(), unknown().nullable())), method(object({
19205
+ deviceIds: array(number()).readonly(),
19206
+ caps: array(string()).readonly().optional()
19207
+ }), record(string(), record(string(), unknown().nullable())));
19129
19208
  method(object({ deviceId: number() }), record(string(), record(string(), unknown()))), method(object({
19130
19209
  deviceId: number(),
19131
19210
  capName: string()
@@ -20533,6 +20612,29 @@ var MotionEventSchema = object({
20533
20612
  * Absent on legacy rows ⇒ treat as `pipeline`.
20534
20613
  */
20535
20614
  var DetectionSourceSchema = _enum(["pipeline", "onboard"]);
20615
+ /**
20616
+ * The confirmed zone crossing that produced an object event. Present ONLY on
20617
+ * an event emitted BY a crossing (`zone.enter` / `zone.exit`); a movement-state
20618
+ * event (`object.entering` / `leaving` / `stationary` / `loitering`) and an
20619
+ * appearance event carry none, so a rule asking for a direction fails closed
20620
+ * on them.
20621
+ *
20622
+ * Exactly ONE crossing per event: the emitter turns each confirmed crossing
20623
+ * into its own event, so a frame in which a track enters A while leaving B
20624
+ * produces two events with two directions — never one ambiguous row.
20625
+ *
20626
+ * `zoneId` is load-bearing for an EXIT: the event's `zones` list is the
20627
+ * membership the box has NOW, and by definition it no longer contains the zone
20628
+ * that was just left. Without the id here, a zone-scoped rule could never match
20629
+ * the exit it asked for.
20630
+ */
20631
+ var ZoneCrossingSchema = object({
20632
+ direction: _enum(["enter", "exit"]),
20633
+ /** Admin zone id crossed. */
20634
+ zoneId: string(),
20635
+ /** Zone display name at crossing time (falls back to the id). */
20636
+ zoneName: string().optional()
20637
+ });
20536
20638
  var ObjectEventSchema = object({
20537
20639
  ...BaseEventFields,
20538
20640
  kind: literal("object"),
@@ -20559,6 +20661,12 @@ var ObjectEventSchema = object({
20559
20661
  zones: array(string()).readonly().optional(),
20560
20662
  /** Omitted in slim projection. */
20561
20663
  state: TrackStateSchema.optional(),
20664
+ /**
20665
+ * The zone crossing this event IS, when it is one. Absent on every other
20666
+ * event kind (movement state, appearance, package) — see
20667
+ * {@link ZoneCrossingSchema}. Omitted in slim projection.
20668
+ */
20669
+ zoneCrossing: ZoneCrossingSchema.optional(),
20562
20670
  /** Detection-frame dimensions in pixels — let consumers normalize the
20563
20671
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
20564
20672
  frameWidth: number().optional(),
@@ -26263,6 +26371,12 @@ Object.freeze({
26263
26371
  addonId: null,
26264
26372
  access: "view"
26265
26373
  },
26374
+ "deviceManager.getDeviceStatusAggregateBatch": {
26375
+ capName: "device-manager",
26376
+ capScope: "system",
26377
+ addonId: null,
26378
+ access: "view"
26379
+ },
26266
26380
  "deviceManager.getLinkedDevices": {
26267
26381
  capName: "device-manager",
26268
26382
  capScope: "system",
package/dist/addon.mjs CHANGED
@@ -21,7 +21,7 @@ import netImpl from "net";
21
21
  import { fileURLToPath } from "url";
22
22
  import { mkdir } from "fs/promises";
23
23
  import os from "node:os";
24
- //#region ../types/dist/event-category-BLcNejAE.mjs
24
+ //#region ../types/dist/event-category-Bz24uP1U.mjs
25
25
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
26
26
  EventCategory["SystemBoot"] = "system.boot";
27
27
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -292,6 +292,19 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
292
292
  */
293
293
  EventCategory["DeviceStateChanged"] = "device.state-changed";
294
294
  /**
295
+ * Frame occupancy for a camera CHANGED — a tracked object was gained or
296
+ * lost. Carries `{ deviceId, totalObjects, byClass, zones }`.
297
+ *
298
+ * Emitted only on a change, so a steady scene is silent. It exists so a
299
+ * client can stop polling `zoneAnalytics.getCurrentSnapshot`: that was the
300
+ * one live badge with no push signal at all, and it cost a request every
301
+ * four seconds per visible camera.
302
+ *
303
+ * Like every event it is telemetry and may be dropped ([D8]) — a consumer
304
+ * keeps a slow reconcile rather than trusting it alone.
305
+ */
306
+ EventCategory["ZoneAnalyticsOccupancyChanged"] = "zone-analytics.occupancy-changed";
307
+ /**
295
308
  * Cap event fired by every device that registers the `battery`
296
309
  * capability. Mirrors the cap definition's `onStatusChanged`. Carries
297
310
  * `{ deviceId, status: BatteryStatus }`. Subscribers (alert center,
@@ -9562,6 +9575,29 @@ var NcOccupancyConditionSchema = object({
9562
9575
  count: number().int().min(0).default(1),
9563
9576
  sustainSeconds: number().int().min(0).max(3600).default(15)
9564
9577
  });
9578
+ /**
9579
+ * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
9580
+ *
9581
+ * The values are not symmetric, and deliberately so — the absent value has to
9582
+ * mean exactly what every rule authored before this condition existed already
9583
+ * does:
9584
+ * - `enter` — entries and every NON-crossing record (movement state,
9585
+ * package, sensor). Exits are rejected. **This is the absent behaviour**:
9586
+ * an operator who never asked for exits must not start receiving them.
9587
+ * - `exit` — ONLY an exit crossing. A record that is not a crossing at all
9588
+ * fails closed, because "the car left the drive" is a question about a
9589
+ * boundary, not about a detection.
9590
+ * - `any` — no direction filter; entries, exits and non-crossings alike.
9591
+ *
9592
+ * A rule asking for a direction should normally also scope `zones`, which the
9593
+ * engine evaluates against the crossed zone as well as the current membership
9594
+ * (an exit's membership no longer contains the zone it just left).
9595
+ */
9596
+ var NcCrossingSchema = _enum([
9597
+ "enter",
9598
+ "exit",
9599
+ "any"
9600
+ ]);
9565
9601
  /** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
9566
9602
  var NcZoneConditionSchema = object({
9567
9603
  ids: array(string().min(1)).min(1),
@@ -9586,6 +9622,13 @@ var NcConditionsSchema = object({
9586
9622
  /** Veto zones — any hit fails the rule. */
9587
9623
  zonesExclude: array(string().min(1)).optional(),
9588
9624
  /**
9625
+ * Zone-crossing direction. IMMEDIATE only — a crossing is a per-event fact
9626
+ * and a closed track carries none, so a `track-end` rule asking for one
9627
+ * fails closed (use `zones`, which tests `zonesVisited`). ABSENT = `enter`,
9628
+ * which is exactly today's behaviour. See {@link NcCrossingSchema}.
9629
+ */
9630
+ crossing: NcCrossingSchema.optional(),
9631
+ /**
9589
9632
  * Exact (case-insensitive) match on the record's collapsed `label`
9590
9633
  * (identity name / plate text / subclass).
9591
9634
  */
@@ -9774,11 +9817,31 @@ var NcMediaPolicySchema = object({
9774
9817
  */
9775
9818
  profile: CamProfileSchema.optional()
9776
9819
  });
9820
+ /**
9821
+ * Cooldown GRANULARITY over the subject's class — how much a fired
9822
+ * notification suppresses.
9823
+ * - `shared` (default, and the absent value) — one window for the whole
9824
+ * rule/scope: a cat silences the next dog for `cooldownSec`.
9825
+ * - `per-class` — an independent window per detected class, so cat→dog fires
9826
+ * at once and cat→cat still waits.
9827
+ *
9828
+ * AUDIO subjects are ALWAYS per-class regardless of this setting: a scream
9829
+ * must not be swallowed by a bark's window (the precedent this generalizes —
9830
+ * see `cooldownKey` in the rule engine).
9831
+ */
9832
+ var NcThrottleGranularitySchema = _enum(["shared", "per-class"]);
9777
9833
  /** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
9778
9834
  var NcThrottleSchema = object({
9779
9835
  cooldownSec: number().int().min(0).max(86400).default(60),
9780
9836
  /** `rule` = one shared cooldown; `rule-device` = per-camera cooldown. */
9781
- scope: _enum(["rule", "rule-device"]).default("rule-device")
9837
+ scope: _enum(["rule", "rule-device"]).default("rule-device"),
9838
+ /**
9839
+ * Class granularity of the cooldown key. Optional rather than defaulted:
9840
+ * a Zod default does NOT run on the addon→addon cap path, so a persisted
9841
+ * rule authored before this field simply carries none — and the engine
9842
+ * reads absent as `shared`, the pre-existing behaviour.
9843
+ */
9844
+ granularity: NcThrottleGranularitySchema.optional()
9782
9845
  });
9783
9846
  /** Client-supplied rule fields (server stamps id/createdBy/createdAt/updatedAt). */
9784
9847
  var NcRuleInputSchema = object({
@@ -9886,6 +9949,7 @@ var NcConditionDescriptorSchema = object({
9886
9949
  "schedule",
9887
9950
  "plateMatcher",
9888
9951
  "packagePhase",
9952
+ "crossingSelect",
9889
9953
  "polygonDraw",
9890
9954
  "occupancy"
9891
9955
  ]),
@@ -14176,6 +14240,18 @@ var motionCapability = {
14176
14240
  name: "motion",
14177
14241
  scope: "device",
14178
14242
  mode: "singleton",
14243
+ /**
14244
+ * Providers register per-device natives via `ctx.registerNativeCap`
14245
+ * (Hikvision/Reolink/Amcrest/Wyze/HA/Homematic/Alexa/Matter) — there is
14246
+ * NO system singleton provider. Without this flag `resolveCapMount`
14247
+ * derived `{ kind: 'singleton' }`, so `motion.getStatus`/`isDetected`
14248
+ * resolved via `registry.getSingleton('motion')` (always null) and every
14249
+ * call 412'd "provider not available" while bindings listed a live
14250
+ * `motion` native (2026-08-02). The flag routes the router through
14251
+ * `requireDeviceScoped` → `getProviderForDevice`, like `motion-trigger`,
14252
+ * `snapshot` and every other per-device native cap.
14253
+ */
14254
+ deviceNative: true,
14179
14255
  deviceTypes: [DeviceType.Camera, DeviceType.Sensor],
14180
14256
  methods: {
14181
14257
  /**
@@ -19120,7 +19196,10 @@ method(object({
19120
19196
  }), method(object({
19121
19197
  deviceId: number(),
19122
19198
  caps: array(string()).readonly().optional()
19123
- }), record(string(), unknown().nullable()));
19199
+ }), record(string(), unknown().nullable())), method(object({
19200
+ deviceIds: array(number()).readonly(),
19201
+ caps: array(string()).readonly().optional()
19202
+ }), record(string(), record(string(), unknown().nullable())));
19124
19203
  method(object({ deviceId: number() }), record(string(), record(string(), unknown()))), method(object({
19125
19204
  deviceId: number(),
19126
19205
  capName: string()
@@ -20528,6 +20607,29 @@ var MotionEventSchema = object({
20528
20607
  * Absent on legacy rows ⇒ treat as `pipeline`.
20529
20608
  */
20530
20609
  var DetectionSourceSchema = _enum(["pipeline", "onboard"]);
20610
+ /**
20611
+ * The confirmed zone crossing that produced an object event. Present ONLY on
20612
+ * an event emitted BY a crossing (`zone.enter` / `zone.exit`); a movement-state
20613
+ * event (`object.entering` / `leaving` / `stationary` / `loitering`) and an
20614
+ * appearance event carry none, so a rule asking for a direction fails closed
20615
+ * on them.
20616
+ *
20617
+ * Exactly ONE crossing per event: the emitter turns each confirmed crossing
20618
+ * into its own event, so a frame in which a track enters A while leaving B
20619
+ * produces two events with two directions — never one ambiguous row.
20620
+ *
20621
+ * `zoneId` is load-bearing for an EXIT: the event's `zones` list is the
20622
+ * membership the box has NOW, and by definition it no longer contains the zone
20623
+ * that was just left. Without the id here, a zone-scoped rule could never match
20624
+ * the exit it asked for.
20625
+ */
20626
+ var ZoneCrossingSchema = object({
20627
+ direction: _enum(["enter", "exit"]),
20628
+ /** Admin zone id crossed. */
20629
+ zoneId: string(),
20630
+ /** Zone display name at crossing time (falls back to the id). */
20631
+ zoneName: string().optional()
20632
+ });
20531
20633
  var ObjectEventSchema = object({
20532
20634
  ...BaseEventFields,
20533
20635
  kind: literal("object"),
@@ -20554,6 +20656,12 @@ var ObjectEventSchema = object({
20554
20656
  zones: array(string()).readonly().optional(),
20555
20657
  /** Omitted in slim projection. */
20556
20658
  state: TrackStateSchema.optional(),
20659
+ /**
20660
+ * The zone crossing this event IS, when it is one. Absent on every other
20661
+ * event kind (movement state, appearance, package) — see
20662
+ * {@link ZoneCrossingSchema}. Omitted in slim projection.
20663
+ */
20664
+ zoneCrossing: ZoneCrossingSchema.optional(),
20557
20665
  /** Detection-frame dimensions in pixels — let consumers normalize the
20558
20666
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
20559
20667
  frameWidth: number().optional(),
@@ -26258,6 +26366,12 @@ Object.freeze({
26258
26366
  addonId: null,
26259
26367
  access: "view"
26260
26368
  },
26369
+ "deviceManager.getDeviceStatusAggregateBatch": {
26370
+ capName: "device-manager",
26371
+ capScope: "system",
26372
+ addonId: null,
26373
+ access: "view"
26374
+ },
26261
26375
  "deviceManager.getLinkedDevices": {
26262
26376
  capName: "device-manager",
26263
26377
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.2.14",
3
+ "version": "1.2.16",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",