@camstack/types 1.2.58 → 1.2.60

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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_event_category = require("./event-category-DxZbWydC.js");
3
- const require_sleep = require("./sleep-DcLy1h8o.js");
3
+ const require_sleep = require("./sleep-BszXLEvP.js");
4
4
  const require_canonical_hash = require("./canonical-hash-DNV8S5ET.js");
5
5
  const require_enums = require("./enums.js");
6
6
  const require_err_msg = require("./err-msg-COpsHMw2.js");
@@ -1610,12 +1610,11 @@ function deriveRecordingMode(config) {
1610
1610
  /**
1611
1611
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
1612
1612
  *
1613
- * One shape shared by the recorder's `relocateFootage` (segments) and
1614
- * pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
1615
- * page renders both movers with one component. Jobs are in-RAM (a restart
1616
- * forgets them re-running is safe by construction: copy-if-absent, delete
1617
- * after verify) and each completed/failed run also lands one durable ops-log
1618
- * row on the owning addon's surface.
1613
+ * One shape shared by the recorder and pipeline-analytics internal movers.
1614
+ * The public admin surface is `storage-migration`; child jobs remain in RAM
1615
+ * because copy-if-absent, verify, delete and index/row repoint are resumable.
1616
+ * Each completed/failed run also lands one durable ops-log row on its owning
1617
+ * addon surface.
1619
1618
  */
1620
1619
  var RelocateJobStateSchema = zod.z.enum([
1621
1620
  "running",
@@ -1642,20 +1641,102 @@ var RelocateJobSchema = zod.z.object({
1642
1641
  finishedAt: zod.z.number().nullable(),
1643
1642
  error: zod.z.string().nullable()
1644
1643
  });
1644
+ /** Profile-derived footage selection used only by the migration coordinator:
1645
+ * `recordings` owns high+mid; `recordingsLow` owns low. */
1646
+ var RelocateFootageClassSchema = zod.z.enum(["recordings", "recordingsLow"]);
1645
1647
  var RelocateFootageInputSchema = zod.z.object({
1646
- deviceId: zod.z.number().optional(),
1647
1648
  fromLocationId: zod.z.string(),
1648
1649
  toLocationId: zod.z.string(),
1649
1650
  entities: zod.z.array(zod.z.enum(["segments"])).optional(),
1651
+ /** Limits relocation to the logical profile class. Omit only for the
1652
+ * pre-orchestration compatibility path. */
1653
+ footageClass: RelocateFootageClassSchema.optional(),
1650
1654
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
1651
1655
  * never allowed to starve live writers. */
1652
1656
  throttleMbps: zod.z.number().min(1).max(1e3).optional()
1653
1657
  });
1658
+ /** Internal, lease-scoped participant operation. It is intentionally separate
1659
+ * from persistent recording settings: a migration never changes
1660
+ * `RecordingConfig.enabled` or camera wrapper bindings. */
1661
+ var StorageMigrationLeaseInputSchema = zod.z.object({ leaseId: zod.z.string().min(1) });
1662
+ var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: zod.z.string().min(1) });
1654
1663
  var RelocateMediaInputSchema = zod.z.object({
1655
- deviceId: zod.z.number().optional(),
1656
1664
  toLocationId: zod.z.string(),
1657
1665
  throttleMbps: zod.z.number().min(1).max(1e3).optional()
1658
1666
  });
1667
+ var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: zod.z.string().min(1) });
1668
+ /** The independently selectable logical storage classes. `recordings`
1669
+ * encompasses the high and mid segment profiles; `recordingsLow` is low
1670
+ * segments; `eventMedia` is post-analysis blobs. */
1671
+ var StorageMigrationClassSchema = zod.z.enum([
1672
+ "recordings",
1673
+ "recordingsLow",
1674
+ "eventMedia"
1675
+ ]);
1676
+ /** A destination is always an existing, fully-qualified location id. The
1677
+ * migration API intentionally never changes a source location's `basePath`:
1678
+ * callers create a new `<type>:<slug>` location, then select it here. */
1679
+ var StorageMigrationDestinationsSchema = zod.z.object({
1680
+ recordings: zod.z.string().min(1).optional(),
1681
+ recordingsLow: zod.z.string().min(1).optional(),
1682
+ eventMedia: zod.z.string().min(1).optional()
1683
+ }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
1684
+ /** Shared input for planning and starting an orchestrated storage migration. */
1685
+ var StorageMigrationInputSchema = zod.z.object({
1686
+ destinations: StorageMigrationDestinationsSchema,
1687
+ throttleMbps: zod.z.number().min(1).max(1e3).optional()
1688
+ });
1689
+ /** The durable coordinator state machine. The only phase that changes default
1690
+ * locations is `repointing`, after every selected mover has completed and been
1691
+ * verified. */
1692
+ var StorageMigrationPhaseSchema = zod.z.enum([
1693
+ "planning",
1694
+ "pausing",
1695
+ "moving",
1696
+ "verifying",
1697
+ "repointing",
1698
+ "refreshing",
1699
+ "resuming",
1700
+ "done",
1701
+ "failed",
1702
+ "cancelled"
1703
+ ]);
1704
+ var StorageMigrationParticipantSchema = zod.z.enum([
1705
+ "pipeline",
1706
+ "recorder",
1707
+ "analytics"
1708
+ ]);
1709
+ var StorageMigrationMoveSchema = zod.z.object({
1710
+ storageClass: StorageMigrationClassSchema,
1711
+ fromLocationId: zod.z.string(),
1712
+ toLocationId: zod.z.string(),
1713
+ moverJobId: zod.z.string().nullable(),
1714
+ state: RelocateJobStateSchema.nullable(),
1715
+ error: zod.z.string().nullable()
1716
+ });
1717
+ var StorageMigrationJobSchema = zod.z.object({
1718
+ jobId: zod.z.string(),
1719
+ phase: StorageMigrationPhaseSchema,
1720
+ destinations: StorageMigrationDestinationsSchema,
1721
+ throttleMbps: zod.z.number(),
1722
+ moves: zod.z.array(StorageMigrationMoveSchema),
1723
+ pauseLeaseId: zod.z.string().nullable(),
1724
+ pausedParticipants: zod.z.array(StorageMigrationParticipantSchema),
1725
+ repointed: zod.z.boolean(),
1726
+ cancelRequested: zod.z.boolean(),
1727
+ startedAt: zod.z.number(),
1728
+ updatedAt: zod.z.number(),
1729
+ finishedAt: zod.z.number().nullable(),
1730
+ error: zod.z.string().nullable()
1731
+ });
1732
+ var StorageMigrationPlanSchema = zod.z.object({
1733
+ destinations: StorageMigrationDestinationsSchema,
1734
+ moves: zod.z.array(zod.z.object({
1735
+ storageClass: StorageMigrationClassSchema,
1736
+ fromLocationId: zod.z.string(),
1737
+ toLocationId: zod.z.string()
1738
+ }))
1739
+ });
1659
1740
  //#endregion
1660
1741
  //#region src/interfaces/server-analysis.ts
1661
1742
  var SUB_DETECTION_TYPES = ["face", "plate"];
@@ -14575,20 +14656,28 @@ var pipelineAnalyticsCapability = {
14575
14656
  }),
14576
14657
  /** The events ops-log rows (newest-first), optionally scoped to one camera.
14577
14658
  * Backed by a declared pipeline-analytics SQLite collection. */
14578
- /**
14579
- * Move event-media blobs onto `toLocationId` (entity-routing spec Phase
14580
- * 4): per-row copy → stamp row.locationId delete old blob. Rows already
14581
- * at the target are skipped, so a re-run resumes. Single-flight.
14582
- */
14583
- relocateMedia: require_sleep.method(RelocateMediaInputSchema, zod.z.object({ jobId: zod.z.string() }), {
14659
+ /** Internal migration-participant lease. It drains active MediaStore
14660
+ * writes and refuses new ones without changing analytics bindings. */
14661
+ pauseForStorageMigration: require_sleep.method(StorageMigrationLeaseInputSchema, zod.z.object({ paused: zod.z.literal(true) }), {
14584
14662
  kind: "mutation",
14585
14663
  auth: "admin"
14586
14664
  }),
14587
- getMediaRelocateStatus: require_sleep.method(zod.z.object({}), zod.z.array(RelocateJobSchema).readonly(), {
14588
- kind: "query",
14665
+ resumeForStorageMigration: require_sleep.method(StorageMigrationLeaseInputSchema, zod.z.object({ resumed: zod.z.literal(true) }), {
14666
+ kind: "mutation",
14589
14667
  auth: "admin"
14590
14668
  }),
14591
- cancelMediaRelocate: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
14669
+ /** Drops cached location roots after the storage coordinator repoints a
14670
+ * default so future event-media writes use the new root. */
14671
+ refreshStorageLocationsForMigration: require_sleep.method(StorageMigrationLeaseInputSchema, zod.z.object({ refreshed: zod.z.literal(true) }), {
14672
+ kind: "mutation",
14673
+ auth: "admin"
14674
+ }),
14675
+ startStorageMigrationMove: require_sleep.method(StorageMigrationMediaMoveInputSchema, zod.z.object({ jobId: zod.z.string() }), {
14676
+ kind: "mutation",
14677
+ auth: "admin"
14678
+ }),
14679
+ getStorageMigrationMoveStatus: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), RelocateJobSchema.nullable(), { auth: "admin" }),
14680
+ cancelStorageMigrationMove: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
14592
14681
  kind: "mutation",
14593
14682
  auth: "admin"
14594
14683
  }),
@@ -16816,6 +16905,16 @@ var pipelineOrchestratorCapability = {
16816
16905
  nodeIdMode: "data",
16817
16906
  exposesDeviceSettings: true,
16818
16907
  methods: {
16908
+ /** Internal storage-migration participant lease. While held, dispatch
16909
+ * requests are accepted as pending but no new runner attachment starts. */
16910
+ pauseForStorageMigration: require_sleep.method(StorageMigrationLeaseInputSchema, zod.z.object({ paused: zod.z.literal(true) }), {
16911
+ kind: "mutation",
16912
+ auth: "admin"
16913
+ }),
16914
+ resumeForStorageMigration: require_sleep.method(StorageMigrationLeaseInputSchema, zod.z.object({ resumed: zod.z.literal(true) }), {
16915
+ kind: "mutation",
16916
+ auth: "admin"
16917
+ }),
16819
16918
  /**
16820
16919
  * Pin a camera's pipeline to a specific agent (L1 affinity).
16821
16920
  * The orchestrator re-evaluates the assignment immediately and persists
@@ -17716,24 +17815,28 @@ var snapshotCapability = {
17716
17815
  *
17717
17816
  * `getSnapshotOverview` is cache-only by contract: it answers from whatever
17718
17817
  * the wrapper happens to hold and never captures. Under D93 the client
17719
- * versions its image URL on that answer, and an image REQUEST is what enrols
17720
- * a camera in the keep-warm loop. Both of those are satisfiable by the
17721
- * client's own image cache — `expo-image` is URL-keyed and never revalidates
17722
- * — so a URL painted in a previous session comes off disk with no network,
17723
- * no enrolment, and nothing warming. Measured on the live hub: reopening
17724
- * after two minutes idle painted 15 of 16 tiles at **168 s old** with zero
17725
- * HTTP requests, and the fleet only recovered because a later poll happened
17726
- * to observe a different identity.
17818
+ * versions its image URL on that answer, and an image REQUEST was the only
17819
+ * demand signal. Both of those are satisfiable by the client's own image
17820
+ * cache — `expo-image` is URL-keyed and never revalidates — so a URL painted
17821
+ * in a previous session comes off disk with no network, no demand, and no
17822
+ * capture. Measured on the live hub: reopening after two minutes idle
17823
+ * painted 15 of 16 tiles at **168 s old** with zero HTTP requests, and the
17824
+ * fleet only recovered because a later poll happened to observe a different
17825
+ * identity.
17727
17826
  *
17728
17827
  * ## The two properties that fix it
17729
17828
  *
17730
17829
  * **It is an RPC, so no client cache can answer it.** The demand signal
17731
- * always reaches the wrapper. This method therefore MAY create keep-warm
17732
- * subscriptions, where `getSnapshotOverview` must never (D93) — the
17733
- * distinction is not "one is newer" but that the overview poll is app-wide
17734
- * (a creating overview would warm every camera on the install) while this is
17735
- * called by a rendered surface naming the tiles it is actually painting, at
17736
- * the width it is painting them.
17830
+ * always reaches the wrapper. This method therefore CAPTURES, where
17831
+ * `getSnapshotOverview` must never (D93) — the distinction is not "one is
17832
+ * newer" but that the overview poll is app-wide (a capturing overview would
17833
+ * dial every camera on the install) while this is called by a rendered
17834
+ * surface naming the tiles it is actually painting, at the width it is
17835
+ * painting them.
17836
+ *
17837
+ * Since 2026-08-11 this is the ONLY thing that refreshes a snapshot: the
17838
+ * server-side keep-warm loop was removed (operator directive — on-demand,
17839
+ * always), so a camera nobody is looking at costs nothing at all.
17737
17840
  *
17738
17841
  * **It waits, briefly and boundedly, for the capture it triggered.** The
17739
17842
  * returned `capturedAt` is the frame the link will serve, not the frame the
@@ -18028,6 +18131,30 @@ var storageEvictableCapability = {
18028
18131
  }
18029
18132
  };
18030
18133
  //#endregion
18134
+ //#region src/capabilities/storage-migration.cap.ts
18135
+ /**
18136
+ * The single operator-facing storage migration surface. It coordinates the
18137
+ * pipeline, recorder and post-analysis participants; callers never mutate a
18138
+ * camera recording config or invoke an individual mover directly.
18139
+ */
18140
+ var storageMigrationCapability = {
18141
+ name: "storage-migration",
18142
+ scope: "system",
18143
+ mode: "singleton",
18144
+ methods: {
18145
+ plan: require_sleep.method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }),
18146
+ start: require_sleep.method(StorageMigrationInputSchema, zod.z.object({ jobId: zod.z.string() }), {
18147
+ kind: "mutation",
18148
+ auth: "admin"
18149
+ }),
18150
+ status: require_sleep.method(zod.z.object({ jobId: zod.z.string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }),
18151
+ cancel: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
18152
+ kind: "mutation",
18153
+ auth: "admin"
18154
+ })
18155
+ }
18156
+ };
18157
+ //#endregion
18031
18158
  //#region src/capabilities/storage-provider.cap.ts
18032
18159
  var ProviderInfoSchema = zod.z.discriminatedUnion("shouldSaveDiskSpace", [zod.z.object({
18033
18160
  providerId: zod.z.string().min(1),
@@ -18179,6 +18306,28 @@ var TerminalProfileInfoSchema = zod.z.object({
18179
18306
  label: zod.z.string(),
18180
18307
  description: zod.z.string().optional()
18181
18308
  });
18309
+ /**
18310
+ * A durable operator-created Terminal instance. Profiles are templates; only
18311
+ * an instance declares a camera.
18312
+ */
18313
+ var TerminalInstanceInfoSchema = zod.z.object({
18314
+ instanceId: zod.z.string(),
18315
+ cameraStableId: zod.z.string(),
18316
+ nodeId: zod.z.string(),
18317
+ profileId: zod.z.string(),
18318
+ profileLabel: zod.z.string(),
18319
+ name: zod.z.string(),
18320
+ enabled: zod.z.boolean()
18321
+ });
18322
+ var TerminalLegacyCameraSchema = zod.z.object({
18323
+ stableId: zod.z.string(),
18324
+ nodeId: zod.z.string(),
18325
+ profileId: zod.z.string(),
18326
+ profileLabel: zod.z.string(),
18327
+ name: zod.z.string(),
18328
+ /** Only legacy monitor cameras can retain their historic stable identity. */
18329
+ adoptable: zod.z.boolean()
18330
+ });
18182
18331
  var TerminalOutputEventSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
18183
18332
  seq: zod.z.number().int().positive(),
18184
18333
  kind: zod.z.literal("data"),
@@ -18198,10 +18347,9 @@ var TerminalOutputBatchSchema = zod.z.object({
18198
18347
  /**
18199
18348
  * terminal-session — singleton system capability for interactive TTY sessions.
18200
18349
  *
18201
- * Phase 1 (this cap): open/resize/close/list a pty running an allowlisted
18202
- * profile, streamed to xterm.js over the data plane. Phase 2 (streaming a
18203
- * session as a camera) is a separate device-provider concern and does not
18204
- * change this contract.
18350
+ * Owns both live PTY lifecycle and durable Terminal instance management.
18351
+ * Profiles are allowlisted templates; an explicit instance is the only path
18352
+ * that declares a camera.
18205
18353
  */
18206
18354
  var terminalSessionCapability = {
18207
18355
  name: "terminal-session",
@@ -18210,6 +18358,37 @@ var terminalSessionCapability = {
18210
18358
  methods: {
18211
18359
  /** Pre-declared profiles the operator may open. */
18212
18360
  listProfiles: require_sleep.method(zod.z.void(), zod.z.array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
18361
+ /** Explicit durable Terminal instances, managed centrally on the hub. */
18362
+ listInstances: require_sleep.method(zod.z.void(), zod.z.array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }),
18363
+ createInstance: require_sleep.method(zod.z.object({
18364
+ targetNodeId: zod.z.string().min(1),
18365
+ profileId: zod.z.string().min(1),
18366
+ name: zod.z.string().trim().min(1).max(160).optional()
18367
+ }), TerminalInstanceInfoSchema, {
18368
+ kind: "mutation",
18369
+ auth: "admin"
18370
+ }),
18371
+ deleteInstance: require_sleep.method(zod.z.object({ instanceId: zod.z.string().min(1) }), zod.z.void(), {
18372
+ kind: "mutation",
18373
+ auth: "admin"
18374
+ }),
18375
+ setInstanceEnabled: require_sleep.method(zod.z.object({
18376
+ instanceId: zod.z.string().min(1),
18377
+ enabled: zod.z.boolean()
18378
+ }), TerminalInstanceInfoSchema, {
18379
+ kind: "mutation",
18380
+ auth: "admin"
18381
+ }),
18382
+ /** Existing automatic cameras are shown for explicit migration only. */
18383
+ listLegacyCameras: require_sleep.method(zod.z.void(), zod.z.array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }),
18384
+ /** Explicitly adopt one legacy monitor camera, retaining its stable id. */
18385
+ adoptLegacyMonitor: require_sleep.method(zod.z.object({
18386
+ stableId: zod.z.string().min(1),
18387
+ name: zod.z.string().trim().min(1).max(160).optional()
18388
+ }), TerminalInstanceInfoSchema, {
18389
+ kind: "mutation",
18390
+ auth: "admin"
18391
+ }),
18213
18392
  /** Live sessions currently hosted by the provider. */
18214
18393
  listSessions: require_sleep.method(zod.z.void(), zod.z.array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }),
18215
18394
  /**
@@ -18241,7 +18420,13 @@ var terminalSessionCapability = {
18241
18420
  pullOutput: require_sleep.method(zod.z.object({
18242
18421
  sessionId: zod.z.string(),
18243
18422
  afterSeq: zod.z.number().int().nonnegative(),
18244
- waitMs: zod.z.number().int().min(0).max(2e3).default(0)
18423
+ waitMs: zod.z.number().int().min(0).max(2e3).default(0),
18424
+ /**
18425
+ * Wait when a just-opened session has no output yet. Kept opt-in so a
18426
+ * browser's initial repaint remains immediate; the camera snapshot
18427
+ * relay uses it to avoid encoding a blank startup frame.
18428
+ */
18429
+ waitForOutput: zod.z.boolean().optional()
18245
18430
  }), TerminalOutputBatchSchema, {
18246
18431
  kind: "mutation",
18247
18432
  auth: "admin",
@@ -25532,12 +25717,6 @@ var recordingCapability = {
25532
25717
  auth: "admin"
25533
25718
  }),
25534
25719
  /**
25535
- * Move footage (recorded segments) from one recordings location to
25536
- * another — the drain workflow's mover (entity-routing spec Phase 4).
25537
- * Throttled copy → size-verify → delete source → index refresh; resumable
25538
- * by construction (copy-if-absent). Single-flight: one job at a time.
25539
- */
25540
- /**
25541
25720
  * Render a short GIF from recorded footage around `aroundMs` (low profile,
25542
25721
  * palette-free ffmpeg gif). Synchronous — the window is a few seconds of
25543
25722
  * `low`, rendering in ~1-2s. Built for notification attachments: the
@@ -25589,16 +25768,28 @@ var recordingCapability = {
25589
25768
  kind: "mutation",
25590
25769
  auth: "admin"
25591
25770
  }),
25592
- relocateFootage: require_sleep.method(RelocateFootageInputSchema, zod.z.object({ jobId: zod.z.string() }), {
25771
+ /** Internal migration-participant lease. Blocks new recorder attaches and
25772
+ * waits for writers to exit while their watchers index final segments. */
25773
+ pauseForStorageMigration: require_sleep.method(StorageMigrationLeaseInputSchema, zod.z.object({ paused: zod.z.literal(true) }), {
25593
25774
  kind: "mutation",
25594
25775
  auth: "admin"
25595
25776
  }),
25596
- /** Every known relocate job (in-RAM, newest-first). */
25597
- getRelocateStatus: require_sleep.method(zod.z.object({}), zod.z.array(RelocateJobSchema).readonly(), {
25598
- kind: "query",
25777
+ resumeForStorageMigration: require_sleep.method(StorageMigrationLeaseInputSchema, zod.z.object({ resumed: zod.z.literal(true) }), {
25778
+ kind: "mutation",
25599
25779
  auth: "admin"
25600
25780
  }),
25601
- cancelRelocate: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
25781
+ /** Re-resolve location roots after the coordinator changes defaults. */
25782
+ refreshStorageLocationsForMigration: require_sleep.method(StorageMigrationLeaseInputSchema, zod.z.object({ refreshed: zod.z.literal(true) }), {
25783
+ kind: "mutation",
25784
+ auth: "admin"
25785
+ }),
25786
+ /** Internal mover, callable only by the storage-migration coordinator. */
25787
+ startStorageMigrationMove: require_sleep.method(StorageMigrationFootageMoveInputSchema, zod.z.object({ jobId: zod.z.string() }), {
25788
+ kind: "mutation",
25789
+ auth: "admin"
25790
+ }),
25791
+ getStorageMigrationMoveStatus: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), RelocateJobSchema.nullable(), { auth: "admin" }),
25792
+ cancelStorageMigrationMove: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
25602
25793
  kind: "mutation",
25603
25794
  auth: "admin"
25604
25795
  })
@@ -28961,9 +29152,10 @@ var DeclaredDevices = class {
28961
29152
  }
28962
29153
  const integrationId = spec.integrationId ?? await this.ensureIntegration(spec.integrationName);
28963
29154
  const index = await this.readIndex();
29155
+ const live = await this.readLiveByStableId();
28964
29156
  const outcomes = [];
28965
29157
  for (const declaration of spec.devices) {
28966
- const outcome = await this.applyDeclaration(declaration, integrationId, index);
29158
+ const outcome = await this.applyDeclaration(declaration, integrationId, index, live);
28967
29159
  if (outcome !== null) outcomes.push(outcome);
28968
29160
  }
28969
29161
  return {
@@ -29009,6 +29201,26 @@ var DeclaredDevices = class {
29009
29201
  return new Map(rows.map((row) => [row.stableId, row]));
29010
29202
  }
29011
29203
  /**
29204
+ * Devices this kernel already has CONSTRUCTED, by stableId.
29205
+ *
29206
+ * Distinct from {@link readIndex}, and the distinction is the bug: the index
29207
+ * is persisted rows, this is live objects. A row without an object must be
29208
+ * adopted; an object must be left exactly as it is.
29209
+ *
29210
+ * Failure is non-fatal and deliberately so — an empty map degrades to the
29211
+ * previous behaviour (attempt the adopt) rather than skipping a device that
29212
+ * genuinely needs bringing up.
29213
+ */
29214
+ async readLiveByStableId() {
29215
+ try {
29216
+ const devices = await this.ports.devices.getAll();
29217
+ return new Map(devices.map((device) => [device.stableId, device]));
29218
+ } catch (err) {
29219
+ this.ports.logger.warn("could not read live devices — falling back to adopt-by-row", { meta: { error: err instanceof Error ? err.message : String(err) } });
29220
+ return /* @__PURE__ */ new Map();
29221
+ }
29222
+ }
29223
+ /**
29012
29224
  * One declaration: adopt what exists, create what does not.
29013
29225
  *
29014
29226
  * The create branch is the destructive one — it seeds `initialMeta`, and
@@ -29017,8 +29229,15 @@ var DeclaredDevices = class {
29017
29229
  * the declared name over the operator's rename. D49: that branch needs a
29018
29230
  * second read to agree.
29019
29231
  */
29020
- async applyDeclaration(declaration, integrationId, index) {
29232
+ async applyDeclaration(declaration, integrationId, index, live) {
29021
29233
  try {
29234
+ const alreadyLive = live.get(declaration.stableId);
29235
+ if (alreadyLive !== void 0) return {
29236
+ stableId: declaration.stableId,
29237
+ deviceId: alreadyLive.id,
29238
+ device: alreadyLive,
29239
+ created: false
29240
+ };
29022
29241
  let existing = index.get(declaration.stableId);
29023
29242
  if (existing === void 0) {
29024
29243
  existing = (await this.readIndex()).get(declaration.stableId);
@@ -30561,6 +30780,7 @@ var CAPABILITY_NAMES = {
30561
30780
  ssoBridge: "sso-bridge",
30562
30781
  storage: "storage",
30563
30782
  storageEvictable: "storage-evictable",
30783
+ storageMigration: "storage-migration",
30564
30784
  storageProvider: "storage-provider",
30565
30785
  streamBroker: "stream-broker",
30566
30786
  streamCatalog: "stream-catalog",
@@ -31078,6 +31298,10 @@ var CAPABILITY_ROUTER_KEYS = [
31078
31298
  key: "storageEvictable",
31079
31299
  name: "storage-evictable"
31080
31300
  },
31301
+ {
31302
+ key: "storageMigration",
31303
+ name: "storage-migration"
31304
+ },
31081
31305
  {
31082
31306
  key: "storageProvider",
31083
31307
  name: "storage-provider"
@@ -31315,6 +31539,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
31315
31539
  ssoBridgeCapability,
31316
31540
  storageCapability,
31317
31541
  storageEvictableCapability,
31542
+ storageMigrationCapability,
31318
31543
  storageProviderCapability,
31319
31544
  streamBrokerCapability,
31320
31545
  streamCatalogCapability,
@@ -34345,7 +34570,7 @@ var METHOD_ACCESS_MAP = Object.freeze({
34345
34570
  addonId: null,
34346
34571
  access: "create"
34347
34572
  },
34348
- "pipelineAnalytics.cancelMediaRelocate": {
34573
+ "pipelineAnalytics.cancelStorageMigrationMove": {
34349
34574
  capName: "pipeline-analytics",
34350
34575
  capScope: "device",
34351
34576
  addonId: null,
@@ -34417,12 +34642,6 @@ var METHOD_ACCESS_MAP = Object.freeze({
34417
34642
  addonId: null,
34418
34643
  access: "view"
34419
34644
  },
34420
- "pipelineAnalytics.getMediaRelocateStatus": {
34421
- capName: "pipeline-analytics",
34422
- capScope: "device",
34423
- addonId: null,
34424
- access: "view"
34425
- },
34426
34645
  "pipelineAnalytics.getMotionEvents": {
34427
34646
  capName: "pipeline-analytics",
34428
34647
  capScope: "device",
@@ -34459,6 +34678,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
34459
34678
  addonId: null,
34460
34679
  access: "view"
34461
34680
  },
34681
+ "pipelineAnalytics.getStorageMigrationMoveStatus": {
34682
+ capName: "pipeline-analytics",
34683
+ capScope: "device",
34684
+ addonId: null,
34685
+ access: "view"
34686
+ },
34462
34687
  "pipelineAnalytics.getTrack": {
34463
34688
  capName: "pipeline-analytics",
34464
34689
  capScope: "device",
@@ -34537,6 +34762,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
34537
34762
  addonId: null,
34538
34763
  access: "view"
34539
34764
  },
34765
+ "pipelineAnalytics.pauseForStorageMigration": {
34766
+ capName: "pipeline-analytics",
34767
+ capScope: "device",
34768
+ addonId: null,
34769
+ access: "create"
34770
+ },
34540
34771
  "pipelineAnalytics.proposeRetrainAnnotations": {
34541
34772
  capName: "pipeline-analytics",
34542
34773
  capScope: "device",
@@ -34567,7 +34798,7 @@ var METHOD_ACCESS_MAP = Object.freeze({
34567
34798
  addonId: null,
34568
34799
  access: "create"
34569
34800
  },
34570
- "pipelineAnalytics.relocateMedia": {
34801
+ "pipelineAnalytics.refreshStorageLocationsForMigration": {
34571
34802
  capName: "pipeline-analytics",
34572
34803
  capScope: "device",
34573
34804
  addonId: null,
@@ -34579,6 +34810,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
34579
34810
  addonId: null,
34580
34811
  access: "create"
34581
34812
  },
34813
+ "pipelineAnalytics.resumeForStorageMigration": {
34814
+ capName: "pipeline-analytics",
34815
+ capScope: "device",
34816
+ addonId: null,
34817
+ access: "create"
34818
+ },
34582
34819
  "pipelineAnalytics.saveRetrainAnnotations": {
34583
34820
  capName: "pipeline-analytics",
34584
34821
  capScope: "device",
@@ -34603,6 +34840,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
34603
34840
  addonId: null,
34604
34841
  access: "create"
34605
34842
  },
34843
+ "pipelineAnalytics.startStorageMigrationMove": {
34844
+ capName: "pipeline-analytics",
34845
+ capScope: "device",
34846
+ addonId: null,
34847
+ access: "create"
34848
+ },
34606
34849
  "pipelineAnalytics.wipeAllAnalytics": {
34607
34850
  capName: "pipeline-analytics",
34608
34851
  capScope: "device",
@@ -34969,6 +35212,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
34969
35212
  addonId: null,
34970
35213
  access: "view"
34971
35214
  },
35215
+ "pipelineOrchestrator.pauseForStorageMigration": {
35216
+ capName: "pipeline-orchestrator",
35217
+ capScope: "system",
35218
+ addonId: null,
35219
+ access: "create"
35220
+ },
34972
35221
  "pipelineOrchestrator.rebalance": {
34973
35222
  capName: "pipeline-orchestrator",
34974
35223
  capScope: "system",
@@ -34993,6 +35242,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
34993
35242
  addonId: null,
34994
35243
  access: "view"
34995
35244
  },
35245
+ "pipelineOrchestrator.resumeForStorageMigration": {
35246
+ capName: "pipeline-orchestrator",
35247
+ capScope: "system",
35248
+ addonId: null,
35249
+ access: "create"
35250
+ },
34996
35251
  "pipelineOrchestrator.saveTemplate": {
34997
35252
  capName: "pipeline-orchestrator",
34998
35253
  capScope: "system",
@@ -35389,7 +35644,7 @@ var METHOD_ACCESS_MAP = Object.freeze({
35389
35644
  addonId: null,
35390
35645
  access: "create"
35391
35646
  },
35392
- "recording.cancelRelocate": {
35647
+ "recording.cancelStorageMigrationMove": {
35393
35648
  capName: "recording",
35394
35649
  capScope: "system",
35395
35650
  addonId: null,
@@ -35425,7 +35680,7 @@ var METHOD_ACCESS_MAP = Object.freeze({
35425
35680
  addonId: null,
35426
35681
  access: "view"
35427
35682
  },
35428
- "recording.getRelocateStatus": {
35683
+ "recording.getStorageMigrationMoveStatus": {
35429
35684
  capName: "recording",
35430
35685
  capScope: "system",
35431
35686
  addonId: null,
@@ -35449,6 +35704,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
35449
35704
  addonId: null,
35450
35705
  access: "view"
35451
35706
  },
35707
+ "recording.pauseForStorageMigration": {
35708
+ capName: "recording",
35709
+ capScope: "system",
35710
+ addonId: null,
35711
+ access: "create"
35712
+ },
35452
35713
  "recording.pruneFootage": {
35453
35714
  capName: "recording",
35454
35715
  capScope: "system",
@@ -35467,7 +35728,7 @@ var METHOD_ACCESS_MAP = Object.freeze({
35467
35728
  addonId: null,
35468
35729
  access: "view"
35469
35730
  },
35470
- "recording.relocateFootage": {
35731
+ "recording.refreshStorageLocationsForMigration": {
35471
35732
  capName: "recording",
35472
35733
  capScope: "system",
35473
35734
  addonId: null,
@@ -35491,12 +35752,24 @@ var METHOD_ACCESS_MAP = Object.freeze({
35491
35752
  addonId: null,
35492
35753
  access: "create"
35493
35754
  },
35755
+ "recording.resumeForStorageMigration": {
35756
+ capName: "recording",
35757
+ capScope: "system",
35758
+ addonId: null,
35759
+ access: "create"
35760
+ },
35494
35761
  "recording.setDeviceConfig": {
35495
35762
  capName: "recording",
35496
35763
  capScope: "system",
35497
35764
  addonId: null,
35498
35765
  access: "create"
35499
35766
  },
35767
+ "recording.startStorageMigrationMove": {
35768
+ capName: "recording",
35769
+ capScope: "system",
35770
+ addonId: null,
35771
+ access: "create"
35772
+ },
35500
35773
  "recordingExport.cancelExport": {
35501
35774
  capName: "recordingExport",
35502
35775
  capScope: "system",
@@ -35887,6 +36160,30 @@ var METHOD_ACCESS_MAP = Object.freeze({
35887
36160
  addonId: null,
35888
36161
  access: "view"
35889
36162
  },
36163
+ "storageMigration.cancel": {
36164
+ capName: "storage-migration",
36165
+ capScope: "system",
36166
+ addonId: null,
36167
+ access: "create"
36168
+ },
36169
+ "storageMigration.plan": {
36170
+ capName: "storage-migration",
36171
+ capScope: "system",
36172
+ addonId: null,
36173
+ access: "view"
36174
+ },
36175
+ "storageMigration.start": {
36176
+ capName: "storage-migration",
36177
+ capScope: "system",
36178
+ addonId: null,
36179
+ access: "create"
36180
+ },
36181
+ "storageMigration.status": {
36182
+ capName: "storage-migration",
36183
+ capScope: "system",
36184
+ addonId: null,
36185
+ access: "view"
36186
+ },
35890
36187
  "storageProvider.abortUpload": {
35891
36188
  capName: "storage-provider",
35892
36189
  capScope: "system",
@@ -36265,12 +36562,42 @@ var METHOD_ACCESS_MAP = Object.freeze({
36265
36562
  addonId: null,
36266
36563
  access: "create"
36267
36564
  },
36565
+ "terminalSession.adoptLegacyMonitor": {
36566
+ capName: "terminal-session",
36567
+ capScope: "system",
36568
+ addonId: null,
36569
+ access: "create"
36570
+ },
36268
36571
  "terminalSession.close": {
36269
36572
  capName: "terminal-session",
36270
36573
  capScope: "system",
36271
36574
  addonId: null,
36272
36575
  access: "create"
36273
36576
  },
36577
+ "terminalSession.createInstance": {
36578
+ capName: "terminal-session",
36579
+ capScope: "system",
36580
+ addonId: null,
36581
+ access: "create"
36582
+ },
36583
+ "terminalSession.deleteInstance": {
36584
+ capName: "terminal-session",
36585
+ capScope: "system",
36586
+ addonId: null,
36587
+ access: "delete"
36588
+ },
36589
+ "terminalSession.listInstances": {
36590
+ capName: "terminal-session",
36591
+ capScope: "system",
36592
+ addonId: null,
36593
+ access: "view"
36594
+ },
36595
+ "terminalSession.listLegacyCameras": {
36596
+ capName: "terminal-session",
36597
+ capScope: "system",
36598
+ addonId: null,
36599
+ access: "view"
36600
+ },
36274
36601
  "terminalSession.listProfiles": {
36275
36602
  capName: "terminal-session",
36276
36603
  capScope: "system",
@@ -36301,6 +36628,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
36301
36628
  addonId: null,
36302
36629
  access: "create"
36303
36630
  },
36631
+ "terminalSession.setInstanceEnabled": {
36632
+ capName: "terminal-session",
36633
+ capScope: "system",
36634
+ addonId: null,
36635
+ access: "create"
36636
+ },
36304
36637
  "terminalSession.writeInput": {
36305
36638
  capName: "terminal-session",
36306
36639
  capScope: "system",
@@ -36902,6 +37235,7 @@ var KNOWN_CAP_NAMES = [
36902
37235
  "sso-bridge",
36903
37236
  "storage",
36904
37237
  "storage-evictable",
37238
+ "storage-migration",
36905
37239
  "storage-provider",
36906
37240
  "stream-broker",
36907
37241
  "stream-catalog",
@@ -37042,6 +37376,7 @@ var SYSTEM_CAP_NAMES = [
37042
37376
  "sso-bridge",
37043
37377
  "storage",
37044
37378
  "storage-evictable",
37379
+ "storage-migration",
37045
37380
  "storage-provider",
37046
37381
  "stream-broker",
37047
37382
  "system",
@@ -37535,6 +37870,8 @@ function createSystemProxy(api) {
37535
37870
  getDetectionConfigSchema: (input) => dispatch("pipelineExecutor", "getDetectionConfigSchema", "query", input)
37536
37871
  },
37537
37872
  pipelineOrchestrator: {
37873
+ pauseForStorageMigration: (input) => dispatch("pipelineOrchestrator", "pauseForStorageMigration", "mutation", input),
37874
+ resumeForStorageMigration: (input) => dispatch("pipelineOrchestrator", "resumeForStorageMigration", "mutation", input),
37538
37875
  rebalance: (input) => dispatch("pipelineOrchestrator", "rebalance", "mutation", input),
37539
37876
  getPipelineAssignments: (input) => dispatch("pipelineOrchestrator", "getPipelineAssignments", "query", input),
37540
37877
  getAgentLoad: (input) => dispatch("pipelineOrchestrator", "getAgentLoad", "query", input),
@@ -37589,9 +37926,12 @@ function createSystemProxy(api) {
37589
37926
  recording: {
37590
37927
  getStorageUsage: (input) => dispatch("recording", "getStorageUsage", "query", input),
37591
37928
  listOpsLog: (input) => dispatch("recording", "listOpsLog", "query", input),
37592
- relocateFootage: (input) => dispatch("recording", "relocateFootage", "mutation", input),
37593
- getRelocateStatus: (input) => dispatch("recording", "getRelocateStatus", "query", input),
37594
- cancelRelocate: (input) => dispatch("recording", "cancelRelocate", "mutation", input)
37929
+ pauseForStorageMigration: (input) => dispatch("recording", "pauseForStorageMigration", "mutation", input),
37930
+ resumeForStorageMigration: (input) => dispatch("recording", "resumeForStorageMigration", "mutation", input),
37931
+ refreshStorageLocationsForMigration: (input) => dispatch("recording", "refreshStorageLocationsForMigration", "mutation", input),
37932
+ startStorageMigrationMove: (input) => dispatch("recording", "startStorageMigrationMove", "mutation", input),
37933
+ getStorageMigrationMoveStatus: (input) => dispatch("recording", "getStorageMigrationMoveStatus", "query", input),
37934
+ cancelStorageMigrationMove: (input) => dispatch("recording", "cancelStorageMigrationMove", "mutation", input)
37595
37935
  },
37596
37936
  recordingExport: {
37597
37937
  getExport: (input) => dispatch("recordingExport", "getExport", "query", input),
@@ -37644,6 +37984,12 @@ function createSystemProxy(api) {
37644
37984
  listProviders: (input) => dispatch("storage", "listProviders", "query", input),
37645
37985
  testConfig: (input) => dispatch("storage", "testConfig", "query", input)
37646
37986
  },
37987
+ storageMigration: {
37988
+ plan: (input) => dispatch("storageMigration", "plan", "query", input),
37989
+ start: (input) => dispatch("storageMigration", "start", "mutation", input),
37990
+ status: (input) => dispatch("storageMigration", "status", "query", input),
37991
+ cancel: (input) => dispatch("storageMigration", "cancel", "mutation", input)
37992
+ },
37647
37993
  streamBroker: {
37648
37994
  fetchEventMedia: (input) => dispatch("streamBroker", "fetchEventMedia", "mutation", input),
37649
37995
  listAllCameraStreams: (input) => dispatch("streamBroker", "listAllCameraStreams", "query", input),
@@ -37683,6 +38029,12 @@ function createSystemProxy(api) {
37683
38029
  },
37684
38030
  terminalSession: {
37685
38031
  listProfiles: (input) => dispatch("terminalSession", "listProfiles", "query", input),
38032
+ listInstances: (input) => dispatch("terminalSession", "listInstances", "query", input),
38033
+ createInstance: (input) => dispatch("terminalSession", "createInstance", "mutation", input),
38034
+ deleteInstance: (input) => dispatch("terminalSession", "deleteInstance", "mutation", input),
38035
+ setInstanceEnabled: (input) => dispatch("terminalSession", "setInstanceEnabled", "mutation", input),
38036
+ listLegacyCameras: (input) => dispatch("terminalSession", "listLegacyCameras", "query", input),
38037
+ adoptLegacyMonitor: (input) => dispatch("terminalSession", "adoptLegacyMonitor", "mutation", input),
37686
38038
  listSessions: (input) => dispatch("terminalSession", "listSessions", "query", input),
37687
38039
  openSession: (input) => dispatch("terminalSession", "openSession", "mutation", input),
37688
38040
  resize: (input) => dispatch("terminalSession", "resize", "mutation", input),
@@ -40570,6 +40922,7 @@ exports.RecordingStorageUsageSchema = RecordingStorageUsageSchema;
40570
40922
  exports.RecordingTriggersSchema = RecordingTriggersSchema;
40571
40923
  exports.RecordingWeekdaySchema = RecordingWeekdaySchema;
40572
40924
  exports.RedirectLoginMethodSchema = RedirectLoginMethodSchema;
40925
+ exports.RelocateFootageClassSchema = RelocateFootageClassSchema;
40573
40926
  exports.RelocateFootageInputSchema = RelocateFootageInputSchema;
40574
40927
  exports.RelocateJobSchema = RelocateJobSchema;
40575
40928
  exports.RelocateJobStateSchema = RelocateJobStateSchema;
@@ -40657,6 +41010,17 @@ exports.StorageLocationDeclarationSchema = StorageLocationDeclarationSchema;
40657
41010
  exports.StorageLocationRefSchema = StorageLocationRefSchema;
40658
41011
  exports.StorageLocationSchema = StorageLocationSchema;
40659
41012
  exports.StorageLocationTypeSchema = StorageLocationTypeSchema;
41013
+ exports.StorageMigrationClassSchema = StorageMigrationClassSchema;
41014
+ exports.StorageMigrationDestinationsSchema = StorageMigrationDestinationsSchema;
41015
+ exports.StorageMigrationFootageMoveInputSchema = StorageMigrationFootageMoveInputSchema;
41016
+ exports.StorageMigrationInputSchema = StorageMigrationInputSchema;
41017
+ exports.StorageMigrationJobSchema = StorageMigrationJobSchema;
41018
+ exports.StorageMigrationLeaseInputSchema = StorageMigrationLeaseInputSchema;
41019
+ exports.StorageMigrationMediaMoveInputSchema = StorageMigrationMediaMoveInputSchema;
41020
+ exports.StorageMigrationMoveSchema = StorageMigrationMoveSchema;
41021
+ exports.StorageMigrationParticipantSchema = StorageMigrationParticipantSchema;
41022
+ exports.StorageMigrationPhaseSchema = StorageMigrationPhaseSchema;
41023
+ exports.StorageMigrationPlanSchema = StorageMigrationPlanSchema;
40660
41024
  exports.StorageProviderInfoSchema = ProviderInfoSchema;
40661
41025
  exports.StorageReadChunkInputSchema = ReadChunkInputSchema;
40662
41026
  exports.StorageTestLocationResultSchema = TestLocationResultSchema;
@@ -40690,6 +41054,8 @@ exports.TargetKindLevelSchema = TargetKindLevelSchema;
40690
41054
  exports.TargetKindSchema = TargetKindSchema;
40691
41055
  exports.TargetSchema = TargetSchema;
40692
41056
  exports.TemperatureSensorStatusSchema = TemperatureSensorStatusSchema;
41057
+ exports.TerminalInstanceInfoSchema = TerminalInstanceInfoSchema;
41058
+ exports.TerminalLegacyCameraSchema = TerminalLegacyCameraSchema;
40693
41059
  exports.TerminalOutputBatchSchema = TerminalOutputBatchSchema;
40694
41060
  exports.TerminalOutputEventSchema = TerminalOutputEventSchema;
40695
41061
  exports.TerminalProfileInfoSchema = TerminalProfileInfoSchema;
@@ -41075,6 +41441,7 @@ exports.startReachabilityPoll = startReachabilityPoll;
41075
41441
  exports.stateVocabularyFor = stateVocabularyFor;
41076
41442
  exports.storageCapability = storageCapability;
41077
41443
  exports.storageEvictableCapability = storageEvictableCapability;
41444
+ exports.storageMigrationCapability = storageMigrationCapability;
41078
41445
  exports.storageProviderCapability = storageProviderCapability;
41079
41446
  exports.streamBrokerCapability = streamBrokerCapability;
41080
41447
  exports.streamCatalogCapability = streamCatalogCapability;