@camstack/addon-provider-tuya 0.2.57 → 0.2.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
@@ -11347,6 +11347,89 @@ var LocationStatSchema = object({
11347
11347
  fileCount: number(),
11348
11348
  present: boolean()
11349
11349
  });
11350
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
11351
+ var BackupRunStateSchema = _enum([
11352
+ "queued",
11353
+ "running",
11354
+ "succeeded",
11355
+ "failed",
11356
+ "cancelled"
11357
+ ]);
11358
+ /**
11359
+ * Where a running backup currently is. `queued` before it starts,
11360
+ * `building` while the tar.gz is being staged, `uploading` during the
11361
+ * per-destination fan-out, `done` once terminal.
11362
+ */
11363
+ var BackupRunPhaseSchema = _enum([
11364
+ "queued",
11365
+ "building",
11366
+ "uploading",
11367
+ "done"
11368
+ ]);
11369
+ /**
11370
+ * Observable state of one backup run — readable WHILE it runs via
11371
+ * `backup.listRuns`. This is what makes the execution queue and
11372
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
11373
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
11374
+ * diagnosable with `du` because nothing reported that runs existed or
11375
+ * how large the staged archive had grown.
11376
+ */
11377
+ var BackupRunSchema = object({
11378
+ /** Stable run id — the handle `backup.cancel` takes. */
11379
+ id: string(),
11380
+ state: BackupRunStateSchema,
11381
+ phase: BackupRunPhaseSchema,
11382
+ /**
11383
+ * Resolved destination location ids. Empty while queued (targets are
11384
+ * resolved when the run starts, against the then-current policies).
11385
+ */
11386
+ destinationIds: array(string()).readonly(),
11387
+ label: string().optional(),
11388
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
11389
+ requestedAt: number(),
11390
+ /** ms-epoch when the run left the queue and started building. */
11391
+ startedAt: number().optional(),
11392
+ /** ms-epoch when the run reached a terminal state. */
11393
+ finishedAt: number().optional(),
11394
+ /** Compressed bytes of the staging archive written so far. */
11395
+ stagedBytes: number(),
11396
+ /** Final staged archive size, once the build phase completes. */
11397
+ archiveSizeBytes: number().optional(),
11398
+ /** Bytes pushed to the destination currently uploading. */
11399
+ uploadedBytes: number(),
11400
+ /** Destinations where the archive fully landed (uploaded + indexed). */
11401
+ completedDestinationIds: array(string()).readonly(),
11402
+ /** Destinations that failed during the fan-out. */
11403
+ failedDestinationIds: array(string()).readonly(),
11404
+ /** Failure message when `state === 'failed'`. */
11405
+ error: string().optional(),
11406
+ /**
11407
+ * 1-based place in the execution queue — 1 = runs next. Present only
11408
+ * while `state === 'queued'`. Stamped by the orchestrator from the
11409
+ * queue's OWN pending order, never derived from timestamps, so the
11410
+ * UI cannot show an order the executor will not honour.
11411
+ */
11412
+ queuePosition: number().int().min(1).optional()
11413
+ });
11414
+ /**
11415
+ * Result of `backup.trigger`. The call still resolves when the run
11416
+ * terminates (compat with schedule-driven runs and the admin UI), but
11417
+ * it now names the run and says whether it had to WAIT: a trigger that
11418
+ * arrives while another run is in flight is enqueued (or joined onto
11419
+ * an identical already-queued run), never started concurrently.
11420
+ */
11421
+ var BackupTriggerResultSchema = object({
11422
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
11423
+ runId: string(),
11424
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
11425
+ queued: boolean(),
11426
+ /** True when this trigger was coalesced onto an identical already-queued run. */
11427
+ joined: boolean(),
11428
+ /** True when the run was cancelled before completing every destination. */
11429
+ cancelled: boolean(),
11430
+ /** One entry per destination the archive landed at (partial on cancel). */
11431
+ entries: array(BackupEntrySchema).readonly()
11432
+ });
11350
11433
  /**
11351
11434
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
11352
11435
  * SET of destination locations. Supersedes the per-location cron on
@@ -11394,7 +11477,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
11394
11477
  * retention (manual runs).
11395
11478
  */
11396
11479
  retentionCount: number().int().min(1).max(1e3).optional()
11397
- }).optional(), array(BackupEntrySchema).readonly(), {
11480
+ }).optional(), BackupTriggerResultSchema, {
11481
+ kind: "mutation",
11482
+ auth: "admin"
11483
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
11398
11484
  kind: "mutation",
11399
11485
  auth: "admin"
11400
11486
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -12111,6 +12197,14 @@ method(object({
12111
12197
  }), object({ success: literal(true) }), {
12112
12198
  kind: "mutation",
12113
12199
  auth: "admin"
12200
+ }), method(object({ deviceId: number().int().nonnegative() }), object({
12201
+ derivedStreamsDeleted: array(string()).readonly(),
12202
+ assignmentsPurged: boolean(),
12203
+ probeSnapshotsDropped: number().int().nonnegative(),
12204
+ rtspTokenRowsDeleted: number().int().nonnegative()
12205
+ }), {
12206
+ kind: "mutation",
12207
+ auth: "admin"
12114
12208
  }), method(object({
12115
12209
  deviceId: number(),
12116
12210
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -20020,7 +20114,20 @@ var RecentTracksQueryInput = object({
20020
20114
  projection: TrackProjectionSchema.optional(),
20021
20115
  /** Include stationary-promoted rows (parked objects). Default false: the
20022
20116
  * feed lists passages; parking records live on the stationary registry. */
20023
- includeStationary: boolean().optional()
20117
+ includeStationary: boolean().optional(),
20118
+ /**
20119
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
20120
+ *
20121
+ * The same filter `listTracks` takes, because the timeline's class chips must
20122
+ * mean the same thing whether the scope is one camera or twelve. Until this
20123
+ * existed the scoped feed downloaded a page and narrowed it on the phone
20124
+ * while the single-camera path narrowed the read — one filter, two costs.
20125
+ *
20126
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
20127
+ * whose class list is unreadable are kept, and the client's rule stays the
20128
+ * exact one.
20129
+ */
20130
+ classes: array(string()).optional()
20024
20131
  });
20025
20132
  var RecentTracksPageSchema = object({
20026
20133
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -24190,8 +24297,22 @@ var automationControlCapability = {
24190
24297
  * threshold.
24191
24298
  */
24192
24299
  var BatteryStatusSchema = object({
24193
- /** 0..100 inclusive. Firmware-reported. */
24194
- percentage: number().min(0).max(100),
24300
+ /**
24301
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
24302
+ * provider has registered the capability but no reading has landed.
24303
+ *
24304
+ * It is nullable because it was not, and the only value a provider could
24305
+ * seed with was `0`. A battery camera behind an NVR therefore announced
24306
+ * itself at 0% on every start and corrected itself a moment later, which is
24307
+ * indistinguishable from a real flat battery: it fires the low-battery alert
24308
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
24309
+ * reading the difference is an alarm.
24310
+ *
24311
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
24312
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
24313
+ * declines to band a non-finite reading, which is the correct shape.
24314
+ */
24315
+ percentage: number().min(0).max(100).nullable(),
24195
24316
  /**
24196
24317
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24197
24318
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -33960,6 +34081,12 @@ Object.freeze({
33960
34081
  addonId: null,
33961
34082
  access: "create"
33962
34083
  },
34084
+ "backup.cancel": {
34085
+ capName: "backup",
34086
+ capScope: "system",
34087
+ addonId: null,
34088
+ access: "create"
34089
+ },
33963
34090
  "backup.delete": {
33964
34091
  capName: "backup",
33965
34092
  capScope: "system",
@@ -34002,6 +34129,12 @@ Object.freeze({
34002
34129
  addonId: null,
34003
34130
  access: "view"
34004
34131
  },
34132
+ "backup.listRuns": {
34133
+ capName: "backup",
34134
+ capScope: "system",
34135
+ addonId: null,
34136
+ access: "view"
34137
+ },
34005
34138
  "backup.listSchedules": {
34006
34139
  capName: "backup",
34007
34140
  capScope: "system",
@@ -38568,6 +38701,12 @@ Object.freeze({
38568
38701
  addonId: null,
38569
38702
  access: "create"
38570
38703
  },
38704
+ "streamBroker.forgetDeviceHardware": {
38705
+ capName: "stream-broker",
38706
+ capScope: "system",
38707
+ addonId: null,
38708
+ access: "delete"
38709
+ },
38571
38710
  "streamBroker.getAllRtspEntries": {
38572
38711
  capName: "stream-broker",
38573
38712
  capScope: "system",
@@ -41026,6 +41165,11 @@ Object.freeze({
41026
41165
  form: "single",
41027
41166
  optional: false
41028
41167
  }],
41168
+ "streamBroker.forgetDeviceHardware": [{
41169
+ name: "deviceId",
41170
+ form: "single",
41171
+ optional: false
41172
+ }],
41029
41173
  "streamBroker.getDeviceAudioMute": [{
41030
41174
  name: "deviceId",
41031
41175
  form: "single",
package/dist/addon.mjs CHANGED
@@ -11346,6 +11346,89 @@ var LocationStatSchema = object({
11346
11346
  fileCount: number(),
11347
11347
  present: boolean()
11348
11348
  });
11349
+ /** Lifecycle of a backup run. Terminal states: succeeded / failed / cancelled. */
11350
+ var BackupRunStateSchema = _enum([
11351
+ "queued",
11352
+ "running",
11353
+ "succeeded",
11354
+ "failed",
11355
+ "cancelled"
11356
+ ]);
11357
+ /**
11358
+ * Where a running backup currently is. `queued` before it starts,
11359
+ * `building` while the tar.gz is being staged, `uploading` during the
11360
+ * per-destination fan-out, `done` once terminal.
11361
+ */
11362
+ var BackupRunPhaseSchema = _enum([
11363
+ "queued",
11364
+ "building",
11365
+ "uploading",
11366
+ "done"
11367
+ ]);
11368
+ /**
11369
+ * Observable state of one backup run — readable WHILE it runs via
11370
+ * `backup.listRuns`. This is what makes the execution queue and
11371
+ * `backup.cancel` usable: the 2026-09-04 incident (two concurrent
11372
+ * multi-GB builds, staging 5.1 GB → 18 GB, load 62) was only
11373
+ * diagnosable with `du` because nothing reported that runs existed or
11374
+ * how large the staged archive had grown.
11375
+ */
11376
+ var BackupRunSchema = object({
11377
+ /** Stable run id — the handle `backup.cancel` takes. */
11378
+ id: string(),
11379
+ state: BackupRunStateSchema,
11380
+ phase: BackupRunPhaseSchema,
11381
+ /**
11382
+ * Resolved destination location ids. Empty while queued (targets are
11383
+ * resolved when the run starts, against the then-current policies).
11384
+ */
11385
+ destinationIds: array(string()).readonly(),
11386
+ label: string().optional(),
11387
+ /** ms-epoch when the run was submitted (trigger call / schedule fire). */
11388
+ requestedAt: number(),
11389
+ /** ms-epoch when the run left the queue and started building. */
11390
+ startedAt: number().optional(),
11391
+ /** ms-epoch when the run reached a terminal state. */
11392
+ finishedAt: number().optional(),
11393
+ /** Compressed bytes of the staging archive written so far. */
11394
+ stagedBytes: number(),
11395
+ /** Final staged archive size, once the build phase completes. */
11396
+ archiveSizeBytes: number().optional(),
11397
+ /** Bytes pushed to the destination currently uploading. */
11398
+ uploadedBytes: number(),
11399
+ /** Destinations where the archive fully landed (uploaded + indexed). */
11400
+ completedDestinationIds: array(string()).readonly(),
11401
+ /** Destinations that failed during the fan-out. */
11402
+ failedDestinationIds: array(string()).readonly(),
11403
+ /** Failure message when `state === 'failed'`. */
11404
+ error: string().optional(),
11405
+ /**
11406
+ * 1-based place in the execution queue — 1 = runs next. Present only
11407
+ * while `state === 'queued'`. Stamped by the orchestrator from the
11408
+ * queue's OWN pending order, never derived from timestamps, so the
11409
+ * UI cannot show an order the executor will not honour.
11410
+ */
11411
+ queuePosition: number().int().min(1).optional()
11412
+ });
11413
+ /**
11414
+ * Result of `backup.trigger`. The call still resolves when the run
11415
+ * terminates (compat with schedule-driven runs and the admin UI), but
11416
+ * it now names the run and says whether it had to WAIT: a trigger that
11417
+ * arrives while another run is in flight is enqueued (or joined onto
11418
+ * an identical already-queued run), never started concurrently.
11419
+ */
11420
+ var BackupTriggerResultSchema = object({
11421
+ /** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
11422
+ runId: string(),
11423
+ /** True when the run waited behind an in-flight run instead of starting immediately. */
11424
+ queued: boolean(),
11425
+ /** True when this trigger was coalesced onto an identical already-queued run. */
11426
+ joined: boolean(),
11427
+ /** True when the run was cancelled before completing every destination. */
11428
+ cancelled: boolean(),
11429
+ /** One entry per destination the archive landed at (partial on cancel). */
11430
+ entries: array(BackupEntrySchema).readonly()
11431
+ });
11349
11432
  /**
11350
11433
  * A backup schedule — the N:M "entry" that binds one cron cadence to a
11351
11434
  * SET of destination locations. Supersedes the per-location cron on
@@ -11393,7 +11476,10 @@ method(_void(), array(BackupDestinationInfoSchema).readonly(), { auth: "admin" }
11393
11476
  * retention (manual runs).
11394
11477
  */
11395
11478
  retentionCount: number().int().min(1).max(1e3).optional()
11396
- }).optional(), array(BackupEntrySchema).readonly(), {
11479
+ }).optional(), BackupTriggerResultSchema, {
11480
+ kind: "mutation",
11481
+ auth: "admin"
11482
+ }), method(_void(), array(BackupRunSchema).readonly(), { auth: "admin" }), method(object({ runId: string() }), object({ cancelled: boolean() }), {
11397
11483
  kind: "mutation",
11398
11484
  auth: "admin"
11399
11485
  }), method(_void(), array(BackupEntrySchema).readonly(), { auth: "admin" }), method(_void(), array(LocationStatSchema).readonly(), { auth: "admin" }), method(object({
@@ -12110,6 +12196,14 @@ method(object({
12110
12196
  }), object({ success: literal(true) }), {
12111
12197
  kind: "mutation",
12112
12198
  auth: "admin"
12199
+ }), method(object({ deviceId: number().int().nonnegative() }), object({
12200
+ derivedStreamsDeleted: array(string()).readonly(),
12201
+ assignmentsPurged: boolean(),
12202
+ probeSnapshotsDropped: number().int().nonnegative(),
12203
+ rtspTokenRowsDeleted: number().int().nonnegative()
12204
+ }), {
12205
+ kind: "mutation",
12206
+ auth: "admin"
12113
12207
  }), method(object({
12114
12208
  deviceId: number(),
12115
12209
  /** Absent = the LOWEST assigned profile — a notification attachment is
@@ -20019,7 +20113,20 @@ var RecentTracksQueryInput = object({
20019
20113
  projection: TrackProjectionSchema.optional(),
20020
20114
  /** Include stationary-promoted rows (parked objects). Default false: the
20021
20115
  * feed lists passages; parking records live on the stationary registry. */
20022
- includeStationary: boolean().optional()
20116
+ includeStationary: boolean().optional(),
20117
+ /**
20118
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
20119
+ *
20120
+ * The same filter `listTracks` takes, because the timeline's class chips must
20121
+ * mean the same thing whether the scope is one camera or twelve. Until this
20122
+ * existed the scoped feed downloaded a page and narrowed it on the phone
20123
+ * while the single-camera path narrowed the read — one filter, two costs.
20124
+ *
20125
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
20126
+ * whose class list is unreadable are kept, and the client's rule stays the
20127
+ * exact one.
20128
+ */
20129
+ classes: array(string()).optional()
20023
20130
  });
20024
20131
  var RecentTracksPageSchema = object({
20025
20132
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -24189,8 +24296,22 @@ var automationControlCapability = {
24189
24296
  * threshold.
24190
24297
  */
24191
24298
  var BatteryStatusSchema = object({
24192
- /** 0..100 inclusive. Firmware-reported. */
24193
- percentage: number().min(0).max(100),
24299
+ /**
24300
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
24301
+ * provider has registered the capability but no reading has landed.
24302
+ *
24303
+ * It is nullable because it was not, and the only value a provider could
24304
+ * seed with was `0`. A battery camera behind an NVR therefore announced
24305
+ * itself at 0% on every start and corrected itself a moment later, which is
24306
+ * indistinguishable from a real flat battery: it fires the low-battery alert
24307
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
24308
+ * reading the difference is an alarm.
24309
+ *
24310
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
24311
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
24312
+ * declines to band a non-finite reading, which is the correct shape.
24313
+ */
24314
+ percentage: number().min(0).max(100).nullable(),
24194
24315
  /**
24195
24316
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24196
24317
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -33959,6 +34080,12 @@ Object.freeze({
33959
34080
  addonId: null,
33960
34081
  access: "create"
33961
34082
  },
34083
+ "backup.cancel": {
34084
+ capName: "backup",
34085
+ capScope: "system",
34086
+ addonId: null,
34087
+ access: "create"
34088
+ },
33962
34089
  "backup.delete": {
33963
34090
  capName: "backup",
33964
34091
  capScope: "system",
@@ -34001,6 +34128,12 @@ Object.freeze({
34001
34128
  addonId: null,
34002
34129
  access: "view"
34003
34130
  },
34131
+ "backup.listRuns": {
34132
+ capName: "backup",
34133
+ capScope: "system",
34134
+ addonId: null,
34135
+ access: "view"
34136
+ },
34004
34137
  "backup.listSchedules": {
34005
34138
  capName: "backup",
34006
34139
  capScope: "system",
@@ -38567,6 +38700,12 @@ Object.freeze({
38567
38700
  addonId: null,
38568
38701
  access: "create"
38569
38702
  },
38703
+ "streamBroker.forgetDeviceHardware": {
38704
+ capName: "stream-broker",
38705
+ capScope: "system",
38706
+ addonId: null,
38707
+ access: "delete"
38708
+ },
38570
38709
  "streamBroker.getAllRtspEntries": {
38571
38710
  capName: "stream-broker",
38572
38711
  capScope: "system",
@@ -41025,6 +41164,11 @@ Object.freeze({
41025
41164
  form: "single",
41026
41165
  optional: false
41027
41166
  }],
41167
+ "streamBroker.forgetDeviceHardware": [{
41168
+ name: "deviceId",
41169
+ form: "single",
41170
+ optional: false
41171
+ }],
41028
41172
  "streamBroker.getDeviceAudioMute": [{
41029
41173
  name: "deviceId",
41030
41174
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-tuya",
3
- "version": "0.2.57",
3
+ "version": "0.2.59",
4
4
  "description": "Tuya / Smart Life device-provider addon for CamStack — account-onboarded (Tuya IoT cloud fetch of device localKeys) + LOCAL DP control via the @apocaliss92/nodetuya encrypted-LAN client, exposing switch / water-heater-family kettle entities",
5
5
  "keywords": [
6
6
  "camstack",