@camstack/addon-provider-tuya 0.2.49 → 0.2.50

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 (3) hide show
  1. package/dist/addon.js +234 -73
  2. package/dist/addon.mjs +234 -73
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -8916,6 +8916,13 @@ var MediaRelocateModeSchema = _enum([
8916
8916
  ]);
8917
8917
  var RelocateMediaInputSchema = object({
8918
8918
  toLocationId: string(),
8919
+ /**
8920
+ * Restrict the pass to rows currently on this location. Omitted / `'*'` =
8921
+ * every row that is not already on `toLocationId` (the historical
8922
+ * behaviour). A named source is what a from→to migration needs: without it
8923
+ * "move events off disk 2" also emptied disk 1.
8924
+ */
8925
+ fromLocationId: string().optional(),
8919
8926
  throttleMbps: number().min(1).max(1e3).optional(),
8920
8927
  /** Omitted = `move`, the pre-existing behaviour. */
8921
8928
  mode: MediaRelocateModeSchema.optional()
@@ -8983,6 +8990,19 @@ var StorageMigrationDestinationsSchema = object({
8983
8990
  galleryMedia: string().min(1).optional()
8984
8991
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8985
8992
  /**
8993
+ * Optional named source per class. Omitted = the class's current default
8994
+ * (the historical behaviour). A named source that is NOT the default is a
8995
+ * drain of that disk: bytes move, the default stays, and the source is
8996
+ * disabled when the move finishes.
8997
+ */
8998
+ var StorageMigrationSourcesSchema = object({
8999
+ recordings: string().min(1).optional(),
9000
+ recordingsLow: string().min(1).optional(),
9001
+ eventMedia: string().min(1).optional(),
9002
+ backups: string().min(1).optional(),
9003
+ galleryMedia: string().min(1).optional()
9004
+ }).optional();
9005
+ /**
8986
9006
  * How a migration sequences the cutover against the byte move.
8987
9007
  *
8988
9008
  * - `blocking` — the historical order: pause, move every byte, repoint,
@@ -9004,6 +9024,8 @@ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
9004
9024
  /** Shared input for planning and starting an orchestrated storage migration. */
9005
9025
  var StorageMigrationInputSchema = object({
9006
9026
  destinations: StorageMigrationDestinationsSchema,
9027
+ /** Omitted = each class's current default. */
9028
+ sources: StorageMigrationSourcesSchema,
9007
9029
  throttleMbps: number().min(1).max(1e3).optional(),
9008
9030
  /** Omitted = `blocking`, which stays the default. */
9009
9031
  mode: StorageMigrationModeSchema.optional()
@@ -9083,6 +9105,13 @@ var StorageMigrationMoveSchema = object({
9083
9105
  storageClass: StorageMigrationClassSchema,
9084
9106
  fromLocationId: string(),
9085
9107
  toLocationId: string(),
9108
+ /**
9109
+ * True when `from` was NOT the class default at plan time. The move still
9110
+ * copies bytes, but the default is left alone and the source is disabled
9111
+ * once the copy verifies. Absent on jobs planned before this field existed
9112
+ * — those jobs always repointed, which is `false`.
9113
+ */
9114
+ freezeSource: boolean().optional(),
9086
9115
  moverJobId: string().nullable(),
9087
9116
  state: RelocateJobStateSchema.nullable(),
9088
9117
  error: string().nullable(),
@@ -9096,6 +9125,7 @@ var StorageMigrationJobSchema = object({
9096
9125
  * can tell a seconds-long cutover from a thirty-hour one. */
9097
9126
  mode: StorageMigrationModeSchema,
9098
9127
  destinations: StorageMigrationDestinationsSchema,
9128
+ sources: StorageMigrationSourcesSchema,
9099
9129
  throttleMbps: number(),
9100
9130
  moves: array(StorageMigrationMoveSchema),
9101
9131
  pauseLeaseId: string().nullable(),
@@ -9121,6 +9151,7 @@ var StorageMigrationFindingSchema = object({
9121
9151
  });
9122
9152
  var StorageMigrationPlanSchema = object({
9123
9153
  destinations: StorageMigrationDestinationsSchema,
9154
+ sources: StorageMigrationSourcesSchema,
9124
9155
  /** The mode this plan was built for. A plan is only valid for its mode: the
9125
9156
  * `eventMedia` seal gate and the single-cardinality refusal both depend on
9126
9157
  * it. */
@@ -9128,7 +9159,8 @@ var StorageMigrationPlanSchema = object({
9128
9159
  moves: array(object({
9129
9160
  storageClass: StorageMigrationClassSchema,
9130
9161
  fromLocationId: string(),
9131
- toLocationId: string()
9162
+ toLocationId: string(),
9163
+ freezeSource: boolean().optional()
9132
9164
  })),
9133
9165
  findings: array(StorageMigrationFindingSchema)
9134
9166
  });
@@ -9306,10 +9338,51 @@ var LedgerWalkReportSchema = object({
9306
9338
  var RelocatableMediaCountSchema = object({ rows: number().int().nonnegative() }).nullable();
9307
9339
  var RelocatableMediaCountInputSchema = object({
9308
9340
  toLocationId: string().min(1),
9341
+ /** Restrict the count to one source; omitted / `'*'` = every non-target row. */
9342
+ fromLocationId: string().optional(),
9309
9343
  /** Omitted = `move`. */
9310
9344
  mode: MediaRelocateModeSchema.optional()
9311
9345
  });
9312
9346
  /**
9347
+ * Operator cleanup of leftover analytics rows, optional debug media, and
9348
+ * ghost ledger entries on frozen footage locations.
9349
+ *
9350
+ * A pass is tens of minutes on a standing backlog. The hub method RETURNS
9351
+ * `{ jobId }` immediately; progress is `cleanupStatus`. Awaiting the work
9352
+ * is how `addons.custom` hit the 60 s UDS deadline while reclaim continued
9353
+ * with no operator-visible status.
9354
+ */
9355
+ var StorageCleanupPhaseSchema = _enum([
9356
+ "orphans",
9357
+ "debug-media",
9358
+ "ghost-ledger",
9359
+ "done",
9360
+ "failed",
9361
+ "cancelled"
9362
+ ]);
9363
+ var StorageCleanupInputSchema = object({
9364
+ /** Also walk motion stills / track filmstrips. Off by default. */
9365
+ includeDebugMedia: boolean().optional() });
9366
+ var StorageCleanupJobSchema = object({
9367
+ jobId: string(),
9368
+ phase: StorageCleanupPhaseSchema,
9369
+ includeDebugMedia: boolean(),
9370
+ orphansReclaimed: number().int().nonnegative(),
9371
+ orphanBytesReclaimed: number().int().nonnegative(),
9372
+ debugMediaReclaimed: number().int().nonnegative(),
9373
+ debugMediaBytesReclaimed: number().int().nonnegative(),
9374
+ ghostsForgotten: number().int().nonnegative(),
9375
+ ghostBytesForgotten: number().int().nonnegative(),
9376
+ /** Short operator-facing line: current collection, pass, or location. */
9377
+ detail: string().nullable(),
9378
+ cancelRequested: boolean(),
9379
+ startedAt: number(),
9380
+ updatedAt: number(),
9381
+ finishedAt: number().nullable(),
9382
+ error: string().nullable()
9383
+ });
9384
+ var StorageCleanupStatusInputSchema = object({ jobId: string().optional() });
9385
+ /**
9313
9386
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
9314
9387
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
9315
9388
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -9337,11 +9410,10 @@ var StorageLocationTypeSchema = string().regex(/^[a-z][a-zA-Z0-9-]*$/);
9337
9410
  * The default location for a type uses `id === <type>:default` by
9338
9411
  * convention (the bare type ref like `'backups'` resolves to it).
9339
9412
  *
9340
- * `isSystem: true` marks a location as orchestrator-seeded and
9341
- * undeletable. The bootstrap-installed defaults (one per type) carry
9342
- * this flag; operator-added locations don't. Editing the config of
9343
- * a system location is allowed (path migration, provider swap) but
9344
- * deleting it is rejected at the cap level.
9413
+ * `isSystem` is a legacy persisted flag. Seed still creates the initial
9414
+ * `<type>:default` locations; the flag is no longer a lock, a badge, or a
9415
+ * prune selector. New writes leave it false. Deletion is gated on uniqueness
9416
+ * / last-enabled, not on this bit.
9345
9417
  */
9346
9418
  var StorageLocationSchema = object({
9347
9419
  id: string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
@@ -13884,6 +13956,12 @@ method(object({
13884
13956
  }), _void(), {
13885
13957
  kind: "mutation",
13886
13958
  auth: "admin"
13959
+ }), method(object({
13960
+ from: string(),
13961
+ to: string()
13962
+ }), object({ moved: number() }), {
13963
+ kind: "mutation",
13964
+ auth: "admin"
13887
13965
  }), method(object({
13888
13966
  deviceId: number(),
13889
13967
  disabled: boolean()
@@ -19892,46 +19970,6 @@ var RecentTracksPageSchema = object({
19892
19970
  /** Cursor for the next page, or null when this page is the last. */
19893
19971
  nextCursor: string().nullable()
19894
19972
  });
19895
- var LIST_GROUPS_DEFAULT_LIMIT = 40;
19896
- var LIST_GROUPS_MAX_LIMIT = 100;
19897
- var AnalyticsGroupRecordSchema = object({
19898
- id: string(),
19899
- deviceId: number().int(),
19900
- openedAt: number().int(),
19901
- closedAt: number().int(),
19902
- timestamp: number().int(),
19903
- memberCount: number().int(),
19904
- memberTrackIds: array(string()).readonly(),
19905
- className: string(),
19906
- classes: array(string()).readonly(),
19907
- /** Relative event-media path, or null when the group has no picture yet. */
19908
- mediaUrl: string().nullable(),
19909
- singleton: boolean()
19910
- });
19911
- var AnalyticsGroupMemberSchema = object({
19912
- trackId: string(),
19913
- deviceId: number().int(),
19914
- className: string(),
19915
- firstSeen: number().int(),
19916
- lastSeen: number().int(),
19917
- mediaUrl: string().nullable()
19918
- });
19919
- var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
19920
- var ListGroupsQueryInput = object({
19921
- /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
19922
- deviceIds: array(number()),
19923
- /** Window lower bound on `closedAt` (inclusive). */
19924
- since: number().optional(),
19925
- /** Window upper bound on `openedAt` (inclusive). */
19926
- until: number().optional(),
19927
- limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
19928
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
19929
- cursor: string().optional()
19930
- });
19931
- var ListGroupsPageSchema = object({
19932
- groups: array(AnalyticsGroupRecordSchema).readonly(),
19933
- nextCursor: string().nullable()
19934
- });
19935
19973
  var KEY_EVENTS_DEFAULT_LIMIT = 50;
19936
19974
  var KEY_EVENTS_MAX_LIMIT = 200;
19937
19975
  var KeyEventQueryInput = object({
@@ -20035,9 +20073,7 @@ var TrackCascadeCountsSchema = object({
20035
20073
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
20036
20074
  plates: number().int(),
20037
20075
  /** Per-track CLIP search vectors removed (best-effort). */
20038
- embeddings: number().int(),
20039
- /** Group membership + group rows removed with their last member (best-effort). */
20040
- groups: number().int()
20076
+ embeddings: number().int()
20041
20077
  });
20042
20078
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
20043
20079
  var DiskReconcileCountsSchema = object({
@@ -20207,6 +20243,47 @@ var RebuildStatusSchema = object({
20207
20243
  /** Present when the pass ended by throwing. */
20208
20244
  error: string().nullable()
20209
20245
  });
20246
+ /**
20247
+ * Acknowledgement that a debug-media reclaim STARTED.
20248
+ *
20249
+ * The pass is paced at ~2 MB/s over a standing 100 GB — tens of minutes — so
20250
+ * it runs detached and this returns immediately. Awaiting it is how the
20251
+ * `addons.custom` door hit the 60 s UDS deadline while the walk carried on
20252
+ * with no status. Poll {@link pipelineAnalyticsCapability.methods.getMediaReclaimStatus}.
20253
+ */
20254
+ var MediaReclaimStartResultSchema = object({
20255
+ started: boolean(),
20256
+ /** True when a pass was already running; the new request is ignored. */
20257
+ alreadyRunning: boolean()
20258
+ });
20259
+ var MediaReclaimInputSchema = object({
20260
+ mode: _enum(["report", "reclaim"]).default("report"),
20261
+ scopes: array(_enum(["motion-still", "track-filmstrip"])).min(1).optional(),
20262
+ deviceIds: array(number().int()).min(1).optional(),
20263
+ restart: boolean().optional(),
20264
+ pageSize: number().int().min(50).max(5e3).optional(),
20265
+ maxRowsPerDevice: number().int().min(1).max(5e5).optional(),
20266
+ maxReclaimPerDevice: number().int().min(1).max(5e5).optional(),
20267
+ maxBytesPerRun: number().int().min(1).optional(),
20268
+ budgetMinutes: number().int().min(1).max(720).optional(),
20269
+ throttleBytesPerSec: number().int().min(64 * 1024).optional(),
20270
+ graceMinutes: number().int().min(1).max(10080).optional()
20271
+ });
20272
+ var MediaReclaimStatusSchema = object({
20273
+ running: boolean(),
20274
+ mode: _enum(["report", "reclaim"]).nullable(),
20275
+ totalExamined: number(),
20276
+ totalEligible: number(),
20277
+ totalReclaimed: number(),
20278
+ totalBytesReclaimed: number(),
20279
+ totalRefused: number(),
20280
+ /** Device+scope windows finished in this pass. */
20281
+ devicesDone: number(),
20282
+ complete: boolean().nullable(),
20283
+ startedAtMs: number().nullable(),
20284
+ finishedAtMs: number().nullable(),
20285
+ error: string().nullable()
20286
+ });
20210
20287
  var ReplayFrameInputSchema = object({
20211
20288
  timestamp: number(),
20212
20289
  frame: PipelineRunResultBridge
@@ -20245,10 +20322,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20245
20322
  * stationary registry). Default false: the timeline lists passages,
20246
20323
  * not parking records (operator decision, 2026-08-15). */
20247
20324
  includeStationary: boolean().optional()
20248
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
20249
- deviceId: number(),
20250
- groupId: string().min(1)
20251
- }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20325
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
20252
20326
  kind: "mutation",
20253
20327
  auth: "admin"
20254
20328
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -20348,6 +20422,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20348
20422
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
20349
20423
  kind: "query",
20350
20424
  auth: "admin"
20425
+ }), method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
20426
+ kind: "mutation",
20427
+ auth: "admin"
20428
+ }), method(object({}), MediaReclaimStatusSchema, {
20429
+ kind: "query",
20430
+ auth: "admin"
20351
20431
  }), method(object({ deviceIds: array(number()).optional() }), TrainingExportSummarySchema, {
20352
20432
  kind: "query",
20353
20433
  auth: "admin"
@@ -22318,7 +22398,13 @@ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin"
22318
22398
  }), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({}), array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }), method(StorageMigrationDrainInputSchema, object({ jobId: string() }), {
22319
22399
  kind: "mutation",
22320
22400
  auth: "admin"
22321
- });
22401
+ }), method(StorageCleanupInputSchema, object({ jobId: string() }), {
22402
+ kind: "mutation",
22403
+ auth: "admin"
22404
+ }), method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
22405
+ kind: "mutation",
22406
+ auth: "admin"
22407
+ }), method(object({}), array(StorageMigrationJobSchema).readonly(), { auth: "admin" });
22322
22408
  var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
22323
22409
  providerId: string().min(1),
22324
22410
  displayName: string().min(1),
@@ -29419,6 +29505,33 @@ var RecordingRebalanceInputSchema = object({
29419
29505
  minMoveGb: number().min(0).optional()
29420
29506
  });
29421
29507
  /**
29508
+ * Operator-facing placement of one camera onto a recordings location.
29509
+ *
29510
+ * `pinLocationId` is the operator instruction: a location id, or `null` for
29511
+ * Auto (the planner may move this camera). `locationId` is where high/mid
29512
+ * currently write — the plan, which may disagree with the pin when Auto.
29513
+ */
29514
+ var RecordingDevicePlacementSchema = object({
29515
+ deviceId: number().int(),
29516
+ profile: string(),
29517
+ locationId: string()
29518
+ });
29519
+ var RecordingDevicePinSchema = object({
29520
+ deviceId: number().int(),
29521
+ /** Recordings-class location this camera is pinned to. */
29522
+ locationId: string()
29523
+ });
29524
+ var RecordingPlacementViewSchema = object({
29525
+ assignments: array(RecordingDevicePlacementSchema),
29526
+ pins: array(RecordingDevicePinSchema),
29527
+ defaultLocations: record(string(), string())
29528
+ });
29529
+ var RecordingSetDevicePlacementInputSchema = object({
29530
+ deviceId: number().int(),
29531
+ /** `null` = Auto. Otherwise a `recordings:*` location id. */
29532
+ locationId: string().nullable()
29533
+ });
29534
+ /**
29422
29535
  * Result of locating footage at a wall-clock instant for one device/profile.
29423
29536
  * `segment` carries the covering segment's window; `gap` reports the forward
29424
29537
  * nearest covered edge (`null` past the end of footage / when none exists)
@@ -29644,6 +29757,12 @@ method(object({
29644
29757
  }), method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
29645
29758
  kind: "mutation",
29646
29759
  auth: "admin"
29760
+ }), method(object({}), RecordingPlacementViewSchema, {
29761
+ kind: "query",
29762
+ auth: "admin"
29763
+ }), method(RecordingSetDevicePlacementInputSchema, object({ ok: literal(true) }), {
29764
+ kind: "mutation",
29765
+ auth: "admin"
29647
29766
  });
29648
29767
  /**
29649
29768
  * `recording-export` cap — render a footage time range into a single downloadable
@@ -34713,6 +34832,12 @@ Object.freeze({
34713
34832
  addonId: null,
34714
34833
  access: "delete"
34715
34834
  },
34835
+ "deviceManager.renameLocation": {
34836
+ capName: "device-manager",
34837
+ capScope: "system",
34838
+ addonId: null,
34839
+ access: "create"
34840
+ },
34716
34841
  "deviceManager.runDeviceAction": {
34717
34842
  capName: "device-manager",
34718
34843
  capScope: "system",
@@ -36405,19 +36530,19 @@ Object.freeze({
36405
36530
  addonId: null,
36406
36531
  access: "view"
36407
36532
  },
36408
- "pipelineAnalytics.getGroup": {
36533
+ "pipelineAnalytics.getKeyEvents": {
36409
36534
  capName: "pipeline-analytics",
36410
36535
  capScope: "device",
36411
36536
  addonId: null,
36412
36537
  access: "view"
36413
36538
  },
36414
- "pipelineAnalytics.getKeyEvents": {
36539
+ "pipelineAnalytics.getKeyEventsBatch": {
36415
36540
  capName: "pipeline-analytics",
36416
36541
  capScope: "device",
36417
36542
  addonId: null,
36418
36543
  access: "view"
36419
36544
  },
36420
- "pipelineAnalytics.getKeyEventsBatch": {
36545
+ "pipelineAnalytics.getMediaReclaimStatus": {
36421
36546
  capName: "pipeline-analytics",
36422
36547
  capScope: "device",
36423
36548
  addonId: null,
@@ -36507,12 +36632,6 @@ Object.freeze({
36507
36632
  addonId: null,
36508
36633
  access: "view"
36509
36634
  },
36510
- "pipelineAnalytics.listGroups": {
36511
- capName: "pipeline-analytics",
36512
- capScope: "device",
36513
- addonId: null,
36514
- access: "view"
36515
- },
36516
36635
  "pipelineAnalytics.listOpsLog": {
36517
36636
  capName: "pipeline-analytics",
36518
36637
  capScope: "device",
@@ -36597,6 +36716,12 @@ Object.freeze({
36597
36716
  addonId: null,
36598
36717
  access: "create"
36599
36718
  },
36719
+ "pipelineAnalytics.reclaimDebugMedia": {
36720
+ capName: "pipeline-analytics",
36721
+ capScope: "device",
36722
+ addonId: null,
36723
+ access: "create"
36724
+ },
36600
36725
  "pipelineAnalytics.reconcileFromDisk": {
36601
36726
  capName: "pipeline-analytics",
36602
36727
  capScope: "device",
@@ -37521,6 +37646,12 @@ Object.freeze({
37521
37646
  addonId: null,
37522
37647
  access: "view"
37523
37648
  },
37649
+ "recording.getPlacement": {
37650
+ capName: "recording",
37651
+ capScope: "system",
37652
+ addonId: null,
37653
+ access: "view"
37654
+ },
37524
37655
  "recording.getPlaybackManifest": {
37525
37656
  capName: "recording",
37526
37657
  capScope: "system",
@@ -37647,6 +37778,12 @@ Object.freeze({
37647
37778
  addonId: null,
37648
37779
  access: "create"
37649
37780
  },
37781
+ "recording.setDevicePlacement": {
37782
+ capName: "recording",
37783
+ capScope: "system",
37784
+ addonId: null,
37785
+ access: "create"
37786
+ },
37650
37787
  "recording.startStorageMigrationMove": {
37651
37788
  capName: "recording",
37652
37789
  capScope: "system",
@@ -38091,12 +38228,36 @@ Object.freeze({
38091
38228
  addonId: null,
38092
38229
  access: "create"
38093
38230
  },
38231
+ "storageMigration.cleanupCancel": {
38232
+ capName: "storage-migration",
38233
+ capScope: "system",
38234
+ addonId: null,
38235
+ access: "create"
38236
+ },
38237
+ "storageMigration.cleanupStart": {
38238
+ capName: "storage-migration",
38239
+ capScope: "system",
38240
+ addonId: null,
38241
+ access: "create"
38242
+ },
38243
+ "storageMigration.cleanupStatus": {
38244
+ capName: "storage-migration",
38245
+ capScope: "system",
38246
+ addonId: null,
38247
+ access: "view"
38248
+ },
38094
38249
  "storageMigration.drain": {
38095
38250
  capName: "storage-migration",
38096
38251
  capScope: "system",
38097
38252
  addonId: null,
38098
38253
  access: "create"
38099
38254
  },
38255
+ "storageMigration.history": {
38256
+ capName: "storage-migration",
38257
+ capScope: "system",
38258
+ addonId: null,
38259
+ access: "view"
38260
+ },
38100
38261
  "storageMigration.movers": {
38101
38262
  capName: "storage-migration",
38102
38263
  capScope: "system",
@@ -40093,11 +40254,6 @@ Object.freeze({
40093
40254
  form: "single",
40094
40255
  optional: true
40095
40256
  }],
40096
- "pipelineAnalytics.getGroup": [{
40097
- name: "deviceId",
40098
- form: "single",
40099
- optional: false
40100
- }],
40101
40257
  "pipelineAnalytics.getKeyEvents": [{
40102
40258
  name: "deviceId",
40103
40259
  form: "single",
@@ -40163,11 +40319,6 @@ Object.freeze({
40163
40319
  form: "single",
40164
40320
  optional: false
40165
40321
  }],
40166
- "pipelineAnalytics.listGroups": [{
40167
- name: "deviceIds",
40168
- form: "array",
40169
- optional: false
40170
- }],
40171
40322
  "pipelineAnalytics.listOpsLog": [{
40172
40323
  name: "deviceId",
40173
40324
  form: "single",
@@ -40213,6 +40364,11 @@ Object.freeze({
40213
40364
  form: "single",
40214
40365
  optional: true
40215
40366
  }],
40367
+ "pipelineAnalytics.reclaimDebugMedia": [{
40368
+ name: "deviceIds",
40369
+ form: "array",
40370
+ optional: true
40371
+ }],
40216
40372
  "pipelineAnalytics.reconcileFromDisk": [{
40217
40373
  name: "deviceId",
40218
40374
  form: "single",
@@ -40578,6 +40734,11 @@ Object.freeze({
40578
40734
  form: "single",
40579
40735
  optional: false
40580
40736
  }],
40737
+ "recording.setDevicePlacement": [{
40738
+ name: "deviceId",
40739
+ form: "single",
40740
+ optional: false
40741
+ }],
40581
40742
  "recording.startStorageMigrationMove": [{
40582
40743
  name: "deviceId",
40583
40744
  form: "single",
package/dist/addon.mjs CHANGED
@@ -8915,6 +8915,13 @@ var MediaRelocateModeSchema = _enum([
8915
8915
  ]);
8916
8916
  var RelocateMediaInputSchema = object({
8917
8917
  toLocationId: string(),
8918
+ /**
8919
+ * Restrict the pass to rows currently on this location. Omitted / `'*'` =
8920
+ * every row that is not already on `toLocationId` (the historical
8921
+ * behaviour). A named source is what a from→to migration needs: without it
8922
+ * "move events off disk 2" also emptied disk 1.
8923
+ */
8924
+ fromLocationId: string().optional(),
8918
8925
  throttleMbps: number().min(1).max(1e3).optional(),
8919
8926
  /** Omitted = `move`, the pre-existing behaviour. */
8920
8927
  mode: MediaRelocateModeSchema.optional()
@@ -8982,6 +8989,19 @@ var StorageMigrationDestinationsSchema = object({
8982
8989
  galleryMedia: string().min(1).optional()
8983
8990
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8984
8991
  /**
8992
+ * Optional named source per class. Omitted = the class's current default
8993
+ * (the historical behaviour). A named source that is NOT the default is a
8994
+ * drain of that disk: bytes move, the default stays, and the source is
8995
+ * disabled when the move finishes.
8996
+ */
8997
+ var StorageMigrationSourcesSchema = object({
8998
+ recordings: string().min(1).optional(),
8999
+ recordingsLow: string().min(1).optional(),
9000
+ eventMedia: string().min(1).optional(),
9001
+ backups: string().min(1).optional(),
9002
+ galleryMedia: string().min(1).optional()
9003
+ }).optional();
9004
+ /**
8985
9005
  * How a migration sequences the cutover against the byte move.
8986
9006
  *
8987
9007
  * - `blocking` — the historical order: pause, move every byte, repoint,
@@ -9003,6 +9023,8 @@ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
9003
9023
  /** Shared input for planning and starting an orchestrated storage migration. */
9004
9024
  var StorageMigrationInputSchema = object({
9005
9025
  destinations: StorageMigrationDestinationsSchema,
9026
+ /** Omitted = each class's current default. */
9027
+ sources: StorageMigrationSourcesSchema,
9006
9028
  throttleMbps: number().min(1).max(1e3).optional(),
9007
9029
  /** Omitted = `blocking`, which stays the default. */
9008
9030
  mode: StorageMigrationModeSchema.optional()
@@ -9082,6 +9104,13 @@ var StorageMigrationMoveSchema = object({
9082
9104
  storageClass: StorageMigrationClassSchema,
9083
9105
  fromLocationId: string(),
9084
9106
  toLocationId: string(),
9107
+ /**
9108
+ * True when `from` was NOT the class default at plan time. The move still
9109
+ * copies bytes, but the default is left alone and the source is disabled
9110
+ * once the copy verifies. Absent on jobs planned before this field existed
9111
+ * — those jobs always repointed, which is `false`.
9112
+ */
9113
+ freezeSource: boolean().optional(),
9085
9114
  moverJobId: string().nullable(),
9086
9115
  state: RelocateJobStateSchema.nullable(),
9087
9116
  error: string().nullable(),
@@ -9095,6 +9124,7 @@ var StorageMigrationJobSchema = object({
9095
9124
  * can tell a seconds-long cutover from a thirty-hour one. */
9096
9125
  mode: StorageMigrationModeSchema,
9097
9126
  destinations: StorageMigrationDestinationsSchema,
9127
+ sources: StorageMigrationSourcesSchema,
9098
9128
  throttleMbps: number(),
9099
9129
  moves: array(StorageMigrationMoveSchema),
9100
9130
  pauseLeaseId: string().nullable(),
@@ -9120,6 +9150,7 @@ var StorageMigrationFindingSchema = object({
9120
9150
  });
9121
9151
  var StorageMigrationPlanSchema = object({
9122
9152
  destinations: StorageMigrationDestinationsSchema,
9153
+ sources: StorageMigrationSourcesSchema,
9123
9154
  /** The mode this plan was built for. A plan is only valid for its mode: the
9124
9155
  * `eventMedia` seal gate and the single-cardinality refusal both depend on
9125
9156
  * it. */
@@ -9127,7 +9158,8 @@ var StorageMigrationPlanSchema = object({
9127
9158
  moves: array(object({
9128
9159
  storageClass: StorageMigrationClassSchema,
9129
9160
  fromLocationId: string(),
9130
- toLocationId: string()
9161
+ toLocationId: string(),
9162
+ freezeSource: boolean().optional()
9131
9163
  })),
9132
9164
  findings: array(StorageMigrationFindingSchema)
9133
9165
  });
@@ -9305,10 +9337,51 @@ var LedgerWalkReportSchema = object({
9305
9337
  var RelocatableMediaCountSchema = object({ rows: number().int().nonnegative() }).nullable();
9306
9338
  var RelocatableMediaCountInputSchema = object({
9307
9339
  toLocationId: string().min(1),
9340
+ /** Restrict the count to one source; omitted / `'*'` = every non-target row. */
9341
+ fromLocationId: string().optional(),
9308
9342
  /** Omitted = `move`. */
9309
9343
  mode: MediaRelocateModeSchema.optional()
9310
9344
  });
9311
9345
  /**
9346
+ * Operator cleanup of leftover analytics rows, optional debug media, and
9347
+ * ghost ledger entries on frozen footage locations.
9348
+ *
9349
+ * A pass is tens of minutes on a standing backlog. The hub method RETURNS
9350
+ * `{ jobId }` immediately; progress is `cleanupStatus`. Awaiting the work
9351
+ * is how `addons.custom` hit the 60 s UDS deadline while reclaim continued
9352
+ * with no operator-visible status.
9353
+ */
9354
+ var StorageCleanupPhaseSchema = _enum([
9355
+ "orphans",
9356
+ "debug-media",
9357
+ "ghost-ledger",
9358
+ "done",
9359
+ "failed",
9360
+ "cancelled"
9361
+ ]);
9362
+ var StorageCleanupInputSchema = object({
9363
+ /** Also walk motion stills / track filmstrips. Off by default. */
9364
+ includeDebugMedia: boolean().optional() });
9365
+ var StorageCleanupJobSchema = object({
9366
+ jobId: string(),
9367
+ phase: StorageCleanupPhaseSchema,
9368
+ includeDebugMedia: boolean(),
9369
+ orphansReclaimed: number().int().nonnegative(),
9370
+ orphanBytesReclaimed: number().int().nonnegative(),
9371
+ debugMediaReclaimed: number().int().nonnegative(),
9372
+ debugMediaBytesReclaimed: number().int().nonnegative(),
9373
+ ghostsForgotten: number().int().nonnegative(),
9374
+ ghostBytesForgotten: number().int().nonnegative(),
9375
+ /** Short operator-facing line: current collection, pass, or location. */
9376
+ detail: string().nullable(),
9377
+ cancelRequested: boolean(),
9378
+ startedAt: number(),
9379
+ updatedAt: number(),
9380
+ finishedAt: number().nullable(),
9381
+ error: string().nullable()
9382
+ });
9383
+ var StorageCleanupStatusInputSchema = object({ jobId: string().optional() });
9384
+ /**
9312
9385
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
9313
9386
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
9314
9387
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -9336,11 +9409,10 @@ var StorageLocationTypeSchema = string().regex(/^[a-z][a-zA-Z0-9-]*$/);
9336
9409
  * The default location for a type uses `id === <type>:default` by
9337
9410
  * convention (the bare type ref like `'backups'` resolves to it).
9338
9411
  *
9339
- * `isSystem: true` marks a location as orchestrator-seeded and
9340
- * undeletable. The bootstrap-installed defaults (one per type) carry
9341
- * this flag; operator-added locations don't. Editing the config of
9342
- * a system location is allowed (path migration, provider swap) but
9343
- * deleting it is rejected at the cap level.
9412
+ * `isSystem` is a legacy persisted flag. Seed still creates the initial
9413
+ * `<type>:default` locations; the flag is no longer a lock, a badge, or a
9414
+ * prune selector. New writes leave it false. Deletion is gated on uniqueness
9415
+ * / last-enabled, not on this bit.
9344
9416
  */
9345
9417
  var StorageLocationSchema = object({
9346
9418
  id: string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
@@ -13883,6 +13955,12 @@ method(object({
13883
13955
  }), _void(), {
13884
13956
  kind: "mutation",
13885
13957
  auth: "admin"
13958
+ }), method(object({
13959
+ from: string(),
13960
+ to: string()
13961
+ }), object({ moved: number() }), {
13962
+ kind: "mutation",
13963
+ auth: "admin"
13886
13964
  }), method(object({
13887
13965
  deviceId: number(),
13888
13966
  disabled: boolean()
@@ -19891,46 +19969,6 @@ var RecentTracksPageSchema = object({
19891
19969
  /** Cursor for the next page, or null when this page is the last. */
19892
19970
  nextCursor: string().nullable()
19893
19971
  });
19894
- var LIST_GROUPS_DEFAULT_LIMIT = 40;
19895
- var LIST_GROUPS_MAX_LIMIT = 100;
19896
- var AnalyticsGroupRecordSchema = object({
19897
- id: string(),
19898
- deviceId: number().int(),
19899
- openedAt: number().int(),
19900
- closedAt: number().int(),
19901
- timestamp: number().int(),
19902
- memberCount: number().int(),
19903
- memberTrackIds: array(string()).readonly(),
19904
- className: string(),
19905
- classes: array(string()).readonly(),
19906
- /** Relative event-media path, or null when the group has no picture yet. */
19907
- mediaUrl: string().nullable(),
19908
- singleton: boolean()
19909
- });
19910
- var AnalyticsGroupMemberSchema = object({
19911
- trackId: string(),
19912
- deviceId: number().int(),
19913
- className: string(),
19914
- firstSeen: number().int(),
19915
- lastSeen: number().int(),
19916
- mediaUrl: string().nullable()
19917
- });
19918
- var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: array(AnalyticsGroupMemberSchema).readonly() });
19919
- var ListGroupsQueryInput = object({
19920
- /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
19921
- deviceIds: array(number()),
19922
- /** Window lower bound on `closedAt` (inclusive). */
19923
- since: number().optional(),
19924
- /** Window upper bound on `openedAt` (inclusive). */
19925
- until: number().optional(),
19926
- limit: number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
19927
- /** Opaque continuation cursor from a previous page's `nextCursor`. */
19928
- cursor: string().optional()
19929
- });
19930
- var ListGroupsPageSchema = object({
19931
- groups: array(AnalyticsGroupRecordSchema).readonly(),
19932
- nextCursor: string().nullable()
19933
- });
19934
19972
  var KEY_EVENTS_DEFAULT_LIMIT = 50;
19935
19973
  var KEY_EVENTS_MAX_LIMIT = 200;
19936
19974
  var KeyEventQueryInput = object({
@@ -20034,9 +20072,7 @@ var TrackCascadeCountsSchema = object({
20034
20072
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
20035
20073
  plates: number().int(),
20036
20074
  /** Per-track CLIP search vectors removed (best-effort). */
20037
- embeddings: number().int(),
20038
- /** Group membership + group rows removed with their last member (best-effort). */
20039
- groups: number().int()
20075
+ embeddings: number().int()
20040
20076
  });
20041
20077
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
20042
20078
  var DiskReconcileCountsSchema = object({
@@ -20206,6 +20242,47 @@ var RebuildStatusSchema = object({
20206
20242
  /** Present when the pass ended by throwing. */
20207
20243
  error: string().nullable()
20208
20244
  });
20245
+ /**
20246
+ * Acknowledgement that a debug-media reclaim STARTED.
20247
+ *
20248
+ * The pass is paced at ~2 MB/s over a standing 100 GB — tens of minutes — so
20249
+ * it runs detached and this returns immediately. Awaiting it is how the
20250
+ * `addons.custom` door hit the 60 s UDS deadline while the walk carried on
20251
+ * with no status. Poll {@link pipelineAnalyticsCapability.methods.getMediaReclaimStatus}.
20252
+ */
20253
+ var MediaReclaimStartResultSchema = object({
20254
+ started: boolean(),
20255
+ /** True when a pass was already running; the new request is ignored. */
20256
+ alreadyRunning: boolean()
20257
+ });
20258
+ var MediaReclaimInputSchema = object({
20259
+ mode: _enum(["report", "reclaim"]).default("report"),
20260
+ scopes: array(_enum(["motion-still", "track-filmstrip"])).min(1).optional(),
20261
+ deviceIds: array(number().int()).min(1).optional(),
20262
+ restart: boolean().optional(),
20263
+ pageSize: number().int().min(50).max(5e3).optional(),
20264
+ maxRowsPerDevice: number().int().min(1).max(5e5).optional(),
20265
+ maxReclaimPerDevice: number().int().min(1).max(5e5).optional(),
20266
+ maxBytesPerRun: number().int().min(1).optional(),
20267
+ budgetMinutes: number().int().min(1).max(720).optional(),
20268
+ throttleBytesPerSec: number().int().min(64 * 1024).optional(),
20269
+ graceMinutes: number().int().min(1).max(10080).optional()
20270
+ });
20271
+ var MediaReclaimStatusSchema = object({
20272
+ running: boolean(),
20273
+ mode: _enum(["report", "reclaim"]).nullable(),
20274
+ totalExamined: number(),
20275
+ totalEligible: number(),
20276
+ totalReclaimed: number(),
20277
+ totalBytesReclaimed: number(),
20278
+ totalRefused: number(),
20279
+ /** Device+scope windows finished in this pass. */
20280
+ devicesDone: number(),
20281
+ complete: boolean().nullable(),
20282
+ startedAtMs: number().nullable(),
20283
+ finishedAtMs: number().nullable(),
20284
+ error: string().nullable()
20285
+ });
20209
20286
  var ReplayFrameInputSchema = object({
20210
20287
  timestamp: number(),
20211
20288
  frame: PipelineRunResultBridge
@@ -20244,10 +20321,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20244
20321
  * stationary registry). Default false: the timeline lists passages,
20245
20322
  * not parking records (operator decision, 2026-08-15). */
20246
20323
  includeStationary: boolean().optional()
20247
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(ListGroupsQueryInput, ListGroupsPageSchema), method(object({
20248
- deviceId: number(),
20249
- groupId: string().min(1)
20250
- }), AnalyticsGroupDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20324
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
20251
20325
  kind: "mutation",
20252
20326
  auth: "admin"
20253
20327
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -20347,6 +20421,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20347
20421
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
20348
20422
  kind: "query",
20349
20423
  auth: "admin"
20424
+ }), method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
20425
+ kind: "mutation",
20426
+ auth: "admin"
20427
+ }), method(object({}), MediaReclaimStatusSchema, {
20428
+ kind: "query",
20429
+ auth: "admin"
20350
20430
  }), method(object({ deviceIds: array(number()).optional() }), TrainingExportSummarySchema, {
20351
20431
  kind: "query",
20352
20432
  auth: "admin"
@@ -22317,7 +22397,13 @@ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin"
22317
22397
  }), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({}), array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }), method(StorageMigrationDrainInputSchema, object({ jobId: string() }), {
22318
22398
  kind: "mutation",
22319
22399
  auth: "admin"
22320
- });
22400
+ }), method(StorageCleanupInputSchema, object({ jobId: string() }), {
22401
+ kind: "mutation",
22402
+ auth: "admin"
22403
+ }), method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
22404
+ kind: "mutation",
22405
+ auth: "admin"
22406
+ }), method(object({}), array(StorageMigrationJobSchema).readonly(), { auth: "admin" });
22321
22407
  var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
22322
22408
  providerId: string().min(1),
22323
22409
  displayName: string().min(1),
@@ -29418,6 +29504,33 @@ var RecordingRebalanceInputSchema = object({
29418
29504
  minMoveGb: number().min(0).optional()
29419
29505
  });
29420
29506
  /**
29507
+ * Operator-facing placement of one camera onto a recordings location.
29508
+ *
29509
+ * `pinLocationId` is the operator instruction: a location id, or `null` for
29510
+ * Auto (the planner may move this camera). `locationId` is where high/mid
29511
+ * currently write — the plan, which may disagree with the pin when Auto.
29512
+ */
29513
+ var RecordingDevicePlacementSchema = object({
29514
+ deviceId: number().int(),
29515
+ profile: string(),
29516
+ locationId: string()
29517
+ });
29518
+ var RecordingDevicePinSchema = object({
29519
+ deviceId: number().int(),
29520
+ /** Recordings-class location this camera is pinned to. */
29521
+ locationId: string()
29522
+ });
29523
+ var RecordingPlacementViewSchema = object({
29524
+ assignments: array(RecordingDevicePlacementSchema),
29525
+ pins: array(RecordingDevicePinSchema),
29526
+ defaultLocations: record(string(), string())
29527
+ });
29528
+ var RecordingSetDevicePlacementInputSchema = object({
29529
+ deviceId: number().int(),
29530
+ /** `null` = Auto. Otherwise a `recordings:*` location id. */
29531
+ locationId: string().nullable()
29532
+ });
29533
+ /**
29421
29534
  * Result of locating footage at a wall-clock instant for one device/profile.
29422
29535
  * `segment` carries the covering segment's window; `gap` reports the forward
29423
29536
  * nearest covered edge (`null` past the end of footage / when none exists)
@@ -29643,6 +29756,12 @@ method(object({
29643
29756
  }), method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
29644
29757
  kind: "mutation",
29645
29758
  auth: "admin"
29759
+ }), method(object({}), RecordingPlacementViewSchema, {
29760
+ kind: "query",
29761
+ auth: "admin"
29762
+ }), method(RecordingSetDevicePlacementInputSchema, object({ ok: literal(true) }), {
29763
+ kind: "mutation",
29764
+ auth: "admin"
29646
29765
  });
29647
29766
  /**
29648
29767
  * `recording-export` cap — render a footage time range into a single downloadable
@@ -34712,6 +34831,12 @@ Object.freeze({
34712
34831
  addonId: null,
34713
34832
  access: "delete"
34714
34833
  },
34834
+ "deviceManager.renameLocation": {
34835
+ capName: "device-manager",
34836
+ capScope: "system",
34837
+ addonId: null,
34838
+ access: "create"
34839
+ },
34715
34840
  "deviceManager.runDeviceAction": {
34716
34841
  capName: "device-manager",
34717
34842
  capScope: "system",
@@ -36404,19 +36529,19 @@ Object.freeze({
36404
36529
  addonId: null,
36405
36530
  access: "view"
36406
36531
  },
36407
- "pipelineAnalytics.getGroup": {
36532
+ "pipelineAnalytics.getKeyEvents": {
36408
36533
  capName: "pipeline-analytics",
36409
36534
  capScope: "device",
36410
36535
  addonId: null,
36411
36536
  access: "view"
36412
36537
  },
36413
- "pipelineAnalytics.getKeyEvents": {
36538
+ "pipelineAnalytics.getKeyEventsBatch": {
36414
36539
  capName: "pipeline-analytics",
36415
36540
  capScope: "device",
36416
36541
  addonId: null,
36417
36542
  access: "view"
36418
36543
  },
36419
- "pipelineAnalytics.getKeyEventsBatch": {
36544
+ "pipelineAnalytics.getMediaReclaimStatus": {
36420
36545
  capName: "pipeline-analytics",
36421
36546
  capScope: "device",
36422
36547
  addonId: null,
@@ -36506,12 +36631,6 @@ Object.freeze({
36506
36631
  addonId: null,
36507
36632
  access: "view"
36508
36633
  },
36509
- "pipelineAnalytics.listGroups": {
36510
- capName: "pipeline-analytics",
36511
- capScope: "device",
36512
- addonId: null,
36513
- access: "view"
36514
- },
36515
36634
  "pipelineAnalytics.listOpsLog": {
36516
36635
  capName: "pipeline-analytics",
36517
36636
  capScope: "device",
@@ -36596,6 +36715,12 @@ Object.freeze({
36596
36715
  addonId: null,
36597
36716
  access: "create"
36598
36717
  },
36718
+ "pipelineAnalytics.reclaimDebugMedia": {
36719
+ capName: "pipeline-analytics",
36720
+ capScope: "device",
36721
+ addonId: null,
36722
+ access: "create"
36723
+ },
36599
36724
  "pipelineAnalytics.reconcileFromDisk": {
36600
36725
  capName: "pipeline-analytics",
36601
36726
  capScope: "device",
@@ -37520,6 +37645,12 @@ Object.freeze({
37520
37645
  addonId: null,
37521
37646
  access: "view"
37522
37647
  },
37648
+ "recording.getPlacement": {
37649
+ capName: "recording",
37650
+ capScope: "system",
37651
+ addonId: null,
37652
+ access: "view"
37653
+ },
37523
37654
  "recording.getPlaybackManifest": {
37524
37655
  capName: "recording",
37525
37656
  capScope: "system",
@@ -37646,6 +37777,12 @@ Object.freeze({
37646
37777
  addonId: null,
37647
37778
  access: "create"
37648
37779
  },
37780
+ "recording.setDevicePlacement": {
37781
+ capName: "recording",
37782
+ capScope: "system",
37783
+ addonId: null,
37784
+ access: "create"
37785
+ },
37649
37786
  "recording.startStorageMigrationMove": {
37650
37787
  capName: "recording",
37651
37788
  capScope: "system",
@@ -38090,12 +38227,36 @@ Object.freeze({
38090
38227
  addonId: null,
38091
38228
  access: "create"
38092
38229
  },
38230
+ "storageMigration.cleanupCancel": {
38231
+ capName: "storage-migration",
38232
+ capScope: "system",
38233
+ addonId: null,
38234
+ access: "create"
38235
+ },
38236
+ "storageMigration.cleanupStart": {
38237
+ capName: "storage-migration",
38238
+ capScope: "system",
38239
+ addonId: null,
38240
+ access: "create"
38241
+ },
38242
+ "storageMigration.cleanupStatus": {
38243
+ capName: "storage-migration",
38244
+ capScope: "system",
38245
+ addonId: null,
38246
+ access: "view"
38247
+ },
38093
38248
  "storageMigration.drain": {
38094
38249
  capName: "storage-migration",
38095
38250
  capScope: "system",
38096
38251
  addonId: null,
38097
38252
  access: "create"
38098
38253
  },
38254
+ "storageMigration.history": {
38255
+ capName: "storage-migration",
38256
+ capScope: "system",
38257
+ addonId: null,
38258
+ access: "view"
38259
+ },
38099
38260
  "storageMigration.movers": {
38100
38261
  capName: "storage-migration",
38101
38262
  capScope: "system",
@@ -40092,11 +40253,6 @@ Object.freeze({
40092
40253
  form: "single",
40093
40254
  optional: true
40094
40255
  }],
40095
- "pipelineAnalytics.getGroup": [{
40096
- name: "deviceId",
40097
- form: "single",
40098
- optional: false
40099
- }],
40100
40256
  "pipelineAnalytics.getKeyEvents": [{
40101
40257
  name: "deviceId",
40102
40258
  form: "single",
@@ -40162,11 +40318,6 @@ Object.freeze({
40162
40318
  form: "single",
40163
40319
  optional: false
40164
40320
  }],
40165
- "pipelineAnalytics.listGroups": [{
40166
- name: "deviceIds",
40167
- form: "array",
40168
- optional: false
40169
- }],
40170
40321
  "pipelineAnalytics.listOpsLog": [{
40171
40322
  name: "deviceId",
40172
40323
  form: "single",
@@ -40212,6 +40363,11 @@ Object.freeze({
40212
40363
  form: "single",
40213
40364
  optional: true
40214
40365
  }],
40366
+ "pipelineAnalytics.reclaimDebugMedia": [{
40367
+ name: "deviceIds",
40368
+ form: "array",
40369
+ optional: true
40370
+ }],
40215
40371
  "pipelineAnalytics.reconcileFromDisk": [{
40216
40372
  name: "deviceId",
40217
40373
  form: "single",
@@ -40577,6 +40733,11 @@ Object.freeze({
40577
40733
  form: "single",
40578
40734
  optional: false
40579
40735
  }],
40736
+ "recording.setDevicePlacement": [{
40737
+ name: "deviceId",
40738
+ form: "single",
40739
+ optional: false
40740
+ }],
40580
40741
  "recording.startStorageMigrationMove": [{
40581
40742
  name: "deviceId",
40582
40743
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-tuya",
3
- "version": "0.2.49",
3
+ "version": "0.2.50",
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",