@camstack/addon-provider-reolink 1.2.80 → 1.2.82

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
@@ -11098,6 +11098,89 @@ var LocationStatSchema = object({
11098
11098
  fileCount: number(),
11099
11099
  present: boolean()
11100
11100
  });
11101
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
11102
+ var BackupRunStateSchema = _enum([
11103
+ "queued",
11104
+ "running",
11105
+ "succeeded",
11106
+ "failed",
11107
+ "cancelled"
11108
+ ]);
11109
+ /**
11110
+ * Where a running backup currently is. `queued` before it starts,
11111
+ * `building` while the tar.gz is being staged, `uploading` during the
11112
+ * per-destination fan-out, `done` once terminal.
11113
+ */
11114
+ var BackupRunPhaseSchema = _enum([
11115
+ "queued",
11116
+ "building",
11117
+ "uploading",
11118
+ "done"
11119
+ ]);
11120
+ /**
11121
+ * Observable state of one backup run — readable WHILE it runs via
11122
+ * `backup.listRuns`. This is what makes the execution queue and
11123
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
11124
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
11125
+ * diagnosable with `du` because nothing reported that runs existed or
11126
+ * how large the staged archive had grown.
11127
+ */
11128
+ var BackupRunSchema = object({
11129
+ /** Stable run id — the handle `backup.cancel` takes. */
11130
+ id: string(),
11131
+ state: BackupRunStateSchema,
11132
+ phase: BackupRunPhaseSchema,
11133
+ /**
11134
+ * Resolved destination location ids. Empty while queued (targets are
11135
+ * resolved when the run starts, against the then-current policies).
11136
+ */
11137
+ destinationIds: array(string()).readonly(),
11138
+ label: string().optional(),
11139
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
11140
+ requestedAt: number(),
11141
+ /** ms-epoch when the run left the queue and started building. */
11142
+ startedAt: number().optional(),
11143
+ /** ms-epoch when the run reached a terminal state. */
11144
+ finishedAt: number().optional(),
11145
+ /** Compressed bytes of the staging archive written so far. */
11146
+ stagedBytes: number(),
11147
+ /** Final staged archive size, once the build phase completes. */
11148
+ archiveSizeBytes: number().optional(),
11149
+ /** Bytes pushed to the destination currently uploading. */
11150
+ uploadedBytes: number(),
11151
+ /** Destinations where the archive fully landed (uploaded + indexed). */
11152
+ completedDestinationIds: array(string()).readonly(),
11153
+ /** Destinations that failed during the fan-out. */
11154
+ failedDestinationIds: array(string()).readonly(),
11155
+ /** Failure message when `state === 'failed'`. */
11156
+ error: string().optional(),
11157
+ /**
11158
+ * 1-based place in the execution queue — 1 = runs next. Present only
11159
+ * while `state === 'queued'`. Stamped by the orchestrator from the
11160
+ * queue's OWN pending order, never derived from timestamps, so the
11161
+ * UI cannot show an order the executor will not honour.
11162
+ */
11163
+ queuePosition: number().int().min(1).optional()
11164
+ });
11165
+ /**
11166
+ * Result of `backup.trigger`. The call still resolves when the run
11167
+ * terminates (compat with schedule-driven runs and the admin UI), but
11168
+ * it now names the run and says whether it had to WAIT: a trigger that
11169
+ * arrives while another run is in flight is enqueued (or joined onto
11170
+ * an identical already-queued run), never started concurrently.
11171
+ */
11172
+ var BackupTriggerResultSchema = object({
11173
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
11174
+ runId: string(),
11175
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
11176
+ queued: boolean(),
11177
+ /** True when this trigger was coalesced onto an identical already-queued run. */
11178
+ joined: boolean(),
11179
+ /** True when the run was cancelled before completing every destination. */
11180
+ cancelled: boolean(),
11181
+ /** One entry per destination the archive landed at (partial on cancel). */
11182
+ entries: array(BackupEntrySchema).readonly()
11183
+ });
11101
11184
  /**
11102
11185
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
11103
11186
  * SET of destination locations. Supersedes the per-location cron on
@@ -11145,7 +11228,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
11145
11228
  * retention (manual runs).
11146
11229
  */
11147
11230
  retentionCount: number().int().min(1).max(1e3).optional()
11148
- }).optional(), array(BackupEntrySchema).readonly(), {
11231
+ }).optional(), BackupTriggerResultSchema, {
11232
+ kind: "mutation",
11233
+ auth: "admin"
11234
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
11149
11235
  kind: "mutation",
11150
11236
  auth: "admin"
11151
11237
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -11862,6 +11948,14 @@ method(object({
11862
11948
  }), object({ success: literal(true) }), {
11863
11949
  kind: "mutation",
11864
11950
  auth: "admin"
11951
+ }), method(object({ deviceId: number().int().nonnegative() }), object({
11952
+ derivedStreamsDeleted: array(string()).readonly(),
11953
+ assignmentsPurged: boolean(),
11954
+ probeSnapshotsDropped: number().int().nonnegative(),
11955
+ rtspTokenRowsDeleted: number().int().nonnegative()
11956
+ }), {
11957
+ kind: "mutation",
11958
+ auth: "admin"
11865
11959
  }), method(object({
11866
11960
  deviceId: number(),
11867
11961
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -19806,7 +19900,20 @@ var RecentTracksQueryInput = object({
19806
19900
  projection: TrackProjectionSchema.optional(),
19807
19901
  /** Include stationary-promoted rows (parked objects). Default false: the
19808
19902
  * feed lists passages; parking records live on the stationary registry. */
19809
- includeStationary: boolean().optional()
19903
+ includeStationary: boolean().optional(),
19904
+ /**
19905
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
19906
+ *
19907
+ * The same filter `listTracks` takes, because the timeline's class chips must
19908
+ * mean the same thing whether the scope is one camera or twelve. Until this
19909
+ * existed the scoped feed downloaded a page and narrowed it on the phone
19910
+ * while the single-camera path narrowed the read — one filter, two costs.
19911
+ *
19912
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
19913
+ * whose class list is unreadable are kept, and the client's rule stays the
19914
+ * exact one.
19915
+ */
19916
+ classes: array(string()).optional()
19810
19917
  });
19811
19918
  var RecentTracksPageSchema = object({
19812
19919
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -24080,8 +24187,22 @@ var automationControlCapability = {
24080
24187
  * threshold.
24081
24188
  */
24082
24189
  var BatteryStatusSchema = object({
24083
- /** 0..100 inclusive. Firmware-reported. */
24084
- percentage: number().min(0).max(100),
24190
+ /**
24191
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
24192
+ * provider has registered the capability but no reading has landed.
24193
+ *
24194
+ * It is nullable because it was not, and the only value a provider could
24195
+ * seed with was `0`. A battery camera behind an NVR therefore announced
24196
+ * itself at 0% on every start and corrected itself a moment later, which is
24197
+ * indistinguishable from a real flat battery: it fires the low-battery alert
24198
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
24199
+ * reading the difference is an alarm.
24200
+ *
24201
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
24202
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
24203
+ * declines to band a non-finite reading, which is the correct shape.
24204
+ */
24205
+ percentage: number().min(0).max(100).nullable(),
24085
24206
  /**
24086
24207
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24087
24208
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -34294,6 +34415,12 @@ Object.freeze({
34294
34415
  addonId: null,
34295
34416
  access: "create"
34296
34417
  },
34418
+ "backup.cancel": {
34419
+ capName: "backup",
34420
+ capScope: "system",
34421
+ addonId: null,
34422
+ access: "create"
34423
+ },
34297
34424
  "backup.delete": {
34298
34425
  capName: "backup",
34299
34426
  capScope: "system",
@@ -34336,6 +34463,12 @@ Object.freeze({
34336
34463
  addonId: null,
34337
34464
  access: "view"
34338
34465
  },
34466
+ "backup.listRuns": {
34467
+ capName: "backup",
34468
+ capScope: "system",
34469
+ addonId: null,
34470
+ access: "view"
34471
+ },
34339
34472
  "backup.listSchedules": {
34340
34473
  capName: "backup",
34341
34474
  capScope: "system",
@@ -38902,6 +39035,12 @@ Object.freeze({
38902
39035
  addonId: null,
38903
39036
  access: "create"
38904
39037
  },
39038
+ "streamBroker.forgetDeviceHardware": {
39039
+ capName: "stream-broker",
39040
+ capScope: "system",
39041
+ addonId: null,
39042
+ access: "delete"
39043
+ },
38905
39044
  "streamBroker.getAllRtspEntries": {
38906
39045
  capName: "stream-broker",
38907
39046
  capScope: "system",
@@ -41360,6 +41499,11 @@ Object.freeze({
41360
41499
  form: "single",
41361
41500
  optional: false
41362
41501
  }],
41502
+ "streamBroker.forgetDeviceHardware": [{
41503
+ name: "deviceId",
41504
+ form: "single",
41505
+ optional: false
41506
+ }],
41363
41507
  "streamBroker.getDeviceAudioMute": [{
41364
41508
  name: "deviceId",
41365
41509
  form: "single",
@@ -235466,7 +235610,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
235466
235610
  * tracker is more reliable.
235467
235611
  */
235468
235612
  mapBatteryInfo(info) {
235469
- const percentage = typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.percentage ?? 0;
235613
+ const percentage = typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.percentage ?? null;
235470
235614
  const adapter = (info.adapterStatus ?? "").toLowerCase();
235471
235615
  const charge = (info.chargeStatus ?? "").toLowerCase();
235472
235616
  const isCharging = charge === "charging" || charge === "chargecomplete";
@@ -235597,7 +235741,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
235597
235741
  }
235598
235742
  });
235599
235743
  if (this.getCapSlice(batteryCapability) === null) this.setCapSlice(batteryCapability, {
235600
- percentage: 0,
235744
+ percentage: null,
235601
235745
  charging: "none",
235602
235746
  sleeping: false,
235603
235747
  lastUpdated: Date.now()
package/dist/addon.mjs CHANGED
@@ -11093,6 +11093,89 @@ var LocationStatSchema = object({
11093
11093
  fileCount: number(),
11094
11094
  present: boolean()
11095
11095
  });
11096
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
11097
+ var BackupRunStateSchema = _enum([
11098
+ "queued",
11099
+ "running",
11100
+ "succeeded",
11101
+ "failed",
11102
+ "cancelled"
11103
+ ]);
11104
+ /**
11105
+ * Where a running backup currently is. `queued` before it starts,
11106
+ * `building` while the tar.gz is being staged, `uploading` during the
11107
+ * per-destination fan-out, `done` once terminal.
11108
+ */
11109
+ var BackupRunPhaseSchema = _enum([
11110
+ "queued",
11111
+ "building",
11112
+ "uploading",
11113
+ "done"
11114
+ ]);
11115
+ /**
11116
+ * Observable state of one backup run — readable WHILE it runs via
11117
+ * `backup.listRuns`. This is what makes the execution queue and
11118
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
11119
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
11120
+ * diagnosable with `du` because nothing reported that runs existed or
11121
+ * how large the staged archive had grown.
11122
+ */
11123
+ var BackupRunSchema = object({
11124
+ /** Stable run id — the handle `backup.cancel` takes. */
11125
+ id: string(),
11126
+ state: BackupRunStateSchema,
11127
+ phase: BackupRunPhaseSchema,
11128
+ /**
11129
+ * Resolved destination location ids. Empty while queued (targets are
11130
+ * resolved when the run starts, against the then-current policies).
11131
+ */
11132
+ destinationIds: array(string()).readonly(),
11133
+ label: string().optional(),
11134
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
11135
+ requestedAt: number(),
11136
+ /** ms-epoch when the run left the queue and started building. */
11137
+ startedAt: number().optional(),
11138
+ /** ms-epoch when the run reached a terminal state. */
11139
+ finishedAt: number().optional(),
11140
+ /** Compressed bytes of the staging archive written so far. */
11141
+ stagedBytes: number(),
11142
+ /** Final staged archive size, once the build phase completes. */
11143
+ archiveSizeBytes: number().optional(),
11144
+ /** Bytes pushed to the destination currently uploading. */
11145
+ uploadedBytes: number(),
11146
+ /** Destinations where the archive fully landed (uploaded + indexed). */
11147
+ completedDestinationIds: array(string()).readonly(),
11148
+ /** Destinations that failed during the fan-out. */
11149
+ failedDestinationIds: array(string()).readonly(),
11150
+ /** Failure message when `state === 'failed'`. */
11151
+ error: string().optional(),
11152
+ /**
11153
+ * 1-based place in the execution queue — 1 = runs next. Present only
11154
+ * while `state === 'queued'`. Stamped by the orchestrator from the
11155
+ * queue's OWN pending order, never derived from timestamps, so the
11156
+ * UI cannot show an order the executor will not honour.
11157
+ */
11158
+ queuePosition: number().int().min(1).optional()
11159
+ });
11160
+ /**
11161
+ * Result of `backup.trigger`. The call still resolves when the run
11162
+ * terminates (compat with schedule-driven runs and the admin UI), but
11163
+ * it now names the run and says whether it had to WAIT: a trigger that
11164
+ * arrives while another run is in flight is enqueued (or joined onto
11165
+ * an identical already-queued run), never started concurrently.
11166
+ */
11167
+ var BackupTriggerResultSchema = object({
11168
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
11169
+ runId: string(),
11170
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
11171
+ queued: boolean(),
11172
+ /** True when this trigger was coalesced onto an identical already-queued run. */
11173
+ joined: boolean(),
11174
+ /** True when the run was cancelled before completing every destination. */
11175
+ cancelled: boolean(),
11176
+ /** One entry per destination the archive landed at (partial on cancel). */
11177
+ entries: array(BackupEntrySchema).readonly()
11178
+ });
11096
11179
  /**
11097
11180
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
11098
11181
  * SET of destination locations. Supersedes the per-location cron on
@@ -11140,7 +11223,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
11140
11223
  * retention (manual runs).
11141
11224
  */
11142
11225
  retentionCount: number().int().min(1).max(1e3).optional()
11143
- }).optional(), array(BackupEntrySchema).readonly(), {
11226
+ }).optional(), BackupTriggerResultSchema, {
11227
+ kind: "mutation",
11228
+ auth: "admin"
11229
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
11144
11230
  kind: "mutation",
11145
11231
  auth: "admin"
11146
11232
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -11857,6 +11943,14 @@ method(object({
11857
11943
  }), object({ success: literal(true) }), {
11858
11944
  kind: "mutation",
11859
11945
  auth: "admin"
11946
+ }), method(object({ deviceId: number().int().nonnegative() }), object({
11947
+ derivedStreamsDeleted: array(string()).readonly(),
11948
+ assignmentsPurged: boolean(),
11949
+ probeSnapshotsDropped: number().int().nonnegative(),
11950
+ rtspTokenRowsDeleted: number().int().nonnegative()
11951
+ }), {
11952
+ kind: "mutation",
11953
+ auth: "admin"
11860
11954
  }), method(object({
11861
11955
  deviceId: number(),
11862
11956
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -19801,7 +19895,20 @@ var RecentTracksQueryInput = object({
19801
19895
  projection: TrackProjectionSchema.optional(),
19802
19896
  /** Include stationary-promoted rows (parked objects). Default false: the
19803
19897
  * feed lists passages; parking records live on the stationary registry. */
19804
- includeStationary: boolean().optional()
19898
+ includeStationary: boolean().optional(),
19899
+ /**
19900
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
19901
+ *
19902
+ * The same filter `listTracks` takes, because the timeline's class chips must
19903
+ * mean the same thing whether the scope is one camera or twelve. Until this
19904
+ * existed the scoped feed downloaded a page and narrowed it on the phone
19905
+ * while the single-camera path narrowed the read — one filter, two costs.
19906
+ *
19907
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
19908
+ * whose class list is unreadable are kept, and the client's rule stays the
19909
+ * exact one.
19910
+ */
19911
+ classes: array(string()).optional()
19805
19912
  });
19806
19913
  var RecentTracksPageSchema = object({
19807
19914
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -24075,8 +24182,22 @@ var automationControlCapability = {
24075
24182
  * threshold.
24076
24183
  */
24077
24184
  var BatteryStatusSchema = object({
24078
- /** 0..100 inclusive. Firmware-reported. */
24079
- percentage: number().min(0).max(100),
24185
+ /**
24186
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
24187
+ * provider has registered the capability but no reading has landed.
24188
+ *
24189
+ * It is nullable because it was not, and the only value a provider could
24190
+ * seed with was `0`. A battery camera behind an NVR therefore announced
24191
+ * itself at 0% on every start and corrected itself a moment later, which is
24192
+ * indistinguishable from a real flat battery: it fires the low-battery alert
24193
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
24194
+ * reading the difference is an alarm.
24195
+ *
24196
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
24197
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
24198
+ * declines to band a non-finite reading, which is the correct shape.
24199
+ */
24200
+ percentage: number().min(0).max(100).nullable(),
24080
24201
  /**
24081
24202
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24082
24203
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -34289,6 +34410,12 @@ Object.freeze({
34289
34410
  addonId: null,
34290
34411
  access: "create"
34291
34412
  },
34413
+ "backup.cancel": {
34414
+ capName: "backup",
34415
+ capScope: "system",
34416
+ addonId: null,
34417
+ access: "create"
34418
+ },
34292
34419
  "backup.delete": {
34293
34420
  capName: "backup",
34294
34421
  capScope: "system",
@@ -34331,6 +34458,12 @@ Object.freeze({
34331
34458
  addonId: null,
34332
34459
  access: "view"
34333
34460
  },
34461
+ "backup.listRuns": {
34462
+ capName: "backup",
34463
+ capScope: "system",
34464
+ addonId: null,
34465
+ access: "view"
34466
+ },
34334
34467
  "backup.listSchedules": {
34335
34468
  capName: "backup",
34336
34469
  capScope: "system",
@@ -38897,6 +39030,12 @@ Object.freeze({
38897
39030
  addonId: null,
38898
39031
  access: "create"
38899
39032
  },
39033
+ "streamBroker.forgetDeviceHardware": {
39034
+ capName: "stream-broker",
39035
+ capScope: "system",
39036
+ addonId: null,
39037
+ access: "delete"
39038
+ },
38900
39039
  "streamBroker.getAllRtspEntries": {
38901
39040
  capName: "stream-broker",
38902
39041
  capScope: "system",
@@ -41355,6 +41494,11 @@ Object.freeze({
41355
41494
  form: "single",
41356
41495
  optional: false
41357
41496
  }],
41497
+ "streamBroker.forgetDeviceHardware": [{
41498
+ name: "deviceId",
41499
+ form: "single",
41500
+ optional: false
41501
+ }],
41358
41502
  "streamBroker.getDeviceAudioMute": [{
41359
41503
  name: "deviceId",
41360
41504
  form: "single",
@@ -235446,7 +235590,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
235446
235590
  * tracker is more reliable.
235447
235591
  */
235448
235592
  mapBatteryInfo(info) {
235449
- const percentage = typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.percentage ?? 0;
235593
+ const percentage = typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.percentage ?? null;
235450
235594
  const adapter = (info.adapterStatus ?? "").toLowerCase();
235451
235595
  const charge = (info.chargeStatus ?? "").toLowerCase();
235452
235596
  const isCharging = charge === "charging" || charge === "chargecomplete";
@@ -235577,7 +235721,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
235577
235721
  }
235578
235722
  });
235579
235723
  if (this.getCapSlice(batteryCapability) === null) this.setCapSlice(batteryCapability, {
235580
- percentage: 0,
235724
+ percentage: null,
235581
235725
  charging: "none",
235582
235726
  sleeping: false,
235583
235727
  lastUpdated: Date.now()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.2.80",
3
+ "version": "1.2.82",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",