@camstack/addon-ai 0.4.57 → 0.4.59

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
@@ -10730,6 +10730,89 @@ var LocationStatSchema = object({
10730
10730
  fileCount: number$1(),
10731
10731
  present: boolean()
10732
10732
  });
10733
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
10734
+ var BackupRunStateSchema = _enum([
10735
+ "queued",
10736
+ "running",
10737
+ "succeeded",
10738
+ "failed",
10739
+ "cancelled"
10740
+ ]);
10741
+ /**
10742
+ * Where a running backup currently is. `queued` before it starts,
10743
+ * `building` while the tar.gz is being staged, `uploading` during the
10744
+ * per-destination fan-out, `done` once terminal.
10745
+ */
10746
+ var BackupRunPhaseSchema = _enum([
10747
+ "queued",
10748
+ "building",
10749
+ "uploading",
10750
+ "done"
10751
+ ]);
10752
+ /**
10753
+ * Observable state of one backup run — readable WHILE it runs via
10754
+ * `backup.listRuns`. This is what makes the execution queue and
10755
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
10756
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
10757
+ * diagnosable with `du` because nothing reported that runs existed or
10758
+ * how large the staged archive had grown.
10759
+ */
10760
+ var BackupRunSchema = object({
10761
+ /** Stable run id — the handle `backup.cancel` takes. */
10762
+ id: string(),
10763
+ state: BackupRunStateSchema,
10764
+ phase: BackupRunPhaseSchema,
10765
+ /**
10766
+ * Resolved destination location ids. Empty while queued (targets are
10767
+ * resolved when the run starts, against the then-current policies).
10768
+ */
10769
+ destinationIds: array(string()).readonly(),
10770
+ label: string().optional(),
10771
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
10772
+ requestedAt: number$1(),
10773
+ /** ms-epoch when the run left the queue and started building. */
10774
+ startedAt: number$1().optional(),
10775
+ /** ms-epoch when the run reached a terminal state. */
10776
+ finishedAt: number$1().optional(),
10777
+ /** Compressed bytes of the staging archive written so far. */
10778
+ stagedBytes: number$1(),
10779
+ /** Final staged archive size, once the build phase completes. */
10780
+ archiveSizeBytes: number$1().optional(),
10781
+ /** Bytes pushed to the destination currently uploading. */
10782
+ uploadedBytes: number$1(),
10783
+ /** Destinations where the archive fully landed (uploaded + indexed). */
10784
+ completedDestinationIds: array(string()).readonly(),
10785
+ /** Destinations that failed during the fan-out. */
10786
+ failedDestinationIds: array(string()).readonly(),
10787
+ /** Failure message when `state === 'failed'`. */
10788
+ error: string().optional(),
10789
+ /**
10790
+ * 1-based place in the execution queue — 1 = runs next. Present only
10791
+ * while `state === 'queued'`. Stamped by the orchestrator from the
10792
+ * queue's OWN pending order, never derived from timestamps, so the
10793
+ * UI cannot show an order the executor will not honour.
10794
+ */
10795
+ queuePosition: number$1().int().min(1).optional()
10796
+ });
10797
+ /**
10798
+ * Result of `backup.trigger`. The call still resolves when the run
10799
+ * terminates (compat with schedule-driven runs and the admin UI), but
10800
+ * it now names the run and says whether it had to WAIT: a trigger that
10801
+ * arrives while another run is in flight is enqueued (or joined onto
10802
+ * an identical already-queued run), never started concurrently.
10803
+ */
10804
+ var BackupTriggerResultSchema = object({
10805
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
10806
+ runId: string(),
10807
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
10808
+ queued: boolean(),
10809
+ /** True when this trigger was coalesced onto an identical already-queued run. */
10810
+ joined: boolean(),
10811
+ /** True when the run was cancelled before completing every destination. */
10812
+ cancelled: boolean(),
10813
+ /** One entry per destination the archive landed at (partial on cancel). */
10814
+ entries: array(BackupEntrySchema).readonly()
10815
+ });
10733
10816
  /**
10734
10817
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
10735
10818
  * SET of destination locations. Supersedes the per-location cron on
@@ -10777,7 +10860,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
10777
10860
  * retention (manual runs).
10778
10861
  */
10779
10862
  retentionCount: number$1().int().min(1).max(1e3).optional()
10780
- }).optional(), array(BackupEntrySchema).readonly(), {
10863
+ }).optional(), BackupTriggerResultSchema, {
10864
+ kind: "mutation",
10865
+ auth: "admin"
10866
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
10781
10867
  kind: "mutation",
10782
10868
  auth: "admin"
10783
10869
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -11494,6 +11580,14 @@ method(object({
11494
11580
  }), object({ success: literal(true) }), {
11495
11581
  kind: "mutation",
11496
11582
  auth: "admin"
11583
+ }), method(object({ deviceId: number$1().int().nonnegative() }), object({
11584
+ derivedStreamsDeleted: array(string()).readonly(),
11585
+ assignmentsPurged: boolean(),
11586
+ probeSnapshotsDropped: number$1().int().nonnegative(),
11587
+ rtspTokenRowsDeleted: number$1().int().nonnegative()
11588
+ }), {
11589
+ kind: "mutation",
11590
+ auth: "admin"
11497
11591
  }), method(object({
11498
11592
  deviceId: number$1(),
11499
11593
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -19138,7 +19232,20 @@ var RecentTracksQueryInput = object({
19138
19232
  projection: TrackProjectionSchema.optional(),
19139
19233
  /** Include stationary-promoted rows (parked objects). Default false: the
19140
19234
  * feed lists passages; parking records live on the stationary registry. */
19141
- includeStationary: boolean().optional()
19235
+ includeStationary: boolean().optional(),
19236
+ /**
19237
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
19238
+ *
19239
+ * The same filter `listTracks` takes, because the timeline's class chips must
19240
+ * mean the same thing whether the scope is one camera or twelve. Until this
19241
+ * existed the scoped feed downloaded a page and narrowed it on the phone
19242
+ * while the single-camera path narrowed the read — one filter, two costs.
19243
+ *
19244
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
19245
+ * whose class list is unreadable are kept, and the client's rule stays the
19246
+ * exact one.
19247
+ */
19248
+ classes: array(string()).optional()
19142
19249
  });
19143
19250
  var RecentTracksPageSchema = object({
19144
19251
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -23176,8 +23283,22 @@ DeviceType.Automation, method(object({ deviceId: number$1().int().nonnegative()
23176
23283
  * threshold.
23177
23284
  */
23178
23285
  var BatteryStatusSchema = object({
23179
- /** 0..100 inclusive. Firmware-reported. */
23180
- percentage: number$1().min(0).max(100),
23286
+ /**
23287
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
23288
+ * provider has registered the capability but no reading has landed.
23289
+ *
23290
+ * It is nullable because it was not, and the only value a provider could
23291
+ * seed with was `0`. A battery camera behind an NVR therefore announced
23292
+ * itself at 0% on every start and corrected itself a moment later, which is
23293
+ * indistinguishable from a real flat battery: it fires the low-battery alert
23294
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
23295
+ * reading the difference is an alarm.
23296
+ *
23297
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
23298
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
23299
+ * declines to band a non-finite reading, which is the correct shape.
23300
+ */
23301
+ percentage: number$1().min(0).max(100).nullable(),
23181
23302
  /**
23182
23303
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
23183
23304
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -29656,6 +29777,12 @@ Object.freeze({
29656
29777
  addonId: null,
29657
29778
  access: "create"
29658
29779
  },
29780
+ "backup.cancel": {
29781
+ capName: "backup",
29782
+ capScope: "system",
29783
+ addonId: null,
29784
+ access: "create"
29785
+ },
29659
29786
  "backup.delete": {
29660
29787
  capName: "backup",
29661
29788
  capScope: "system",
@@ -29698,6 +29825,12 @@ Object.freeze({
29698
29825
  addonId: null,
29699
29826
  access: "view"
29700
29827
  },
29828
+ "backup.listRuns": {
29829
+ capName: "backup",
29830
+ capScope: "system",
29831
+ addonId: null,
29832
+ access: "view"
29833
+ },
29701
29834
  "backup.listSchedules": {
29702
29835
  capName: "backup",
29703
29836
  capScope: "system",
@@ -34264,6 +34397,12 @@ Object.freeze({
34264
34397
  addonId: null,
34265
34398
  access: "create"
34266
34399
  },
34400
+ "streamBroker.forgetDeviceHardware": {
34401
+ capName: "stream-broker",
34402
+ capScope: "system",
34403
+ addonId: null,
34404
+ access: "delete"
34405
+ },
34267
34406
  "streamBroker.getAllRtspEntries": {
34268
34407
  capName: "stream-broker",
34269
34408
  capScope: "system",
@@ -36722,6 +36861,11 @@ Object.freeze({
36722
36861
  form: "single",
36723
36862
  optional: false
36724
36863
  }],
36864
+ "streamBroker.forgetDeviceHardware": [{
36865
+ name: "deviceId",
36866
+ form: "single",
36867
+ optional: false
36868
+ }],
36725
36869
  "streamBroker.getDeviceAudioMute": [{
36726
36870
  name: "deviceId",
36727
36871
  form: "single",
package/dist/addon.mjs CHANGED
@@ -10757,6 +10757,89 @@ var LocationStatSchema = object({
10757
10757
  fileCount: number$1(),
10758
10758
  present: boolean()
10759
10759
  });
10760
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
10761
+ var BackupRunStateSchema = _enum([
10762
+ "queued",
10763
+ "running",
10764
+ "succeeded",
10765
+ "failed",
10766
+ "cancelled"
10767
+ ]);
10768
+ /**
10769
+ * Where a running backup currently is. `queued` before it starts,
10770
+ * `building` while the tar.gz is being staged, `uploading` during the
10771
+ * per-destination fan-out, `done` once terminal.
10772
+ */
10773
+ var BackupRunPhaseSchema = _enum([
10774
+ "queued",
10775
+ "building",
10776
+ "uploading",
10777
+ "done"
10778
+ ]);
10779
+ /**
10780
+ * Observable state of one backup run — readable WHILE it runs via
10781
+ * `backup.listRuns`. This is what makes the execution queue and
10782
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
10783
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
10784
+ * diagnosable with `du` because nothing reported that runs existed or
10785
+ * how large the staged archive had grown.
10786
+ */
10787
+ var BackupRunSchema = object({
10788
+ /** Stable run id — the handle `backup.cancel` takes. */
10789
+ id: string(),
10790
+ state: BackupRunStateSchema,
10791
+ phase: BackupRunPhaseSchema,
10792
+ /**
10793
+ * Resolved destination location ids. Empty while queued (targets are
10794
+ * resolved when the run starts, against the then-current policies).
10795
+ */
10796
+ destinationIds: array(string()).readonly(),
10797
+ label: string().optional(),
10798
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
10799
+ requestedAt: number$1(),
10800
+ /** ms-epoch when the run left the queue and started building. */
10801
+ startedAt: number$1().optional(),
10802
+ /** ms-epoch when the run reached a terminal state. */
10803
+ finishedAt: number$1().optional(),
10804
+ /** Compressed bytes of the staging archive written so far. */
10805
+ stagedBytes: number$1(),
10806
+ /** Final staged archive size, once the build phase completes. */
10807
+ archiveSizeBytes: number$1().optional(),
10808
+ /** Bytes pushed to the destination currently uploading. */
10809
+ uploadedBytes: number$1(),
10810
+ /** Destinations where the archive fully landed (uploaded + indexed). */
10811
+ completedDestinationIds: array(string()).readonly(),
10812
+ /** Destinations that failed during the fan-out. */
10813
+ failedDestinationIds: array(string()).readonly(),
10814
+ /** Failure message when `state === 'failed'`. */
10815
+ error: string().optional(),
10816
+ /**
10817
+ * 1-based place in the execution queue — 1 = runs next. Present only
10818
+ * while `state === 'queued'`. Stamped by the orchestrator from the
10819
+ * queue's OWN pending order, never derived from timestamps, so the
10820
+ * UI cannot show an order the executor will not honour.
10821
+ */
10822
+ queuePosition: number$1().int().min(1).optional()
10823
+ });
10824
+ /**
10825
+ * Result of `backup.trigger`. The call still resolves when the run
10826
+ * terminates (compat with schedule-driven runs and the admin UI), but
10827
+ * it now names the run and says whether it had to WAIT: a trigger that
10828
+ * arrives while another run is in flight is enqueued (or joined onto
10829
+ * an identical already-queued run), never started concurrently.
10830
+ */
10831
+ var BackupTriggerResultSchema = object({
10832
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
10833
+ runId: string(),
10834
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
10835
+ queued: boolean(),
10836
+ /** True when this trigger was coalesced onto an identical already-queued run. */
10837
+ joined: boolean(),
10838
+ /** True when the run was cancelled before completing every destination. */
10839
+ cancelled: boolean(),
10840
+ /** One entry per destination the archive landed at (partial on cancel). */
10841
+ entries: array(BackupEntrySchema).readonly()
10842
+ });
10760
10843
  /**
10761
10844
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
10762
10845
  * SET of destination locations. Supersedes the per-location cron on
@@ -10804,7 +10887,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
10804
10887
  * retention (manual runs).
10805
10888
  */
10806
10889
  retentionCount: number$1().int().min(1).max(1e3).optional()
10807
- }).optional(), array(BackupEntrySchema).readonly(), {
10890
+ }).optional(), BackupTriggerResultSchema, {
10891
+ kind: "mutation",
10892
+ auth: "admin"
10893
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
10808
10894
  kind: "mutation",
10809
10895
  auth: "admin"
10810
10896
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -11521,6 +11607,14 @@ method(object({
11521
11607
  }), object({ success: literal(true) }), {
11522
11608
  kind: "mutation",
11523
11609
  auth: "admin"
11610
+ }), method(object({ deviceId: number$1().int().nonnegative() }), object({
11611
+ derivedStreamsDeleted: array(string()).readonly(),
11612
+ assignmentsPurged: boolean(),
11613
+ probeSnapshotsDropped: number$1().int().nonnegative(),
11614
+ rtspTokenRowsDeleted: number$1().int().nonnegative()
11615
+ }), {
11616
+ kind: "mutation",
11617
+ auth: "admin"
11524
11618
  }), method(object({
11525
11619
  deviceId: number$1(),
11526
11620
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -19165,7 +19259,20 @@ var RecentTracksQueryInput = object({
19165
19259
  projection: TrackProjectionSchema.optional(),
19166
19260
  /** Include stationary-promoted rows (parked objects). Default false: the
19167
19261
  * feed lists passages; parking records live on the stationary registry. */
19168
- includeStationary: boolean().optional()
19262
+ includeStationary: boolean().optional(),
19263
+ /**
19264
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
19265
+ *
19266
+ * The same filter `listTracks` takes, because the timeline's class chips must
19267
+ * mean the same thing whether the scope is one camera or twelve. Until this
19268
+ * existed the scoped feed downloaded a page and narrowed it on the phone
19269
+ * while the single-camera path narrowed the read — one filter, two costs.
19270
+ *
19271
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
19272
+ * whose class list is unreadable are kept, and the client's rule stays the
19273
+ * exact one.
19274
+ */
19275
+ classes: array(string()).optional()
19169
19276
  });
19170
19277
  var RecentTracksPageSchema = object({
19171
19278
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -23203,8 +23310,22 @@ DeviceType.Automation, method(object({ deviceId: number$1().int().nonnegative()
23203
23310
  * threshold.
23204
23311
  */
23205
23312
  var BatteryStatusSchema = object({
23206
- /** 0..100 inclusive. Firmware-reported. */
23207
- percentage: number$1().min(0).max(100),
23313
+ /**
23314
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
23315
+ * provider has registered the capability but no reading has landed.
23316
+ *
23317
+ * It is nullable because it was not, and the only value a provider could
23318
+ * seed with was `0`. A battery camera behind an NVR therefore announced
23319
+ * itself at 0% on every start and corrected itself a moment later, which is
23320
+ * indistinguishable from a real flat battery: it fires the low-battery alert
23321
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
23322
+ * reading the difference is an alarm.
23323
+ *
23324
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
23325
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
23326
+ * declines to band a non-finite reading, which is the correct shape.
23327
+ */
23328
+ percentage: number$1().min(0).max(100).nullable(),
23208
23329
  /**
23209
23330
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
23210
23331
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -29683,6 +29804,12 @@ Object.freeze({
29683
29804
  addonId: null,
29684
29805
  access: "create"
29685
29806
  },
29807
+ "backup.cancel": {
29808
+ capName: "backup",
29809
+ capScope: "system",
29810
+ addonId: null,
29811
+ access: "create"
29812
+ },
29686
29813
  "backup.delete": {
29687
29814
  capName: "backup",
29688
29815
  capScope: "system",
@@ -29725,6 +29852,12 @@ Object.freeze({
29725
29852
  addonId: null,
29726
29853
  access: "view"
29727
29854
  },
29855
+ "backup.listRuns": {
29856
+ capName: "backup",
29857
+ capScope: "system",
29858
+ addonId: null,
29859
+ access: "view"
29860
+ },
29728
29861
  "backup.listSchedules": {
29729
29862
  capName: "backup",
29730
29863
  capScope: "system",
@@ -34291,6 +34424,12 @@ Object.freeze({
34291
34424
  addonId: null,
34292
34425
  access: "create"
34293
34426
  },
34427
+ "streamBroker.forgetDeviceHardware": {
34428
+ capName: "stream-broker",
34429
+ capScope: "system",
34430
+ addonId: null,
34431
+ access: "delete"
34432
+ },
34294
34433
  "streamBroker.getAllRtspEntries": {
34295
34434
  capName: "stream-broker",
34296
34435
  capScope: "system",
@@ -36749,6 +36888,11 @@ Object.freeze({
36749
36888
  form: "single",
36750
36889
  optional: false
36751
36890
  }],
36891
+ "streamBroker.forgetDeviceHardware": [{
36892
+ name: "deviceId",
36893
+ form: "single",
36894
+ optional: false
36895
+ }],
36752
36896
  "streamBroker.getDeviceAudioMute": [{
36753
36897
  name: "deviceId",
36754
36898
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-ai",
3
- "version": "0.4.57",
3
+ "version": "0.4.59",
4
4
  "description": "AI addon for CamStack — the `llm` collection provider (cloud, LAN, and camstack-managed local llama.cpp profiles) plus the per-node `llm-runtime` managed executor.",
5
5
  "keywords": [
6
6
  "camstack",