@camstack/addon-agent-ui 1.2.60 → 1.2.62

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 (2) hide show
  1. package/dist/addon.js +149 -5
  2. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -10530,6 +10530,89 @@ var LocationStatSchema = object({
10530
10530
  fileCount: number(),
10531
10531
  present: boolean()
10532
10532
  });
10533
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
10534
+ var BackupRunStateSchema = _enum([
10535
+ "queued",
10536
+ "running",
10537
+ "succeeded",
10538
+ "failed",
10539
+ "cancelled"
10540
+ ]);
10541
+ /**
10542
+ * Where a running backup currently is. `queued` before it starts,
10543
+ * `building` while the tar.gz is being staged, `uploading` during the
10544
+ * per-destination fan-out, `done` once terminal.
10545
+ */
10546
+ var BackupRunPhaseSchema = _enum([
10547
+ "queued",
10548
+ "building",
10549
+ "uploading",
10550
+ "done"
10551
+ ]);
10552
+ /**
10553
+ * Observable state of one backup run — readable WHILE it runs via
10554
+ * `backup.listRuns`. This is what makes the execution queue and
10555
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
10556
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
10557
+ * diagnosable with `du` because nothing reported that runs existed or
10558
+ * how large the staged archive had grown.
10559
+ */
10560
+ var BackupRunSchema = object({
10561
+ /** Stable run id — the handle `backup.cancel` takes. */
10562
+ id: string(),
10563
+ state: BackupRunStateSchema,
10564
+ phase: BackupRunPhaseSchema,
10565
+ /**
10566
+ * Resolved destination location ids. Empty while queued (targets are
10567
+ * resolved when the run starts, against the then-current policies).
10568
+ */
10569
+ destinationIds: array(string()).readonly(),
10570
+ label: string().optional(),
10571
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
10572
+ requestedAt: number(),
10573
+ /** ms-epoch when the run left the queue and started building. */
10574
+ startedAt: number().optional(),
10575
+ /** ms-epoch when the run reached a terminal state. */
10576
+ finishedAt: number().optional(),
10577
+ /** Compressed bytes of the staging archive written so far. */
10578
+ stagedBytes: number(),
10579
+ /** Final staged archive size, once the build phase completes. */
10580
+ archiveSizeBytes: number().optional(),
10581
+ /** Bytes pushed to the destination currently uploading. */
10582
+ uploadedBytes: number(),
10583
+ /** Destinations where the archive fully landed (uploaded + indexed). */
10584
+ completedDestinationIds: array(string()).readonly(),
10585
+ /** Destinations that failed during the fan-out. */
10586
+ failedDestinationIds: array(string()).readonly(),
10587
+ /** Failure message when `state === 'failed'`. */
10588
+ error: string().optional(),
10589
+ /**
10590
+ * 1-based place in the execution queue — 1 = runs next. Present only
10591
+ * while `state === 'queued'`. Stamped by the orchestrator from the
10592
+ * queue's OWN pending order, never derived from timestamps, so the
10593
+ * UI cannot show an order the executor will not honour.
10594
+ */
10595
+ queuePosition: number().int().min(1).optional()
10596
+ });
10597
+ /**
10598
+ * Result of `backup.trigger`. The call still resolves when the run
10599
+ * terminates (compat with schedule-driven runs and the admin UI), but
10600
+ * it now names the run and says whether it had to WAIT: a trigger that
10601
+ * arrives while another run is in flight is enqueued (or joined onto
10602
+ * an identical already-queued run), never started concurrently.
10603
+ */
10604
+ var BackupTriggerResultSchema = object({
10605
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
10606
+ runId: string(),
10607
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
10608
+ queued: boolean(),
10609
+ /** True when this trigger was coalesced onto an identical already-queued run. */
10610
+ joined: boolean(),
10611
+ /** True when the run was cancelled before completing every destination. */
10612
+ cancelled: boolean(),
10613
+ /** One entry per destination the archive landed at (partial on cancel). */
10614
+ entries: array(BackupEntrySchema).readonly()
10615
+ });
10533
10616
  /**
10534
10617
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
10535
10618
  * SET of destination locations. Supersedes the per-location cron on
@@ -10577,7 +10660,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
10577
10660
  * retention (manual runs).
10578
10661
  */
10579
10662
  retentionCount: number().int().min(1).max(1e3).optional()
10580
- }).optional(), array(BackupEntrySchema).readonly(), {
10663
+ }).optional(), BackupTriggerResultSchema, {
10664
+ kind: "mutation",
10665
+ auth: "admin"
10666
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
10581
10667
  kind: "mutation",
10582
10668
  auth: "admin"
10583
10669
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -11294,6 +11380,14 @@ method(object({
11294
11380
  }), object({ success: literal(true) }), {
11295
11381
  kind: "mutation",
11296
11382
  auth: "admin"
11383
+ }), method(object({ deviceId: number().int().nonnegative() }), object({
11384
+ derivedStreamsDeleted: array(string()).readonly(),
11385
+ assignmentsPurged: boolean(),
11386
+ probeSnapshotsDropped: number().int().nonnegative(),
11387
+ rtspTokenRowsDeleted: number().int().nonnegative()
11388
+ }), {
11389
+ kind: "mutation",
11390
+ auth: "admin"
11297
11391
  }), method(object({
11298
11392
  deviceId: number(),
11299
11393
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -18844,7 +18938,20 @@ var RecentTracksQueryInput = object({
18844
18938
  projection: TrackProjectionSchema.optional(),
18845
18939
  /** Include stationary-promoted rows (parked objects). Default false: the
18846
18940
  * feed lists passages; parking records live on the stationary registry. */
18847
- includeStationary: boolean().optional()
18941
+ includeStationary: boolean().optional(),
18942
+ /**
18943
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
18944
+ *
18945
+ * The same filter `listTracks` takes, because the timeline's class chips must
18946
+ * mean the same thing whether the scope is one camera or twelve. Until this
18947
+ * existed the scoped feed downloaded a page and narrowed it on the phone
18948
+ * while the single-camera path narrowed the read — one filter, two costs.
18949
+ *
18950
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
18951
+ * whose class list is unreadable are kept, and the client's rule stays the
18952
+ * exact one.
18953
+ */
18954
+ classes: array(string()).optional()
18848
18955
  });
18849
18956
  var RecentTracksPageSchema = object({
18850
18957
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -22882,8 +22989,22 @@ DeviceType.Automation, method(object({ deviceId: number().int().nonnegative() })
22882
22989
  * threshold.
22883
22990
  */
22884
22991
  var BatteryStatusSchema = object({
22885
- /** 0..100 inclusive. Firmware-reported. */
22886
- percentage: number().min(0).max(100),
22992
+ /**
22993
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
22994
+ * provider has registered the capability but no reading has landed.
22995
+ *
22996
+ * It is nullable because it was not, and the only value a provider could
22997
+ * seed with was `0`. A battery camera behind an NVR therefore announced
22998
+ * itself at 0% on every start and corrected itself a moment later, which is
22999
+ * indistinguishable from a real flat battery: it fires the low-battery alert
23000
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
23001
+ * reading the difference is an alarm.
23002
+ *
23003
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
23004
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
23005
+ * declines to band a non-finite reading, which is the correct shape.
23006
+ */
23007
+ percentage: number().min(0).max(100).nullable(),
22887
23008
  /**
22888
23009
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
22889
23010
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -29362,6 +29483,12 @@ Object.freeze({
29362
29483
  addonId: null,
29363
29484
  access: "create"
29364
29485
  },
29486
+ "backup.cancel": {
29487
+ capName: "backup",
29488
+ capScope: "system",
29489
+ addonId: null,
29490
+ access: "create"
29491
+ },
29365
29492
  "backup.delete": {
29366
29493
  capName: "backup",
29367
29494
  capScope: "system",
@@ -29404,6 +29531,12 @@ Object.freeze({
29404
29531
  addonId: null,
29405
29532
  access: "view"
29406
29533
  },
29534
+ "backup.listRuns": {
29535
+ capName: "backup",
29536
+ capScope: "system",
29537
+ addonId: null,
29538
+ access: "view"
29539
+ },
29407
29540
  "backup.listSchedules": {
29408
29541
  capName: "backup",
29409
29542
  capScope: "system",
@@ -33970,6 +34103,12 @@ Object.freeze({
33970
34103
  addonId: null,
33971
34104
  access: "create"
33972
34105
  },
34106
+ "streamBroker.forgetDeviceHardware": {
34107
+ capName: "stream-broker",
34108
+ capScope: "system",
34109
+ addonId: null,
34110
+ access: "delete"
34111
+ },
33973
34112
  "streamBroker.getAllRtspEntries": {
33974
34113
  capName: "stream-broker",
33975
34114
  capScope: "system",
@@ -36428,6 +36567,11 @@ Object.freeze({
36428
36567
  form: "single",
36429
36568
  optional: false
36430
36569
  }],
36570
+ "streamBroker.forgetDeviceHardware": [{
36571
+ name: "deviceId",
36572
+ form: "single",
36573
+ optional: false
36574
+ }],
36431
36575
  "streamBroker.getDeviceAudioMute": [{
36432
36576
  name: "deviceId",
36433
36577
  form: "single",
@@ -37186,7 +37330,7 @@ var AgentUIAddon = class extends BaseAddon {
37186
37330
  capability: adminUiCapability,
37187
37331
  provider: {
37188
37332
  getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
37189
- getVersion: async () => ({ version: "1.2.60" })
37333
+ getVersion: async () => ({ version: "1.2.62" })
37190
37334
  }
37191
37335
  }];
37192
37336
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-agent-ui",
3
- "version": "1.2.60",
3
+ "version": "1.2.62",
4
4
  "description": "Agent UI — lightweight status dashboard served by every agent node",
5
5
  "keywords": [
6
6
  "camstack",