camstack 1.2.69 → 1.2.71
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.
|
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
|
|
|
23633
23633
|
}
|
|
23634
23634
|
});
|
|
23635
23635
|
|
|
23636
|
-
// ../system/dist/dist-
|
|
23637
|
-
var
|
|
23638
|
-
"../system/dist/dist-
|
|
23636
|
+
// ../system/dist/dist-CFTKQGym.js
|
|
23637
|
+
var require_dist_CFTKQGym = __commonJS({
|
|
23638
|
+
"../system/dist/dist-CFTKQGym.js"(exports) {
|
|
23639
23639
|
"use strict";
|
|
23640
23640
|
var zod = require_zod();
|
|
23641
23641
|
var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
|
|
@@ -26326,6 +26326,13 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
26326
26326
|
]);
|
|
26327
26327
|
var RelocateMediaInputSchema = zod.z.object({
|
|
26328
26328
|
toLocationId: zod.z.string(),
|
|
26329
|
+
/**
|
|
26330
|
+
* Restrict the pass to rows currently on this location. Omitted / `'*'` =
|
|
26331
|
+
* every row that is not already on `toLocationId` (the historical
|
|
26332
|
+
* behaviour). A named source is what a from→to migration needs: without it
|
|
26333
|
+
* "move events off disk 2" also emptied disk 1.
|
|
26334
|
+
*/
|
|
26335
|
+
fromLocationId: zod.z.string().optional(),
|
|
26329
26336
|
throttleMbps: zod.z.number().min(1).max(1e3).optional(),
|
|
26330
26337
|
/** Omitted = `move`, the pre-existing behaviour. */
|
|
26331
26338
|
mode: MediaRelocateModeSchema.optional()
|
|
@@ -26357,9 +26364,18 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
26357
26364
|
backups: zod.z.string().min(1).optional(),
|
|
26358
26365
|
galleryMedia: zod.z.string().min(1).optional()
|
|
26359
26366
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
26367
|
+
var StorageMigrationSourcesSchema = zod.z.object({
|
|
26368
|
+
recordings: zod.z.string().min(1).optional(),
|
|
26369
|
+
recordingsLow: zod.z.string().min(1).optional(),
|
|
26370
|
+
eventMedia: zod.z.string().min(1).optional(),
|
|
26371
|
+
backups: zod.z.string().min(1).optional(),
|
|
26372
|
+
galleryMedia: zod.z.string().min(1).optional()
|
|
26373
|
+
}).optional();
|
|
26360
26374
|
var StorageMigrationModeSchema = zod.z.enum(["blocking", "nonBlocking"]);
|
|
26361
26375
|
var StorageMigrationInputSchema = zod.z.object({
|
|
26362
26376
|
destinations: StorageMigrationDestinationsSchema,
|
|
26377
|
+
/** Omitted = each class's current default. */
|
|
26378
|
+
sources: StorageMigrationSourcesSchema,
|
|
26363
26379
|
throttleMbps: zod.z.number().min(1).max(1e3).optional(),
|
|
26364
26380
|
/** Omitted = `blocking`, which stays the default. */
|
|
26365
26381
|
mode: StorageMigrationModeSchema.optional()
|
|
@@ -26405,6 +26421,13 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
26405
26421
|
storageClass: StorageMigrationClassSchema,
|
|
26406
26422
|
fromLocationId: zod.z.string(),
|
|
26407
26423
|
toLocationId: zod.z.string(),
|
|
26424
|
+
/**
|
|
26425
|
+
* True when `from` was NOT the class default at plan time. The move still
|
|
26426
|
+
* copies bytes, but the default is left alone and the source is disabled
|
|
26427
|
+
* once the copy verifies. Absent on jobs planned before this field existed
|
|
26428
|
+
* — those jobs always repointed, which is `false`.
|
|
26429
|
+
*/
|
|
26430
|
+
freezeSource: zod.z.boolean().optional(),
|
|
26408
26431
|
moverJobId: zod.z.string().nullable(),
|
|
26409
26432
|
state: RelocateJobStateSchema.nullable(),
|
|
26410
26433
|
error: zod.z.string().nullable(),
|
|
@@ -26418,6 +26441,7 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
26418
26441
|
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
26419
26442
|
mode: StorageMigrationModeSchema,
|
|
26420
26443
|
destinations: StorageMigrationDestinationsSchema,
|
|
26444
|
+
sources: StorageMigrationSourcesSchema,
|
|
26421
26445
|
throttleMbps: zod.z.number(),
|
|
26422
26446
|
moves: zod.z.array(StorageMigrationMoveSchema),
|
|
26423
26447
|
pauseLeaseId: zod.z.string().nullable(),
|
|
@@ -26444,6 +26468,7 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
26444
26468
|
});
|
|
26445
26469
|
var StorageMigrationPlanSchema = zod.z.object({
|
|
26446
26470
|
destinations: StorageMigrationDestinationsSchema,
|
|
26471
|
+
sources: StorageMigrationSourcesSchema,
|
|
26447
26472
|
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
26448
26473
|
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
26449
26474
|
* it. */
|
|
@@ -26451,7 +26476,8 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
26451
26476
|
moves: zod.z.array(zod.z.object({
|
|
26452
26477
|
storageClass: StorageMigrationClassSchema,
|
|
26453
26478
|
fromLocationId: zod.z.string(),
|
|
26454
|
-
toLocationId: zod.z.string()
|
|
26479
|
+
toLocationId: zod.z.string(),
|
|
26480
|
+
freezeSource: zod.z.boolean().optional()
|
|
26455
26481
|
})),
|
|
26456
26482
|
findings: zod.z.array(StorageMigrationFindingSchema)
|
|
26457
26483
|
});
|
|
@@ -26563,9 +26589,42 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
26563
26589
|
var RelocatableMediaCountSchema = zod.z.object({ rows: zod.z.number().int().nonnegative() }).nullable();
|
|
26564
26590
|
var RelocatableMediaCountInputSchema = zod.z.object({
|
|
26565
26591
|
toLocationId: zod.z.string().min(1),
|
|
26592
|
+
/** Restrict the count to one source; omitted / `'*'` = every non-target row. */
|
|
26593
|
+
fromLocationId: zod.z.string().optional(),
|
|
26566
26594
|
/** Omitted = `move`. */
|
|
26567
26595
|
mode: MediaRelocateModeSchema.optional()
|
|
26568
26596
|
});
|
|
26597
|
+
var StorageCleanupPhaseSchema = zod.z.enum([
|
|
26598
|
+
"orphans",
|
|
26599
|
+
"debug-media",
|
|
26600
|
+
"ghost-ledger",
|
|
26601
|
+
"done",
|
|
26602
|
+
"failed",
|
|
26603
|
+
"cancelled"
|
|
26604
|
+
]);
|
|
26605
|
+
var StorageCleanupInputSchema = zod.z.object({
|
|
26606
|
+
/** Also walk motion stills / track filmstrips. Off by default. */
|
|
26607
|
+
includeDebugMedia: zod.z.boolean().optional()
|
|
26608
|
+
});
|
|
26609
|
+
var StorageCleanupJobSchema = zod.z.object({
|
|
26610
|
+
jobId: zod.z.string(),
|
|
26611
|
+
phase: StorageCleanupPhaseSchema,
|
|
26612
|
+
includeDebugMedia: zod.z.boolean(),
|
|
26613
|
+
orphansReclaimed: zod.z.number().int().nonnegative(),
|
|
26614
|
+
orphanBytesReclaimed: zod.z.number().int().nonnegative(),
|
|
26615
|
+
debugMediaReclaimed: zod.z.number().int().nonnegative(),
|
|
26616
|
+
debugMediaBytesReclaimed: zod.z.number().int().nonnegative(),
|
|
26617
|
+
ghostsForgotten: zod.z.number().int().nonnegative(),
|
|
26618
|
+
ghostBytesForgotten: zod.z.number().int().nonnegative(),
|
|
26619
|
+
/** Short operator-facing line: current collection, pass, or location. */
|
|
26620
|
+
detail: zod.z.string().nullable(),
|
|
26621
|
+
cancelRequested: zod.z.boolean(),
|
|
26622
|
+
startedAt: zod.z.number(),
|
|
26623
|
+
updatedAt: zod.z.number(),
|
|
26624
|
+
finishedAt: zod.z.number().nullable(),
|
|
26625
|
+
error: zod.z.string().nullable()
|
|
26626
|
+
});
|
|
26627
|
+
var StorageCleanupStatusInputSchema = zod.z.object({ jobId: zod.z.string().optional() });
|
|
26569
26628
|
var StorageLocationTypeSchema = zod.z.string().regex(/^[a-z][a-zA-Z0-9-]*$/);
|
|
26570
26629
|
var StorageLocationSchema = zod.z.object({
|
|
26571
26630
|
id: zod.z.string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
|
|
@@ -37286,6 +37345,39 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
37286
37345
|
/** Present when the pass ended by throwing. */
|
|
37287
37346
|
error: zod.z.string().nullable()
|
|
37288
37347
|
});
|
|
37348
|
+
var MediaReclaimStartResultSchema = zod.z.object({
|
|
37349
|
+
started: zod.z.boolean(),
|
|
37350
|
+
/** True when a pass was already running; the new request is ignored. */
|
|
37351
|
+
alreadyRunning: zod.z.boolean()
|
|
37352
|
+
});
|
|
37353
|
+
var MediaReclaimInputSchema = zod.z.object({
|
|
37354
|
+
mode: zod.z.enum(["report", "reclaim"]).default("report"),
|
|
37355
|
+
scopes: zod.z.array(zod.z.enum(["motion-still", "track-filmstrip"])).min(1).optional(),
|
|
37356
|
+
deviceIds: zod.z.array(zod.z.number().int()).min(1).optional(),
|
|
37357
|
+
restart: zod.z.boolean().optional(),
|
|
37358
|
+
pageSize: zod.z.number().int().min(50).max(5e3).optional(),
|
|
37359
|
+
maxRowsPerDevice: zod.z.number().int().min(1).max(5e5).optional(),
|
|
37360
|
+
maxReclaimPerDevice: zod.z.number().int().min(1).max(5e5).optional(),
|
|
37361
|
+
maxBytesPerRun: zod.z.number().int().min(1).optional(),
|
|
37362
|
+
budgetMinutes: zod.z.number().int().min(1).max(720).optional(),
|
|
37363
|
+
throttleBytesPerSec: zod.z.number().int().min(64 * 1024).optional(),
|
|
37364
|
+
graceMinutes: zod.z.number().int().min(1).max(10080).optional()
|
|
37365
|
+
});
|
|
37366
|
+
var MediaReclaimStatusSchema = zod.z.object({
|
|
37367
|
+
running: zod.z.boolean(),
|
|
37368
|
+
mode: zod.z.enum(["report", "reclaim"]).nullable(),
|
|
37369
|
+
totalExamined: zod.z.number(),
|
|
37370
|
+
totalEligible: zod.z.number(),
|
|
37371
|
+
totalReclaimed: zod.z.number(),
|
|
37372
|
+
totalBytesReclaimed: zod.z.number(),
|
|
37373
|
+
totalRefused: zod.z.number(),
|
|
37374
|
+
/** Device+scope windows finished in this pass. */
|
|
37375
|
+
devicesDone: zod.z.number(),
|
|
37376
|
+
complete: zod.z.boolean().nullable(),
|
|
37377
|
+
startedAtMs: zod.z.number().nullable(),
|
|
37378
|
+
finishedAtMs: zod.z.number().nullable(),
|
|
37379
|
+
error: zod.z.string().nullable()
|
|
37380
|
+
});
|
|
37289
37381
|
var ReplayFrameInputSchema = zod.z.object({
|
|
37290
37382
|
timestamp: zod.z.number(),
|
|
37291
37383
|
frame: PipelineRunResultBridge
|
|
@@ -37709,6 +37801,20 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
37709
37801
|
auth: "admin"
|
|
37710
37802
|
}),
|
|
37711
37803
|
/**
|
|
37804
|
+
* Reclaim the standing debug-media backlog (motion-visit stills + track
|
|
37805
|
+
* filmstrips). DETACHED: returns `{ started }` immediately. The pass is
|
|
37806
|
+
* tens of minutes; awaiting it is a timeout, not a verdict. Dry-run unless
|
|
37807
|
+
* `mode: 'reclaim'`. Poll `getMediaReclaimStatus`.
|
|
37808
|
+
*/
|
|
37809
|
+
reclaimDebugMedia: method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
|
|
37810
|
+
kind: "mutation",
|
|
37811
|
+
auth: "admin"
|
|
37812
|
+
}),
|
|
37813
|
+
getMediaReclaimStatus: method(zod.z.object({}), MediaReclaimStatusSchema, {
|
|
37814
|
+
kind: "query",
|
|
37815
|
+
auth: "admin"
|
|
37816
|
+
}),
|
|
37817
|
+
/**
|
|
37712
37818
|
* The CHEAP QUESTION, asked before any media moves: how big is the dataset
|
|
37713
37819
|
* the marked (`markForTrain`) tracks would produce?
|
|
37714
37820
|
*
|
|
@@ -40296,7 +40402,23 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
40296
40402
|
drain: method(StorageMigrationDrainInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
40297
40403
|
kind: "mutation",
|
|
40298
40404
|
auth: "admin"
|
|
40299
|
-
})
|
|
40405
|
+
}),
|
|
40406
|
+
/**
|
|
40407
|
+
* One operator cleanup of leftover analytics (DB + blobs) and ghost
|
|
40408
|
+
* ledger rows on frozen footage locations. Optional debug-media sweep.
|
|
40409
|
+
* Returns immediately; poll {@link cleanupStatus}.
|
|
40410
|
+
*/
|
|
40411
|
+
cleanupStart: method(StorageCleanupInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
40412
|
+
kind: "mutation",
|
|
40413
|
+
auth: "admin"
|
|
40414
|
+
}),
|
|
40415
|
+
cleanupStatus: method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }),
|
|
40416
|
+
cleanupCancel: method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
|
|
40417
|
+
kind: "mutation",
|
|
40418
|
+
auth: "admin"
|
|
40419
|
+
}),
|
|
40420
|
+
/** Recent finished migration jobs, newest first. The live job is `status`. */
|
|
40421
|
+
history: method(zod.z.object({}), zod.z.array(StorageMigrationJobSchema).readonly(), { auth: "admin" })
|
|
40300
40422
|
}
|
|
40301
40423
|
};
|
|
40302
40424
|
var ProviderInfoSchema = zod.z.discriminatedUnion("shouldSaveDiskSpace", [zod.z.object({
|
|
@@ -47088,6 +47210,26 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
47088
47210
|
/** Ignore piles smaller than this (default 1 GB). */
|
|
47089
47211
|
minMoveGb: zod.z.number().min(0).optional()
|
|
47090
47212
|
});
|
|
47213
|
+
var RecordingDevicePlacementSchema = zod.z.object({
|
|
47214
|
+
deviceId: zod.z.number().int(),
|
|
47215
|
+
profile: zod.z.string(),
|
|
47216
|
+
locationId: zod.z.string()
|
|
47217
|
+
});
|
|
47218
|
+
var RecordingDevicePinSchema = zod.z.object({
|
|
47219
|
+
deviceId: zod.z.number().int(),
|
|
47220
|
+
/** Recordings-class location this camera is pinned to. */
|
|
47221
|
+
locationId: zod.z.string()
|
|
47222
|
+
});
|
|
47223
|
+
var RecordingPlacementViewSchema = zod.z.object({
|
|
47224
|
+
assignments: zod.z.array(RecordingDevicePlacementSchema),
|
|
47225
|
+
pins: zod.z.array(RecordingDevicePinSchema),
|
|
47226
|
+
defaultLocations: zod.z.record(zod.z.string(), zod.z.string())
|
|
47227
|
+
});
|
|
47228
|
+
var RecordingSetDevicePlacementInputSchema = zod.z.object({
|
|
47229
|
+
deviceId: zod.z.number().int(),
|
|
47230
|
+
/** `null` = Auto. Otherwise a `recordings:*` location id. */
|
|
47231
|
+
locationId: zod.z.string().nullable()
|
|
47232
|
+
});
|
|
47091
47233
|
var LocateSegmentResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
|
|
47092
47234
|
kind: zod.z.literal("segment"),
|
|
47093
47235
|
startMs: zod.z.number(),
|
|
@@ -47406,6 +47548,22 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
47406
47548
|
startStorageRebalance: method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
|
|
47407
47549
|
kind: "mutation",
|
|
47408
47550
|
auth: "admin"
|
|
47551
|
+
}),
|
|
47552
|
+
/**
|
|
47553
|
+
* The placement plan in force plus operator pins. Drives the Locations
|
|
47554
|
+
* admin page: Auto vs a named recordings location, per camera.
|
|
47555
|
+
*/
|
|
47556
|
+
getPlacement: method(zod.z.object({}), RecordingPlacementViewSchema, {
|
|
47557
|
+
kind: "query",
|
|
47558
|
+
auth: "admin"
|
|
47559
|
+
}),
|
|
47560
|
+
/**
|
|
47561
|
+
* Pin a camera to a recordings location, or clear the pin (Auto). High and
|
|
47562
|
+
* mid follow the pin; low stays with the recordingsLow planner.
|
|
47563
|
+
*/
|
|
47564
|
+
setDevicePlacement: method(RecordingSetDevicePlacementInputSchema, zod.z.object({ ok: zod.z.literal(true) }), {
|
|
47565
|
+
kind: "mutation",
|
|
47566
|
+
auth: "admin"
|
|
47409
47567
|
})
|
|
47410
47568
|
}
|
|
47411
47569
|
};
|
|
@@ -53519,6 +53677,12 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
53519
53677
|
addonId: null,
|
|
53520
53678
|
access: "view"
|
|
53521
53679
|
},
|
|
53680
|
+
"pipelineAnalytics.getMediaReclaimStatus": {
|
|
53681
|
+
capName: "pipeline-analytics",
|
|
53682
|
+
capScope: "device",
|
|
53683
|
+
addonId: null,
|
|
53684
|
+
access: "view"
|
|
53685
|
+
},
|
|
53522
53686
|
"pipelineAnalytics.getMotionEvents": {
|
|
53523
53687
|
capName: "pipeline-analytics",
|
|
53524
53688
|
capScope: "device",
|
|
@@ -53693,6 +53857,12 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
53693
53857
|
addonId: null,
|
|
53694
53858
|
access: "create"
|
|
53695
53859
|
},
|
|
53860
|
+
"pipelineAnalytics.reclaimDebugMedia": {
|
|
53861
|
+
capName: "pipeline-analytics",
|
|
53862
|
+
capScope: "device",
|
|
53863
|
+
addonId: null,
|
|
53864
|
+
access: "create"
|
|
53865
|
+
},
|
|
53696
53866
|
"pipelineAnalytics.reconcileFromDisk": {
|
|
53697
53867
|
capName: "pipeline-analytics",
|
|
53698
53868
|
capScope: "device",
|
|
@@ -54617,6 +54787,12 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
54617
54787
|
addonId: null,
|
|
54618
54788
|
access: "view"
|
|
54619
54789
|
},
|
|
54790
|
+
"recording.getPlacement": {
|
|
54791
|
+
capName: "recording",
|
|
54792
|
+
capScope: "system",
|
|
54793
|
+
addonId: null,
|
|
54794
|
+
access: "view"
|
|
54795
|
+
},
|
|
54620
54796
|
"recording.getPlaybackManifest": {
|
|
54621
54797
|
capName: "recording",
|
|
54622
54798
|
capScope: "system",
|
|
@@ -54743,6 +54919,12 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
54743
54919
|
addonId: null,
|
|
54744
54920
|
access: "create"
|
|
54745
54921
|
},
|
|
54922
|
+
"recording.setDevicePlacement": {
|
|
54923
|
+
capName: "recording",
|
|
54924
|
+
capScope: "system",
|
|
54925
|
+
addonId: null,
|
|
54926
|
+
access: "create"
|
|
54927
|
+
},
|
|
54746
54928
|
"recording.startStorageMigrationMove": {
|
|
54747
54929
|
capName: "recording",
|
|
54748
54930
|
capScope: "system",
|
|
@@ -55187,12 +55369,36 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
55187
55369
|
addonId: null,
|
|
55188
55370
|
access: "create"
|
|
55189
55371
|
},
|
|
55372
|
+
"storageMigration.cleanupCancel": {
|
|
55373
|
+
capName: "storage-migration",
|
|
55374
|
+
capScope: "system",
|
|
55375
|
+
addonId: null,
|
|
55376
|
+
access: "create"
|
|
55377
|
+
},
|
|
55378
|
+
"storageMigration.cleanupStart": {
|
|
55379
|
+
capName: "storage-migration",
|
|
55380
|
+
capScope: "system",
|
|
55381
|
+
addonId: null,
|
|
55382
|
+
access: "create"
|
|
55383
|
+
},
|
|
55384
|
+
"storageMigration.cleanupStatus": {
|
|
55385
|
+
capName: "storage-migration",
|
|
55386
|
+
capScope: "system",
|
|
55387
|
+
addonId: null,
|
|
55388
|
+
access: "view"
|
|
55389
|
+
},
|
|
55190
55390
|
"storageMigration.drain": {
|
|
55191
55391
|
capName: "storage-migration",
|
|
55192
55392
|
capScope: "system",
|
|
55193
55393
|
addonId: null,
|
|
55194
55394
|
access: "create"
|
|
55195
55395
|
},
|
|
55396
|
+
"storageMigration.history": {
|
|
55397
|
+
capName: "storage-migration",
|
|
55398
|
+
capScope: "system",
|
|
55399
|
+
addonId: null,
|
|
55400
|
+
access: "view"
|
|
55401
|
+
},
|
|
55196
55402
|
"storageMigration.movers": {
|
|
55197
55403
|
capName: "storage-migration",
|
|
55198
55404
|
capScope: "system",
|
|
@@ -57309,6 +57515,11 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
57309
57515
|
form: "single",
|
|
57310
57516
|
optional: true
|
|
57311
57517
|
}],
|
|
57518
|
+
"pipelineAnalytics.reclaimDebugMedia": [{
|
|
57519
|
+
name: "deviceIds",
|
|
57520
|
+
form: "array",
|
|
57521
|
+
optional: true
|
|
57522
|
+
}],
|
|
57312
57523
|
"pipelineAnalytics.reconcileFromDisk": [{
|
|
57313
57524
|
name: "deviceId",
|
|
57314
57525
|
form: "single",
|
|
@@ -57674,6 +57885,11 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
57674
57885
|
form: "single",
|
|
57675
57886
|
optional: false
|
|
57676
57887
|
}],
|
|
57888
|
+
"recording.setDevicePlacement": [{
|
|
57889
|
+
name: "deviceId",
|
|
57890
|
+
form: "single",
|
|
57891
|
+
optional: false
|
|
57892
|
+
}],
|
|
57677
57893
|
"recording.startStorageMigrationMove": [{
|
|
57678
57894
|
name: "deviceId",
|
|
57679
57895
|
form: "single",
|
|
@@ -58914,6 +59130,12 @@ var require_dist_B29Skpzo = __commonJS({
|
|
|
58914
59130
|
return ScopedTokenSchema;
|
|
58915
59131
|
}
|
|
58916
59132
|
});
|
|
59133
|
+
Object.defineProperty(exports, "StorageCleanupJobSchema", {
|
|
59134
|
+
enumerable: true,
|
|
59135
|
+
get: function() {
|
|
59136
|
+
return StorageCleanupJobSchema;
|
|
59137
|
+
}
|
|
59138
|
+
});
|
|
58917
59139
|
Object.defineProperty(exports, "StorageLocationTypeSchema", {
|
|
58918
59140
|
enumerable: true,
|
|
58919
59141
|
get: function() {
|
|
@@ -59418,7 +59640,7 @@ var require_alerts_addon = __commonJS({
|
|
|
59418
59640
|
[Symbol.toStringTag]: { value: "Module" }
|
|
59419
59641
|
});
|
|
59420
59642
|
require_chunk_Cek0wNdY();
|
|
59421
|
-
var require_dist10 =
|
|
59643
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
59422
59644
|
function selectExpired(alerts, cutoffMs) {
|
|
59423
59645
|
return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
|
|
59424
59646
|
}
|
|
@@ -60237,7 +60459,7 @@ var require_console_logging = __commonJS({
|
|
|
60237
60459
|
[Symbol.toStringTag]: { value: "Module" }
|
|
60238
60460
|
});
|
|
60239
60461
|
require_chunk_Cek0wNdY();
|
|
60240
|
-
var require_dist10 =
|
|
60462
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
60241
60463
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
60242
60464
|
var LEVEL_RANK = {
|
|
60243
60465
|
debug: 0,
|
|
@@ -60331,7 +60553,7 @@ var require_core_blocks_addon = __commonJS({
|
|
|
60331
60553
|
"use strict";
|
|
60332
60554
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
60333
60555
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
60334
|
-
var require_dist10 =
|
|
60556
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
60335
60557
|
var node_crypto = __require("crypto");
|
|
60336
60558
|
var node_fs_promises = __require("fs/promises");
|
|
60337
60559
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -61228,11 +61450,11 @@ var require_core_blocks = __commonJS({
|
|
|
61228
61450
|
}
|
|
61229
61451
|
});
|
|
61230
61452
|
|
|
61231
|
-
// ../system/dist/retired-settings-keys-
|
|
61232
|
-
var
|
|
61233
|
-
"../system/dist/retired-settings-keys-
|
|
61453
|
+
// ../system/dist/retired-settings-keys-dehyu2N3.js
|
|
61454
|
+
var require_retired_settings_keys_dehyu2N3 = __commonJS({
|
|
61455
|
+
"../system/dist/retired-settings-keys-dehyu2N3.js"(exports) {
|
|
61234
61456
|
"use strict";
|
|
61235
|
-
var require_dist10 =
|
|
61457
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
61236
61458
|
function settingsStoreIsAuthoritativeHere(env) {
|
|
61237
61459
|
const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
|
|
61238
61460
|
return raw === "" || raw === "hub";
|
|
@@ -63446,8 +63668,8 @@ var require_device_manager_addon = __commonJS({
|
|
|
63446
63668
|
[Symbol.toStringTag]: { value: "Module" }
|
|
63447
63669
|
});
|
|
63448
63670
|
require_chunk_Cek0wNdY();
|
|
63449
|
-
var require_dist10 =
|
|
63450
|
-
var require_retired_settings_keys =
|
|
63671
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
63672
|
+
var require_retired_settings_keys = require_retired_settings_keys_dehyu2N3();
|
|
63451
63673
|
var node_crypto = __require("crypto");
|
|
63452
63674
|
var _camstack_types_node = require_node();
|
|
63453
63675
|
var JOB_HISTORY = 20;
|
|
@@ -64425,6 +64647,9 @@ var require_device_manager_addon = __commonJS({
|
|
|
64425
64647
|
for (const f of features) if (DEVICE_FEATURE_VALUES.has(f)) out.push(f);
|
|
64426
64648
|
return out;
|
|
64427
64649
|
}
|
|
64650
|
+
function persistedIsCamera(type) {
|
|
64651
|
+
return type === require_dist10.DeviceType.Camera;
|
|
64652
|
+
}
|
|
64428
64653
|
function buildSourceInfoFromConfig(persistedConfig, stableId, addonId) {
|
|
64429
64654
|
const id = typeof persistedConfig["entityId"] === "string" ? persistedConfig["entityId"] : void 0;
|
|
64430
64655
|
const system = typeof persistedConfig["system"] === "string" ? persistedConfig["system"] : void 0;
|
|
@@ -64571,7 +64796,7 @@ var require_device_manager_addon = __commonJS({
|
|
|
64571
64796
|
online: pctx.host.resolveDeviceOnline(m.id, pctx.registry !== null),
|
|
64572
64797
|
probed: pctx.host.resolveDeviceProbed(m.id),
|
|
64573
64798
|
features: persistedFeatures(m.features),
|
|
64574
|
-
isCamera: persistedType
|
|
64799
|
+
isCamera: persistedIsCamera(persistedType),
|
|
64575
64800
|
config: persistedConfig ?? {},
|
|
64576
64801
|
metadata,
|
|
64577
64802
|
...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
|
|
@@ -64616,7 +64841,7 @@ var require_device_manager_addon = __commonJS({
|
|
|
64616
64841
|
online: pctx.host.resolveDeviceOnline(deviceId, true),
|
|
64617
64842
|
probed: pctx.host.resolveDeviceProbed(deviceId),
|
|
64618
64843
|
features: persistedFeatures(m.features),
|
|
64619
|
-
isCamera:
|
|
64844
|
+
isCamera: persistedIsCamera(m.type),
|
|
64620
64845
|
config: persistedConfig ?? {},
|
|
64621
64846
|
metadata,
|
|
64622
64847
|
...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
|
|
@@ -64664,7 +64889,7 @@ var require_device_manager_addon = __commonJS({
|
|
|
64664
64889
|
online: pctx.host.resolveDeviceOnline(m.id, pctx.registry !== null),
|
|
64665
64890
|
probed: pctx.host.resolveDeviceProbed(m.id),
|
|
64666
64891
|
features: persistedFeatures(m.features),
|
|
64667
|
-
isCamera:
|
|
64892
|
+
isCamera: persistedIsCamera(m.type),
|
|
64668
64893
|
config: persistedConfig,
|
|
64669
64894
|
metadata,
|
|
64670
64895
|
...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
|
|
@@ -68260,7 +68485,7 @@ var require_hub_forwarder = __commonJS({
|
|
|
68260
68485
|
[Symbol.toStringTag]: { value: "Module" }
|
|
68261
68486
|
});
|
|
68262
68487
|
require_chunk_Cek0wNdY();
|
|
68263
|
-
var require_dist10 =
|
|
68488
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
68264
68489
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
68265
68490
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
68266
68491
|
var HubForwarderDestination = class {
|
|
@@ -68397,7 +68622,7 @@ var require_liveness_monitor_addon = __commonJS({
|
|
|
68397
68622
|
"use strict";
|
|
68398
68623
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
68399
68624
|
require_chunk_Cek0wNdY();
|
|
68400
|
-
var require_dist10 =
|
|
68625
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
68401
68626
|
var NO_DEVICES = "liveness:no-devices";
|
|
68402
68627
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
68403
68628
|
var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
|
|
@@ -68587,7 +68812,7 @@ var require_local_auth_addon = __commonJS({
|
|
|
68587
68812
|
[Symbol.toStringTag]: { value: "Module" }
|
|
68588
68813
|
});
|
|
68589
68814
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
68590
|
-
var require_dist10 =
|
|
68815
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
68591
68816
|
var node_crypto = __require("crypto");
|
|
68592
68817
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
68593
68818
|
var crypto$1 = __require("crypto");
|
|
@@ -76400,7 +76625,7 @@ var require_loki_logging = __commonJS({
|
|
|
76400
76625
|
[Symbol.toStringTag]: { value: "Module" }
|
|
76401
76626
|
});
|
|
76402
76627
|
require_chunk_Cek0wNdY();
|
|
76403
|
-
var require_dist10 =
|
|
76628
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
76404
76629
|
function sanitizeLabelName(raw) {
|
|
76405
76630
|
const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
|
|
76406
76631
|
return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
|
|
@@ -76965,7 +77190,7 @@ var require_native_metrics_addon = __commonJS({
|
|
|
76965
77190
|
[Symbol.toStringTag]: { value: "Module" }
|
|
76966
77191
|
});
|
|
76967
77192
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
76968
|
-
var require_dist10 =
|
|
77193
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
76969
77194
|
var node_fs_promises = __require("fs/promises");
|
|
76970
77195
|
var node_child_process = __require("child_process");
|
|
76971
77196
|
var node_util = __require("util");
|
|
@@ -79587,7 +79812,7 @@ var require_filesystem_storage_addon = __commonJS({
|
|
|
79587
79812
|
[Symbol.toStringTag]: { value: "Module" }
|
|
79588
79813
|
});
|
|
79589
79814
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
79590
|
-
var require_dist10 =
|
|
79815
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
79591
79816
|
var node_crypto = __require("crypto");
|
|
79592
79817
|
var node_fs_promises = __require("fs/promises");
|
|
79593
79818
|
var node_path = __require("path");
|
|
@@ -80703,8 +80928,8 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
80703
80928
|
[Symbol.toStringTag]: { value: "Module" }
|
|
80704
80929
|
});
|
|
80705
80930
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
80706
|
-
var require_dist10 =
|
|
80707
|
-
var require_retired_settings_keys =
|
|
80931
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
80932
|
+
var require_retired_settings_keys = require_retired_settings_keys_dehyu2N3();
|
|
80708
80933
|
var node_crypto = __require("crypto");
|
|
80709
80934
|
var node_fs = __require("fs");
|
|
80710
80935
|
var node_module = __require("module");
|
|
@@ -80740,6 +80965,14 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
80740
80965
|
var SQLITE_PROFILE_REPORT_INTERVAL_MS = 6e4;
|
|
80741
80966
|
var SQLITE_PROFILE_REPORT_FLOOR_MS = 250;
|
|
80742
80967
|
var SQLITE_PROFILE_TOP_N = 5;
|
|
80968
|
+
var SQLITE_ENGINE_STORM_WALL_SHARE = 0.5;
|
|
80969
|
+
function sqliteEngineStorm(stats, windowMs) {
|
|
80970
|
+
if (windowMs <= 0) return null;
|
|
80971
|
+
const top = stats[0];
|
|
80972
|
+
if (top === void 0) return null;
|
|
80973
|
+
if (top.totalMs / windowMs < 0.5) return null;
|
|
80974
|
+
return top;
|
|
80975
|
+
}
|
|
80743
80976
|
function rowsOf(value) {
|
|
80744
80977
|
if (Array.isArray(value)) return value.length;
|
|
80745
80978
|
if (value === void 0 || value === null) return 0;
|
|
@@ -80874,21 +81107,39 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
80874
81107
|
const stats = this.drain();
|
|
80875
81108
|
const busyMs = stats.reduce((acc, s) => acc + s.totalMs, 0);
|
|
80876
81109
|
if (busyMs < this.reportFloorMs) return;
|
|
81110
|
+
const busyPct = Math.round(busyMs / windowMs * 100);
|
|
81111
|
+
const calls = stats.reduce((acc, s) => acc + s.calls, 0);
|
|
81112
|
+
const top = stats.slice(0, this.topN).map((s) => ({
|
|
81113
|
+
op: s.op,
|
|
81114
|
+
collection: s.collection,
|
|
81115
|
+
...s.owner === void 0 ? {} : { owner: s.owner },
|
|
81116
|
+
...s.shape === void 0 ? {} : { shape: s.shape },
|
|
81117
|
+
calls: s.calls,
|
|
81118
|
+
totalMs: Math.round(s.totalMs),
|
|
81119
|
+
maxMs: Math.round(s.maxMs),
|
|
81120
|
+
rows: s.rows
|
|
81121
|
+
}));
|
|
80877
81122
|
this.logger.info("sqlite engine busy", { meta: {
|
|
80878
81123
|
busyMs: Math.round(busyMs),
|
|
80879
81124
|
windowMs: Math.round(windowMs),
|
|
80880
|
-
busyPct
|
|
80881
|
-
calls
|
|
80882
|
-
top
|
|
80883
|
-
|
|
80884
|
-
|
|
80885
|
-
|
|
80886
|
-
|
|
80887
|
-
|
|
80888
|
-
|
|
80889
|
-
|
|
80890
|
-
|
|
80891
|
-
|
|
81125
|
+
busyPct,
|
|
81126
|
+
calls,
|
|
81127
|
+
top
|
|
81128
|
+
} });
|
|
81129
|
+
const storm = sqliteEngineStorm(stats, windowMs);
|
|
81130
|
+
if (storm !== null) this.logger.warn("sqlite engine storm", { meta: {
|
|
81131
|
+
busyMs: Math.round(busyMs),
|
|
81132
|
+
windowMs: Math.round(windowMs),
|
|
81133
|
+
busyPct,
|
|
81134
|
+
wallPct: Math.round(storm.totalMs / windowMs * 100),
|
|
81135
|
+
op: storm.op,
|
|
81136
|
+
collection: storm.collection,
|
|
81137
|
+
...storm.owner === void 0 ? {} : { owner: storm.owner },
|
|
81138
|
+
...storm.shape === void 0 ? {} : { shape: storm.shape },
|
|
81139
|
+
calls: storm.calls,
|
|
81140
|
+
totalMs: Math.round(storm.totalMs),
|
|
81141
|
+
maxMs: Math.round(storm.maxMs),
|
|
81142
|
+
rows: storm.rows
|
|
80892
81143
|
} });
|
|
80893
81144
|
}
|
|
80894
81145
|
start() {
|
|
@@ -82968,6 +83219,7 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
82968
83219
|
return this.vectorIndex;
|
|
82969
83220
|
}
|
|
82970
83221
|
};
|
|
83222
|
+
exports.SQLITE_ENGINE_STORM_WALL_SHARE = SQLITE_ENGINE_STORM_WALL_SHARE;
|
|
82971
83223
|
exports.SQLITE_JOURNAL_SIZE_LIMIT_BYTES = SQLITE_JOURNAL_SIZE_LIMIT_BYTES;
|
|
82972
83224
|
exports.SQLITE_MMAP_CEILING_BYTES = SQLITE_MMAP_CEILING_BYTES;
|
|
82973
83225
|
exports.SQLITE_MMAP_FLOOR_BYTES = SQLITE_MMAP_FLOOR_BYTES;
|
|
@@ -82987,6 +83239,7 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
82987
83239
|
exports.WAL_MAINTENANCE_INTERVAL_MS = WAL_MAINTENANCE_INTERVAL_MS;
|
|
82988
83240
|
exports.WalMaintenance = WalMaintenance;
|
|
82989
83241
|
exports.prefixRange = prefixRange;
|
|
83242
|
+
exports.sqliteEngineStorm = sqliteEngineStorm;
|
|
82990
83243
|
exports.sqliteMmapSizeFor = sqliteMmapSizeFor;
|
|
82991
83244
|
exports.sqlitePageCacheKibFor = sqlitePageCacheKibFor;
|
|
82992
83245
|
}
|
|
@@ -83051,6 +83304,7 @@ var require_sqlite_storage = __commonJS({
|
|
|
83051
83304
|
exports.DeviceStore$1 = DeviceStore;
|
|
83052
83305
|
exports.FilesystemStorageAddon = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageAddon;
|
|
83053
83306
|
exports.FilesystemStorageProvider = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageProvider;
|
|
83307
|
+
exports.SQLITE_ENGINE_STORM_WALL_SHARE = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_ENGINE_STORM_WALL_SHARE;
|
|
83054
83308
|
exports.SQLITE_JOURNAL_SIZE_LIMIT_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_JOURNAL_SIZE_LIMIT_BYTES;
|
|
83055
83309
|
exports.SQLITE_MMAP_CEILING_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_MMAP_CEILING_BYTES;
|
|
83056
83310
|
exports.SQLITE_MMAP_FLOOR_BYTES = require_builtins_sqlite_storage_sqlite_settings_addon.SQLITE_MMAP_FLOOR_BYTES;
|
|
@@ -83069,6 +83323,7 @@ var require_sqlite_storage = __commonJS({
|
|
|
83069
83323
|
exports.WAL_MAINTENANCE_INTERVAL_MS = require_builtins_sqlite_storage_sqlite_settings_addon.WAL_MAINTENANCE_INTERVAL_MS;
|
|
83070
83324
|
exports.WalMaintenance = require_builtins_sqlite_storage_sqlite_settings_addon.WalMaintenance;
|
|
83071
83325
|
exports.default = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageAddon;
|
|
83326
|
+
exports.sqliteEngineStorm = require_builtins_sqlite_storage_sqlite_settings_addon.sqliteEngineStorm;
|
|
83072
83327
|
exports.sqliteMmapSizeFor = require_builtins_sqlite_storage_sqlite_settings_addon.sqliteMmapSizeFor;
|
|
83073
83328
|
exports.sqlitePageCacheKibFor = require_builtins_sqlite_storage_sqlite_settings_addon.sqlitePageCacheKibFor;
|
|
83074
83329
|
}
|
|
@@ -83083,7 +83338,8 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83083
83338
|
[Symbol.toStringTag]: { value: "Module" }
|
|
83084
83339
|
});
|
|
83085
83340
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
83086
|
-
var require_dist10 =
|
|
83341
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
83342
|
+
var zod = require_zod();
|
|
83087
83343
|
var node_crypto = __require("crypto");
|
|
83088
83344
|
var node_fs_promises = __require("fs/promises");
|
|
83089
83345
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -83267,17 +83523,13 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83267
83523
|
"recordings",
|
|
83268
83524
|
"recordingsLow",
|
|
83269
83525
|
"eventMedia",
|
|
83270
|
-
"backups"
|
|
83271
|
-
"galleryMedia"
|
|
83526
|
+
"backups"
|
|
83272
83527
|
];
|
|
83273
83528
|
var MOVER_CLASSES = [
|
|
83274
83529
|
"recordings",
|
|
83275
83530
|
"recordingsLow",
|
|
83276
|
-
"eventMedia"
|
|
83277
|
-
"galleryMedia"
|
|
83531
|
+
"eventMedia"
|
|
83278
83532
|
];
|
|
83279
|
-
var BLOCKING_ONLY_CLASSES = ["galleryMedia"];
|
|
83280
|
-
var GALLERY_FORBIDDEN_NEIGHBOUR_TYPES = ["recordings", "recordingsLow"];
|
|
83281
83533
|
var MOVE_LANES = ["media", "footage"];
|
|
83282
83534
|
var PARTICIPANTS = [
|
|
83283
83535
|
"pipeline",
|
|
@@ -83302,35 +83554,34 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83302
83554
|
this.deps = deps;
|
|
83303
83555
|
}
|
|
83304
83556
|
async plan(input) {
|
|
83557
|
+
refuseRetiredGalleryClass(input.destinations);
|
|
83305
83558
|
const mode = input.mode ?? "blocking";
|
|
83306
83559
|
const moves = [];
|
|
83307
83560
|
const findings = [];
|
|
83308
83561
|
for (const storageClass of STORAGE_CLASSES) {
|
|
83309
83562
|
const targetId = input.destinations[storageClass];
|
|
83310
83563
|
if (targetId === void 0) continue;
|
|
83311
|
-
const
|
|
83312
|
-
|
|
83564
|
+
const namedSourceId = input.sources?.[storageClass];
|
|
83565
|
+
const defaultLoc = this.deps.locations.getDefaultLocation(storageClass);
|
|
83566
|
+
const source = namedSourceId ? this.deps.locations.getLocationById(namedSourceId) : defaultLoc;
|
|
83567
|
+
if (!source) throw new Error(namedSourceId ? `Storage location "${namedSourceId}" not found` : `No default storage location for "${storageClass}"`);
|
|
83568
|
+
if (source.type !== storageClass) throw new Error(`Storage location "${source.id}" is type "${source.type}", expected "${storageClass}"`);
|
|
83313
83569
|
const target = this.deps.locations.getLocationById(targetId);
|
|
83314
83570
|
if (!target) throw new Error(`Storage location "${targetId}" not found`);
|
|
83315
83571
|
if (target.type !== storageClass) throw new Error(`Storage location "${targetId}" is type "${target.type}", expected "${storageClass}"`);
|
|
83316
|
-
if (source.id === target.id) throw new Error(`Storage location "${targetId}" is already the "${storageClass}" default`);
|
|
83572
|
+
if (source.id === target.id) throw new Error(namedSourceId ? `Source and destination are the same location ("${targetId}")` : `Storage location "${targetId}" is already the "${storageClass}" default`);
|
|
83573
|
+
const freezeSource = defaultLoc !== void 0 && source.id !== defaultLoc.id;
|
|
83317
83574
|
if (!MOVER_CLASSES.includes(storageClass)) throw new Error(`No mover owns "${storageClass}" \u2014 the migration can repoint its default but cannot move its bytes. Move it by hand, then repoint the default with upsertLocation.`);
|
|
83318
|
-
if (mode === "nonBlocking" && BLOCKING_ONLY_CLASSES.includes(storageClass)) throw new Error(`"${storageClass}" is a single-cardinality storage class: it can never exist at two locations at once, so it cannot be repointed first and drained behind. Use mode "blocking".`);
|
|
83319
|
-
await this.refuseGalleryOntoRecordingsVolume(storageClass, targetId);
|
|
83320
83575
|
moves.push({
|
|
83321
83576
|
storageClass,
|
|
83322
83577
|
fromLocationId: source.id,
|
|
83323
83578
|
toLocationId: target.id,
|
|
83579
|
+
freezeSource,
|
|
83324
83580
|
moverJobId: null,
|
|
83325
83581
|
state: null,
|
|
83326
83582
|
error: null,
|
|
83327
83583
|
progress: null
|
|
83328
83584
|
});
|
|
83329
|
-
if (BLOCKING_ONLY_CLASSES.includes(storageClass)) findings.push({
|
|
83330
|
-
code: "blockingOnly",
|
|
83331
|
-
storageClass,
|
|
83332
|
-
message: `"${storageClass}" is single-cardinality: this move is stop-the-world for its whole duration, in every mode. It is a few KB per enrolled sample, which is why that is acceptable.`
|
|
83333
|
-
});
|
|
83334
83585
|
findings.push(...await this.deviceFindings(storageClass, source.id, target.id));
|
|
83335
83586
|
}
|
|
83336
83587
|
if (moves.length === 0) throw new Error("select at least one storage class");
|
|
@@ -83356,38 +83607,17 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83356
83607
|
}
|
|
83357
83608
|
return {
|
|
83358
83609
|
destinations: input.destinations,
|
|
83610
|
+
sources: input.sources,
|
|
83359
83611
|
mode,
|
|
83360
|
-
moves: moves.map(({ storageClass, fromLocationId, toLocationId }) => ({
|
|
83612
|
+
moves: moves.map(({ storageClass, fromLocationId, toLocationId, freezeSource }) => ({
|
|
83361
83613
|
storageClass,
|
|
83362
83614
|
fromLocationId,
|
|
83363
|
-
toLocationId
|
|
83615
|
+
toLocationId,
|
|
83616
|
+
freezeSource
|
|
83364
83617
|
})),
|
|
83365
83618
|
findings
|
|
83366
83619
|
};
|
|
83367
83620
|
}
|
|
83368
|
-
/**
|
|
83369
|
-
* HARD refusal: `galleryMedia` onto a volume a recordings class lives on.
|
|
83370
|
-
*
|
|
83371
|
-
* This is the one same-device case that is a refusal rather than a finding,
|
|
83372
|
-
* because its consequence is silent and arrives months later — the gallery is
|
|
83373
|
-
* wiped by the next footage wipe, quota eviction or recordings disk swap, and
|
|
83374
|
-
* nothing at that moment points back at this migration.
|
|
83375
|
-
*
|
|
83376
|
-
* It can only refuse what it can SEE. `deviceKeyOf` is a realpath, so it
|
|
83377
|
-
* catches a symlink, a bind mount and a literally-shared directory — and
|
|
83378
|
-
* misses two distinct directories on one filesystem, and any location pinned
|
|
83379
|
-
* to another node. Those come back `null`/distinct and produce a
|
|
83380
|
-
* `deviceIdentityUnknown` finding instead.
|
|
83381
|
-
*/
|
|
83382
|
-
async refuseGalleryOntoRecordingsVolume(storageClass, targetId) {
|
|
83383
|
-
if (storageClass !== "galleryMedia") return;
|
|
83384
|
-
const targetKey = await this.deviceKey(targetId);
|
|
83385
|
-
if (targetKey === null) return;
|
|
83386
|
-
for (const type of GALLERY_FORBIDDEN_NEIGHBOUR_TYPES) for (const neighbour of this.deps.locations.listLocations({ type })) {
|
|
83387
|
-
if (await this.deviceKey(neighbour.id) !== targetKey) continue;
|
|
83388
|
-
throw new Error(`Storage location "${targetId}" shares a volume with "${neighbour.id}" (${type}). galleryMedia is deliberately NOT on the recordings volume: enrolment images survive every retention sweep, so they must also survive a footage wipe, a quota eviction and a recordings disk swap. Choose a destination on another volume.`);
|
|
83389
|
-
}
|
|
83390
|
-
}
|
|
83391
83621
|
/** Same-device observations that are reported, not refused. */
|
|
83392
83622
|
async deviceFindings(storageClass, sourceId, targetId) {
|
|
83393
83623
|
if (this.deps.deviceKeyOf === void 0) return [];
|
|
@@ -83413,12 +83643,12 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83413
83643
|
this.startReserved = true;
|
|
83414
83644
|
try {
|
|
83415
83645
|
const existing = await this.status();
|
|
83416
|
-
if (existing && isTerminal(existing) && existing.pausedParticipants.length > 0) {
|
|
83646
|
+
if (existing && isTerminal$1(existing) && existing.pausedParticipants.length > 0) {
|
|
83417
83647
|
await this.releaseAfterTerminal(existing);
|
|
83418
83648
|
await this.persist(existing);
|
|
83419
83649
|
if (existing.pausedParticipants.length > 0) throw new Error(`storage migration ${existing.jobId} still holds maintenance leases`);
|
|
83420
83650
|
}
|
|
83421
|
-
if (existing && !isTerminal(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
|
|
83651
|
+
if (existing && !isTerminal$1(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
|
|
83422
83652
|
const plan = await this.plan(input);
|
|
83423
83653
|
const now = this.deps.now();
|
|
83424
83654
|
const job = {
|
|
@@ -83426,6 +83656,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83426
83656
|
phase: "planning",
|
|
83427
83657
|
mode: plan.mode,
|
|
83428
83658
|
destinations: input.destinations,
|
|
83659
|
+
sources: input.sources,
|
|
83429
83660
|
throttleMbps: input.throttleMbps ?? 40,
|
|
83430
83661
|
moves: plan.moves.map((move) => ({
|
|
83431
83662
|
...move,
|
|
@@ -83457,10 +83688,15 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83457
83688
|
if (jobId !== void 0 && job?.jobId !== jobId) return null;
|
|
83458
83689
|
return job;
|
|
83459
83690
|
}
|
|
83691
|
+
/** Finished jobs, newest first, excluding the one `status` currently shows. */
|
|
83692
|
+
async history() {
|
|
83693
|
+
const current = await this.status();
|
|
83694
|
+
return (await this.deps.history?.get() ?? []).filter((job) => job.jobId !== current?.jobId);
|
|
83695
|
+
}
|
|
83460
83696
|
async cancel(jobId) {
|
|
83461
83697
|
const job = await this.status(jobId);
|
|
83462
83698
|
const cutoverInFlight = job !== null && job.repointed && (job.phase === "refreshing" || job.phase === "resuming");
|
|
83463
|
-
if (!job || isTerminal(job) || cutoverInFlight) return false;
|
|
83699
|
+
if (!job || isTerminal$1(job) || cutoverInFlight) return false;
|
|
83464
83700
|
job.cancelRequested = true;
|
|
83465
83701
|
await this.persist(job);
|
|
83466
83702
|
await Promise.all(job.moves.filter((move) => move.moverJobId !== null).map((move) => this.cancelMove(move)));
|
|
@@ -83517,18 +83753,22 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83517
83753
|
const target = this.deps.locations.getDefaultLocation(storageClass);
|
|
83518
83754
|
if (!target) continue;
|
|
83519
83755
|
if (laneOf(storageClass) === "media") {
|
|
83520
|
-
const
|
|
83521
|
-
|
|
83522
|
-
|
|
83523
|
-
|
|
83524
|
-
|
|
83525
|
-
|
|
83526
|
-
|
|
83527
|
-
|
|
83528
|
-
|
|
83529
|
-
|
|
83530
|
-
|
|
83531
|
-
|
|
83756
|
+
for (const source of this.deps.locations.listLocations({ type: storageClass })) {
|
|
83757
|
+
if (source.id === target.id) continue;
|
|
83758
|
+
const count = await unanswerable(this.deps.participants.analytics.residue({
|
|
83759
|
+
toLocationId: target.id,
|
|
83760
|
+
fromLocationId: source.id,
|
|
83761
|
+
mode: "move"
|
|
83762
|
+
}));
|
|
83763
|
+
if (count !== null && count.rows === 0) continue;
|
|
83764
|
+
out.push({
|
|
83765
|
+
storageClass,
|
|
83766
|
+
fromLocationId: source.id,
|
|
83767
|
+
toLocationId: target.id,
|
|
83768
|
+
items: count?.rows ?? null,
|
|
83769
|
+
bytes: null
|
|
83770
|
+
});
|
|
83771
|
+
}
|
|
83532
83772
|
continue;
|
|
83533
83773
|
}
|
|
83534
83774
|
for (const source of this.deps.locations.listLocations({ type: storageClass })) {
|
|
@@ -83582,12 +83822,12 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83582
83822
|
this.startReserved = true;
|
|
83583
83823
|
try {
|
|
83584
83824
|
const existing = await this.status();
|
|
83585
|
-
if (existing && isTerminal(existing) && existing.pausedParticipants.length > 0) {
|
|
83825
|
+
if (existing && isTerminal$1(existing) && existing.pausedParticipants.length > 0) {
|
|
83586
83826
|
await this.releaseAfterTerminal(existing);
|
|
83587
83827
|
await this.persist(existing);
|
|
83588
83828
|
if (existing.pausedParticipants.length > 0) throw new Error(`storage migration ${existing.jobId} still holds maintenance leases`);
|
|
83589
83829
|
}
|
|
83590
|
-
if (existing && !isTerminal(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
|
|
83830
|
+
if (existing && !isTerminal$1(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
|
|
83591
83831
|
for (const storageClass of input.classes) {
|
|
83592
83832
|
if (MOVER_CLASSES.includes(storageClass)) continue;
|
|
83593
83833
|
throw new Error(`No mover owns "${storageClass}" \u2014 there is nothing that can drain it. Move it by hand.`);
|
|
@@ -83652,7 +83892,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83652
83892
|
await this.persist(job);
|
|
83653
83893
|
return;
|
|
83654
83894
|
}
|
|
83655
|
-
if (isTerminal(job)) {
|
|
83895
|
+
if (isTerminal$1(job)) {
|
|
83656
83896
|
if (job.pausedParticipants.length > 0) {
|
|
83657
83897
|
await this.releaseAfterTerminal(job);
|
|
83658
83898
|
await this.persist(job);
|
|
@@ -83713,11 +83953,12 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83713
83953
|
if (job.phase === "verifying" && !nonBlocking) {
|
|
83714
83954
|
await this.verifyMoves(job);
|
|
83715
83955
|
if (job.cancelRequested) return this.finishCancelled(job);
|
|
83956
|
+
await this.freezeDrainedSources(job);
|
|
83716
83957
|
await this.setPhase(job, "repointing");
|
|
83717
83958
|
}
|
|
83718
83959
|
if (job.phase === "repointing") {
|
|
83719
|
-
const targets = new Map(job.moves.map((move) => [move.storageClass, move.toLocationId]));
|
|
83720
|
-
await this.deps.locations.setDefaultLocations(targets);
|
|
83960
|
+
const targets = new Map(job.moves.filter((move) => move.freezeSource !== true).map((move) => [move.storageClass, move.toLocationId]));
|
|
83961
|
+
if (targets.size > 0) await this.deps.locations.setDefaultLocations(targets);
|
|
83721
83962
|
job.repointed = true;
|
|
83722
83963
|
await this.setPhase(job, "refreshing");
|
|
83723
83964
|
}
|
|
@@ -83740,6 +83981,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83740
83981
|
if (job.phase === "verifying" && nonBlocking) {
|
|
83741
83982
|
await this.verifyMoves(job);
|
|
83742
83983
|
if (job.cancelRequested) return this.finishCancelled(job);
|
|
83984
|
+
await this.freezeDrainedSources(job);
|
|
83743
83985
|
await this.setPhase(job, "done");
|
|
83744
83986
|
}
|
|
83745
83987
|
} catch (err) {
|
|
@@ -83755,7 +83997,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83755
83997
|
await this.releaseAfterTerminal(job);
|
|
83756
83998
|
await this.persist(job);
|
|
83757
83999
|
} finally {
|
|
83758
|
-
if (isTerminal(job)) {
|
|
84000
|
+
if (isTerminal$1(job)) {
|
|
83759
84001
|
await this.releaseAfterTerminal(job);
|
|
83760
84002
|
this.active = job;
|
|
83761
84003
|
}
|
|
@@ -83799,9 +84041,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83799
84041
|
*
|
|
83800
84042
|
* Two lanes — the recorder's footage engine and post-analysis's media engine
|
|
83801
84043
|
* — run in parallel with each other and strictly FIFO within themselves.
|
|
83802
|
-
* `
|
|
83803
|
-
* the same `MediaRelocateEngine`, which refuses a second running job; starting
|
|
83804
|
-
* both would fail the second one instantly.
|
|
84044
|
+
* `eventMedia` is the only class on the media lane.
|
|
83805
84045
|
*/
|
|
83806
84046
|
async startOrResumeMoves(job) {
|
|
83807
84047
|
if (job.cancelRequested) return;
|
|
@@ -83918,6 +84158,24 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83918
84158
|
for (const move of job.moves) if (move.state !== "done") throw new Error(`${move.storageClass} move did not complete verification`);
|
|
83919
84159
|
}
|
|
83920
84160
|
/**
|
|
84161
|
+
* After a from→to copy whose source was NOT the class default: stop new
|
|
84162
|
+
* writes to `from`. The default is unchanged (that is the whole point of
|
|
84163
|
+
* naming a non-default source). A location that is already disabled is
|
|
84164
|
+
* left alone.
|
|
84165
|
+
*/
|
|
84166
|
+
freezeDrainedSources(job) {
|
|
84167
|
+
for (const move of job.moves) {
|
|
84168
|
+
if (move.freezeSource !== true) continue;
|
|
84169
|
+
const loc = this.deps.locations.getLocationById(move.fromLocationId);
|
|
84170
|
+
if (!loc || loc.enabled === false) continue;
|
|
84171
|
+
const { createdAt: _c, updatedAt: _u, capacity: _cap, ...rest } = loc;
|
|
84172
|
+
this.deps.locations.upsertLocation({
|
|
84173
|
+
...rest,
|
|
84174
|
+
enabled: false
|
|
84175
|
+
});
|
|
84176
|
+
}
|
|
84177
|
+
}
|
|
84178
|
+
/**
|
|
83921
84179
|
* Arm one class's mover.
|
|
83922
84180
|
*
|
|
83923
84181
|
* `draining` runs after every writer has been resumed, so there is no lease
|
|
@@ -83930,8 +84188,9 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83930
84188
|
if (laneOf(move.storageClass) === "media") {
|
|
83931
84189
|
const input2 = {
|
|
83932
84190
|
toLocationId: move.toLocationId,
|
|
84191
|
+
fromLocationId: move.fromLocationId,
|
|
83933
84192
|
throttleMbps: job.throttleMbps,
|
|
83934
|
-
mode:
|
|
84193
|
+
mode: "move"
|
|
83935
84194
|
};
|
|
83936
84195
|
return (unleased ? await this.deps.participants.analytics.startDrain(input2) : await this.deps.participants.analytics.startMove({
|
|
83937
84196
|
...input2,
|
|
@@ -83963,7 +84222,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83963
84222
|
}
|
|
83964
84223
|
async setPhase(job, phase) {
|
|
83965
84224
|
job.phase = phase;
|
|
83966
|
-
if (isTerminal(job)) job.finishedAt = this.deps.now();
|
|
84225
|
+
if (isTerminal$1(job)) job.finishedAt = this.deps.now();
|
|
83967
84226
|
await this.persist(job);
|
|
83968
84227
|
}
|
|
83969
84228
|
async finishCancelled(job) {
|
|
@@ -83975,6 +84234,9 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83975
84234
|
async persist(job) {
|
|
83976
84235
|
job.updatedAt = this.deps.now();
|
|
83977
84236
|
await this.deps.state.set(job);
|
|
84237
|
+
if (!isTerminal$1(job) || this.deps.history === void 0) return;
|
|
84238
|
+
const prev = [...await this.deps.history.get() ?? []];
|
|
84239
|
+
await this.deps.history.set([job, ...prev.filter((row) => row.jobId !== job.jobId)].slice(0, HISTORY_CAP));
|
|
83978
84240
|
}
|
|
83979
84241
|
};
|
|
83980
84242
|
async function unanswerable(read) {
|
|
@@ -83988,11 +84250,16 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83988
84250
|
if (job.pauseLeaseId === null) throw new Error("storage migration has no maintenance lease");
|
|
83989
84251
|
return job.pauseLeaseId;
|
|
83990
84252
|
}
|
|
83991
|
-
function isTerminal(job) {
|
|
84253
|
+
function isTerminal$1(job) {
|
|
83992
84254
|
return job.phase === "done" || job.phase === "failed" || job.phase === "cancelled";
|
|
83993
84255
|
}
|
|
84256
|
+
var HISTORY_CAP = 20;
|
|
83994
84257
|
function laneOf(storageClass) {
|
|
83995
|
-
return storageClass === "eventMedia"
|
|
84258
|
+
return storageClass === "eventMedia" ? "media" : "footage";
|
|
84259
|
+
}
|
|
84260
|
+
function refuseRetiredGalleryClass(destinations) {
|
|
84261
|
+
if (destinations.galleryMedia === void 0) return;
|
|
84262
|
+
throw new Error("galleryMedia is no longer a storage class. Enrolled gallery lives in the pipeline-analytics addon data directory, not a location the operator places.");
|
|
83996
84263
|
}
|
|
83997
84264
|
function runsUnleased(job) {
|
|
83998
84265
|
if (job.phase === "sealing" || job.phase === "draining") return true;
|
|
@@ -84039,6 +84306,46 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84039
84306
|
function canProbeOccupancyLocally(locality) {
|
|
84040
84307
|
return locality === true;
|
|
84041
84308
|
}
|
|
84309
|
+
var STORAGE_CLASS_SUBTREES = {
|
|
84310
|
+
eventMedia: ["events"],
|
|
84311
|
+
recordingsLow: ["low"],
|
|
84312
|
+
recordings: ["high", "mid"]
|
|
84313
|
+
};
|
|
84314
|
+
function isDotEntry(name) {
|
|
84315
|
+
return name.startsWith(".");
|
|
84316
|
+
}
|
|
84317
|
+
async function dirHasAnyEntry(dir) {
|
|
84318
|
+
let handle;
|
|
84319
|
+
try {
|
|
84320
|
+
handle = await (0, node_fs_promises.opendir)(dir);
|
|
84321
|
+
} catch (err) {
|
|
84322
|
+
if (err.code === "ENOENT") return false;
|
|
84323
|
+
throw err;
|
|
84324
|
+
}
|
|
84325
|
+
try {
|
|
84326
|
+
return await handle.read() !== null;
|
|
84327
|
+
} finally {
|
|
84328
|
+
await handle.close();
|
|
84329
|
+
}
|
|
84330
|
+
}
|
|
84331
|
+
async function probeLocalDirectoryOccupancy(input) {
|
|
84332
|
+
let names;
|
|
84333
|
+
try {
|
|
84334
|
+
names = await (0, node_fs_promises.readdir)(input.basePath);
|
|
84335
|
+
} catch (err) {
|
|
84336
|
+
if (err.code === "ENOENT") return "empty";
|
|
84337
|
+
return "unknown";
|
|
84338
|
+
}
|
|
84339
|
+
const visible = names.filter((name) => !isDotEntry(name));
|
|
84340
|
+
const subtrees = STORAGE_CLASS_SUBTREES[input.type];
|
|
84341
|
+
if (subtrees === void 0) return visible.length > 0 ? "occupied" : "empty";
|
|
84342
|
+
try {
|
|
84343
|
+
for (const camera of visible) for (const subtree of subtrees) if (await dirHasAnyEntry(node_path.default.join(input.basePath, camera, subtree))) return "occupied";
|
|
84344
|
+
} catch {
|
|
84345
|
+
return "unknown";
|
|
84346
|
+
}
|
|
84347
|
+
return "empty";
|
|
84348
|
+
}
|
|
84042
84349
|
function resolveEngine(getEngines) {
|
|
84043
84350
|
const engines = getEngines();
|
|
84044
84351
|
if (engines.length === 0) throw new Error("settings-store: no data-store-provider engine is registered \u2014 the data door has nothing behind it");
|
|
@@ -84128,6 +84435,164 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84128
84435
|
}
|
|
84129
84436
|
return out;
|
|
84130
84437
|
}
|
|
84438
|
+
var FOOTAGE_TYPES = /* @__PURE__ */ new Set(["recordings", "recordingsLow"]);
|
|
84439
|
+
function isTerminal(job) {
|
|
84440
|
+
return job.phase === "done" || job.phase === "failed" || job.phase === "cancelled";
|
|
84441
|
+
}
|
|
84442
|
+
function footageFrozen(location) {
|
|
84443
|
+
return location.enabled === false || location.config["readOnly"] === true;
|
|
84444
|
+
}
|
|
84445
|
+
var StorageCleanupCoordinator = class {
|
|
84446
|
+
deps;
|
|
84447
|
+
active = null;
|
|
84448
|
+
startReserved = false;
|
|
84449
|
+
constructor(deps) {
|
|
84450
|
+
this.deps = deps;
|
|
84451
|
+
}
|
|
84452
|
+
async start(input) {
|
|
84453
|
+
if (this.startReserved) throw new Error("storage cleanup is already active");
|
|
84454
|
+
this.startReserved = true;
|
|
84455
|
+
try {
|
|
84456
|
+
const existing = await this.status();
|
|
84457
|
+
if (existing && !isTerminal(existing)) throw new Error(`storage cleanup is already active (${existing.jobId})`);
|
|
84458
|
+
const now = this.deps.now();
|
|
84459
|
+
const job = {
|
|
84460
|
+
jobId: this.deps.newId(),
|
|
84461
|
+
phase: "orphans",
|
|
84462
|
+
includeDebugMedia: input.includeDebugMedia === true,
|
|
84463
|
+
orphansReclaimed: 0,
|
|
84464
|
+
orphanBytesReclaimed: 0,
|
|
84465
|
+
debugMediaReclaimed: 0,
|
|
84466
|
+
debugMediaBytesReclaimed: 0,
|
|
84467
|
+
ghostsForgotten: 0,
|
|
84468
|
+
ghostBytesForgotten: 0,
|
|
84469
|
+
detail: "Starting orphan reclaim",
|
|
84470
|
+
cancelRequested: false,
|
|
84471
|
+
startedAt: now,
|
|
84472
|
+
updatedAt: now,
|
|
84473
|
+
finishedAt: null,
|
|
84474
|
+
error: null
|
|
84475
|
+
};
|
|
84476
|
+
await this.persist(job);
|
|
84477
|
+
this.active = job;
|
|
84478
|
+
this.run(job);
|
|
84479
|
+
return job.jobId;
|
|
84480
|
+
} finally {
|
|
84481
|
+
this.startReserved = false;
|
|
84482
|
+
}
|
|
84483
|
+
}
|
|
84484
|
+
async status(jobId) {
|
|
84485
|
+
const job = this.active ?? await this.deps.state.get();
|
|
84486
|
+
if (jobId !== void 0 && job?.jobId !== jobId) return null;
|
|
84487
|
+
return job;
|
|
84488
|
+
}
|
|
84489
|
+
async cancel(jobId) {
|
|
84490
|
+
const job = await this.status(jobId);
|
|
84491
|
+
if (!job || isTerminal(job)) return false;
|
|
84492
|
+
job.cancelRequested = true;
|
|
84493
|
+
job.detail = "Cancel requested \u2014 finishing the current step";
|
|
84494
|
+
await this.persist(job);
|
|
84495
|
+
return true;
|
|
84496
|
+
}
|
|
84497
|
+
async run(job) {
|
|
84498
|
+
try {
|
|
84499
|
+
await this.reclaimOrphans(job);
|
|
84500
|
+
if (await this.stopped(job)) return;
|
|
84501
|
+
if (job.includeDebugMedia) {
|
|
84502
|
+
await this.setPhase(job, "debug-media", "Reclaiming debug media");
|
|
84503
|
+
await this.reclaimDebugMedia(job);
|
|
84504
|
+
if (await this.stopped(job)) return;
|
|
84505
|
+
}
|
|
84506
|
+
await this.setPhase(job, "ghost-ledger", "Forgetting ghost footage rows");
|
|
84507
|
+
await this.forgetGhosts(job);
|
|
84508
|
+
if (await this.stopped(job)) return;
|
|
84509
|
+
await this.finish(job, "done", null);
|
|
84510
|
+
} catch (err) {
|
|
84511
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
84512
|
+
await this.finish(job, "failed", message);
|
|
84513
|
+
}
|
|
84514
|
+
}
|
|
84515
|
+
async reclaimOrphans(job) {
|
|
84516
|
+
let restart = true;
|
|
84517
|
+
for (; ; ) {
|
|
84518
|
+
if (await this.stopped(job)) return;
|
|
84519
|
+
const start = await this.deps.participants.startOrphan(restart);
|
|
84520
|
+
restart = false;
|
|
84521
|
+
if (!start.started && !start.alreadyRunning) throw new Error("orphan reclaim did not start");
|
|
84522
|
+
const status = await this.waitUntilIdle(() => this.deps.participants.orphanStatus(), job, (s) => `Orphan reclaim: ${s.totalReclaimed} rows / ${String(s.totalBytesReclaimed)} bytes`);
|
|
84523
|
+
job.orphansReclaimed += status.totalReclaimed;
|
|
84524
|
+
job.orphanBytesReclaimed += status.totalBytesReclaimed;
|
|
84525
|
+
job.detail = `Orphans: ${job.orphansReclaimed} rows, ${String(job.orphanBytesReclaimed)} bytes`;
|
|
84526
|
+
await this.persist(job);
|
|
84527
|
+
if (status.error) throw new Error(status.error);
|
|
84528
|
+
if (status.complete === true) return;
|
|
84529
|
+
}
|
|
84530
|
+
}
|
|
84531
|
+
async reclaimDebugMedia(job) {
|
|
84532
|
+
const start = await this.deps.participants.startDebugMedia();
|
|
84533
|
+
if (!start.started && !start.alreadyRunning) throw new Error("debug-media reclaim did not start");
|
|
84534
|
+
const status = await this.waitUntilIdle(() => this.deps.participants.debugMediaStatus(), job, (s) => `Debug media: ${s.totalReclaimed} files`);
|
|
84535
|
+
job.debugMediaReclaimed = status.totalReclaimed;
|
|
84536
|
+
job.debugMediaBytesReclaimed = status.totalBytesReclaimed;
|
|
84537
|
+
await this.persist(job);
|
|
84538
|
+
if (status.error) throw new Error(status.error);
|
|
84539
|
+
}
|
|
84540
|
+
async forgetGhosts(job) {
|
|
84541
|
+
const frozen = this.deps.locations.listLocations().filter((l) => FOOTAGE_TYPES.has(l.type) && footageFrozen(l));
|
|
84542
|
+
if (frozen.length === 0) {
|
|
84543
|
+
job.detail = "No frozen footage locations";
|
|
84544
|
+
await this.persist(job);
|
|
84545
|
+
return;
|
|
84546
|
+
}
|
|
84547
|
+
for (const loc of frozen) {
|
|
84548
|
+
if (await this.stopped(job)) return;
|
|
84549
|
+
job.detail = `Ghost ledger: ${loc.id}`;
|
|
84550
|
+
await this.persist(job);
|
|
84551
|
+
const report = await this.deps.participants.walkLedger({
|
|
84552
|
+
locationId: loc.id,
|
|
84553
|
+
apply: true
|
|
84554
|
+
});
|
|
84555
|
+
job.ghostsForgotten += report.forgottenSegments;
|
|
84556
|
+
job.ghostBytesForgotten += report.forgottenBytes;
|
|
84557
|
+
await this.persist(job);
|
|
84558
|
+
}
|
|
84559
|
+
}
|
|
84560
|
+
async waitUntilIdle(read, job, detail) {
|
|
84561
|
+
const pollMs = this.deps.pollMs ?? 2e3;
|
|
84562
|
+
const sleep = this.deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
84563
|
+
for (; ; ) {
|
|
84564
|
+
const status = await read();
|
|
84565
|
+
job.detail = detail(status);
|
|
84566
|
+
await this.persist(job);
|
|
84567
|
+
if (!status.running) return status;
|
|
84568
|
+
await sleep(pollMs);
|
|
84569
|
+
}
|
|
84570
|
+
}
|
|
84571
|
+
async stopped(job) {
|
|
84572
|
+
if ((await this.status(job.jobId))?.cancelRequested === true) {
|
|
84573
|
+
await this.finish(job, "cancelled", null);
|
|
84574
|
+
return true;
|
|
84575
|
+
}
|
|
84576
|
+
return false;
|
|
84577
|
+
}
|
|
84578
|
+
async setPhase(job, phase, detail) {
|
|
84579
|
+
job.phase = phase;
|
|
84580
|
+
job.detail = detail;
|
|
84581
|
+
await this.persist(job);
|
|
84582
|
+
}
|
|
84583
|
+
async finish(job, phase, error) {
|
|
84584
|
+
job.phase = phase;
|
|
84585
|
+
job.error = error;
|
|
84586
|
+
job.finishedAt = this.deps.now();
|
|
84587
|
+
job.detail = phase === "done" ? "Cleanup finished" : job.detail;
|
|
84588
|
+
await this.persist(job);
|
|
84589
|
+
}
|
|
84590
|
+
async persist(job) {
|
|
84591
|
+
job.updatedAt = this.deps.now();
|
|
84592
|
+
this.active = job;
|
|
84593
|
+
await this.deps.state.set(job);
|
|
84594
|
+
}
|
|
84595
|
+
};
|
|
84131
84596
|
var SESSION_VOCABULARY = {
|
|
84132
84597
|
upload: {
|
|
84133
84598
|
idLabel: "uploadId",
|
|
@@ -84215,7 +84680,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84215
84680
|
* Reconciles both directions so operator edits survive a reboot:
|
|
84216
84681
|
* 1. hydrate — DB rows win over any early in-memory seed (restores
|
|
84217
84682
|
* operator config like `minFreePercent` that the pre-store boot
|
|
84218
|
-
* can't see)
|
|
84683
|
+
* can't see);
|
|
84219
84684
|
* 2. backfill — in-memory locations the DB doesn't have yet (the
|
|
84220
84685
|
* pre-store seed defaults on a fresh install) are persisted, so the
|
|
84221
84686
|
* store becomes the durable source of truth from here on.
|
|
@@ -84237,15 +84702,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84237
84702
|
const rows = await store.loadAll();
|
|
84238
84703
|
this.locationStore = store;
|
|
84239
84704
|
const dbIds = new Set(rows.map((r) => r.id));
|
|
84240
|
-
for (const loc of rows)
|
|
84241
|
-
const upgraded = !loc.isSystem && loc.id === `${loc.type}:default` ? {
|
|
84242
|
-
...loc,
|
|
84243
|
-
isSystem: true
|
|
84244
|
-
} : loc;
|
|
84245
|
-
this.locations.set(upgraded.id, upgraded);
|
|
84246
|
-
if (upgraded !== loc) store.upsert(upgraded).catch(() => {
|
|
84247
|
-
});
|
|
84248
|
-
}
|
|
84705
|
+
for (const loc of rows) this.locations.set(loc.id, loc);
|
|
84249
84706
|
const backfill = [...this.locations.values()].filter((l) => !dbIds.has(l.id));
|
|
84250
84707
|
for (const loc of backfill) store.upsert(loc).catch((err) => {
|
|
84251
84708
|
this.logger.warn("storage-orchestrator: attachStore backfill persist failed", { meta: {
|
|
@@ -84263,14 +84720,13 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84263
84720
|
/**
|
|
84264
84721
|
* Shout about a persisted row that is BOTH the type default and disabled.
|
|
84265
84722
|
*
|
|
84266
|
-
* `upsertLocation`
|
|
84267
|
-
*
|
|
84268
|
-
*
|
|
84269
|
-
*
|
|
84270
|
-
*
|
|
84723
|
+
* `upsertLocation` can now produce this (enabled is the write set; `isDefault`
|
|
84724
|
+
* is store residue). Hydrate also writes rows straight into the map, so a
|
|
84725
|
+
* hand-edited store or a row written by another build can too. It matters
|
|
84726
|
+
* because every bare-type ref still resolves through {@link getDefaultLocation}
|
|
84727
|
+
* until Stage 5 of the enabled-write-set design: on such a row
|
|
84271
84728
|
* `storage.write({ location: 'eventMedia' })` and the migration coordinator's
|
|
84272
|
-
* drain destination both point at a disk the operator turned off.
|
|
84273
|
-
* one thing this model must never do silently.
|
|
84729
|
+
* drain destination both point at a disk the operator turned off.
|
|
84274
84730
|
*
|
|
84275
84731
|
* Reported, never repaired: flipping an operator's flag back on at boot would
|
|
84276
84732
|
* be the system overruling the switch instead of obeying it. The coordinator
|
|
@@ -84338,25 +84794,8 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84338
84794
|
async initialize() {
|
|
84339
84795
|
if (!this.locationStore) return;
|
|
84340
84796
|
const rows = await this.locationStore.loadAll();
|
|
84341
|
-
|
|
84342
|
-
|
|
84343
|
-
const upgradedLoc = {
|
|
84344
|
-
...loc,
|
|
84345
|
-
isSystem: true
|
|
84346
|
-
};
|
|
84347
|
-
this.locations.set(upgradedLoc.id, upgradedLoc);
|
|
84348
|
-
this.locationStore.upsert(upgradedLoc).catch((err) => {
|
|
84349
|
-
this.logger.warn("storage-orchestrator: isSystem upgrade persist failed", { meta: {
|
|
84350
|
-
id: upgradedLoc.id,
|
|
84351
|
-
error: err instanceof Error ? err.message : String(err)
|
|
84352
|
-
} });
|
|
84353
|
-
});
|
|
84354
|
-
upgraded++;
|
|
84355
|
-
} else this.locations.set(loc.id, loc);
|
|
84356
|
-
this.logger.info("storage-orchestrator: hydrated locations from store", { meta: {
|
|
84357
|
-
loaded: this.locations.size,
|
|
84358
|
-
isSystemUpgraded: upgraded
|
|
84359
|
-
} });
|
|
84797
|
+
for (const loc of rows) this.locations.set(loc.id, loc);
|
|
84798
|
+
this.logger.info("storage-orchestrator: hydrated locations from store", { meta: { loaded: this.locations.size } });
|
|
84360
84799
|
this.reportDisabledDefaults();
|
|
84361
84800
|
}
|
|
84362
84801
|
/**
|
|
@@ -84542,10 +84981,6 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84542
84981
|
...input,
|
|
84543
84982
|
nodeId: "hub"
|
|
84544
84983
|
};
|
|
84545
|
-
if (existing?.isSystem === true) input = {
|
|
84546
|
-
...input,
|
|
84547
|
-
isSystem: true
|
|
84548
|
-
};
|
|
84549
84984
|
input = {
|
|
84550
84985
|
...input,
|
|
84551
84986
|
...resolveEnabled(input, existing, this.hasAnyLocationOfType(input.type))
|
|
@@ -84555,6 +84990,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84555
84990
|
createdAt: existing?.createdAt ?? now,
|
|
84556
84991
|
updatedAt: now
|
|
84557
84992
|
};
|
|
84993
|
+
refuseLastWriteTargetDisabled(existing, next, this.locations.values());
|
|
84558
84994
|
const demoted = [];
|
|
84559
84995
|
if (next.isDefault) {
|
|
84560
84996
|
for (const [otherId, otherLoc] of this.locations) if (otherLoc.type === next.type && otherLoc.id !== next.id && otherLoc.isDefault) {
|
|
@@ -84591,21 +85027,22 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84591
85027
|
return next;
|
|
84592
85028
|
}
|
|
84593
85029
|
/**
|
|
84594
|
-
* Remove a location. Refuses
|
|
84595
|
-
*
|
|
84596
|
-
*
|
|
84597
|
-
*
|
|
84598
|
-
*
|
|
84599
|
-
*
|
|
84600
|
-
* routed to the logger — see `upsertLocation` for the rationale.
|
|
85030
|
+
* Remove a location. Refuses the last location of a type and the last
|
|
85031
|
+
* enabled location of a type. `isSystem` is informational — a frozen
|
|
85032
|
+
* recordings `:default` is deletable once a sibling is live. Deleting
|
|
85033
|
+
* the flagged default promotes an enabled sibling. Occupancy still
|
|
85034
|
+
* refuses unless `force` is set; force never overrides uniqueness /
|
|
85035
|
+
* last-enabled.
|
|
84601
85036
|
*/
|
|
84602
85037
|
async deleteLocation(id, options) {
|
|
84603
85038
|
const loc = this.locations.get(id);
|
|
84604
85039
|
if (!loc) throw new Error(`Storage location "${id}" not found`);
|
|
84605
|
-
|
|
84606
|
-
if (
|
|
84607
|
-
|
|
84608
|
-
}
|
|
85040
|
+
const ofType = [...this.locations.values()].filter((l) => l.type === loc.type);
|
|
85041
|
+
if (ofType.length <= 1) throw new Error(`Cannot delete "${id}" \u2014 it is the only location for type "${loc.type}"`);
|
|
85042
|
+
const enabledOfType = ofType.filter((l) => l.enabled !== false);
|
|
85043
|
+
if (loc.enabled !== false && enabledOfType.length <= 1) throw new Error(`Cannot delete "${id}" \u2014 it is the only enabled location for type "${loc.type}"`);
|
|
85044
|
+
const successor = loc.isDefault === true ? ofType.find((l) => l.id !== id && l.enabled !== false) : void 0;
|
|
85045
|
+
if (loc.isDefault === true && successor === void 0) throw new Error(`Cannot delete "${id}" \u2014 it is the only enabled location for type "${loc.type}"`);
|
|
84609
85046
|
const occupancy = await this.probeOccupancy(loc);
|
|
84610
85047
|
if (occupancy !== "empty") {
|
|
84611
85048
|
if (options?.force !== true) throw new Error(occupancy === "occupied" ? `Storage location "${id}" still holds data \u2014 drain it first (storage migration / relocate), or pass force to delete the record anyway and strand what is on it` : `Storage location "${id}" could not be checked for remaining data (unreachable provider, another node, or an unmounted root) \u2014 pass force to delete the record anyway`);
|
|
@@ -84615,6 +85052,21 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84615
85052
|
occupancy
|
|
84616
85053
|
} });
|
|
84617
85054
|
}
|
|
85055
|
+
if (successor !== void 0 && successor.isDefault !== true) {
|
|
85056
|
+
const now = Date.now();
|
|
85057
|
+
const promoted = {
|
|
85058
|
+
...successor,
|
|
85059
|
+
isDefault: true,
|
|
85060
|
+
updatedAt: now
|
|
85061
|
+
};
|
|
85062
|
+
this.locations.set(successor.id, promoted);
|
|
85063
|
+
if (this.locationStore) this.locationStore.upsert(promoted).catch((err) => {
|
|
85064
|
+
this.logger.error("storage-orchestrator: default promotion persist failed", { meta: {
|
|
85065
|
+
id: successor.id,
|
|
85066
|
+
error: err instanceof Error ? err.message : String(err)
|
|
85067
|
+
} });
|
|
85068
|
+
});
|
|
85069
|
+
}
|
|
84618
85070
|
this.locations.delete(id);
|
|
84619
85071
|
if (this.locationStore) this.locationStore.delete(id).catch((err) => {
|
|
84620
85072
|
this.logger.error("storage-orchestrator: delete persistence failed", { meta: {
|
|
@@ -84641,15 +85093,14 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84641
85093
|
}
|
|
84642
85094
|
}
|
|
84643
85095
|
/**
|
|
84644
|
-
* Remove
|
|
84645
|
-
* addon (stale defaults from a removed location type).
|
|
84646
|
-
*
|
|
84647
|
-
* operator owns them. Requires the registry to be set first.
|
|
85096
|
+
* Remove seed-shaped locations (`<type>:default`) whose type is no longer
|
|
85097
|
+
* declared by any addon (stale defaults from a removed location type).
|
|
85098
|
+
* Operator-added locations of an undeclared type are KEPT but warned.
|
|
84648
85099
|
*
|
|
84649
85100
|
* FAIL-SAFE: if the registry is EMPTY (no addon declared any location), we
|
|
84650
85101
|
* refuse to prune anything. An empty registry almost always means
|
|
84651
85102
|
* declarations failed to load (boot ordering, a stale install) — pruning
|
|
84652
|
-
* "everything undeclared" in that state would wipe every
|
|
85103
|
+
* "everything undeclared" in that state would wipe every seeded location
|
|
84653
85104
|
* (data/logs/recordings/…). Better to keep stale rows than destroy live ones.
|
|
84654
85105
|
*/
|
|
84655
85106
|
pruneUndeclaredSystemLocations() {
|
|
@@ -84660,7 +85111,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84660
85111
|
}
|
|
84661
85112
|
for (const [id, loc] of Array.from(this.locations)) {
|
|
84662
85113
|
if (this.registry.cardinalityOf(loc.type) !== null) continue;
|
|
84663
|
-
if (loc.
|
|
85114
|
+
if (loc.id === `${loc.type}:default`) {
|
|
84664
85115
|
this.locations.delete(id);
|
|
84665
85116
|
if (this.locationStore) this.locationStore.delete(id).catch((err) => {
|
|
84666
85117
|
this.logger.error("storage-orchestrator: prune persistence failed", { meta: {
|
|
@@ -84668,7 +85119,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84668
85119
|
error: err instanceof Error ? err.message : String(err)
|
|
84669
85120
|
} });
|
|
84670
85121
|
});
|
|
84671
|
-
this.logger.info("storage-orchestrator: pruned stale
|
|
85122
|
+
this.logger.info("storage-orchestrator: pruned stale seeded location", { meta: {
|
|
84672
85123
|
id,
|
|
84673
85124
|
type: loc.type
|
|
84674
85125
|
} });
|
|
@@ -84828,7 +85279,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84828
85279
|
providerId: input.providerId,
|
|
84829
85280
|
config: { basePath: base },
|
|
84830
85281
|
isDefault: true,
|
|
84831
|
-
isSystem:
|
|
85282
|
+
isSystem: false
|
|
84832
85283
|
});
|
|
84833
85284
|
added++;
|
|
84834
85285
|
}
|
|
@@ -84849,9 +85300,20 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84849
85300
|
if (existing) return {};
|
|
84850
85301
|
return { enabled: input.isDefault || !typeAlreadyHasLocation };
|
|
84851
85302
|
}
|
|
84852
|
-
if (input.isDefault && requested === false) return { enabled: true };
|
|
84853
85303
|
return { enabled: requested };
|
|
84854
85304
|
}
|
|
85305
|
+
var OPTIONAL_WRITE_TYPES = /* @__PURE__ */ new Set(["backups"]);
|
|
85306
|
+
function refuseLastWriteTargetDisabled(existing, next, locations) {
|
|
85307
|
+
if (OPTIONAL_WRITE_TYPES.has(next.type)) return;
|
|
85308
|
+
if (next.enabled !== false) return;
|
|
85309
|
+
if (existing === void 0) return;
|
|
85310
|
+
if (existing.enabled === false) return;
|
|
85311
|
+
for (const loc of locations) {
|
|
85312
|
+
if (loc.id === next.id || loc.type !== next.type) continue;
|
|
85313
|
+
if (loc.enabled !== false) return;
|
|
85314
|
+
}
|
|
85315
|
+
throw new Error(`Cannot disable "${next.id}": it is the last enabled location of type "${next.type}". Enable another location of this type first.`);
|
|
85316
|
+
}
|
|
84855
85317
|
var DEFAULT_MAX_ROUNDS = 8;
|
|
84856
85318
|
var DEFAULT_HYSTERESIS_PERCENT = 1;
|
|
84857
85319
|
var StoragePressureManager = class {
|
|
@@ -84999,6 +85461,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84999
85461
|
pressureTimer = null;
|
|
85000
85462
|
pressureSweepInFlight = false;
|
|
85001
85463
|
migration = null;
|
|
85464
|
+
cleanup = null;
|
|
85002
85465
|
/**
|
|
85003
85466
|
* Cached `providerId → nodeLocal` snapshot (SP1). Backs the orchestrator's
|
|
85004
85467
|
* synchronous `NodeLocalResolver` — `getProviderInfo()` is async, so we
|
|
@@ -85056,7 +85519,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85056
85519
|
const rows = type !== void 0 ? service.listLocations({ type }) : service.listLocations();
|
|
85057
85520
|
return Promise.all(rows.map(async (loc) => ({
|
|
85058
85521
|
...this.redacted(loc),
|
|
85059
|
-
capacity: await this.localCapacityOf(loc)
|
|
85522
|
+
capacity: loc.enabled === false ? null : await this.localCapacityOf(loc)
|
|
85060
85523
|
})));
|
|
85061
85524
|
},
|
|
85062
85525
|
getDefaultLocation: async ({ type }) => {
|
|
@@ -85224,6 +85687,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85224
85687
|
const migration = new StorageMigrationCoordinator({
|
|
85225
85688
|
locations: service,
|
|
85226
85689
|
state: this.state("storage-migration", require_dist10.StorageMigrationJobSchema.nullable(), null),
|
|
85690
|
+
history: this.state("storage-migration-history", zod.z.array(require_dist10.StorageMigrationJobSchema), []),
|
|
85227
85691
|
participants: {
|
|
85228
85692
|
pipeline: {
|
|
85229
85693
|
pause: async (leaseId) => {
|
|
@@ -85274,6 +85738,36 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85274
85738
|
deviceKeyOf: (locationId) => this.locationDeviceKey(locationId)
|
|
85275
85739
|
});
|
|
85276
85740
|
this.migration = migration;
|
|
85741
|
+
const cleanup = new StorageCleanupCoordinator({
|
|
85742
|
+
locations: service,
|
|
85743
|
+
state: this.state("storage-cleanup", require_dist10.StorageCleanupJobSchema.nullable(), null),
|
|
85744
|
+
participants: {
|
|
85745
|
+
startOrphan: async (restart) => {
|
|
85746
|
+
return parseStarted(await this.ctx.api.addons.custom.mutate({
|
|
85747
|
+
addonId: "pipeline-analytics",
|
|
85748
|
+
action: "retention.orphanAudit",
|
|
85749
|
+
input: {
|
|
85750
|
+
mode: "reclaim",
|
|
85751
|
+
restart,
|
|
85752
|
+
maxRowsPerScope: 2e4
|
|
85753
|
+
}
|
|
85754
|
+
}));
|
|
85755
|
+
},
|
|
85756
|
+
orphanStatus: async () => {
|
|
85757
|
+
return parseOrphanStatus(await this.ctx.api.addons.custom.mutate({
|
|
85758
|
+
addonId: "pipeline-analytics",
|
|
85759
|
+
action: "retention.orphanAuditStatus",
|
|
85760
|
+
input: {}
|
|
85761
|
+
}));
|
|
85762
|
+
},
|
|
85763
|
+
startDebugMedia: () => this.ctx.api.pipelineAnalytics.reclaimDebugMedia.mutate({ mode: "reclaim" }),
|
|
85764
|
+
debugMediaStatus: () => this.ctx.api.pipelineAnalytics.getMediaReclaimStatus.query({}),
|
|
85765
|
+
walkLedger: (input) => this.ctx.api.recording.reconcileLedgerAgainstDisk.mutate(input)
|
|
85766
|
+
},
|
|
85767
|
+
now: () => Date.now(),
|
|
85768
|
+
newId: () => (0, node_crypto.randomUUID)()
|
|
85769
|
+
});
|
|
85770
|
+
this.cleanup = cleanup;
|
|
85277
85771
|
const migrationProvider = {
|
|
85278
85772
|
plan: (input) => migration.plan(input),
|
|
85279
85773
|
start: async (input) => ({ jobId: await migration.start(input) }),
|
|
@@ -85281,7 +85775,11 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85281
85775
|
cancel: async ({ jobId }) => ({ cancelled: await migration.cancel(jobId) }),
|
|
85282
85776
|
movers: () => migration.movers(),
|
|
85283
85777
|
residue: () => migration.residue(),
|
|
85284
|
-
drain: async (input) => ({ jobId: await migration.drain(input) })
|
|
85778
|
+
drain: async (input) => ({ jobId: await migration.drain(input) }),
|
|
85779
|
+
cleanupStart: async (input) => ({ jobId: await cleanup.start(input) }),
|
|
85780
|
+
cleanupStatus: ({ jobId }) => cleanup.status(jobId),
|
|
85781
|
+
cleanupCancel: async ({ jobId }) => ({ cancelled: await cleanup.cancel(jobId) }),
|
|
85782
|
+
history: () => migration.history()
|
|
85285
85783
|
};
|
|
85286
85784
|
await this.seedFromDeclarations();
|
|
85287
85785
|
const eventBus = this.ctx.eventBus;
|
|
@@ -85526,11 +86024,14 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85526
86024
|
}
|
|
85527
86025
|
}
|
|
85528
86026
|
/**
|
|
85529
|
-
* Does this location still hold anything
|
|
85530
|
-
*
|
|
85531
|
-
*
|
|
85532
|
-
*
|
|
85533
|
-
*
|
|
86027
|
+
* Does this location still hold anything of ITS class?
|
|
86028
|
+
*
|
|
86029
|
+
* Shared roots (`/recordings` hosting high + low + events) are scored by
|
|
86030
|
+
* class subtree (`<camera>/high|mid`, `/low`, `/events`), not by a raw
|
|
86031
|
+
* `readdir` of the root — camera dirs and `.camstack-location` would
|
|
86032
|
+
* otherwise make every class look occupied. The walk stays shallow: one
|
|
86033
|
+
* dirent per camera, then first-entry of the named subtree. A `find` of
|
|
86034
|
+
* segments is precisely what must not happen here.
|
|
85534
86035
|
*
|
|
85535
86036
|
* **What it cannot see, stated rather than papered over:**
|
|
85536
86037
|
*
|
|
@@ -85539,9 +86040,10 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85539
86040
|
* `unknown`, never `empty`.
|
|
85540
86041
|
* - A location with no `basePath` — same answer.
|
|
85541
86042
|
* - The difference between "holds live footage" and "holds one stray
|
|
85542
|
-
* lock-file". It measures
|
|
85543
|
-
* a location holding orphan files that no index
|
|
85544
|
-
* the safe one, and `force` is the escape
|
|
86043
|
+
* lock-file". It measures ON-DISK entries of this class, not durable
|
|
86044
|
+
* rows, so it refuses a location holding orphan files that no index
|
|
86045
|
+
* names. That direction is the safe one, and `force` is the escape
|
|
86046
|
+
* hatch for it.
|
|
85545
86047
|
*
|
|
85546
86048
|
* A missing root (`ENOENT`) is `empty`, not `unknown`: an unmounted disk and
|
|
85547
86049
|
* a deleted directory are indistinguishable here, and if the record's own
|
|
@@ -85559,16 +86061,16 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85559
86061
|
if ((location.nodeId === void 0 || location.nodeId === "" ? HUB_NODE_ID : location.nodeId) !== (this.service?.getLocalNodeId() ?? HUB_NODE_ID)) return "unknown";
|
|
85560
86062
|
const basePath = this.locationBasePath(location.id);
|
|
85561
86063
|
if (basePath === null) return "unknown";
|
|
85562
|
-
|
|
85563
|
-
|
|
85564
|
-
|
|
85565
|
-
|
|
85566
|
-
|
|
85567
|
-
|
|
85568
|
-
|
|
85569
|
-
|
|
85570
|
-
|
|
85571
|
-
|
|
86064
|
+
const occupancy = await probeLocalDirectoryOccupancy({
|
|
86065
|
+
type: location.type,
|
|
86066
|
+
basePath
|
|
86067
|
+
});
|
|
86068
|
+
if (occupancy === "unknown") this.ctx.logger.warn("storage-orchestrator: could not read a location root to check it", { meta: {
|
|
86069
|
+
id: location.id,
|
|
86070
|
+
basePath,
|
|
86071
|
+
type: location.type
|
|
86072
|
+
} });
|
|
86073
|
+
return occupancy;
|
|
85572
86074
|
}
|
|
85573
86075
|
/** Free capacity (%) on a location's volume via `statfs`; 100 (guard inert) when unstattable. */
|
|
85574
86076
|
async locationFreePercent(locationId) {
|
|
@@ -85644,6 +86146,38 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85644
86146
|
}
|
|
85645
86147
|
}
|
|
85646
86148
|
};
|
|
86149
|
+
function parseStarted(raw) {
|
|
86150
|
+
if (raw !== null && typeof raw === "object") {
|
|
86151
|
+
const o = raw;
|
|
86152
|
+
if (typeof o["started"] === "boolean" && typeof o["alreadyRunning"] === "boolean") return {
|
|
86153
|
+
started: o["started"],
|
|
86154
|
+
alreadyRunning: o["alreadyRunning"]
|
|
86155
|
+
};
|
|
86156
|
+
}
|
|
86157
|
+
return {
|
|
86158
|
+
started: false,
|
|
86159
|
+
alreadyRunning: false
|
|
86160
|
+
};
|
|
86161
|
+
}
|
|
86162
|
+
function parseOrphanStatus(raw) {
|
|
86163
|
+
if (raw !== null && typeof raw === "object") {
|
|
86164
|
+
const o = raw;
|
|
86165
|
+
return {
|
|
86166
|
+
running: o["running"] === true,
|
|
86167
|
+
complete: typeof o["complete"] === "boolean" ? o["complete"] : null,
|
|
86168
|
+
totalReclaimed: typeof o["totalReclaimed"] === "number" ? o["totalReclaimed"] : 0,
|
|
86169
|
+
totalBytesReclaimed: typeof o["totalBytesReclaimed"] === "number" ? o["totalBytesReclaimed"] : 0,
|
|
86170
|
+
error: typeof o["error"] === "string" ? o["error"] : null
|
|
86171
|
+
};
|
|
86172
|
+
}
|
|
86173
|
+
return {
|
|
86174
|
+
running: false,
|
|
86175
|
+
complete: true,
|
|
86176
|
+
totalReclaimed: 0,
|
|
86177
|
+
totalBytesReclaimed: 0,
|
|
86178
|
+
error: "orphan audit status unreadable"
|
|
86179
|
+
};
|
|
86180
|
+
}
|
|
85647
86181
|
exports.SqliteLocationStore = SqliteLocationStore;
|
|
85648
86182
|
exports.StorageMigrationCoordinator = StorageMigrationCoordinator;
|
|
85649
86183
|
exports.StorageOrchestratorAddon = StorageOrchestratorAddon;
|
|
@@ -85680,7 +86214,7 @@ var require_system_config_addon = __commonJS({
|
|
|
85680
86214
|
[Symbol.toStringTag]: { value: "Module" }
|
|
85681
86215
|
});
|
|
85682
86216
|
require_chunk_Cek0wNdY();
|
|
85683
|
-
var require_dist10 =
|
|
86217
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
85684
86218
|
var SECTION_TITLES = {
|
|
85685
86219
|
server: "Server",
|
|
85686
86220
|
auth: "Authentication"
|
|
@@ -103741,7 +104275,7 @@ var require_winston_logging = __commonJS({
|
|
|
103741
104275
|
[Symbol.toStringTag]: { value: "Module" }
|
|
103742
104276
|
});
|
|
103743
104277
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
103744
|
-
var require_dist10 =
|
|
104278
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
103745
104279
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
103746
104280
|
var node_path = __require("path");
|
|
103747
104281
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -105684,9 +106218,9 @@ var require_event_category_BaEgqJNv = __commonJS({
|
|
|
105684
106218
|
}
|
|
105685
106219
|
});
|
|
105686
106220
|
|
|
105687
|
-
// ../types/dist/sleep-
|
|
105688
|
-
var
|
|
105689
|
-
"../types/dist/sleep-
|
|
106221
|
+
// ../types/dist/sleep-CqVyhcl-.js
|
|
106222
|
+
var require_sleep_CqVyhcl = __commonJS({
|
|
106223
|
+
"../types/dist/sleep-CqVyhcl-.js"(exports) {
|
|
105690
106224
|
"use strict";
|
|
105691
106225
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
105692
106226
|
var zod = require_zod();
|
|
@@ -108393,6 +108927,8 @@ var require_sleep_DIg3xuEw = __commonJS({
|
|
|
108393
108927
|
listRelocateMediaJobs: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRelocateMediaJobs", "query", input),
|
|
108394
108928
|
cancelRelocateMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "cancelRelocateMedia", "mutation", input),
|
|
108395
108929
|
listOpsLog: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listOpsLog", "query", input),
|
|
108930
|
+
reclaimDebugMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "reclaimDebugMedia", "mutation", input),
|
|
108931
|
+
getMediaReclaimStatus: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getMediaReclaimStatus", "query", input),
|
|
108396
108932
|
getTrainingExportSummary: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrainingExportSummary", "query", input),
|
|
108397
108933
|
getTrainingExportUrl: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrainingExportUrl", "query", input),
|
|
108398
108934
|
listRetrainStaging: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRetrainStaging", "query", input),
|
|
@@ -109357,7 +109893,7 @@ var require_addon = __commonJS({
|
|
|
109357
109893
|
"use strict";
|
|
109358
109894
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
109359
109895
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
109360
|
-
var require_sleep =
|
|
109896
|
+
var require_sleep = require_sleep_CqVyhcl();
|
|
109361
109897
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
109362
109898
|
var CAP_INPUT_DEFAULTS = Object.freeze({
|
|
109363
109899
|
"addons": { "getLogs": { "limit": 100 } },
|
|
@@ -109473,6 +110009,7 @@ var require_addon = __commonJS({
|
|
|
109473
110009
|
"getSensorEvents": { "limit": 1e3 },
|
|
109474
110010
|
"listGroups": { "limit": 40 },
|
|
109475
110011
|
"listRecentTracks": { "limit": 200 },
|
|
110012
|
+
"reclaimDebugMedia": { "mode": "report" },
|
|
109476
110013
|
"searchObjectEvents": {
|
|
109477
110014
|
"limit": 50,
|
|
109478
110015
|
"minScore": 0.2
|
|
@@ -116240,12 +116777,12 @@ var require_dist2 = __commonJS({
|
|
|
116240
116777
|
}
|
|
116241
116778
|
});
|
|
116242
116779
|
|
|
116243
|
-
// ../system/dist/manifest-system-deps-
|
|
116244
|
-
var
|
|
116245
|
-
"../system/dist/manifest-system-deps-
|
|
116780
|
+
// ../system/dist/manifest-system-deps-BIxY1Y5e.js
|
|
116781
|
+
var require_manifest_system_deps_BIxY1Y5e = __commonJS({
|
|
116782
|
+
"../system/dist/manifest-system-deps-BIxY1Y5e.js"(exports) {
|
|
116246
116783
|
"use strict";
|
|
116247
116784
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
116248
|
-
|
|
116785
|
+
require_dist_CFTKQGym();
|
|
116249
116786
|
var node_crypto = __require("crypto");
|
|
116250
116787
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
116251
116788
|
var _camstack_types_node = require_node();
|
|
@@ -123530,6 +124067,93 @@ var require_manifest_system_deps_DBje540e = __commonJS({
|
|
|
123530
124067
|
}
|
|
123531
124068
|
await deps.installPythonRequirements(reqAbs);
|
|
123532
124069
|
}
|
|
124070
|
+
var DISTRO_PACKAGE_ALLOWLIST = {
|
|
124071
|
+
apt: ["smbclient"],
|
|
124072
|
+
apk: ["samba-client"],
|
|
124073
|
+
dnf: ["samba-client"]
|
|
124074
|
+
};
|
|
124075
|
+
function packageIsAllowlisted(manager, packageName) {
|
|
124076
|
+
if (manager === "brew") return true;
|
|
124077
|
+
if (packageName.length === 0) return false;
|
|
124078
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9+._-]*$/.test(packageName)) return false;
|
|
124079
|
+
return DISTRO_PACKAGE_ALLOWLIST[manager].includes(packageName);
|
|
124080
|
+
}
|
|
124081
|
+
function decidePackageInstall(input) {
|
|
124082
|
+
if (input.manager === "brew") return { kind: "local" };
|
|
124083
|
+
if (!packageIsAllowlisted(input.manager, input.packageName)) return {
|
|
124084
|
+
kind: "refuse",
|
|
124085
|
+
reason: "not-allowlisted"
|
|
124086
|
+
};
|
|
124087
|
+
if (!input.helperAvailable) return {
|
|
124088
|
+
kind: "refuse",
|
|
124089
|
+
reason: "helper-unavailable"
|
|
124090
|
+
};
|
|
124091
|
+
return { kind: "helper" };
|
|
124092
|
+
}
|
|
124093
|
+
function pkgdSocketPath() {
|
|
124094
|
+
return process.env["CAMSTACK_PKGD_SOCKET"] ?? "/run/camstack/pkgd.sock";
|
|
124095
|
+
}
|
|
124096
|
+
function privilegedHelperAvailable(socketPath = pkgdSocketPath()) {
|
|
124097
|
+
return (0, node_fs.existsSync)(socketPath);
|
|
124098
|
+
}
|
|
124099
|
+
function requestPrivilegedInstall(req, socketPath = pkgdSocketPath(), timeoutMs = 360 * 1e3) {
|
|
124100
|
+
return new Promise((resolve) => {
|
|
124101
|
+
const socket = (0, node_net.createConnection)({ path: socketPath });
|
|
124102
|
+
const chunks = [];
|
|
124103
|
+
const finish = (result) => {
|
|
124104
|
+
socket.destroy();
|
|
124105
|
+
resolve(result);
|
|
124106
|
+
};
|
|
124107
|
+
const timer = setTimeout(() => {
|
|
124108
|
+
finish({
|
|
124109
|
+
ok: false,
|
|
124110
|
+
error: `privileged helper timed out after ${timeoutMs}ms`
|
|
124111
|
+
});
|
|
124112
|
+
}, timeoutMs);
|
|
124113
|
+
socket.on("connect", () => {
|
|
124114
|
+
socket.write(`${JSON.stringify({
|
|
124115
|
+
v: 1,
|
|
124116
|
+
...req
|
|
124117
|
+
})}
|
|
124118
|
+
`);
|
|
124119
|
+
});
|
|
124120
|
+
socket.on("data", (data) => {
|
|
124121
|
+
chunks.push(data);
|
|
124122
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
124123
|
+
const nl = text.indexOf("\n");
|
|
124124
|
+
if (nl === -1) return;
|
|
124125
|
+
clearTimeout(timer);
|
|
124126
|
+
try {
|
|
124127
|
+
const parsed = JSON.parse(text.slice(0, nl));
|
|
124128
|
+
finish({
|
|
124129
|
+
ok: parsed.ok === true,
|
|
124130
|
+
...parsed.error !== void 0 ? { error: parsed.error } : {}
|
|
124131
|
+
});
|
|
124132
|
+
} catch (err) {
|
|
124133
|
+
finish({
|
|
124134
|
+
ok: false,
|
|
124135
|
+
error: err instanceof Error ? err.message : String(err)
|
|
124136
|
+
});
|
|
124137
|
+
}
|
|
124138
|
+
});
|
|
124139
|
+
socket.on("error", (err) => {
|
|
124140
|
+
clearTimeout(timer);
|
|
124141
|
+
finish({
|
|
124142
|
+
ok: false,
|
|
124143
|
+
error: err.message
|
|
124144
|
+
});
|
|
124145
|
+
});
|
|
124146
|
+
socket.on("end", () => {
|
|
124147
|
+
if (chunks.length === 0) {
|
|
124148
|
+
clearTimeout(timer);
|
|
124149
|
+
finish({
|
|
124150
|
+
ok: false,
|
|
124151
|
+
error: "privileged helper closed without a reply"
|
|
124152
|
+
});
|
|
124153
|
+
}
|
|
124154
|
+
});
|
|
124155
|
+
});
|
|
124156
|
+
}
|
|
123533
124157
|
var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
|
|
123534
124158
|
var INSTALL_TIMEOUT_MS = 300 * 1e3;
|
|
123535
124159
|
var PROBE_TIMEOUT_MS = 1e4;
|
|
@@ -123540,12 +124164,16 @@ var require_manifest_system_deps_DBje540e = __commonJS({
|
|
|
123540
124164
|
const detectManager = options.detectManager ?? defaultDetectManager;
|
|
123541
124165
|
const run = options.run ?? defaultRun;
|
|
123542
124166
|
const platform = options.platform ?? process.platform;
|
|
124167
|
+
const helperAvailable = options.helperAvailable ?? (async () => privilegedHelperAvailable());
|
|
124168
|
+
const requestInstall = options.requestInstall ?? ((req) => requestPrivilegedInstall(req));
|
|
123543
124169
|
for (const dep of deps) try {
|
|
123544
124170
|
await satisfyOne(dep, declaration.id, {
|
|
123545
124171
|
hasBinary,
|
|
123546
124172
|
detectManager,
|
|
123547
124173
|
run,
|
|
123548
|
-
platform
|
|
124174
|
+
platform,
|
|
124175
|
+
helperAvailable,
|
|
124176
|
+
requestInstall
|
|
123549
124177
|
}, logger);
|
|
123550
124178
|
} catch (err) {
|
|
123551
124179
|
logger.warn("system dependency step failed", { meta: {
|
|
@@ -123583,15 +124211,43 @@ var require_manifest_system_deps_DBje540e = __commonJS({
|
|
|
123583
124211
|
} });
|
|
123584
124212
|
return;
|
|
123585
124213
|
}
|
|
123586
|
-
const
|
|
124214
|
+
const decision = decidePackageInstall({
|
|
124215
|
+
manager,
|
|
124216
|
+
packageName,
|
|
124217
|
+
helperAvailable: await rt.helperAvailable()
|
|
124218
|
+
});
|
|
124219
|
+
if (decision.kind === "refuse") {
|
|
124220
|
+
const message = decision.reason === "helper-unavailable" ? "system dependency missing and the privileged helper is not running \u2014 apt cannot run as uid 1001" : "system dependency missing and the package is not on the helper allowlist";
|
|
124221
|
+
logger.warn(message, { meta: {
|
|
124222
|
+
addonId,
|
|
124223
|
+
binary: dep.binary,
|
|
124224
|
+
manager,
|
|
124225
|
+
package: packageName,
|
|
124226
|
+
reason: decision.reason,
|
|
124227
|
+
...dep.reason !== void 0 ? { reason: dep.reason } : {}
|
|
124228
|
+
} });
|
|
124229
|
+
return;
|
|
124230
|
+
}
|
|
123587
124231
|
logger.info("installing system dependency", { meta: {
|
|
123588
124232
|
addonId,
|
|
123589
124233
|
binary: dep.binary,
|
|
123590
124234
|
manager,
|
|
123591
|
-
package: packageName
|
|
124235
|
+
package: packageName,
|
|
124236
|
+
via: decision.kind
|
|
123592
124237
|
} });
|
|
123593
124238
|
try {
|
|
123594
|
-
|
|
124239
|
+
if (decision.kind === "helper") {
|
|
124240
|
+
const result = await rt.requestInstall({
|
|
124241
|
+
addonId,
|
|
124242
|
+
binary: dep.binary,
|
|
124243
|
+
manager,
|
|
124244
|
+
packageName
|
|
124245
|
+
});
|
|
124246
|
+
if (!result.ok) throw new Error(result.error ?? "privileged helper refused");
|
|
124247
|
+
} else {
|
|
124248
|
+
const plan = planFor(manager, packageName);
|
|
124249
|
+
for (const [command, args] of plan.steps) await rt.run(command, args);
|
|
124250
|
+
}
|
|
123595
124251
|
} catch (err) {
|
|
123596
124252
|
logger.warn("system dependency install failed \u2014 the addon loads, its capability must refuse", { meta: {
|
|
123597
124253
|
addonId,
|
|
@@ -128274,7 +128930,7 @@ var require_dist3 = __commonJS({
|
|
|
128274
128930
|
"use strict";
|
|
128275
128931
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
128276
128932
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
128277
|
-
var require_dist10 =
|
|
128933
|
+
var require_dist10 = require_dist_CFTKQGym();
|
|
128278
128934
|
var require_builtins_alerts_alerts_addon = require_alerts_addon();
|
|
128279
128935
|
require_alerts();
|
|
128280
128936
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
@@ -128300,7 +128956,7 @@ var require_dist3 = __commonJS({
|
|
|
128300
128956
|
var require_builtins_winston_logging_index = require_winston_logging();
|
|
128301
128957
|
var require_file_data_plane = require_file_data_plane_DO8KbxCe();
|
|
128302
128958
|
var require_tls$1 = require_tls_BxQlomxd();
|
|
128303
|
-
var require_manifest_system_deps =
|
|
128959
|
+
var require_manifest_system_deps = require_manifest_system_deps_BIxY1Y5e();
|
|
128304
128960
|
var require_resource_monitor = require_resource_monitor_CdnzxBLP();
|
|
128305
128961
|
var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
|
|
128306
128962
|
var zod = require_zod();
|
|
@@ -209142,7 +209798,7 @@ var require_dist4 = __commonJS({
|
|
|
209142
209798
|
"use strict";
|
|
209143
209799
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
209144
209800
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
209145
|
-
var require_sleep =
|
|
209801
|
+
var require_sleep = require_sleep_CqVyhcl();
|
|
209146
209802
|
var require_canonical_hash = require_canonical_hash_DNV8S5ET();
|
|
209147
209803
|
var require_enums2 = require_enums();
|
|
209148
209804
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
@@ -210541,6 +211197,13 @@ var require_dist4 = __commonJS({
|
|
|
210541
211197
|
]);
|
|
210542
211198
|
var RelocateMediaInputSchema = zod.z.object({
|
|
210543
211199
|
toLocationId: zod.z.string(),
|
|
211200
|
+
/**
|
|
211201
|
+
* Restrict the pass to rows currently on this location. Omitted / `'*'` =
|
|
211202
|
+
* every row that is not already on `toLocationId` (the historical
|
|
211203
|
+
* behaviour). A named source is what a from→to migration needs: without it
|
|
211204
|
+
* "move events off disk 2" also emptied disk 1.
|
|
211205
|
+
*/
|
|
211206
|
+
fromLocationId: zod.z.string().optional(),
|
|
210544
211207
|
throttleMbps: zod.z.number().min(1).max(1e3).optional(),
|
|
210545
211208
|
/** Omitted = `move`, the pre-existing behaviour. */
|
|
210546
211209
|
mode: MediaRelocateModeSchema.optional()
|
|
@@ -210572,9 +211235,18 @@ var require_dist4 = __commonJS({
|
|
|
210572
211235
|
backups: zod.z.string().min(1).optional(),
|
|
210573
211236
|
galleryMedia: zod.z.string().min(1).optional()
|
|
210574
211237
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
211238
|
+
var StorageMigrationSourcesSchema = zod.z.object({
|
|
211239
|
+
recordings: zod.z.string().min(1).optional(),
|
|
211240
|
+
recordingsLow: zod.z.string().min(1).optional(),
|
|
211241
|
+
eventMedia: zod.z.string().min(1).optional(),
|
|
211242
|
+
backups: zod.z.string().min(1).optional(),
|
|
211243
|
+
galleryMedia: zod.z.string().min(1).optional()
|
|
211244
|
+
}).optional();
|
|
210575
211245
|
var StorageMigrationModeSchema = zod.z.enum(["blocking", "nonBlocking"]);
|
|
210576
211246
|
var StorageMigrationInputSchema = zod.z.object({
|
|
210577
211247
|
destinations: StorageMigrationDestinationsSchema,
|
|
211248
|
+
/** Omitted = each class's current default. */
|
|
211249
|
+
sources: StorageMigrationSourcesSchema,
|
|
210578
211250
|
throttleMbps: zod.z.number().min(1).max(1e3).optional(),
|
|
210579
211251
|
/** Omitted = `blocking`, which stays the default. */
|
|
210580
211252
|
mode: StorageMigrationModeSchema.optional()
|
|
@@ -210620,6 +211292,13 @@ var require_dist4 = __commonJS({
|
|
|
210620
211292
|
storageClass: StorageMigrationClassSchema,
|
|
210621
211293
|
fromLocationId: zod.z.string(),
|
|
210622
211294
|
toLocationId: zod.z.string(),
|
|
211295
|
+
/**
|
|
211296
|
+
* True when `from` was NOT the class default at plan time. The move still
|
|
211297
|
+
* copies bytes, but the default is left alone and the source is disabled
|
|
211298
|
+
* once the copy verifies. Absent on jobs planned before this field existed
|
|
211299
|
+
* — those jobs always repointed, which is `false`.
|
|
211300
|
+
*/
|
|
211301
|
+
freezeSource: zod.z.boolean().optional(),
|
|
210623
211302
|
moverJobId: zod.z.string().nullable(),
|
|
210624
211303
|
state: RelocateJobStateSchema.nullable(),
|
|
210625
211304
|
error: zod.z.string().nullable(),
|
|
@@ -210633,6 +211312,7 @@ var require_dist4 = __commonJS({
|
|
|
210633
211312
|
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
210634
211313
|
mode: StorageMigrationModeSchema,
|
|
210635
211314
|
destinations: StorageMigrationDestinationsSchema,
|
|
211315
|
+
sources: StorageMigrationSourcesSchema,
|
|
210636
211316
|
throttleMbps: zod.z.number(),
|
|
210637
211317
|
moves: zod.z.array(StorageMigrationMoveSchema),
|
|
210638
211318
|
pauseLeaseId: zod.z.string().nullable(),
|
|
@@ -210659,6 +211339,7 @@ var require_dist4 = __commonJS({
|
|
|
210659
211339
|
});
|
|
210660
211340
|
var StorageMigrationPlanSchema = zod.z.object({
|
|
210661
211341
|
destinations: StorageMigrationDestinationsSchema,
|
|
211342
|
+
sources: StorageMigrationSourcesSchema,
|
|
210662
211343
|
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
210663
211344
|
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
210664
211345
|
* it. */
|
|
@@ -210666,7 +211347,8 @@ var require_dist4 = __commonJS({
|
|
|
210666
211347
|
moves: zod.z.array(zod.z.object({
|
|
210667
211348
|
storageClass: StorageMigrationClassSchema,
|
|
210668
211349
|
fromLocationId: zod.z.string(),
|
|
210669
|
-
toLocationId: zod.z.string()
|
|
211350
|
+
toLocationId: zod.z.string(),
|
|
211351
|
+
freezeSource: zod.z.boolean().optional()
|
|
210670
211352
|
})),
|
|
210671
211353
|
findings: zod.z.array(StorageMigrationFindingSchema)
|
|
210672
211354
|
});
|
|
@@ -210778,9 +211460,42 @@ var require_dist4 = __commonJS({
|
|
|
210778
211460
|
var RelocatableMediaCountSchema = zod.z.object({ rows: zod.z.number().int().nonnegative() }).nullable();
|
|
210779
211461
|
var RelocatableMediaCountInputSchema = zod.z.object({
|
|
210780
211462
|
toLocationId: zod.z.string().min(1),
|
|
211463
|
+
/** Restrict the count to one source; omitted / `'*'` = every non-target row. */
|
|
211464
|
+
fromLocationId: zod.z.string().optional(),
|
|
210781
211465
|
/** Omitted = `move`. */
|
|
210782
211466
|
mode: MediaRelocateModeSchema.optional()
|
|
210783
211467
|
});
|
|
211468
|
+
var StorageCleanupPhaseSchema = zod.z.enum([
|
|
211469
|
+
"orphans",
|
|
211470
|
+
"debug-media",
|
|
211471
|
+
"ghost-ledger",
|
|
211472
|
+
"done",
|
|
211473
|
+
"failed",
|
|
211474
|
+
"cancelled"
|
|
211475
|
+
]);
|
|
211476
|
+
var StorageCleanupInputSchema = zod.z.object({
|
|
211477
|
+
/** Also walk motion stills / track filmstrips. Off by default. */
|
|
211478
|
+
includeDebugMedia: zod.z.boolean().optional()
|
|
211479
|
+
});
|
|
211480
|
+
var StorageCleanupJobSchema = zod.z.object({
|
|
211481
|
+
jobId: zod.z.string(),
|
|
211482
|
+
phase: StorageCleanupPhaseSchema,
|
|
211483
|
+
includeDebugMedia: zod.z.boolean(),
|
|
211484
|
+
orphansReclaimed: zod.z.number().int().nonnegative(),
|
|
211485
|
+
orphanBytesReclaimed: zod.z.number().int().nonnegative(),
|
|
211486
|
+
debugMediaReclaimed: zod.z.number().int().nonnegative(),
|
|
211487
|
+
debugMediaBytesReclaimed: zod.z.number().int().nonnegative(),
|
|
211488
|
+
ghostsForgotten: zod.z.number().int().nonnegative(),
|
|
211489
|
+
ghostBytesForgotten: zod.z.number().int().nonnegative(),
|
|
211490
|
+
/** Short operator-facing line: current collection, pass, or location. */
|
|
211491
|
+
detail: zod.z.string().nullable(),
|
|
211492
|
+
cancelRequested: zod.z.boolean(),
|
|
211493
|
+
startedAt: zod.z.number(),
|
|
211494
|
+
updatedAt: zod.z.number(),
|
|
211495
|
+
finishedAt: zod.z.number().nullable(),
|
|
211496
|
+
error: zod.z.string().nullable()
|
|
211497
|
+
});
|
|
211498
|
+
var StorageCleanupStatusInputSchema = zod.z.object({ jobId: zod.z.string().optional() });
|
|
210784
211499
|
var SUB_DETECTION_TYPES = ["face", "plate"];
|
|
210785
211500
|
var RECOGNITION_TYPES = [
|
|
210786
211501
|
"face",
|
|
@@ -223483,6 +224198,39 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
223483
224198
|
/** Present when the pass ended by throwing. */
|
|
223484
224199
|
error: zod.z.string().nullable()
|
|
223485
224200
|
});
|
|
224201
|
+
var MediaReclaimStartResultSchema = zod.z.object({
|
|
224202
|
+
started: zod.z.boolean(),
|
|
224203
|
+
/** True when a pass was already running; the new request is ignored. */
|
|
224204
|
+
alreadyRunning: zod.z.boolean()
|
|
224205
|
+
});
|
|
224206
|
+
var MediaReclaimInputSchema = zod.z.object({
|
|
224207
|
+
mode: zod.z.enum(["report", "reclaim"]).default("report"),
|
|
224208
|
+
scopes: zod.z.array(zod.z.enum(["motion-still", "track-filmstrip"])).min(1).optional(),
|
|
224209
|
+
deviceIds: zod.z.array(zod.z.number().int()).min(1).optional(),
|
|
224210
|
+
restart: zod.z.boolean().optional(),
|
|
224211
|
+
pageSize: zod.z.number().int().min(50).max(5e3).optional(),
|
|
224212
|
+
maxRowsPerDevice: zod.z.number().int().min(1).max(5e5).optional(),
|
|
224213
|
+
maxReclaimPerDevice: zod.z.number().int().min(1).max(5e5).optional(),
|
|
224214
|
+
maxBytesPerRun: zod.z.number().int().min(1).optional(),
|
|
224215
|
+
budgetMinutes: zod.z.number().int().min(1).max(720).optional(),
|
|
224216
|
+
throttleBytesPerSec: zod.z.number().int().min(64 * 1024).optional(),
|
|
224217
|
+
graceMinutes: zod.z.number().int().min(1).max(10080).optional()
|
|
224218
|
+
});
|
|
224219
|
+
var MediaReclaimStatusSchema = zod.z.object({
|
|
224220
|
+
running: zod.z.boolean(),
|
|
224221
|
+
mode: zod.z.enum(["report", "reclaim"]).nullable(),
|
|
224222
|
+
totalExamined: zod.z.number(),
|
|
224223
|
+
totalEligible: zod.z.number(),
|
|
224224
|
+
totalReclaimed: zod.z.number(),
|
|
224225
|
+
totalBytesReclaimed: zod.z.number(),
|
|
224226
|
+
totalRefused: zod.z.number(),
|
|
224227
|
+
/** Device+scope windows finished in this pass. */
|
|
224228
|
+
devicesDone: zod.z.number(),
|
|
224229
|
+
complete: zod.z.boolean().nullable(),
|
|
224230
|
+
startedAtMs: zod.z.number().nullable(),
|
|
224231
|
+
finishedAtMs: zod.z.number().nullable(),
|
|
224232
|
+
error: zod.z.string().nullable()
|
|
224233
|
+
});
|
|
223486
224234
|
var ReplayFrameInputSchema = zod.z.object({
|
|
223487
224235
|
timestamp: zod.z.number(),
|
|
223488
224236
|
frame: PipelineRunResultBridge
|
|
@@ -223906,6 +224654,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
223906
224654
|
auth: "admin"
|
|
223907
224655
|
}),
|
|
223908
224656
|
/**
|
|
224657
|
+
* Reclaim the standing debug-media backlog (motion-visit stills + track
|
|
224658
|
+
* filmstrips). DETACHED: returns `{ started }` immediately. The pass is
|
|
224659
|
+
* tens of minutes; awaiting it is a timeout, not a verdict. Dry-run unless
|
|
224660
|
+
* `mode: 'reclaim'`. Poll `getMediaReclaimStatus`.
|
|
224661
|
+
*/
|
|
224662
|
+
reclaimDebugMedia: require_sleep.method(MediaReclaimInputSchema, MediaReclaimStartResultSchema, {
|
|
224663
|
+
kind: "mutation",
|
|
224664
|
+
auth: "admin"
|
|
224665
|
+
}),
|
|
224666
|
+
getMediaReclaimStatus: require_sleep.method(zod.z.object({}), MediaReclaimStatusSchema, {
|
|
224667
|
+
kind: "query",
|
|
224668
|
+
auth: "admin"
|
|
224669
|
+
}),
|
|
224670
|
+
/**
|
|
223909
224671
|
* The CHEAP QUESTION, asked before any media moves: how big is the dataset
|
|
223910
224672
|
* the marked (`markForTrain`) tracks would produce?
|
|
223911
224673
|
*
|
|
@@ -226657,7 +227419,23 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
226657
227419
|
drain: require_sleep.method(StorageMigrationDrainInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
226658
227420
|
kind: "mutation",
|
|
226659
227421
|
auth: "admin"
|
|
226660
|
-
})
|
|
227422
|
+
}),
|
|
227423
|
+
/**
|
|
227424
|
+
* One operator cleanup of leftover analytics (DB + blobs) and ghost
|
|
227425
|
+
* ledger rows on frozen footage locations. Optional debug-media sweep.
|
|
227426
|
+
* Returns immediately; poll {@link cleanupStatus}.
|
|
227427
|
+
*/
|
|
227428
|
+
cleanupStart: require_sleep.method(StorageCleanupInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
227429
|
+
kind: "mutation",
|
|
227430
|
+
auth: "admin"
|
|
227431
|
+
}),
|
|
227432
|
+
cleanupStatus: require_sleep.method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }),
|
|
227433
|
+
cleanupCancel: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
|
|
227434
|
+
kind: "mutation",
|
|
227435
|
+
auth: "admin"
|
|
227436
|
+
}),
|
|
227437
|
+
/** Recent finished migration jobs, newest first. The live job is `status`. */
|
|
227438
|
+
history: require_sleep.method(zod.z.object({}), zod.z.array(StorageMigrationJobSchema).readonly(), { auth: "admin" })
|
|
226661
227439
|
}
|
|
226662
227440
|
};
|
|
226663
227441
|
var ProviderInfoSchema = zod.z.discriminatedUnion("shouldSaveDiskSpace", [zod.z.object({
|
|
@@ -233458,6 +234236,26 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
233458
234236
|
/** Ignore piles smaller than this (default 1 GB). */
|
|
233459
234237
|
minMoveGb: zod.z.number().min(0).optional()
|
|
233460
234238
|
});
|
|
234239
|
+
var RecordingDevicePlacementSchema = zod.z.object({
|
|
234240
|
+
deviceId: zod.z.number().int(),
|
|
234241
|
+
profile: zod.z.string(),
|
|
234242
|
+
locationId: zod.z.string()
|
|
234243
|
+
});
|
|
234244
|
+
var RecordingDevicePinSchema = zod.z.object({
|
|
234245
|
+
deviceId: zod.z.number().int(),
|
|
234246
|
+
/** Recordings-class location this camera is pinned to. */
|
|
234247
|
+
locationId: zod.z.string()
|
|
234248
|
+
});
|
|
234249
|
+
var RecordingPlacementViewSchema = zod.z.object({
|
|
234250
|
+
assignments: zod.z.array(RecordingDevicePlacementSchema),
|
|
234251
|
+
pins: zod.z.array(RecordingDevicePinSchema),
|
|
234252
|
+
defaultLocations: zod.z.record(zod.z.string(), zod.z.string())
|
|
234253
|
+
});
|
|
234254
|
+
var RecordingSetDevicePlacementInputSchema = zod.z.object({
|
|
234255
|
+
deviceId: zod.z.number().int(),
|
|
234256
|
+
/** `null` = Auto. Otherwise a `recordings:*` location id. */
|
|
234257
|
+
locationId: zod.z.string().nullable()
|
|
234258
|
+
});
|
|
233461
234259
|
var LocateSegmentResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
|
|
233462
234260
|
kind: zod.z.literal("segment"),
|
|
233463
234261
|
startMs: zod.z.number(),
|
|
@@ -233776,6 +234574,22 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
233776
234574
|
startStorageRebalance: require_sleep.method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
|
|
233777
234575
|
kind: "mutation",
|
|
233778
234576
|
auth: "admin"
|
|
234577
|
+
}),
|
|
234578
|
+
/**
|
|
234579
|
+
* The placement plan in force plus operator pins. Drives the Locations
|
|
234580
|
+
* admin page: Auto vs a named recordings location, per camera.
|
|
234581
|
+
*/
|
|
234582
|
+
getPlacement: require_sleep.method(zod.z.object({}), RecordingPlacementViewSchema, {
|
|
234583
|
+
kind: "query",
|
|
234584
|
+
auth: "admin"
|
|
234585
|
+
}),
|
|
234586
|
+
/**
|
|
234587
|
+
* Pin a camera to a recordings location, or clear the pin (Auto). High and
|
|
234588
|
+
* mid follow the pin; low stays with the recordingsLow planner.
|
|
234589
|
+
*/
|
|
234590
|
+
setDevicePlacement: require_sleep.method(RecordingSetDevicePlacementInputSchema, zod.z.object({ ok: zod.z.literal(true) }), {
|
|
234591
|
+
kind: "mutation",
|
|
234592
|
+
auth: "admin"
|
|
233779
234593
|
})
|
|
233780
234594
|
}
|
|
233781
234595
|
};
|
|
@@ -242825,6 +243639,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
242825
243639
|
addonId: null,
|
|
242826
243640
|
access: "view"
|
|
242827
243641
|
},
|
|
243642
|
+
"pipelineAnalytics.getMediaReclaimStatus": {
|
|
243643
|
+
capName: "pipeline-analytics",
|
|
243644
|
+
capScope: "device",
|
|
243645
|
+
addonId: null,
|
|
243646
|
+
access: "view"
|
|
243647
|
+
},
|
|
242828
243648
|
"pipelineAnalytics.getMotionEvents": {
|
|
242829
243649
|
capName: "pipeline-analytics",
|
|
242830
243650
|
capScope: "device",
|
|
@@ -242999,6 +243819,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
242999
243819
|
addonId: null,
|
|
243000
243820
|
access: "create"
|
|
243001
243821
|
},
|
|
243822
|
+
"pipelineAnalytics.reclaimDebugMedia": {
|
|
243823
|
+
capName: "pipeline-analytics",
|
|
243824
|
+
capScope: "device",
|
|
243825
|
+
addonId: null,
|
|
243826
|
+
access: "create"
|
|
243827
|
+
},
|
|
243002
243828
|
"pipelineAnalytics.reconcileFromDisk": {
|
|
243003
243829
|
capName: "pipeline-analytics",
|
|
243004
243830
|
capScope: "device",
|
|
@@ -243923,6 +244749,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
243923
244749
|
addonId: null,
|
|
243924
244750
|
access: "view"
|
|
243925
244751
|
},
|
|
244752
|
+
"recording.getPlacement": {
|
|
244753
|
+
capName: "recording",
|
|
244754
|
+
capScope: "system",
|
|
244755
|
+
addonId: null,
|
|
244756
|
+
access: "view"
|
|
244757
|
+
},
|
|
243926
244758
|
"recording.getPlaybackManifest": {
|
|
243927
244759
|
capName: "recording",
|
|
243928
244760
|
capScope: "system",
|
|
@@ -244049,6 +244881,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
244049
244881
|
addonId: null,
|
|
244050
244882
|
access: "create"
|
|
244051
244883
|
},
|
|
244884
|
+
"recording.setDevicePlacement": {
|
|
244885
|
+
capName: "recording",
|
|
244886
|
+
capScope: "system",
|
|
244887
|
+
addonId: null,
|
|
244888
|
+
access: "create"
|
|
244889
|
+
},
|
|
244052
244890
|
"recording.startStorageMigrationMove": {
|
|
244053
244891
|
capName: "recording",
|
|
244054
244892
|
capScope: "system",
|
|
@@ -244493,12 +245331,36 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
244493
245331
|
addonId: null,
|
|
244494
245332
|
access: "create"
|
|
244495
245333
|
},
|
|
245334
|
+
"storageMigration.cleanupCancel": {
|
|
245335
|
+
capName: "storage-migration",
|
|
245336
|
+
capScope: "system",
|
|
245337
|
+
addonId: null,
|
|
245338
|
+
access: "create"
|
|
245339
|
+
},
|
|
245340
|
+
"storageMigration.cleanupStart": {
|
|
245341
|
+
capName: "storage-migration",
|
|
245342
|
+
capScope: "system",
|
|
245343
|
+
addonId: null,
|
|
245344
|
+
access: "create"
|
|
245345
|
+
},
|
|
245346
|
+
"storageMigration.cleanupStatus": {
|
|
245347
|
+
capName: "storage-migration",
|
|
245348
|
+
capScope: "system",
|
|
245349
|
+
addonId: null,
|
|
245350
|
+
access: "view"
|
|
245351
|
+
},
|
|
244496
245352
|
"storageMigration.drain": {
|
|
244497
245353
|
capName: "storage-migration",
|
|
244498
245354
|
capScope: "system",
|
|
244499
245355
|
addonId: null,
|
|
244500
245356
|
access: "create"
|
|
244501
245357
|
},
|
|
245358
|
+
"storageMigration.history": {
|
|
245359
|
+
capName: "storage-migration",
|
|
245360
|
+
capScope: "system",
|
|
245361
|
+
addonId: null,
|
|
245362
|
+
access: "view"
|
|
245363
|
+
},
|
|
244502
245364
|
"storageMigration.movers": {
|
|
244503
245365
|
capName: "storage-migration",
|
|
244504
245366
|
capScope: "system",
|
|
@@ -246873,6 +247735,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
246873
247735
|
form: "single",
|
|
246874
247736
|
optional: true
|
|
246875
247737
|
}],
|
|
247738
|
+
"pipelineAnalytics.reclaimDebugMedia": [{
|
|
247739
|
+
name: "deviceIds",
|
|
247740
|
+
form: "array",
|
|
247741
|
+
optional: true
|
|
247742
|
+
}],
|
|
246876
247743
|
"pipelineAnalytics.reconcileFromDisk": [{
|
|
246877
247744
|
name: "deviceId",
|
|
246878
247745
|
form: "single",
|
|
@@ -247238,6 +248105,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
247238
248105
|
form: "single",
|
|
247239
248106
|
optional: false
|
|
247240
248107
|
}],
|
|
248108
|
+
"recording.setDevicePlacement": [{
|
|
248109
|
+
name: "deviceId",
|
|
248110
|
+
form: "single",
|
|
248111
|
+
optional: false
|
|
248112
|
+
}],
|
|
247241
248113
|
"recording.startStorageMigrationMove": [{
|
|
247242
248114
|
name: "deviceId",
|
|
247243
248115
|
form: "single",
|
|
@@ -247707,6 +248579,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
247707
248579
|
"recording.renderGif",
|
|
247708
248580
|
"recording.rescanStorage",
|
|
247709
248581
|
"recording.setDeviceConfig",
|
|
248582
|
+
"recording.setDevicePlacement",
|
|
247710
248583
|
"recording.startStorageMigrationMove",
|
|
247711
248584
|
"recordingExport.createExport",
|
|
247712
248585
|
"recordingExport.listExports",
|
|
@@ -248590,7 +249463,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248590
249463
|
reconcileLedgerAgainstDisk: (input) => dispatch("recording", "reconcileLedgerAgainstDisk", "mutation", input),
|
|
248591
249464
|
cancelRelocateJob: (input) => dispatch("recording", "cancelRelocateJob", "mutation", input),
|
|
248592
249465
|
planStorageRebalance: (input) => dispatch("recording", "planStorageRebalance", "query", input),
|
|
248593
|
-
startStorageRebalance: (input) => dispatch("recording", "startStorageRebalance", "mutation", input)
|
|
249466
|
+
startStorageRebalance: (input) => dispatch("recording", "startStorageRebalance", "mutation", input),
|
|
249467
|
+
getPlacement: (input) => dispatch("recording", "getPlacement", "query", input),
|
|
249468
|
+
setDevicePlacement: (input) => dispatch("recording", "setDevicePlacement", "mutation", input)
|
|
248594
249469
|
},
|
|
248595
249470
|
recordingExport: {
|
|
248596
249471
|
createExport: (input) => dispatch("recordingExport", "createExport", "mutation", input),
|
|
@@ -248654,7 +249529,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248654
249529
|
cancel: (input) => dispatch("storageMigration", "cancel", "mutation", input),
|
|
248655
249530
|
movers: (input) => dispatch("storageMigration", "movers", "query", input),
|
|
248656
249531
|
residue: (input) => dispatch("storageMigration", "residue", "query", input),
|
|
248657
|
-
drain: (input) => dispatch("storageMigration", "drain", "mutation", input)
|
|
249532
|
+
drain: (input) => dispatch("storageMigration", "drain", "mutation", input),
|
|
249533
|
+
cleanupStart: (input) => dispatch("storageMigration", "cleanupStart", "mutation", input),
|
|
249534
|
+
cleanupStatus: (input) => dispatch("storageMigration", "cleanupStatus", "query", input),
|
|
249535
|
+
cleanupCancel: (input) => dispatch("storageMigration", "cleanupCancel", "mutation", input),
|
|
249536
|
+
history: (input) => dispatch("storageMigration", "history", "query", input)
|
|
248658
249537
|
},
|
|
248659
249538
|
streamBroker: {
|
|
248660
249539
|
fetchEventMedia: (input) => dispatch("streamBroker", "fetchEventMedia", "mutation", input),
|
|
@@ -252271,6 +253150,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252271
253150
|
exports.StorageBeginDownloadResultSchema = BeginDownloadResultSchema;
|
|
252272
253151
|
exports.StorageBeginUploadInputSchema = BeginUploadInputSchema;
|
|
252273
253152
|
exports.StorageBeginUploadResultSchema = BeginUploadResultSchema;
|
|
253153
|
+
exports.StorageCleanupInputSchema = StorageCleanupInputSchema;
|
|
253154
|
+
exports.StorageCleanupJobSchema = StorageCleanupJobSchema;
|
|
253155
|
+
exports.StorageCleanupPhaseSchema = StorageCleanupPhaseSchema;
|
|
253156
|
+
exports.StorageCleanupStatusInputSchema = StorageCleanupStatusInputSchema;
|
|
252274
253157
|
exports.StorageEndDownloadInputSchema = EndDownloadInputSchema;
|
|
252275
253158
|
exports.StorageFinalizeUploadInputSchema = FinalizeUploadInputSchema;
|
|
252276
253159
|
exports.StorageLocationDeclarationSchema = StorageLocationDeclarationSchema;
|
|
@@ -252296,6 +253179,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252296
253179
|
exports.StorageMigrationPhaseSchema = StorageMigrationPhaseSchema;
|
|
252297
253180
|
exports.StorageMigrationPlanSchema = StorageMigrationPlanSchema;
|
|
252298
253181
|
exports.StorageMigrationResidueSchema = StorageMigrationResidueSchema;
|
|
253182
|
+
exports.StorageMigrationSourcesSchema = StorageMigrationSourcesSchema;
|
|
252299
253183
|
exports.StorageProviderInfoSchema = ProviderInfoSchema;
|
|
252300
253184
|
exports.StorageReadChunkInputSchema = ReadChunkInputSchema;
|
|
252301
253185
|
exports.StorageTestLocationResultSchema = TestLocationResultSchema;
|