@camstack/addon-pipeline-orchestrator 1.2.43 → 1.2.45

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
@@ -8393,12 +8393,11 @@ var RecordingConfigSchema = object({
8393
8393
  /**
8394
8394
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
8395
8395
  *
8396
- * One shape shared by the recorder's `relocateFootage` (segments) and
8397
- * pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
8398
- * page renders both movers with one component. Jobs are in-RAM (a restart
8399
- * forgets them re-running is safe by construction: copy-if-absent, delete
8400
- * after verify) and each completed/failed run also lands one durable ops-log
8401
- * row on the owning addon's surface.
8396
+ * One shape shared by the recorder and pipeline-analytics internal movers.
8397
+ * The public admin surface is `storage-migration`; child jobs remain in RAM
8398
+ * because copy-if-absent, verify, delete and index/row repoint are resumable.
8399
+ * Each completed/failed run also lands one durable ops-log row on its owning
8400
+ * addon surface.
8402
8401
  */
8403
8402
  var RelocateJobStateSchema = _enum([
8404
8403
  "running",
@@ -8425,19 +8424,100 @@ var RelocateJobSchema = object({
8425
8424
  finishedAt: number().nullable(),
8426
8425
  error: string().nullable()
8427
8426
  });
8427
+ /** Profile-derived footage selection used only by the migration coordinator:
8428
+ * `recordings` owns high+mid; `recordingsLow` owns low. */
8429
+ var RelocateFootageClassSchema = _enum(["recordings", "recordingsLow"]);
8428
8430
  var RelocateFootageInputSchema = object({
8429
- deviceId: number().optional(),
8430
8431
  fromLocationId: string(),
8431
8432
  toLocationId: string(),
8432
8433
  entities: array(_enum(["segments"])).optional(),
8434
+ /** Limits relocation to the logical profile class. Omit only for the
8435
+ * pre-orchestration compatibility path. */
8436
+ footageClass: RelocateFootageClassSchema.optional(),
8433
8437
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
8434
8438
  * never allowed to starve live writers. */
8435
8439
  throttleMbps: number().min(1).max(1e3).optional()
8436
8440
  });
8437
- var RelocateMediaInputSchema = object({
8438
- deviceId: number().optional(),
8441
+ /** Internal, lease-scoped participant operation. It is intentionally separate
8442
+ * from persistent recording settings: a migration never changes
8443
+ * `RecordingConfig.enabled` or camera wrapper bindings. */
8444
+ var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8445
+ var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8446
+ var StorageMigrationMediaMoveInputSchema = object({
8439
8447
  toLocationId: string(),
8440
8448
  throttleMbps: number().min(1).max(1e3).optional()
8449
+ }).extend({ leaseId: string().min(1) });
8450
+ /** The independently selectable logical storage classes. `recordings`
8451
+ * encompasses the high and mid segment profiles; `recordingsLow` is low
8452
+ * segments; `eventMedia` is post-analysis blobs. */
8453
+ var StorageMigrationClassSchema = _enum([
8454
+ "recordings",
8455
+ "recordingsLow",
8456
+ "eventMedia"
8457
+ ]);
8458
+ /** A destination is always an existing, fully-qualified location id. The
8459
+ * migration API intentionally never changes a source location's `basePath`:
8460
+ * callers create a new `<type>:<slug>` location, then select it here. */
8461
+ var StorageMigrationDestinationsSchema = object({
8462
+ recordings: string().min(1).optional(),
8463
+ recordingsLow: string().min(1).optional(),
8464
+ eventMedia: string().min(1).optional()
8465
+ }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8466
+ /** Shared input for planning and starting an orchestrated storage migration. */
8467
+ var StorageMigrationInputSchema = object({
8468
+ destinations: StorageMigrationDestinationsSchema,
8469
+ throttleMbps: number().min(1).max(1e3).optional()
8470
+ });
8471
+ /** The durable coordinator state machine. The only phase that changes default
8472
+ * locations is `repointing`, after every selected mover has completed and been
8473
+ * verified. */
8474
+ var StorageMigrationPhaseSchema = _enum([
8475
+ "planning",
8476
+ "pausing",
8477
+ "moving",
8478
+ "verifying",
8479
+ "repointing",
8480
+ "refreshing",
8481
+ "resuming",
8482
+ "done",
8483
+ "failed",
8484
+ "cancelled"
8485
+ ]);
8486
+ var StorageMigrationParticipantSchema = _enum([
8487
+ "pipeline",
8488
+ "recorder",
8489
+ "analytics"
8490
+ ]);
8491
+ var StorageMigrationMoveSchema = object({
8492
+ storageClass: StorageMigrationClassSchema,
8493
+ fromLocationId: string(),
8494
+ toLocationId: string(),
8495
+ moverJobId: string().nullable(),
8496
+ state: RelocateJobStateSchema.nullable(),
8497
+ error: string().nullable()
8498
+ });
8499
+ var StorageMigrationJobSchema = object({
8500
+ jobId: string(),
8501
+ phase: StorageMigrationPhaseSchema,
8502
+ destinations: StorageMigrationDestinationsSchema,
8503
+ throttleMbps: number(),
8504
+ moves: array(StorageMigrationMoveSchema),
8505
+ pauseLeaseId: string().nullable(),
8506
+ pausedParticipants: array(StorageMigrationParticipantSchema),
8507
+ repointed: boolean(),
8508
+ cancelRequested: boolean(),
8509
+ startedAt: number(),
8510
+ updatedAt: number(),
8511
+ finishedAt: number().nullable(),
8512
+ error: string().nullable()
8513
+ });
8514
+ var StorageMigrationPlanSchema = object({
8515
+ destinations: StorageMigrationDestinationsSchema,
8516
+ moves: array(object({
8517
+ storageClass: StorageMigrationClassSchema,
8518
+ fromLocationId: string(),
8519
+ toLocationId: string()
8520
+ }))
8441
8521
  });
8442
8522
  /**
8443
8523
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -16879,13 +16959,19 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16879
16959
  }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
16880
16960
  kind: "mutation",
16881
16961
  auth: "admin"
16882
- }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
16962
+ }), method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
16883
16963
  kind: "mutation",
16884
16964
  auth: "admin"
16885
- }), method(object({}), array(RelocateJobSchema).readonly(), {
16886
- kind: "query",
16965
+ }), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
16966
+ kind: "mutation",
16887
16967
  auth: "admin"
16888
- }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
16968
+ }), method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
16969
+ kind: "mutation",
16970
+ auth: "admin"
16971
+ }), method(StorageMigrationMediaMoveInputSchema, object({ jobId: string() }), {
16972
+ kind: "mutation",
16973
+ auth: "admin"
16974
+ }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
16889
16975
  kind: "mutation",
16890
16976
  auth: "admin"
16891
16977
  }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
@@ -18725,6 +18811,16 @@ var pipelineOrchestratorCapability = {
18725
18811
  nodeIdMode: "data",
18726
18812
  exposesDeviceSettings: true,
18727
18813
  methods: {
18814
+ /** Internal storage-migration participant lease. While held, dispatch
18815
+ * requests are accepted as pending but no new runner attachment starts. */
18816
+ pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
18817
+ kind: "mutation",
18818
+ auth: "admin"
18819
+ }),
18820
+ resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
18821
+ kind: "mutation",
18822
+ auth: "admin"
18823
+ }),
18728
18824
  /**
18729
18825
  * Pin a camera's pipeline to a specific agent (L1 affinity).
18730
18826
  * The orchestrator re-evaluates the assignment immediately and persists
@@ -19672,6 +19768,13 @@ method(object({ locationId: string() }), EvictableUsageSchema), method(object({
19672
19768
  locationId: string(),
19673
19769
  targetBytes: number().int().positive()
19674
19770
  }), EvictResultSchema, { kind: "mutation" });
19771
+ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }), method(StorageMigrationInputSchema, object({ jobId: string() }), {
19772
+ kind: "mutation",
19773
+ auth: "admin"
19774
+ }), method(object({ jobId: string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
19775
+ kind: "mutation",
19776
+ auth: "admin"
19777
+ });
19675
19778
  var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19676
19779
  providerId: string().min(1),
19677
19780
  displayName: string().min(1),
@@ -19775,6 +19878,28 @@ var TerminalProfileInfoSchema = object({
19775
19878
  label: string(),
19776
19879
  description: string().optional()
19777
19880
  });
19881
+ /**
19882
+ * A durable operator-created Terminal instance. Profiles are templates; only
19883
+ * an instance declares a camera.
19884
+ */
19885
+ var TerminalInstanceInfoSchema = object({
19886
+ instanceId: string(),
19887
+ cameraStableId: string(),
19888
+ nodeId: string(),
19889
+ profileId: string(),
19890
+ profileLabel: string(),
19891
+ name: string(),
19892
+ enabled: boolean()
19893
+ });
19894
+ var TerminalLegacyCameraSchema = object({
19895
+ stableId: string(),
19896
+ nodeId: string(),
19897
+ profileId: string(),
19898
+ profileLabel: string(),
19899
+ name: string(),
19900
+ /** Only legacy monitor cameras can retain their historic stable identity. */
19901
+ adoptable: boolean()
19902
+ });
19778
19903
  var TerminalOutputEventSchema = discriminatedUnion("kind", [object({
19779
19904
  seq: number().int().positive(),
19780
19905
  kind: literal("data"),
@@ -19791,7 +19916,29 @@ var TerminalOutputBatchSchema = object({
19791
19916
  snapshot: string().optional(),
19792
19917
  events: array(TerminalOutputEventSchema).readonly()
19793
19918
  });
19794
- method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19919
+ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
19920
+ targetNodeId: string().min(1),
19921
+ profileId: string().min(1),
19922
+ name: string().trim().min(1).max(160).optional()
19923
+ }), TerminalInstanceInfoSchema, {
19924
+ kind: "mutation",
19925
+ auth: "admin"
19926
+ }), method(object({ instanceId: string().min(1) }), _void(), {
19927
+ kind: "mutation",
19928
+ auth: "admin"
19929
+ }), method(object({
19930
+ instanceId: string().min(1),
19931
+ enabled: boolean()
19932
+ }), TerminalInstanceInfoSchema, {
19933
+ kind: "mutation",
19934
+ auth: "admin"
19935
+ }), method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }), method(object({
19936
+ stableId: string().min(1),
19937
+ name: string().trim().min(1).max(160).optional()
19938
+ }), TerminalInstanceInfoSchema, {
19939
+ kind: "mutation",
19940
+ auth: "admin"
19941
+ }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19795
19942
  profileId: string(),
19796
19943
  cols: number().int().positive(),
19797
19944
  rows: number().int().positive()
@@ -19808,7 +19955,13 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
19808
19955
  }), method(object({
19809
19956
  sessionId: string(),
19810
19957
  afterSeq: number().int().nonnegative(),
19811
- waitMs: number().int().min(0).max(2e3).default(0)
19958
+ waitMs: number().int().min(0).max(2e3).default(0),
19959
+ /**
19960
+ * Wait when a just-opened session has no output yet. Kept opt-in so a
19961
+ * browser's initial repaint remains immediate; the camera snapshot
19962
+ * relay uses it to avoid encoding a blank startup frame.
19963
+ */
19964
+ waitForOutput: boolean().optional()
19812
19965
  }), TerminalOutputBatchSchema, {
19813
19966
  kind: "mutation",
19814
19967
  auth: "admin",
@@ -21749,6 +21902,7 @@ var FaceInfoSchema = object({
21749
21902
  var FaceFilterEnum = _enum([
21750
21903
  "unassigned",
21751
21904
  "recognized",
21905
+ "identified",
21752
21906
  "all"
21753
21907
  ]);
21754
21908
  var MediaFileLiteSchema$1 = object({
@@ -21777,6 +21931,8 @@ method(_void(), array(IdentitySchema).readonly()), method(object({ name: string(
21777
21931
  kind: "mutation",
21778
21932
  auth: "admin"
21779
21933
  }), method(object({
21934
+ /** Restrict to one camera. Absent keeps the cluster-wide gallery view. */
21935
+ deviceId: number().int().optional(),
21780
21936
  limit: number().int().positive().optional(),
21781
21937
  filter: FaceFilterEnum.optional(),
21782
21938
  /**
@@ -23542,6 +23698,10 @@ var OsdSourceSchema = discriminatedUnion("kind", [
23542
23698
  capName: string().min(1).max(64),
23543
23699
  /** Dot path inside the slice, e.g. `detected`, `value`, `mode`. */
23544
23700
  valuePath: string().min(1).max(64)
23701
+ }),
23702
+ object({
23703
+ kind: literal("latest-recognition"),
23704
+ recognition: _enum(["person", "plate"])
23545
23705
  })
23546
23706
  ]);
23547
23707
  var OsdSlotBindingSchema = object({
@@ -23647,6 +23807,15 @@ method(object({ deviceId: number().int() }), object({
23647
23807
  }), object({ success: literal(true) }), {
23648
23808
  kind: "mutation",
23649
23809
  auth: "admin"
23810
+ }), method(object({
23811
+ sourceDeviceId: number().int(),
23812
+ targetDeviceId: number().int()
23813
+ }), object({
23814
+ copied: number().int().nonnegative(),
23815
+ skipped: number().int().nonnegative()
23816
+ }), {
23817
+ kind: "mutation",
23818
+ auth: "admin"
23650
23819
  }), method(object({
23651
23820
  deviceId: number().int(),
23652
23821
  slotId: string().min(1),
@@ -24532,13 +24701,19 @@ method(object({
24532
24701
  }), {
24533
24702
  kind: "mutation",
24534
24703
  auth: "admin"
24535
- }), method(RelocateFootageInputSchema, object({ jobId: string() }), {
24704
+ }), method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
24536
24705
  kind: "mutation",
24537
24706
  auth: "admin"
24538
- }), method(object({}), array(RelocateJobSchema).readonly(), {
24539
- kind: "query",
24707
+ }), method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
24708
+ kind: "mutation",
24709
+ auth: "admin"
24710
+ }), method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
24711
+ kind: "mutation",
24540
24712
  auth: "admin"
24541
- }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
24713
+ }), method(StorageMigrationFootageMoveInputSchema, object({ jobId: string() }), {
24714
+ kind: "mutation",
24715
+ auth: "admin"
24716
+ }), method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
24542
24717
  kind: "mutation",
24543
24718
  auth: "admin"
24544
24719
  });
@@ -28737,6 +28912,12 @@ Object.freeze({
28737
28912
  addonId: null,
28738
28913
  access: "delete"
28739
28914
  },
28915
+ "osdManager.copyDeviceConfiguration": {
28916
+ capName: "osd-manager",
28917
+ capScope: "system",
28918
+ addonId: null,
28919
+ access: "create"
28920
+ },
28740
28921
  "osdManager.getConditionSupport": {
28741
28922
  capName: "osd-manager",
28742
28923
  capScope: "system",
@@ -28833,7 +29014,7 @@ Object.freeze({
28833
29014
  addonId: null,
28834
29015
  access: "create"
28835
29016
  },
28836
- "pipelineAnalytics.cancelMediaRelocate": {
29017
+ "pipelineAnalytics.cancelStorageMigrationMove": {
28837
29018
  capName: "pipeline-analytics",
28838
29019
  capScope: "device",
28839
29020
  addonId: null,
@@ -28905,12 +29086,6 @@ Object.freeze({
28905
29086
  addonId: null,
28906
29087
  access: "view"
28907
29088
  },
28908
- "pipelineAnalytics.getMediaRelocateStatus": {
28909
- capName: "pipeline-analytics",
28910
- capScope: "device",
28911
- addonId: null,
28912
- access: "view"
28913
- },
28914
29089
  "pipelineAnalytics.getMotionEvents": {
28915
29090
  capName: "pipeline-analytics",
28916
29091
  capScope: "device",
@@ -28947,6 +29122,12 @@ Object.freeze({
28947
29122
  addonId: null,
28948
29123
  access: "view"
28949
29124
  },
29125
+ "pipelineAnalytics.getStorageMigrationMoveStatus": {
29126
+ capName: "pipeline-analytics",
29127
+ capScope: "device",
29128
+ addonId: null,
29129
+ access: "view"
29130
+ },
28950
29131
  "pipelineAnalytics.getTrack": {
28951
29132
  capName: "pipeline-analytics",
28952
29133
  capScope: "device",
@@ -29025,6 +29206,12 @@ Object.freeze({
29025
29206
  addonId: null,
29026
29207
  access: "view"
29027
29208
  },
29209
+ "pipelineAnalytics.pauseForStorageMigration": {
29210
+ capName: "pipeline-analytics",
29211
+ capScope: "device",
29212
+ addonId: null,
29213
+ access: "create"
29214
+ },
29028
29215
  "pipelineAnalytics.proposeRetrainAnnotations": {
29029
29216
  capName: "pipeline-analytics",
29030
29217
  capScope: "device",
@@ -29055,7 +29242,7 @@ Object.freeze({
29055
29242
  addonId: null,
29056
29243
  access: "create"
29057
29244
  },
29058
- "pipelineAnalytics.relocateMedia": {
29245
+ "pipelineAnalytics.refreshStorageLocationsForMigration": {
29059
29246
  capName: "pipeline-analytics",
29060
29247
  capScope: "device",
29061
29248
  addonId: null,
@@ -29067,6 +29254,12 @@ Object.freeze({
29067
29254
  addonId: null,
29068
29255
  access: "create"
29069
29256
  },
29257
+ "pipelineAnalytics.resumeForStorageMigration": {
29258
+ capName: "pipeline-analytics",
29259
+ capScope: "device",
29260
+ addonId: null,
29261
+ access: "create"
29262
+ },
29070
29263
  "pipelineAnalytics.saveRetrainAnnotations": {
29071
29264
  capName: "pipeline-analytics",
29072
29265
  capScope: "device",
@@ -29091,6 +29284,12 @@ Object.freeze({
29091
29284
  addonId: null,
29092
29285
  access: "create"
29093
29286
  },
29287
+ "pipelineAnalytics.startStorageMigrationMove": {
29288
+ capName: "pipeline-analytics",
29289
+ capScope: "device",
29290
+ addonId: null,
29291
+ access: "create"
29292
+ },
29094
29293
  "pipelineAnalytics.wipeAllAnalytics": {
29095
29294
  capName: "pipeline-analytics",
29096
29295
  capScope: "device",
@@ -29457,6 +29656,12 @@ Object.freeze({
29457
29656
  addonId: null,
29458
29657
  access: "view"
29459
29658
  },
29659
+ "pipelineOrchestrator.pauseForStorageMigration": {
29660
+ capName: "pipeline-orchestrator",
29661
+ capScope: "system",
29662
+ addonId: null,
29663
+ access: "create"
29664
+ },
29460
29665
  "pipelineOrchestrator.rebalance": {
29461
29666
  capName: "pipeline-orchestrator",
29462
29667
  capScope: "system",
@@ -29481,6 +29686,12 @@ Object.freeze({
29481
29686
  addonId: null,
29482
29687
  access: "view"
29483
29688
  },
29689
+ "pipelineOrchestrator.resumeForStorageMigration": {
29690
+ capName: "pipeline-orchestrator",
29691
+ capScope: "system",
29692
+ addonId: null,
29693
+ access: "create"
29694
+ },
29484
29695
  "pipelineOrchestrator.saveTemplate": {
29485
29696
  capName: "pipeline-orchestrator",
29486
29697
  capScope: "system",
@@ -29877,7 +30088,7 @@ Object.freeze({
29877
30088
  addonId: null,
29878
30089
  access: "create"
29879
30090
  },
29880
- "recording.cancelRelocate": {
30091
+ "recording.cancelStorageMigrationMove": {
29881
30092
  capName: "recording",
29882
30093
  capScope: "system",
29883
30094
  addonId: null,
@@ -29913,7 +30124,7 @@ Object.freeze({
29913
30124
  addonId: null,
29914
30125
  access: "view"
29915
30126
  },
29916
- "recording.getRelocateStatus": {
30127
+ "recording.getStorageMigrationMoveStatus": {
29917
30128
  capName: "recording",
29918
30129
  capScope: "system",
29919
30130
  addonId: null,
@@ -29937,6 +30148,12 @@ Object.freeze({
29937
30148
  addonId: null,
29938
30149
  access: "view"
29939
30150
  },
30151
+ "recording.pauseForStorageMigration": {
30152
+ capName: "recording",
30153
+ capScope: "system",
30154
+ addonId: null,
30155
+ access: "create"
30156
+ },
29940
30157
  "recording.pruneFootage": {
29941
30158
  capName: "recording",
29942
30159
  capScope: "system",
@@ -29955,7 +30172,7 @@ Object.freeze({
29955
30172
  addonId: null,
29956
30173
  access: "view"
29957
30174
  },
29958
- "recording.relocateFootage": {
30175
+ "recording.refreshStorageLocationsForMigration": {
29959
30176
  capName: "recording",
29960
30177
  capScope: "system",
29961
30178
  addonId: null,
@@ -29979,12 +30196,24 @@ Object.freeze({
29979
30196
  addonId: null,
29980
30197
  access: "create"
29981
30198
  },
30199
+ "recording.resumeForStorageMigration": {
30200
+ capName: "recording",
30201
+ capScope: "system",
30202
+ addonId: null,
30203
+ access: "create"
30204
+ },
29982
30205
  "recording.setDeviceConfig": {
29983
30206
  capName: "recording",
29984
30207
  capScope: "system",
29985
30208
  addonId: null,
29986
30209
  access: "create"
29987
30210
  },
30211
+ "recording.startStorageMigrationMove": {
30212
+ capName: "recording",
30213
+ capScope: "system",
30214
+ addonId: null,
30215
+ access: "create"
30216
+ },
29988
30217
  "recordingExport.cancelExport": {
29989
30218
  capName: "recordingExport",
29990
30219
  capScope: "system",
@@ -30375,6 +30604,30 @@ Object.freeze({
30375
30604
  addonId: null,
30376
30605
  access: "view"
30377
30606
  },
30607
+ "storageMigration.cancel": {
30608
+ capName: "storage-migration",
30609
+ capScope: "system",
30610
+ addonId: null,
30611
+ access: "create"
30612
+ },
30613
+ "storageMigration.plan": {
30614
+ capName: "storage-migration",
30615
+ capScope: "system",
30616
+ addonId: null,
30617
+ access: "view"
30618
+ },
30619
+ "storageMigration.start": {
30620
+ capName: "storage-migration",
30621
+ capScope: "system",
30622
+ addonId: null,
30623
+ access: "create"
30624
+ },
30625
+ "storageMigration.status": {
30626
+ capName: "storage-migration",
30627
+ capScope: "system",
30628
+ addonId: null,
30629
+ access: "view"
30630
+ },
30378
30631
  "storageProvider.abortUpload": {
30379
30632
  capName: "storage-provider",
30380
30633
  capScope: "system",
@@ -30753,12 +31006,42 @@ Object.freeze({
30753
31006
  addonId: null,
30754
31007
  access: "create"
30755
31008
  },
31009
+ "terminalSession.adoptLegacyMonitor": {
31010
+ capName: "terminal-session",
31011
+ capScope: "system",
31012
+ addonId: null,
31013
+ access: "create"
31014
+ },
30756
31015
  "terminalSession.close": {
30757
31016
  capName: "terminal-session",
30758
31017
  capScope: "system",
30759
31018
  addonId: null,
30760
31019
  access: "create"
30761
31020
  },
31021
+ "terminalSession.createInstance": {
31022
+ capName: "terminal-session",
31023
+ capScope: "system",
31024
+ addonId: null,
31025
+ access: "create"
31026
+ },
31027
+ "terminalSession.deleteInstance": {
31028
+ capName: "terminal-session",
31029
+ capScope: "system",
31030
+ addonId: null,
31031
+ access: "delete"
31032
+ },
31033
+ "terminalSession.listInstances": {
31034
+ capName: "terminal-session",
31035
+ capScope: "system",
31036
+ addonId: null,
31037
+ access: "view"
31038
+ },
31039
+ "terminalSession.listLegacyCameras": {
31040
+ capName: "terminal-session",
31041
+ capScope: "system",
31042
+ addonId: null,
31043
+ access: "view"
31044
+ },
30762
31045
  "terminalSession.listProfiles": {
30763
31046
  capName: "terminal-session",
30764
31047
  capScope: "system",
@@ -30789,6 +31072,12 @@ Object.freeze({
30789
31072
  addonId: null,
30790
31073
  access: "create"
30791
31074
  },
31075
+ "terminalSession.setInstanceEnabled": {
31076
+ capName: "terminal-session",
31077
+ capScope: "system",
31078
+ addonId: null,
31079
+ access: "create"
31080
+ },
30792
31081
  "terminalSession.writeInput": {
30793
31082
  capName: "terminal-session",
30794
31083
  capScope: "system",
@@ -35743,11 +36032,17 @@ var PlacementService = class {
35743
36032
  deps;
35744
36033
  /** True while an auto-rebalance pass is running (skip overlap). */
35745
36034
  autoRebalanceInFlight = false;
36035
+ inFlightAttaches = 0;
36036
+ idleWaiters = [];
35746
36037
  constructor(deps) {
35747
36038
  this.deps = deps;
35748
36039
  }
35749
36040
  async dispatchCamera(runnerConfig) {
35750
36041
  if (!this.deps.ctx()) throw new Error("PipelineOrchestrator: dispatchCamera called before initialize");
36042
+ if (this.deps.maintenancePaused?.() === true) return {
36043
+ success: true,
36044
+ kind: "pending"
36045
+ };
35751
36046
  const currentDeviceKey = this.deps.ledger.getConfig(runnerConfig.deviceId)?.deviceKey ?? null;
35752
36047
  this.deps.ledger.setConfig(runnerConfig.deviceId, runnerConfig);
35753
36048
  if (this.deps.loadShed.dispatchDeferralCheck(runnerConfig.deviceId)) return {
@@ -36138,6 +36433,7 @@ var PlacementService = class {
36138
36433
  * an absent field would produce.
36139
36434
  */
36140
36435
  async attachOn(nodeId, config) {
36436
+ if (this.deps.maintenancePaused?.() === true) throw new Error("pipeline dispatch is paused for storage migration");
36141
36437
  const ctx = this.deps.ctx();
36142
36438
  const api = ctx.api;
36143
36439
  if (!api) throw new Error(`attachOn(${nodeId}, ${config.deviceId}): this.ctx.api not available`);
@@ -36172,6 +36468,7 @@ var PlacementService = class {
36172
36468
  meta: logMeta
36173
36469
  });
36174
36470
  }).catch(() => {});
36471
+ this.inFlightAttaches++;
36175
36472
  try {
36176
36473
  await api.pipelineRunner.attachCamera.mutate({
36177
36474
  ...config,
@@ -36201,8 +36498,17 @@ var PlacementService = class {
36201
36498
  });
36202
36499
  }
36203
36500
  throw err;
36501
+ } finally {
36502
+ this.inFlightAttaches--;
36503
+ if (this.inFlightAttaches === 0) for (const resolve of this.idleWaiters.splice(0)) resolve();
36204
36504
  }
36205
36505
  }
36506
+ /** Wait until every attach that began before the maintenance gate closed has
36507
+ * settled. New attaches are rejected at the top of `attachOn`. */
36508
+ waitForMigrationIdle() {
36509
+ if (this.inFlightAttaches === 0) return Promise.resolve();
36510
+ return new Promise((resolve) => this.idleWaiters.push(resolve));
36511
+ }
36206
36512
  async detachOn(nodeId, deviceId) {
36207
36513
  const api = this.deps.ctx().api;
36208
36514
  if (!api) return;
@@ -40099,7 +40405,8 @@ async function buildOrchestratorControllers(deps) {
40099
40405
  activeSessionNode: (deviceId) => session.activeSessionNode(deviceId),
40100
40406
  closeActiveSession: (deviceId) => session.closeSessionForReassign(deviceId),
40101
40407
  reconcilePlacementFromRunners: () => reconcile.reconcilePlacementFromRunners(),
40102
- emitResolvedCameraUpdated: (deviceId) => deps.emitResolvedCameraUpdated(deviceId)
40408
+ emitResolvedCameraUpdated: (deviceId) => deps.emitResolvedCameraUpdated(deviceId),
40409
+ maintenancePaused: () => deps.maintenancePaused()
40103
40410
  });
40104
40411
  const session = new SessionDispatchController({
40105
40412
  ledger,
@@ -41124,6 +41431,9 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
41124
41431
  /** Periodic auto-rebalance sweep timer (drift correction under hysteresis). */
41125
41432
  autoRebalanceTimer = null;
41126
41433
  initTimestamp = 0;
41434
+ /** Storage migration maintenance lease. It only gates dispatch; it does not
41435
+ * change any camera wrapper or persistent pipeline configuration. */
41436
+ storageMigrationLeaseId = null;
41127
41437
  constructor() {
41128
41438
  super({});
41129
41439
  }
@@ -41171,6 +41481,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
41171
41481
  rebalance: (opts) => this.rebalance(opts),
41172
41482
  setCameraPipelineForAgent: (input) => this.setCameraPipelineForAgent(input),
41173
41483
  dispatchCamera: (config) => this.dispatchCamera(config),
41484
+ maintenancePaused: () => this.storageMigrationLeaseId !== null,
41174
41485
  setTopology: (topology) => {
41175
41486
  this.topology = topology;
41176
41487
  },
@@ -41317,8 +41628,29 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
41317
41628
  this.settingsStore = null;
41318
41629
  }
41319
41630
  async dispatchCamera(runnerConfig) {
41631
+ if (this.storageMigrationLeaseId !== null) return {
41632
+ success: true,
41633
+ kind: "pending"
41634
+ };
41320
41635
  return this.placement.dispatchCamera(runnerConfig);
41321
41636
  }
41637
+ async pauseForStorageMigration(input) {
41638
+ if (this.storageMigrationLeaseId !== null && this.storageMigrationLeaseId !== input.leaseId) throw new Error("pipeline dispatch is already paused by another storage migration");
41639
+ this.storageMigrationLeaseId = input.leaseId;
41640
+ try {
41641
+ await this.placement.waitForMigrationIdle();
41642
+ return { paused: true };
41643
+ } catch (err) {
41644
+ this.storageMigrationLeaseId = null;
41645
+ throw err;
41646
+ }
41647
+ }
41648
+ async resumeForStorageMigration(input) {
41649
+ if (this.storageMigrationLeaseId === null) return { resumed: true };
41650
+ if (this.storageMigrationLeaseId !== input.leaseId) throw new Error("pipeline storage migration lease does not match");
41651
+ this.storageMigrationLeaseId = null;
41652
+ return { resumed: true };
41653
+ }
41322
41654
  async releaseCamera(input) {
41323
41655
  return this.placement.releaseCamera(input);
41324
41656
  }