@camstack/addon-export-google 0.1.21 → 0.1.23

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.
@@ -10746,6 +10746,89 @@ var LocationStatSchema = object({
10746
10746
  fileCount: number(),
10747
10747
  present: boolean()
10748
10748
  });
10749
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
10750
+ var BackupRunStateSchema = _enum([
10751
+ "queued",
10752
+ "running",
10753
+ "succeeded",
10754
+ "failed",
10755
+ "cancelled"
10756
+ ]);
10757
+ /**
10758
+ * Where a running backup currently is. `queued` before it starts,
10759
+ * `building` while the tar.gz is being staged, `uploading` during the
10760
+ * per-destination fan-out, `done` once terminal.
10761
+ */
10762
+ var BackupRunPhaseSchema = _enum([
10763
+ "queued",
10764
+ "building",
10765
+ "uploading",
10766
+ "done"
10767
+ ]);
10768
+ /**
10769
+ * Observable state of one backup run — readable WHILE it runs via
10770
+ * `backup.listRuns`. This is what makes the execution queue and
10771
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
10772
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
10773
+ * diagnosable with `du` because nothing reported that runs existed or
10774
+ * how large the staged archive had grown.
10775
+ */
10776
+ var BackupRunSchema = object({
10777
+ /** Stable run id — the handle `backup.cancel` takes. */
10778
+ id: string(),
10779
+ state: BackupRunStateSchema,
10780
+ phase: BackupRunPhaseSchema,
10781
+ /**
10782
+ * Resolved destination location ids. Empty while queued (targets are
10783
+ * resolved when the run starts, against the then-current policies).
10784
+ */
10785
+ destinationIds: array(string()).readonly(),
10786
+ label: string().optional(),
10787
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
10788
+ requestedAt: number(),
10789
+ /** ms-epoch when the run left the queue and started building. */
10790
+ startedAt: number().optional(),
10791
+ /** ms-epoch when the run reached a terminal state. */
10792
+ finishedAt: number().optional(),
10793
+ /** Compressed bytes of the staging archive written so far. */
10794
+ stagedBytes: number(),
10795
+ /** Final staged archive size, once the build phase completes. */
10796
+ archiveSizeBytes: number().optional(),
10797
+ /** Bytes pushed to the destination currently uploading. */
10798
+ uploadedBytes: number(),
10799
+ /** Destinations where the archive fully landed (uploaded + indexed). */
10800
+ completedDestinationIds: array(string()).readonly(),
10801
+ /** Destinations that failed during the fan-out. */
10802
+ failedDestinationIds: array(string()).readonly(),
10803
+ /** Failure message when `state === 'failed'`. */
10804
+ error: string().optional(),
10805
+ /**
10806
+ * 1-based place in the execution queue — 1 = runs next. Present only
10807
+ * while `state === 'queued'`. Stamped by the orchestrator from the
10808
+ * queue's OWN pending order, never derived from timestamps, so the
10809
+ * UI cannot show an order the executor will not honour.
10810
+ */
10811
+ queuePosition: number().int().min(1).optional()
10812
+ });
10813
+ /**
10814
+ * Result of `backup.trigger`. The call still resolves when the run
10815
+ * terminates (compat with schedule-driven runs and the admin UI), but
10816
+ * it now names the run and says whether it had to WAIT: a trigger that
10817
+ * arrives while another run is in flight is enqueued (or joined onto
10818
+ * an identical already-queued run), never started concurrently.
10819
+ */
10820
+ var BackupTriggerResultSchema = object({
10821
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
10822
+ runId: string(),
10823
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
10824
+ queued: boolean(),
10825
+ /** True when this trigger was coalesced onto an identical already-queued run. */
10826
+ joined: boolean(),
10827
+ /** True when the run was cancelled before completing every destination. */
10828
+ cancelled: boolean(),
10829
+ /** One entry per destination the archive landed at (partial on cancel). */
10830
+ entries: array(BackupEntrySchema).readonly()
10831
+ });
10749
10832
  /**
10750
10833
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
10751
10834
  * SET of destination locations. Supersedes the per-location cron on
@@ -10793,7 +10876,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
10793
10876
  * retention (manual runs).
10794
10877
  */
10795
10878
  retentionCount: number().int().min(1).max(1e3).optional()
10796
- }).optional(), array(BackupEntrySchema).readonly(), {
10879
+ }).optional(), BackupTriggerResultSchema, {
10880
+ kind: "mutation",
10881
+ auth: "admin"
10882
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
10797
10883
  kind: "mutation",
10798
10884
  auth: "admin"
10799
10885
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -11510,6 +11596,14 @@ method(object({
11510
11596
  }), object({ success: literal(true) }), {
11511
11597
  kind: "mutation",
11512
11598
  auth: "admin"
11599
+ }), method(object({ deviceId: number().int().nonnegative() }), object({
11600
+ derivedStreamsDeleted: array(string()).readonly(),
11601
+ assignmentsPurged: boolean(),
11602
+ probeSnapshotsDropped: number().int().nonnegative(),
11603
+ rtspTokenRowsDeleted: number().int().nonnegative()
11604
+ }), {
11605
+ kind: "mutation",
11606
+ auth: "admin"
11513
11607
  }), method(object({
11514
11608
  deviceId: number(),
11515
11609
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -19123,7 +19217,20 @@ var RecentTracksQueryInput = object({
19123
19217
  projection: TrackProjectionSchema.optional(),
19124
19218
  /** Include stationary-promoted rows (parked objects). Default false: the
19125
19219
  * feed lists passages; parking records live on the stationary registry. */
19126
- includeStationary: boolean().optional()
19220
+ includeStationary: boolean().optional(),
19221
+ /**
19222
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
19223
+ *
19224
+ * The same filter `listTracks` takes, because the timeline's class chips must
19225
+ * mean the same thing whether the scope is one camera or twelve. Until this
19226
+ * existed the scoped feed downloaded a page and narrowed it on the phone
19227
+ * while the single-camera path narrowed the read — one filter, two costs.
19228
+ *
19229
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
19230
+ * whose class list is unreadable are kept, and the client's rule stays the
19231
+ * exact one.
19232
+ */
19233
+ classes: array(string()).optional()
19127
19234
  });
19128
19235
  var RecentTracksPageSchema = object({
19129
19236
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -23161,8 +23268,22 @@ DeviceType.Automation, method(object({ deviceId: number().int().nonnegative() })
23161
23268
  * threshold.
23162
23269
  */
23163
23270
  var BatteryStatusSchema = object({
23164
- /** 0..100 inclusive. Firmware-reported. */
23165
- percentage: number().min(0).max(100),
23271
+ /**
23272
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
23273
+ * provider has registered the capability but no reading has landed.
23274
+ *
23275
+ * It is nullable because it was not, and the only value a provider could
23276
+ * seed with was `0`. A battery camera behind an NVR therefore announced
23277
+ * itself at 0% on every start and corrected itself a moment later, which is
23278
+ * indistinguishable from a real flat battery: it fires the low-battery alert
23279
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
23280
+ * reading the difference is an alarm.
23281
+ *
23282
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
23283
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
23284
+ * declines to band a non-finite reading, which is the correct shape.
23285
+ */
23286
+ percentage: number().min(0).max(100).nullable(),
23166
23287
  /**
23167
23288
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
23168
23289
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -29660,6 +29781,12 @@ Object.freeze({
29660
29781
  addonId: null,
29661
29782
  access: "create"
29662
29783
  },
29784
+ "backup.cancel": {
29785
+ capName: "backup",
29786
+ capScope: "system",
29787
+ addonId: null,
29788
+ access: "create"
29789
+ },
29663
29790
  "backup.delete": {
29664
29791
  capName: "backup",
29665
29792
  capScope: "system",
@@ -29702,6 +29829,12 @@ Object.freeze({
29702
29829
  addonId: null,
29703
29830
  access: "view"
29704
29831
  },
29832
+ "backup.listRuns": {
29833
+ capName: "backup",
29834
+ capScope: "system",
29835
+ addonId: null,
29836
+ access: "view"
29837
+ },
29705
29838
  "backup.listSchedules": {
29706
29839
  capName: "backup",
29707
29840
  capScope: "system",
@@ -34268,6 +34401,12 @@ Object.freeze({
34268
34401
  addonId: null,
34269
34402
  access: "create"
34270
34403
  },
34404
+ "streamBroker.forgetDeviceHardware": {
34405
+ capName: "stream-broker",
34406
+ capScope: "system",
34407
+ addonId: null,
34408
+ access: "delete"
34409
+ },
34271
34410
  "streamBroker.getAllRtspEntries": {
34272
34411
  capName: "stream-broker",
34273
34412
  capScope: "system",
@@ -36726,6 +36865,11 @@ Object.freeze({
36726
36865
  form: "single",
36727
36866
  optional: false
36728
36867
  }],
36868
+ "streamBroker.forgetDeviceHardware": [{
36869
+ name: "deviceId",
36870
+ form: "single",
36871
+ optional: false
36872
+ }],
36729
36873
  "streamBroker.getDeviceAudioMute": [{
36730
36874
  name: "deviceId",
36731
36875
  form: "single",
@@ -10742,6 +10742,89 @@ var LocationStatSchema = object({
10742
10742
  fileCount: number(),
10743
10743
  present: boolean()
10744
10744
  });
10745
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
10746
+ var BackupRunStateSchema = _enum([
10747
+ "queued",
10748
+ "running",
10749
+ "succeeded",
10750
+ "failed",
10751
+ "cancelled"
10752
+ ]);
10753
+ /**
10754
+ * Where a running backup currently is. `queued` before it starts,
10755
+ * `building` while the tar.gz is being staged, `uploading` during the
10756
+ * per-destination fan-out, `done` once terminal.
10757
+ */
10758
+ var BackupRunPhaseSchema = _enum([
10759
+ "queued",
10760
+ "building",
10761
+ "uploading",
10762
+ "done"
10763
+ ]);
10764
+ /**
10765
+ * Observable state of one backup run — readable WHILE it runs via
10766
+ * `backup.listRuns`. This is what makes the execution queue and
10767
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
10768
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
10769
+ * diagnosable with `du` because nothing reported that runs existed or
10770
+ * how large the staged archive had grown.
10771
+ */
10772
+ var BackupRunSchema = object({
10773
+ /** Stable run id — the handle `backup.cancel` takes. */
10774
+ id: string(),
10775
+ state: BackupRunStateSchema,
10776
+ phase: BackupRunPhaseSchema,
10777
+ /**
10778
+ * Resolved destination location ids. Empty while queued (targets are
10779
+ * resolved when the run starts, against the then-current policies).
10780
+ */
10781
+ destinationIds: array(string()).readonly(),
10782
+ label: string().optional(),
10783
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
10784
+ requestedAt: number(),
10785
+ /** ms-epoch when the run left the queue and started building. */
10786
+ startedAt: number().optional(),
10787
+ /** ms-epoch when the run reached a terminal state. */
10788
+ finishedAt: number().optional(),
10789
+ /** Compressed bytes of the staging archive written so far. */
10790
+ stagedBytes: number(),
10791
+ /** Final staged archive size, once the build phase completes. */
10792
+ archiveSizeBytes: number().optional(),
10793
+ /** Bytes pushed to the destination currently uploading. */
10794
+ uploadedBytes: number(),
10795
+ /** Destinations where the archive fully landed (uploaded + indexed). */
10796
+ completedDestinationIds: array(string()).readonly(),
10797
+ /** Destinations that failed during the fan-out. */
10798
+ failedDestinationIds: array(string()).readonly(),
10799
+ /** Failure message when `state === 'failed'`. */
10800
+ error: string().optional(),
10801
+ /**
10802
+ * 1-based place in the execution queue — 1 = runs next. Present only
10803
+ * while `state === 'queued'`. Stamped by the orchestrator from the
10804
+ * queue's OWN pending order, never derived from timestamps, so the
10805
+ * UI cannot show an order the executor will not honour.
10806
+ */
10807
+ queuePosition: number().int().min(1).optional()
10808
+ });
10809
+ /**
10810
+ * Result of `backup.trigger`. The call still resolves when the run
10811
+ * terminates (compat with schedule-driven runs and the admin UI), but
10812
+ * it now names the run and says whether it had to WAIT: a trigger that
10813
+ * arrives while another run is in flight is enqueued (or joined onto
10814
+ * an identical already-queued run), never started concurrently.
10815
+ */
10816
+ var BackupTriggerResultSchema = object({
10817
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
10818
+ runId: string(),
10819
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
10820
+ queued: boolean(),
10821
+ /** True when this trigger was coalesced onto an identical already-queued run. */
10822
+ joined: boolean(),
10823
+ /** True when the run was cancelled before completing every destination. */
10824
+ cancelled: boolean(),
10825
+ /** One entry per destination the archive landed at (partial on cancel). */
10826
+ entries: array(BackupEntrySchema).readonly()
10827
+ });
10745
10828
  /**
10746
10829
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
10747
10830
  * SET of destination locations. Supersedes the per-location cron on
@@ -10789,7 +10872,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
10789
10872
  * retention (manual runs).
10790
10873
  */
10791
10874
  retentionCount: number().int().min(1).max(1e3).optional()
10792
- }).optional(), array(BackupEntrySchema).readonly(), {
10875
+ }).optional(), BackupTriggerResultSchema, {
10876
+ kind: "mutation",
10877
+ auth: "admin"
10878
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
10793
10879
  kind: "mutation",
10794
10880
  auth: "admin"
10795
10881
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -11506,6 +11592,14 @@ method(object({
11506
11592
  }), object({ success: literal(true) }), {
11507
11593
  kind: "mutation",
11508
11594
  auth: "admin"
11595
+ }), method(object({ deviceId: number().int().nonnegative() }), object({
11596
+ derivedStreamsDeleted: array(string()).readonly(),
11597
+ assignmentsPurged: boolean(),
11598
+ probeSnapshotsDropped: number().int().nonnegative(),
11599
+ rtspTokenRowsDeleted: number().int().nonnegative()
11600
+ }), {
11601
+ kind: "mutation",
11602
+ auth: "admin"
11509
11603
  }), method(object({
11510
11604
  deviceId: number(),
11511
11605
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -19119,7 +19213,20 @@ var RecentTracksQueryInput = object({
19119
19213
  projection: TrackProjectionSchema.optional(),
19120
19214
  /** Include stationary-promoted rows (parked objects). Default false: the
19121
19215
  * feed lists passages; parking records live on the stationary registry. */
19122
- includeStationary: boolean().optional()
19216
+ includeStationary: boolean().optional(),
19217
+ /**
19218
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
19219
+ *
19220
+ * The same filter `listTracks` takes, because the timeline's class chips must
19221
+ * mean the same thing whether the scope is one camera or twelve. Until this
19222
+ * existed the scoped feed downloaded a page and narrowed it on the phone
19223
+ * while the single-camera path narrowed the read — one filter, two costs.
19224
+ *
19225
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
19226
+ * whose class list is unreadable are kept, and the client's rule stays the
19227
+ * exact one.
19228
+ */
19229
+ classes: array(string()).optional()
19123
19230
  });
19124
19231
  var RecentTracksPageSchema = object({
19125
19232
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -23157,8 +23264,22 @@ DeviceType.Automation, method(object({ deviceId: number().int().nonnegative() })
23157
23264
  * threshold.
23158
23265
  */
23159
23266
  var BatteryStatusSchema = object({
23160
- /** 0..100 inclusive. Firmware-reported. */
23161
- percentage: number().min(0).max(100),
23267
+ /**
23268
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
23269
+ * provider has registered the capability but no reading has landed.
23270
+ *
23271
+ * It is nullable because it was not, and the only value a provider could
23272
+ * seed with was `0`. A battery camera behind an NVR therefore announced
23273
+ * itself at 0% on every start and corrected itself a moment later, which is
23274
+ * indistinguishable from a real flat battery: it fires the low-battery alert
23275
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
23276
+ * reading the difference is an alarm.
23277
+ *
23278
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
23279
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
23280
+ * declines to band a non-finite reading, which is the correct shape.
23281
+ */
23282
+ percentage: number().min(0).max(100).nullable(),
23162
23283
  /**
23163
23284
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
23164
23285
  * 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-google",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "Google Home export — hub-side smart-home fulfillment (SYNC / QUERY / EXECUTE / DISCONNECT) for the non-camera fleet, served over the hub's own OAuth account link. No Google credential is stored, sent or required.",
5
5
  "keywords": [
6
6
  "camstack",