camstack 1.2.70 → 1.2.72
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-DCdtLXgx.js
|
|
23637
|
+
var require_dist_DCdtLXgx = __commonJS({
|
|
23638
|
+
"../system/dist/dist-DCdtLXgx.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_BhE8zNfY = __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_BhE8zNfY = __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_BhE8zNfY = __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_BhE8zNfY = __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_BhE8zNfY = __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_BhE8zNfY = __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_BhE8zNfY = __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-]+$/),
|
|
@@ -31416,6 +31475,27 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
31416
31475
|
kind: "mutation",
|
|
31417
31476
|
auth: "admin"
|
|
31418
31477
|
}),
|
|
31478
|
+
/** Rename a room: replace the label in the registry IN PLACE and move
|
|
31479
|
+
* every device that carried it, as ONE server operation.
|
|
31480
|
+
*
|
|
31481
|
+
* The admin UI used to do this as `addLocation(to)` → N ×
|
|
31482
|
+
* `setLocation(device, to)` → `removeLocation(from)` from the browser.
|
|
31483
|
+
* Nothing bound those three together, so a closed tab left the fleet
|
|
31484
|
+
* split across two rooms — one of which the operator believed was gone.
|
|
31485
|
+
*
|
|
31486
|
+
* `from` is matched the way the registry matches everywhere else
|
|
31487
|
+
* (trimmed, case-insensitive) and need NOT be registered: the registry is
|
|
31488
|
+
* a suggestion list, and the devices that most need a rename are exactly
|
|
31489
|
+
* the ones carrying a label nobody registered. `to` renames onto an
|
|
31490
|
+
* existing room by MERGING into it, leaving no duplicate label. An empty
|
|
31491
|
+
* `to` throws before anything is written. */
|
|
31492
|
+
renameLocation: method(zod.z.object({
|
|
31493
|
+
from: zod.z.string(),
|
|
31494
|
+
to: zod.z.string()
|
|
31495
|
+
}), zod.z.object({ moved: zod.z.number() }), {
|
|
31496
|
+
kind: "mutation",
|
|
31497
|
+
auth: "admin"
|
|
31498
|
+
}),
|
|
31419
31499
|
/** Soft-disable / re-enable the device. Drivers consult
|
|
31420
31500
|
* `BaseDevice.disabled` to gate lifecycle hooks. */
|
|
31421
31501
|
setDisabled: method(zod.z.object({
|
|
@@ -37037,46 +37117,6 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
37037
37117
|
/** Cursor for the next page, or null when this page is the last. */
|
|
37038
37118
|
nextCursor: zod.z.string().nullable()
|
|
37039
37119
|
});
|
|
37040
|
-
var LIST_GROUPS_DEFAULT_LIMIT = 40;
|
|
37041
|
-
var LIST_GROUPS_MAX_LIMIT = 100;
|
|
37042
|
-
var AnalyticsGroupRecordSchema = zod.z.object({
|
|
37043
|
-
id: zod.z.string(),
|
|
37044
|
-
deviceId: zod.z.number().int(),
|
|
37045
|
-
openedAt: zod.z.number().int(),
|
|
37046
|
-
closedAt: zod.z.number().int(),
|
|
37047
|
-
timestamp: zod.z.number().int(),
|
|
37048
|
-
memberCount: zod.z.number().int(),
|
|
37049
|
-
memberTrackIds: zod.z.array(zod.z.string()).readonly(),
|
|
37050
|
-
className: zod.z.string(),
|
|
37051
|
-
classes: zod.z.array(zod.z.string()).readonly(),
|
|
37052
|
-
/** Relative event-media path, or null when the group has no picture yet. */
|
|
37053
|
-
mediaUrl: zod.z.string().nullable(),
|
|
37054
|
-
singleton: zod.z.boolean()
|
|
37055
|
-
});
|
|
37056
|
-
var AnalyticsGroupMemberSchema = zod.z.object({
|
|
37057
|
-
trackId: zod.z.string(),
|
|
37058
|
-
deviceId: zod.z.number().int(),
|
|
37059
|
-
className: zod.z.string(),
|
|
37060
|
-
firstSeen: zod.z.number().int(),
|
|
37061
|
-
lastSeen: zod.z.number().int(),
|
|
37062
|
-
mediaUrl: zod.z.string().nullable()
|
|
37063
|
-
});
|
|
37064
|
-
var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: zod.z.array(AnalyticsGroupMemberSchema).readonly() });
|
|
37065
|
-
var ListGroupsQueryInput = zod.z.object({
|
|
37066
|
-
/** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
|
|
37067
|
-
deviceIds: zod.z.array(zod.z.number()),
|
|
37068
|
-
/** Window lower bound on `closedAt` (inclusive). */
|
|
37069
|
-
since: zod.z.number().optional(),
|
|
37070
|
-
/** Window upper bound on `openedAt` (inclusive). */
|
|
37071
|
-
until: zod.z.number().optional(),
|
|
37072
|
-
limit: zod.z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
|
|
37073
|
-
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
37074
|
-
cursor: zod.z.string().optional()
|
|
37075
|
-
});
|
|
37076
|
-
var ListGroupsPageSchema = zod.z.object({
|
|
37077
|
-
groups: zod.z.array(AnalyticsGroupRecordSchema).readonly(),
|
|
37078
|
-
nextCursor: zod.z.string().nullable()
|
|
37079
|
-
});
|
|
37080
37120
|
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
37081
37121
|
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
37082
37122
|
var KeyEventQueryInput = zod.z.object({
|
|
@@ -37169,9 +37209,7 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
37169
37209
|
/** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
|
|
37170
37210
|
plates: zod.z.number().int(),
|
|
37171
37211
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
37172
|
-
embeddings: zod.z.number().int()
|
|
37173
|
-
/** Group membership + group rows removed with their last member (best-effort). */
|
|
37174
|
-
groups: zod.z.number().int()
|
|
37212
|
+
embeddings: zod.z.number().int()
|
|
37175
37213
|
});
|
|
37176
37214
|
var DiskReconcileCountsSchema = zod.z.object({
|
|
37177
37215
|
mediaDropped: zod.z.number().int(),
|
|
@@ -37384,16 +37422,6 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
37384
37422
|
* are not included (same contract as `listTracks`).
|
|
37385
37423
|
*/
|
|
37386
37424
|
listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
|
|
37387
|
-
/**
|
|
37388
|
-
* Batched co-moving group listing — the Groups feed. Same merge/cursor
|
|
37389
|
-
* contract as {@link listRecentTracks}. A group is a sealed partition of
|
|
37390
|
-
* one session; `getGroup` is the detail with members.
|
|
37391
|
-
*/
|
|
37392
|
-
listGroups: method(ListGroupsQueryInput, ListGroupsPageSchema),
|
|
37393
|
-
getGroup: method(zod.z.object({
|
|
37394
|
-
deviceId: zod.z.number(),
|
|
37395
|
-
groupId: zod.z.string().min(1)
|
|
37396
|
-
}), AnalyticsGroupDetailSchema.nullable()),
|
|
37397
37425
|
clearTracks: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
|
|
37398
37426
|
kind: "mutation",
|
|
37399
37427
|
auth: "admin"
|
|
@@ -40343,7 +40371,23 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
40343
40371
|
drain: method(StorageMigrationDrainInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
40344
40372
|
kind: "mutation",
|
|
40345
40373
|
auth: "admin"
|
|
40346
|
-
})
|
|
40374
|
+
}),
|
|
40375
|
+
/**
|
|
40376
|
+
* One operator cleanup of leftover analytics (DB + blobs) and ghost
|
|
40377
|
+
* ledger rows on frozen footage locations. Optional debug-media sweep.
|
|
40378
|
+
* Returns immediately; poll {@link cleanupStatus}.
|
|
40379
|
+
*/
|
|
40380
|
+
cleanupStart: method(StorageCleanupInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
40381
|
+
kind: "mutation",
|
|
40382
|
+
auth: "admin"
|
|
40383
|
+
}),
|
|
40384
|
+
cleanupStatus: method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }),
|
|
40385
|
+
cleanupCancel: method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
|
|
40386
|
+
kind: "mutation",
|
|
40387
|
+
auth: "admin"
|
|
40388
|
+
}),
|
|
40389
|
+
/** Recent finished migration jobs, newest first. The live job is `status`. */
|
|
40390
|
+
history: method(zod.z.object({}), zod.z.array(StorageMigrationJobSchema).readonly(), { auth: "admin" })
|
|
40347
40391
|
}
|
|
40348
40392
|
};
|
|
40349
40393
|
var ProviderInfoSchema = zod.z.discriminatedUnion("shouldSaveDiskSpace", [zod.z.object({
|
|
@@ -47135,6 +47179,26 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
47135
47179
|
/** Ignore piles smaller than this (default 1 GB). */
|
|
47136
47180
|
minMoveGb: zod.z.number().min(0).optional()
|
|
47137
47181
|
});
|
|
47182
|
+
var RecordingDevicePlacementSchema = zod.z.object({
|
|
47183
|
+
deviceId: zod.z.number().int(),
|
|
47184
|
+
profile: zod.z.string(),
|
|
47185
|
+
locationId: zod.z.string()
|
|
47186
|
+
});
|
|
47187
|
+
var RecordingDevicePinSchema = zod.z.object({
|
|
47188
|
+
deviceId: zod.z.number().int(),
|
|
47189
|
+
/** Recordings-class location this camera is pinned to. */
|
|
47190
|
+
locationId: zod.z.string()
|
|
47191
|
+
});
|
|
47192
|
+
var RecordingPlacementViewSchema = zod.z.object({
|
|
47193
|
+
assignments: zod.z.array(RecordingDevicePlacementSchema),
|
|
47194
|
+
pins: zod.z.array(RecordingDevicePinSchema),
|
|
47195
|
+
defaultLocations: zod.z.record(zod.z.string(), zod.z.string())
|
|
47196
|
+
});
|
|
47197
|
+
var RecordingSetDevicePlacementInputSchema = zod.z.object({
|
|
47198
|
+
deviceId: zod.z.number().int(),
|
|
47199
|
+
/** `null` = Auto. Otherwise a `recordings:*` location id. */
|
|
47200
|
+
locationId: zod.z.string().nullable()
|
|
47201
|
+
});
|
|
47138
47202
|
var LocateSegmentResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
|
|
47139
47203
|
kind: zod.z.literal("segment"),
|
|
47140
47204
|
startMs: zod.z.number(),
|
|
@@ -47453,6 +47517,22 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
47453
47517
|
startStorageRebalance: method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
|
|
47454
47518
|
kind: "mutation",
|
|
47455
47519
|
auth: "admin"
|
|
47520
|
+
}),
|
|
47521
|
+
/**
|
|
47522
|
+
* The placement plan in force plus operator pins. Drives the Locations
|
|
47523
|
+
* admin page: Auto vs a named recordings location, per camera.
|
|
47524
|
+
*/
|
|
47525
|
+
getPlacement: method(zod.z.object({}), RecordingPlacementViewSchema, {
|
|
47526
|
+
kind: "query",
|
|
47527
|
+
auth: "admin"
|
|
47528
|
+
}),
|
|
47529
|
+
/**
|
|
47530
|
+
* Pin a camera to a recordings location, or clear the pin (Auto). High and
|
|
47531
|
+
* mid follow the pin; low stays with the recordingsLow planner.
|
|
47532
|
+
*/
|
|
47533
|
+
setDevicePlacement: method(RecordingSetDevicePlacementInputSchema, zod.z.object({ ok: zod.z.literal(true) }), {
|
|
47534
|
+
kind: "mutation",
|
|
47535
|
+
auth: "admin"
|
|
47456
47536
|
})
|
|
47457
47537
|
}
|
|
47458
47538
|
};
|
|
@@ -51856,6 +51936,12 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
51856
51936
|
addonId: null,
|
|
51857
51937
|
access: "delete"
|
|
51858
51938
|
},
|
|
51939
|
+
"deviceManager.renameLocation": {
|
|
51940
|
+
capName: "device-manager",
|
|
51941
|
+
capScope: "system",
|
|
51942
|
+
addonId: null,
|
|
51943
|
+
access: "create"
|
|
51944
|
+
},
|
|
51859
51945
|
"deviceManager.runDeviceAction": {
|
|
51860
51946
|
capName: "device-manager",
|
|
51861
51947
|
capScope: "system",
|
|
@@ -53548,12 +53634,6 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
53548
53634
|
addonId: null,
|
|
53549
53635
|
access: "view"
|
|
53550
53636
|
},
|
|
53551
|
-
"pipelineAnalytics.getGroup": {
|
|
53552
|
-
capName: "pipeline-analytics",
|
|
53553
|
-
capScope: "device",
|
|
53554
|
-
addonId: null,
|
|
53555
|
-
access: "view"
|
|
53556
|
-
},
|
|
53557
53637
|
"pipelineAnalytics.getKeyEvents": {
|
|
53558
53638
|
capName: "pipeline-analytics",
|
|
53559
53639
|
capScope: "device",
|
|
@@ -53656,12 +53736,6 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
53656
53736
|
addonId: null,
|
|
53657
53737
|
access: "view"
|
|
53658
53738
|
},
|
|
53659
|
-
"pipelineAnalytics.listGroups": {
|
|
53660
|
-
capName: "pipeline-analytics",
|
|
53661
|
-
capScope: "device",
|
|
53662
|
-
addonId: null,
|
|
53663
|
-
access: "view"
|
|
53664
|
-
},
|
|
53665
53739
|
"pipelineAnalytics.listOpsLog": {
|
|
53666
53740
|
capName: "pipeline-analytics",
|
|
53667
53741
|
capScope: "device",
|
|
@@ -54676,6 +54750,12 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
54676
54750
|
addonId: null,
|
|
54677
54751
|
access: "view"
|
|
54678
54752
|
},
|
|
54753
|
+
"recording.getPlacement": {
|
|
54754
|
+
capName: "recording",
|
|
54755
|
+
capScope: "system",
|
|
54756
|
+
addonId: null,
|
|
54757
|
+
access: "view"
|
|
54758
|
+
},
|
|
54679
54759
|
"recording.getPlaybackManifest": {
|
|
54680
54760
|
capName: "recording",
|
|
54681
54761
|
capScope: "system",
|
|
@@ -54802,6 +54882,12 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
54802
54882
|
addonId: null,
|
|
54803
54883
|
access: "create"
|
|
54804
54884
|
},
|
|
54885
|
+
"recording.setDevicePlacement": {
|
|
54886
|
+
capName: "recording",
|
|
54887
|
+
capScope: "system",
|
|
54888
|
+
addonId: null,
|
|
54889
|
+
access: "create"
|
|
54890
|
+
},
|
|
54805
54891
|
"recording.startStorageMigrationMove": {
|
|
54806
54892
|
capName: "recording",
|
|
54807
54893
|
capScope: "system",
|
|
@@ -55246,12 +55332,36 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
55246
55332
|
addonId: null,
|
|
55247
55333
|
access: "create"
|
|
55248
55334
|
},
|
|
55335
|
+
"storageMigration.cleanupCancel": {
|
|
55336
|
+
capName: "storage-migration",
|
|
55337
|
+
capScope: "system",
|
|
55338
|
+
addonId: null,
|
|
55339
|
+
access: "create"
|
|
55340
|
+
},
|
|
55341
|
+
"storageMigration.cleanupStart": {
|
|
55342
|
+
capName: "storage-migration",
|
|
55343
|
+
capScope: "system",
|
|
55344
|
+
addonId: null,
|
|
55345
|
+
access: "create"
|
|
55346
|
+
},
|
|
55347
|
+
"storageMigration.cleanupStatus": {
|
|
55348
|
+
capName: "storage-migration",
|
|
55349
|
+
capScope: "system",
|
|
55350
|
+
addonId: null,
|
|
55351
|
+
access: "view"
|
|
55352
|
+
},
|
|
55249
55353
|
"storageMigration.drain": {
|
|
55250
55354
|
capName: "storage-migration",
|
|
55251
55355
|
capScope: "system",
|
|
55252
55356
|
addonId: null,
|
|
55253
55357
|
access: "create"
|
|
55254
55358
|
},
|
|
55359
|
+
"storageMigration.history": {
|
|
55360
|
+
capName: "storage-migration",
|
|
55361
|
+
capScope: "system",
|
|
55362
|
+
addonId: null,
|
|
55363
|
+
access: "view"
|
|
55364
|
+
},
|
|
55255
55365
|
"storageMigration.movers": {
|
|
55256
55366
|
capName: "storage-migration",
|
|
55257
55367
|
capScope: "system",
|
|
@@ -57248,11 +57358,6 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
57248
57358
|
form: "single",
|
|
57249
57359
|
optional: true
|
|
57250
57360
|
}],
|
|
57251
|
-
"pipelineAnalytics.getGroup": [{
|
|
57252
|
-
name: "deviceId",
|
|
57253
|
-
form: "single",
|
|
57254
|
-
optional: false
|
|
57255
|
-
}],
|
|
57256
57361
|
"pipelineAnalytics.getKeyEvents": [{
|
|
57257
57362
|
name: "deviceId",
|
|
57258
57363
|
form: "single",
|
|
@@ -57318,11 +57423,6 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
57318
57423
|
form: "single",
|
|
57319
57424
|
optional: false
|
|
57320
57425
|
}],
|
|
57321
|
-
"pipelineAnalytics.listGroups": [{
|
|
57322
|
-
name: "deviceIds",
|
|
57323
|
-
form: "array",
|
|
57324
|
-
optional: false
|
|
57325
|
-
}],
|
|
57326
57426
|
"pipelineAnalytics.listOpsLog": [{
|
|
57327
57427
|
name: "deviceId",
|
|
57328
57428
|
form: "single",
|
|
@@ -57738,6 +57838,11 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
57738
57838
|
form: "single",
|
|
57739
57839
|
optional: false
|
|
57740
57840
|
}],
|
|
57841
|
+
"recording.setDevicePlacement": [{
|
|
57842
|
+
name: "deviceId",
|
|
57843
|
+
form: "single",
|
|
57844
|
+
optional: false
|
|
57845
|
+
}],
|
|
57741
57846
|
"recording.startStorageMigrationMove": [{
|
|
57742
57847
|
name: "deviceId",
|
|
57743
57848
|
form: "single",
|
|
@@ -58978,6 +59083,12 @@ var require_dist_BhE8zNfY = __commonJS({
|
|
|
58978
59083
|
return ScopedTokenSchema;
|
|
58979
59084
|
}
|
|
58980
59085
|
});
|
|
59086
|
+
Object.defineProperty(exports, "StorageCleanupJobSchema", {
|
|
59087
|
+
enumerable: true,
|
|
59088
|
+
get: function() {
|
|
59089
|
+
return StorageCleanupJobSchema;
|
|
59090
|
+
}
|
|
59091
|
+
});
|
|
58981
59092
|
Object.defineProperty(exports, "StorageLocationTypeSchema", {
|
|
58982
59093
|
enumerable: true,
|
|
58983
59094
|
get: function() {
|
|
@@ -59482,7 +59593,7 @@ var require_alerts_addon = __commonJS({
|
|
|
59482
59593
|
[Symbol.toStringTag]: { value: "Module" }
|
|
59483
59594
|
});
|
|
59484
59595
|
require_chunk_Cek0wNdY();
|
|
59485
|
-
var require_dist10 =
|
|
59596
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
59486
59597
|
function selectExpired(alerts, cutoffMs) {
|
|
59487
59598
|
return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
|
|
59488
59599
|
}
|
|
@@ -60301,7 +60412,7 @@ var require_console_logging = __commonJS({
|
|
|
60301
60412
|
[Symbol.toStringTag]: { value: "Module" }
|
|
60302
60413
|
});
|
|
60303
60414
|
require_chunk_Cek0wNdY();
|
|
60304
|
-
var require_dist10 =
|
|
60415
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
60305
60416
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
60306
60417
|
var LEVEL_RANK = {
|
|
60307
60418
|
debug: 0,
|
|
@@ -60395,7 +60506,7 @@ var require_core_blocks_addon = __commonJS({
|
|
|
60395
60506
|
"use strict";
|
|
60396
60507
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
60397
60508
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
60398
|
-
var require_dist10 =
|
|
60509
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
60399
60510
|
var node_crypto = __require("crypto");
|
|
60400
60511
|
var node_fs_promises = __require("fs/promises");
|
|
60401
60512
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -61292,11 +61403,11 @@ var require_core_blocks = __commonJS({
|
|
|
61292
61403
|
}
|
|
61293
61404
|
});
|
|
61294
61405
|
|
|
61295
|
-
// ../system/dist/retired-settings-keys-
|
|
61296
|
-
var
|
|
61297
|
-
"../system/dist/retired-settings-keys-
|
|
61406
|
+
// ../system/dist/retired-settings-keys-DobfRRgq.js
|
|
61407
|
+
var require_retired_settings_keys_DobfRRgq = __commonJS({
|
|
61408
|
+
"../system/dist/retired-settings-keys-DobfRRgq.js"(exports) {
|
|
61298
61409
|
"use strict";
|
|
61299
|
-
var require_dist10 =
|
|
61410
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
61300
61411
|
function settingsStoreIsAuthoritativeHere(env) {
|
|
61301
61412
|
const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
|
|
61302
61413
|
return raw === "" || raw === "hub";
|
|
@@ -63510,8 +63621,8 @@ var require_device_manager_addon = __commonJS({
|
|
|
63510
63621
|
[Symbol.toStringTag]: { value: "Module" }
|
|
63511
63622
|
});
|
|
63512
63623
|
require_chunk_Cek0wNdY();
|
|
63513
|
-
var require_dist10 =
|
|
63514
|
-
var require_retired_settings_keys =
|
|
63624
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
63625
|
+
var require_retired_settings_keys = require_retired_settings_keys_DobfRRgq();
|
|
63515
63626
|
var node_crypto = __require("crypto");
|
|
63516
63627
|
var _camstack_types_node = require_node();
|
|
63517
63628
|
var JOB_HISTORY = 20;
|
|
@@ -66268,20 +66379,17 @@ var require_device_manager_addon = __commonJS({
|
|
|
66268
66379
|
const cascaded = [];
|
|
66269
66380
|
const failed = [];
|
|
66270
66381
|
await pctx.metaStore.withMetaWriteLock(async () => {
|
|
66271
|
-
|
|
66272
|
-
if (!persisted) throw new Error(`[device-manager] setLocation: unknown device id=${deviceId}`);
|
|
66382
|
+
if (!await pctx.metaStore.resolvePersistedById(deviceId)) throw new Error(`[device-manager] setLocation: unknown device id=${deviceId}`);
|
|
66273
66383
|
await pctx.metaStore.rows.patch(deviceId, { location });
|
|
66274
|
-
|
|
66275
|
-
|
|
66276
|
-
|
|
66277
|
-
|
|
66278
|
-
|
|
66279
|
-
|
|
66280
|
-
|
|
66281
|
-
|
|
66282
|
-
|
|
66283
|
-
});
|
|
66284
|
-
}
|
|
66384
|
+
const descendants = await collectDescendants(pctx.metaStore, deviceId);
|
|
66385
|
+
for (const descendant of descendants) try {
|
|
66386
|
+
await pctx.metaStore.rows.patch(descendant.id, { location });
|
|
66387
|
+
cascaded.push(descendant.id);
|
|
66388
|
+
} catch (err) {
|
|
66389
|
+
failed.push({
|
|
66390
|
+
id: descendant.id,
|
|
66391
|
+
error: err
|
|
66392
|
+
});
|
|
66285
66393
|
}
|
|
66286
66394
|
});
|
|
66287
66395
|
pctx.host.ctx.eventBus.emit({
|
|
@@ -66312,7 +66420,7 @@ var require_device_manager_addon = __commonJS({
|
|
|
66312
66420
|
value: location
|
|
66313
66421
|
}
|
|
66314
66422
|
});
|
|
66315
|
-
if (cascaded.length > 0 || failed.length > 0) pctx.host.ctx.logger.info("setLocation: cascaded location to
|
|
66423
|
+
if (cascaded.length > 0 || failed.length > 0) pctx.host.ctx.logger.info("setLocation: cascaded location to descendants", {
|
|
66316
66424
|
tags: { deviceId },
|
|
66317
66425
|
meta: {
|
|
66318
66426
|
location,
|
|
@@ -66628,6 +66736,54 @@ var require_device_manager_addon = __commonJS({
|
|
|
66628
66736
|
await pctx.settings.writeAddonStore({ locations: [...current, trimmed] });
|
|
66629
66737
|
});
|
|
66630
66738
|
}
|
|
66739
|
+
async function renameLocation(pctx, input) {
|
|
66740
|
+
const from = input.from.trim();
|
|
66741
|
+
const to = input.to.trim();
|
|
66742
|
+
if (from.length === 0) throw new Error("[device-manager] renameLocation: `from` must be non-empty");
|
|
66743
|
+
if (to.length === 0) throw new Error("[device-manager] renameLocation: `to` must be non-empty");
|
|
66744
|
+
const fromKey = from.toLowerCase();
|
|
66745
|
+
const toKey = to.toLowerCase();
|
|
66746
|
+
await pctx.bindingsDeps.withAddonStoreWriteLock(async () => {
|
|
66747
|
+
const current = (await pctx.metaStore.readStore()).locations ?? [];
|
|
66748
|
+
if (!current.some((l) => l.trim().toLowerCase() === fromKey)) return;
|
|
66749
|
+
const kept = current.filter((l) => {
|
|
66750
|
+
const key = l.trim().toLowerCase();
|
|
66751
|
+
return key !== fromKey && key !== toKey;
|
|
66752
|
+
});
|
|
66753
|
+
await pctx.settings.writeAddonStore({ locations: [...kept, to] });
|
|
66754
|
+
});
|
|
66755
|
+
const moved = await pctx.metaStore.withMetaWriteLock(async () => {
|
|
66756
|
+
const out = [];
|
|
66757
|
+
for (const row of await pctx.metaStore.rows.listAll()) {
|
|
66758
|
+
const location = row.meta.location;
|
|
66759
|
+
if (typeof location !== "string") continue;
|
|
66760
|
+
if (location.trim().toLowerCase() !== fromKey) continue;
|
|
66761
|
+
await pctx.metaStore.rows.patch(row.meta.id, { location: to });
|
|
66762
|
+
out.push(row.meta.id);
|
|
66763
|
+
}
|
|
66764
|
+
return out;
|
|
66765
|
+
});
|
|
66766
|
+
for (const deviceId of moved) pctx.host.ctx.eventBus.emit({
|
|
66767
|
+
id: (0, node_crypto.randomUUID)(),
|
|
66768
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
66769
|
+
source: {
|
|
66770
|
+
type: "device",
|
|
66771
|
+
id: deviceId
|
|
66772
|
+
},
|
|
66773
|
+
category: require_dist10.EventCategory.DeviceMetaChanged,
|
|
66774
|
+
data: {
|
|
66775
|
+
deviceId,
|
|
66776
|
+
field: "location",
|
|
66777
|
+
value: to
|
|
66778
|
+
}
|
|
66779
|
+
});
|
|
66780
|
+
pctx.host.ctx.logger.info("renameLocation: room renamed", { meta: {
|
|
66781
|
+
from,
|
|
66782
|
+
to,
|
|
66783
|
+
moved: moved.length
|
|
66784
|
+
} });
|
|
66785
|
+
return { moved: moved.length };
|
|
66786
|
+
}
|
|
66631
66787
|
async function removeLocation(pctx, input) {
|
|
66632
66788
|
const trimmed = input.name.trim();
|
|
66633
66789
|
if (trimmed.length === 0) return;
|
|
@@ -68121,6 +68277,7 @@ var require_device_manager_addon = __commonJS({
|
|
|
68121
68277
|
listLocations: () => listLocations(pctx),
|
|
68122
68278
|
addLocation: (input) => addLocation(pctx, input),
|
|
68123
68279
|
removeLocation: (input) => removeLocation(pctx, input),
|
|
68280
|
+
renameLocation: (input) => renameLocation(pctx, input),
|
|
68124
68281
|
listPersistedByAddon: (input) => listPersistedByAddon(pctx, input),
|
|
68125
68282
|
listAll: (input) => listAll(pctx, input),
|
|
68126
68283
|
getDevice: (input) => getDevice(pctx, input),
|
|
@@ -68327,7 +68484,7 @@ var require_hub_forwarder = __commonJS({
|
|
|
68327
68484
|
[Symbol.toStringTag]: { value: "Module" }
|
|
68328
68485
|
});
|
|
68329
68486
|
require_chunk_Cek0wNdY();
|
|
68330
|
-
var require_dist10 =
|
|
68487
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
68331
68488
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
68332
68489
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
68333
68490
|
var HubForwarderDestination = class {
|
|
@@ -68464,7 +68621,7 @@ var require_liveness_monitor_addon = __commonJS({
|
|
|
68464
68621
|
"use strict";
|
|
68465
68622
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
68466
68623
|
require_chunk_Cek0wNdY();
|
|
68467
|
-
var require_dist10 =
|
|
68624
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
68468
68625
|
var NO_DEVICES = "liveness:no-devices";
|
|
68469
68626
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
68470
68627
|
var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
|
|
@@ -68654,7 +68811,7 @@ var require_local_auth_addon = __commonJS({
|
|
|
68654
68811
|
[Symbol.toStringTag]: { value: "Module" }
|
|
68655
68812
|
});
|
|
68656
68813
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
68657
|
-
var require_dist10 =
|
|
68814
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
68658
68815
|
var node_crypto = __require("crypto");
|
|
68659
68816
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
68660
68817
|
var crypto$1 = __require("crypto");
|
|
@@ -76467,7 +76624,7 @@ var require_loki_logging = __commonJS({
|
|
|
76467
76624
|
[Symbol.toStringTag]: { value: "Module" }
|
|
76468
76625
|
});
|
|
76469
76626
|
require_chunk_Cek0wNdY();
|
|
76470
|
-
var require_dist10 =
|
|
76627
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
76471
76628
|
function sanitizeLabelName(raw) {
|
|
76472
76629
|
const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
|
|
76473
76630
|
return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
|
|
@@ -77032,7 +77189,7 @@ var require_native_metrics_addon = __commonJS({
|
|
|
77032
77189
|
[Symbol.toStringTag]: { value: "Module" }
|
|
77033
77190
|
});
|
|
77034
77191
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
77035
|
-
var require_dist10 =
|
|
77192
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
77036
77193
|
var node_fs_promises = __require("fs/promises");
|
|
77037
77194
|
var node_child_process = __require("child_process");
|
|
77038
77195
|
var node_util = __require("util");
|
|
@@ -79654,7 +79811,7 @@ var require_filesystem_storage_addon = __commonJS({
|
|
|
79654
79811
|
[Symbol.toStringTag]: { value: "Module" }
|
|
79655
79812
|
});
|
|
79656
79813
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
79657
|
-
var require_dist10 =
|
|
79814
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
79658
79815
|
var node_crypto = __require("crypto");
|
|
79659
79816
|
var node_fs_promises = __require("fs/promises");
|
|
79660
79817
|
var node_path = __require("path");
|
|
@@ -80770,8 +80927,8 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
80770
80927
|
[Symbol.toStringTag]: { value: "Module" }
|
|
80771
80928
|
});
|
|
80772
80929
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
80773
|
-
var require_dist10 =
|
|
80774
|
-
var require_retired_settings_keys =
|
|
80930
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
80931
|
+
var require_retired_settings_keys = require_retired_settings_keys_DobfRRgq();
|
|
80775
80932
|
var node_crypto = __require("crypto");
|
|
80776
80933
|
var node_fs = __require("fs");
|
|
80777
80934
|
var node_module = __require("module");
|
|
@@ -81041,15 +81198,28 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
81041
81198
|
const wanted = sqliteMmapSizeFor(fileSizeBytes);
|
|
81042
81199
|
return wanted > currentMmapBytes ? wanted : null;
|
|
81043
81200
|
}
|
|
81044
|
-
var RETIRED_COLLECTIONS = [
|
|
81045
|
-
|
|
81046
|
-
|
|
81047
|
-
|
|
81048
|
-
|
|
81049
|
-
|
|
81050
|
-
|
|
81051
|
-
|
|
81052
|
-
|
|
81201
|
+
var RETIRED_COLLECTIONS = [
|
|
81202
|
+
{
|
|
81203
|
+
collection: "devices",
|
|
81204
|
+
owner: "integration-registry",
|
|
81205
|
+
reason: "the device half of the integration-registry is deleted; the fleet is `device-manager:devices` and always was (0 rows here against 974 live devices)"
|
|
81206
|
+
},
|
|
81207
|
+
{
|
|
81208
|
+
collection: "device_settings_kv",
|
|
81209
|
+
owner: "integration-registry",
|
|
81210
|
+
reason: "per-device settings of a device table that never had a row; the live per-camera store is the device-manager row plus `addon-device-settings`"
|
|
81211
|
+
},
|
|
81212
|
+
{
|
|
81213
|
+
collection: "pipeline-analytics:track-groups",
|
|
81214
|
+
owner: "pipeline-analytics",
|
|
81215
|
+
reason: "the co-moving group entity is deleted (operator decision 2026-09-01, after the 2026-08-24 kill switch); nothing declares, writes or reads it"
|
|
81216
|
+
},
|
|
81217
|
+
{
|
|
81218
|
+
collection: "pipeline-analytics:track-group-members",
|
|
81219
|
+
owner: "pipeline-analytics",
|
|
81220
|
+
reason: "membership rows of the deleted group entity; the track cascade that used to carry them away no longer has a group leg"
|
|
81221
|
+
}
|
|
81222
|
+
];
|
|
81053
81223
|
function retiredCollectionStoreOf(backend) {
|
|
81054
81224
|
return { async drop(collection) {
|
|
81055
81225
|
return backend.dropRetiredTable(collection);
|
|
@@ -83180,7 +83350,8 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83180
83350
|
[Symbol.toStringTag]: { value: "Module" }
|
|
83181
83351
|
});
|
|
83182
83352
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
83183
|
-
var require_dist10 =
|
|
83353
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
83354
|
+
var zod = require_zod();
|
|
83184
83355
|
var node_crypto = __require("crypto");
|
|
83185
83356
|
var node_fs_promises = __require("fs/promises");
|
|
83186
83357
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -83402,17 +83573,22 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83402
83573
|
for (const storageClass of STORAGE_CLASSES) {
|
|
83403
83574
|
const targetId = input.destinations[storageClass];
|
|
83404
83575
|
if (targetId === void 0) continue;
|
|
83405
|
-
const
|
|
83406
|
-
|
|
83576
|
+
const namedSourceId = input.sources?.[storageClass];
|
|
83577
|
+
const defaultLoc = this.deps.locations.getDefaultLocation(storageClass);
|
|
83578
|
+
const source = namedSourceId ? this.deps.locations.getLocationById(namedSourceId) : defaultLoc;
|
|
83579
|
+
if (!source) throw new Error(namedSourceId ? `Storage location "${namedSourceId}" not found` : `No default storage location for "${storageClass}"`);
|
|
83580
|
+
if (source.type !== storageClass) throw new Error(`Storage location "${source.id}" is type "${source.type}", expected "${storageClass}"`);
|
|
83407
83581
|
const target = this.deps.locations.getLocationById(targetId);
|
|
83408
83582
|
if (!target) throw new Error(`Storage location "${targetId}" not found`);
|
|
83409
83583
|
if (target.type !== storageClass) throw new Error(`Storage location "${targetId}" is type "${target.type}", expected "${storageClass}"`);
|
|
83410
|
-
if (source.id === target.id) throw new Error(`Storage location "${targetId}" is already the "${storageClass}" default`);
|
|
83584
|
+
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`);
|
|
83585
|
+
const freezeSource = defaultLoc !== void 0 && source.id !== defaultLoc.id;
|
|
83411
83586
|
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.`);
|
|
83412
83587
|
moves.push({
|
|
83413
83588
|
storageClass,
|
|
83414
83589
|
fromLocationId: source.id,
|
|
83415
83590
|
toLocationId: target.id,
|
|
83591
|
+
freezeSource,
|
|
83416
83592
|
moverJobId: null,
|
|
83417
83593
|
state: null,
|
|
83418
83594
|
error: null,
|
|
@@ -83443,11 +83619,13 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83443
83619
|
}
|
|
83444
83620
|
return {
|
|
83445
83621
|
destinations: input.destinations,
|
|
83622
|
+
sources: input.sources,
|
|
83446
83623
|
mode,
|
|
83447
|
-
moves: moves.map(({ storageClass, fromLocationId, toLocationId }) => ({
|
|
83624
|
+
moves: moves.map(({ storageClass, fromLocationId, toLocationId, freezeSource }) => ({
|
|
83448
83625
|
storageClass,
|
|
83449
83626
|
fromLocationId,
|
|
83450
|
-
toLocationId
|
|
83627
|
+
toLocationId,
|
|
83628
|
+
freezeSource
|
|
83451
83629
|
})),
|
|
83452
83630
|
findings
|
|
83453
83631
|
};
|
|
@@ -83477,12 +83655,12 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83477
83655
|
this.startReserved = true;
|
|
83478
83656
|
try {
|
|
83479
83657
|
const existing = await this.status();
|
|
83480
|
-
if (existing && isTerminal(existing) && existing.pausedParticipants.length > 0) {
|
|
83658
|
+
if (existing && isTerminal$1(existing) && existing.pausedParticipants.length > 0) {
|
|
83481
83659
|
await this.releaseAfterTerminal(existing);
|
|
83482
83660
|
await this.persist(existing);
|
|
83483
83661
|
if (existing.pausedParticipants.length > 0) throw new Error(`storage migration ${existing.jobId} still holds maintenance leases`);
|
|
83484
83662
|
}
|
|
83485
|
-
if (existing && !isTerminal(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
|
|
83663
|
+
if (existing && !isTerminal$1(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
|
|
83486
83664
|
const plan = await this.plan(input);
|
|
83487
83665
|
const now = this.deps.now();
|
|
83488
83666
|
const job = {
|
|
@@ -83490,6 +83668,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83490
83668
|
phase: "planning",
|
|
83491
83669
|
mode: plan.mode,
|
|
83492
83670
|
destinations: input.destinations,
|
|
83671
|
+
sources: input.sources,
|
|
83493
83672
|
throttleMbps: input.throttleMbps ?? 40,
|
|
83494
83673
|
moves: plan.moves.map((move) => ({
|
|
83495
83674
|
...move,
|
|
@@ -83521,10 +83700,15 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83521
83700
|
if (jobId !== void 0 && job?.jobId !== jobId) return null;
|
|
83522
83701
|
return job;
|
|
83523
83702
|
}
|
|
83703
|
+
/** Finished jobs, newest first, excluding the one `status` currently shows. */
|
|
83704
|
+
async history() {
|
|
83705
|
+
const current = await this.status();
|
|
83706
|
+
return (await this.deps.history?.get() ?? []).filter((job) => job.jobId !== current?.jobId);
|
|
83707
|
+
}
|
|
83524
83708
|
async cancel(jobId) {
|
|
83525
83709
|
const job = await this.status(jobId);
|
|
83526
83710
|
const cutoverInFlight = job !== null && job.repointed && (job.phase === "refreshing" || job.phase === "resuming");
|
|
83527
|
-
if (!job || isTerminal(job) || cutoverInFlight) return false;
|
|
83711
|
+
if (!job || isTerminal$1(job) || cutoverInFlight) return false;
|
|
83528
83712
|
job.cancelRequested = true;
|
|
83529
83713
|
await this.persist(job);
|
|
83530
83714
|
await Promise.all(job.moves.filter((move) => move.moverJobId !== null).map((move) => this.cancelMove(move)));
|
|
@@ -83581,18 +83765,22 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83581
83765
|
const target = this.deps.locations.getDefaultLocation(storageClass);
|
|
83582
83766
|
if (!target) continue;
|
|
83583
83767
|
if (laneOf(storageClass) === "media") {
|
|
83584
|
-
const
|
|
83585
|
-
|
|
83586
|
-
|
|
83587
|
-
|
|
83588
|
-
|
|
83589
|
-
|
|
83590
|
-
|
|
83591
|
-
|
|
83592
|
-
|
|
83593
|
-
|
|
83594
|
-
|
|
83595
|
-
|
|
83768
|
+
for (const source of this.deps.locations.listLocations({ type: storageClass })) {
|
|
83769
|
+
if (source.id === target.id) continue;
|
|
83770
|
+
const count = await unanswerable(this.deps.participants.analytics.residue({
|
|
83771
|
+
toLocationId: target.id,
|
|
83772
|
+
fromLocationId: source.id,
|
|
83773
|
+
mode: "move"
|
|
83774
|
+
}));
|
|
83775
|
+
if (count !== null && count.rows === 0) continue;
|
|
83776
|
+
out.push({
|
|
83777
|
+
storageClass,
|
|
83778
|
+
fromLocationId: source.id,
|
|
83779
|
+
toLocationId: target.id,
|
|
83780
|
+
items: count?.rows ?? null,
|
|
83781
|
+
bytes: null
|
|
83782
|
+
});
|
|
83783
|
+
}
|
|
83596
83784
|
continue;
|
|
83597
83785
|
}
|
|
83598
83786
|
for (const source of this.deps.locations.listLocations({ type: storageClass })) {
|
|
@@ -83646,12 +83834,12 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83646
83834
|
this.startReserved = true;
|
|
83647
83835
|
try {
|
|
83648
83836
|
const existing = await this.status();
|
|
83649
|
-
if (existing && isTerminal(existing) && existing.pausedParticipants.length > 0) {
|
|
83837
|
+
if (existing && isTerminal$1(existing) && existing.pausedParticipants.length > 0) {
|
|
83650
83838
|
await this.releaseAfterTerminal(existing);
|
|
83651
83839
|
await this.persist(existing);
|
|
83652
83840
|
if (existing.pausedParticipants.length > 0) throw new Error(`storage migration ${existing.jobId} still holds maintenance leases`);
|
|
83653
83841
|
}
|
|
83654
|
-
if (existing && !isTerminal(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
|
|
83842
|
+
if (existing && !isTerminal$1(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
|
|
83655
83843
|
for (const storageClass of input.classes) {
|
|
83656
83844
|
if (MOVER_CLASSES.includes(storageClass)) continue;
|
|
83657
83845
|
throw new Error(`No mover owns "${storageClass}" \u2014 there is nothing that can drain it. Move it by hand.`);
|
|
@@ -83716,7 +83904,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83716
83904
|
await this.persist(job);
|
|
83717
83905
|
return;
|
|
83718
83906
|
}
|
|
83719
|
-
if (isTerminal(job)) {
|
|
83907
|
+
if (isTerminal$1(job)) {
|
|
83720
83908
|
if (job.pausedParticipants.length > 0) {
|
|
83721
83909
|
await this.releaseAfterTerminal(job);
|
|
83722
83910
|
await this.persist(job);
|
|
@@ -83777,11 +83965,12 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83777
83965
|
if (job.phase === "verifying" && !nonBlocking) {
|
|
83778
83966
|
await this.verifyMoves(job);
|
|
83779
83967
|
if (job.cancelRequested) return this.finishCancelled(job);
|
|
83968
|
+
await this.freezeDrainedSources(job);
|
|
83780
83969
|
await this.setPhase(job, "repointing");
|
|
83781
83970
|
}
|
|
83782
83971
|
if (job.phase === "repointing") {
|
|
83783
|
-
const targets = new Map(job.moves.map((move) => [move.storageClass, move.toLocationId]));
|
|
83784
|
-
await this.deps.locations.setDefaultLocations(targets);
|
|
83972
|
+
const targets = new Map(job.moves.filter((move) => move.freezeSource !== true).map((move) => [move.storageClass, move.toLocationId]));
|
|
83973
|
+
if (targets.size > 0) await this.deps.locations.setDefaultLocations(targets);
|
|
83785
83974
|
job.repointed = true;
|
|
83786
83975
|
await this.setPhase(job, "refreshing");
|
|
83787
83976
|
}
|
|
@@ -83804,6 +83993,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83804
83993
|
if (job.phase === "verifying" && nonBlocking) {
|
|
83805
83994
|
await this.verifyMoves(job);
|
|
83806
83995
|
if (job.cancelRequested) return this.finishCancelled(job);
|
|
83996
|
+
await this.freezeDrainedSources(job);
|
|
83807
83997
|
await this.setPhase(job, "done");
|
|
83808
83998
|
}
|
|
83809
83999
|
} catch (err) {
|
|
@@ -83819,7 +84009,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83819
84009
|
await this.releaseAfterTerminal(job);
|
|
83820
84010
|
await this.persist(job);
|
|
83821
84011
|
} finally {
|
|
83822
|
-
if (isTerminal(job)) {
|
|
84012
|
+
if (isTerminal$1(job)) {
|
|
83823
84013
|
await this.releaseAfterTerminal(job);
|
|
83824
84014
|
this.active = job;
|
|
83825
84015
|
}
|
|
@@ -83980,6 +84170,24 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83980
84170
|
for (const move of job.moves) if (move.state !== "done") throw new Error(`${move.storageClass} move did not complete verification`);
|
|
83981
84171
|
}
|
|
83982
84172
|
/**
|
|
84173
|
+
* After a from→to copy whose source was NOT the class default: stop new
|
|
84174
|
+
* writes to `from`. The default is unchanged (that is the whole point of
|
|
84175
|
+
* naming a non-default source). A location that is already disabled is
|
|
84176
|
+
* left alone.
|
|
84177
|
+
*/
|
|
84178
|
+
freezeDrainedSources(job) {
|
|
84179
|
+
for (const move of job.moves) {
|
|
84180
|
+
if (move.freezeSource !== true) continue;
|
|
84181
|
+
const loc = this.deps.locations.getLocationById(move.fromLocationId);
|
|
84182
|
+
if (!loc || loc.enabled === false) continue;
|
|
84183
|
+
const { createdAt: _c, updatedAt: _u, capacity: _cap, ...rest } = loc;
|
|
84184
|
+
this.deps.locations.upsertLocation({
|
|
84185
|
+
...rest,
|
|
84186
|
+
enabled: false
|
|
84187
|
+
});
|
|
84188
|
+
}
|
|
84189
|
+
}
|
|
84190
|
+
/**
|
|
83983
84191
|
* Arm one class's mover.
|
|
83984
84192
|
*
|
|
83985
84193
|
* `draining` runs after every writer has been resumed, so there is no lease
|
|
@@ -83992,6 +84200,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83992
84200
|
if (laneOf(move.storageClass) === "media") {
|
|
83993
84201
|
const input2 = {
|
|
83994
84202
|
toLocationId: move.toLocationId,
|
|
84203
|
+
fromLocationId: move.fromLocationId,
|
|
83995
84204
|
throttleMbps: job.throttleMbps,
|
|
83996
84205
|
mode: "move"
|
|
83997
84206
|
};
|
|
@@ -84025,7 +84234,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84025
84234
|
}
|
|
84026
84235
|
async setPhase(job, phase) {
|
|
84027
84236
|
job.phase = phase;
|
|
84028
|
-
if (isTerminal(job)) job.finishedAt = this.deps.now();
|
|
84237
|
+
if (isTerminal$1(job)) job.finishedAt = this.deps.now();
|
|
84029
84238
|
await this.persist(job);
|
|
84030
84239
|
}
|
|
84031
84240
|
async finishCancelled(job) {
|
|
@@ -84037,6 +84246,9 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84037
84246
|
async persist(job) {
|
|
84038
84247
|
job.updatedAt = this.deps.now();
|
|
84039
84248
|
await this.deps.state.set(job);
|
|
84249
|
+
if (!isTerminal$1(job) || this.deps.history === void 0) return;
|
|
84250
|
+
const prev = [...await this.deps.history.get() ?? []];
|
|
84251
|
+
await this.deps.history.set([job, ...prev.filter((row) => row.jobId !== job.jobId)].slice(0, HISTORY_CAP));
|
|
84040
84252
|
}
|
|
84041
84253
|
};
|
|
84042
84254
|
async function unanswerable(read) {
|
|
@@ -84050,9 +84262,10 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84050
84262
|
if (job.pauseLeaseId === null) throw new Error("storage migration has no maintenance lease");
|
|
84051
84263
|
return job.pauseLeaseId;
|
|
84052
84264
|
}
|
|
84053
|
-
function isTerminal(job) {
|
|
84265
|
+
function isTerminal$1(job) {
|
|
84054
84266
|
return job.phase === "done" || job.phase === "failed" || job.phase === "cancelled";
|
|
84055
84267
|
}
|
|
84268
|
+
var HISTORY_CAP = 20;
|
|
84056
84269
|
function laneOf(storageClass) {
|
|
84057
84270
|
return storageClass === "eventMedia" ? "media" : "footage";
|
|
84058
84271
|
}
|
|
@@ -84105,6 +84318,46 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84105
84318
|
function canProbeOccupancyLocally(locality) {
|
|
84106
84319
|
return locality === true;
|
|
84107
84320
|
}
|
|
84321
|
+
var STORAGE_CLASS_SUBTREES = {
|
|
84322
|
+
eventMedia: ["events"],
|
|
84323
|
+
recordingsLow: ["low"],
|
|
84324
|
+
recordings: ["high", "mid"]
|
|
84325
|
+
};
|
|
84326
|
+
function isDotEntry(name) {
|
|
84327
|
+
return name.startsWith(".");
|
|
84328
|
+
}
|
|
84329
|
+
async function dirHasAnyEntry(dir) {
|
|
84330
|
+
let handle;
|
|
84331
|
+
try {
|
|
84332
|
+
handle = await (0, node_fs_promises.opendir)(dir);
|
|
84333
|
+
} catch (err) {
|
|
84334
|
+
if (err.code === "ENOENT") return false;
|
|
84335
|
+
throw err;
|
|
84336
|
+
}
|
|
84337
|
+
try {
|
|
84338
|
+
return await handle.read() !== null;
|
|
84339
|
+
} finally {
|
|
84340
|
+
await handle.close();
|
|
84341
|
+
}
|
|
84342
|
+
}
|
|
84343
|
+
async function probeLocalDirectoryOccupancy(input) {
|
|
84344
|
+
let names;
|
|
84345
|
+
try {
|
|
84346
|
+
names = await (0, node_fs_promises.readdir)(input.basePath);
|
|
84347
|
+
} catch (err) {
|
|
84348
|
+
if (err.code === "ENOENT") return "empty";
|
|
84349
|
+
return "unknown";
|
|
84350
|
+
}
|
|
84351
|
+
const visible = names.filter((name) => !isDotEntry(name));
|
|
84352
|
+
const subtrees = STORAGE_CLASS_SUBTREES[input.type];
|
|
84353
|
+
if (subtrees === void 0) return visible.length > 0 ? "occupied" : "empty";
|
|
84354
|
+
try {
|
|
84355
|
+
for (const camera of visible) for (const subtree of subtrees) if (await dirHasAnyEntry(node_path.default.join(input.basePath, camera, subtree))) return "occupied";
|
|
84356
|
+
} catch {
|
|
84357
|
+
return "unknown";
|
|
84358
|
+
}
|
|
84359
|
+
return "empty";
|
|
84360
|
+
}
|
|
84108
84361
|
function resolveEngine(getEngines) {
|
|
84109
84362
|
const engines = getEngines();
|
|
84110
84363
|
if (engines.length === 0) throw new Error("settings-store: no data-store-provider engine is registered \u2014 the data door has nothing behind it");
|
|
@@ -84194,6 +84447,164 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84194
84447
|
}
|
|
84195
84448
|
return out;
|
|
84196
84449
|
}
|
|
84450
|
+
var FOOTAGE_TYPES = /* @__PURE__ */ new Set(["recordings", "recordingsLow"]);
|
|
84451
|
+
function isTerminal(job) {
|
|
84452
|
+
return job.phase === "done" || job.phase === "failed" || job.phase === "cancelled";
|
|
84453
|
+
}
|
|
84454
|
+
function footageFrozen(location) {
|
|
84455
|
+
return location.enabled === false || location.config["readOnly"] === true;
|
|
84456
|
+
}
|
|
84457
|
+
var StorageCleanupCoordinator = class {
|
|
84458
|
+
deps;
|
|
84459
|
+
active = null;
|
|
84460
|
+
startReserved = false;
|
|
84461
|
+
constructor(deps) {
|
|
84462
|
+
this.deps = deps;
|
|
84463
|
+
}
|
|
84464
|
+
async start(input) {
|
|
84465
|
+
if (this.startReserved) throw new Error("storage cleanup is already active");
|
|
84466
|
+
this.startReserved = true;
|
|
84467
|
+
try {
|
|
84468
|
+
const existing = await this.status();
|
|
84469
|
+
if (existing && !isTerminal(existing)) throw new Error(`storage cleanup is already active (${existing.jobId})`);
|
|
84470
|
+
const now = this.deps.now();
|
|
84471
|
+
const job = {
|
|
84472
|
+
jobId: this.deps.newId(),
|
|
84473
|
+
phase: "orphans",
|
|
84474
|
+
includeDebugMedia: input.includeDebugMedia === true,
|
|
84475
|
+
orphansReclaimed: 0,
|
|
84476
|
+
orphanBytesReclaimed: 0,
|
|
84477
|
+
debugMediaReclaimed: 0,
|
|
84478
|
+
debugMediaBytesReclaimed: 0,
|
|
84479
|
+
ghostsForgotten: 0,
|
|
84480
|
+
ghostBytesForgotten: 0,
|
|
84481
|
+
detail: "Starting orphan reclaim",
|
|
84482
|
+
cancelRequested: false,
|
|
84483
|
+
startedAt: now,
|
|
84484
|
+
updatedAt: now,
|
|
84485
|
+
finishedAt: null,
|
|
84486
|
+
error: null
|
|
84487
|
+
};
|
|
84488
|
+
await this.persist(job);
|
|
84489
|
+
this.active = job;
|
|
84490
|
+
this.run(job);
|
|
84491
|
+
return job.jobId;
|
|
84492
|
+
} finally {
|
|
84493
|
+
this.startReserved = false;
|
|
84494
|
+
}
|
|
84495
|
+
}
|
|
84496
|
+
async status(jobId) {
|
|
84497
|
+
const job = this.active ?? await this.deps.state.get();
|
|
84498
|
+
if (jobId !== void 0 && job?.jobId !== jobId) return null;
|
|
84499
|
+
return job;
|
|
84500
|
+
}
|
|
84501
|
+
async cancel(jobId) {
|
|
84502
|
+
const job = await this.status(jobId);
|
|
84503
|
+
if (!job || isTerminal(job)) return false;
|
|
84504
|
+
job.cancelRequested = true;
|
|
84505
|
+
job.detail = "Cancel requested \u2014 finishing the current step";
|
|
84506
|
+
await this.persist(job);
|
|
84507
|
+
return true;
|
|
84508
|
+
}
|
|
84509
|
+
async run(job) {
|
|
84510
|
+
try {
|
|
84511
|
+
await this.reclaimOrphans(job);
|
|
84512
|
+
if (await this.stopped(job)) return;
|
|
84513
|
+
if (job.includeDebugMedia) {
|
|
84514
|
+
await this.setPhase(job, "debug-media", "Reclaiming debug media");
|
|
84515
|
+
await this.reclaimDebugMedia(job);
|
|
84516
|
+
if (await this.stopped(job)) return;
|
|
84517
|
+
}
|
|
84518
|
+
await this.setPhase(job, "ghost-ledger", "Forgetting ghost footage rows");
|
|
84519
|
+
await this.forgetGhosts(job);
|
|
84520
|
+
if (await this.stopped(job)) return;
|
|
84521
|
+
await this.finish(job, "done", null);
|
|
84522
|
+
} catch (err) {
|
|
84523
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
84524
|
+
await this.finish(job, "failed", message);
|
|
84525
|
+
}
|
|
84526
|
+
}
|
|
84527
|
+
async reclaimOrphans(job) {
|
|
84528
|
+
let restart = true;
|
|
84529
|
+
for (; ; ) {
|
|
84530
|
+
if (await this.stopped(job)) return;
|
|
84531
|
+
const start = await this.deps.participants.startOrphan(restart);
|
|
84532
|
+
restart = false;
|
|
84533
|
+
if (!start.started && !start.alreadyRunning) throw new Error("orphan reclaim did not start");
|
|
84534
|
+
const status = await this.waitUntilIdle(() => this.deps.participants.orphanStatus(), job, (s) => `Orphan reclaim: ${s.totalReclaimed} rows / ${String(s.totalBytesReclaimed)} bytes`);
|
|
84535
|
+
job.orphansReclaimed += status.totalReclaimed;
|
|
84536
|
+
job.orphanBytesReclaimed += status.totalBytesReclaimed;
|
|
84537
|
+
job.detail = `Orphans: ${job.orphansReclaimed} rows, ${String(job.orphanBytesReclaimed)} bytes`;
|
|
84538
|
+
await this.persist(job);
|
|
84539
|
+
if (status.error) throw new Error(status.error);
|
|
84540
|
+
if (status.complete === true) return;
|
|
84541
|
+
}
|
|
84542
|
+
}
|
|
84543
|
+
async reclaimDebugMedia(job) {
|
|
84544
|
+
const start = await this.deps.participants.startDebugMedia();
|
|
84545
|
+
if (!start.started && !start.alreadyRunning) throw new Error("debug-media reclaim did not start");
|
|
84546
|
+
const status = await this.waitUntilIdle(() => this.deps.participants.debugMediaStatus(), job, (s) => `Debug media: ${s.totalReclaimed} files`);
|
|
84547
|
+
job.debugMediaReclaimed = status.totalReclaimed;
|
|
84548
|
+
job.debugMediaBytesReclaimed = status.totalBytesReclaimed;
|
|
84549
|
+
await this.persist(job);
|
|
84550
|
+
if (status.error) throw new Error(status.error);
|
|
84551
|
+
}
|
|
84552
|
+
async forgetGhosts(job) {
|
|
84553
|
+
const frozen = this.deps.locations.listLocations().filter((l) => FOOTAGE_TYPES.has(l.type) && footageFrozen(l));
|
|
84554
|
+
if (frozen.length === 0) {
|
|
84555
|
+
job.detail = "No frozen footage locations";
|
|
84556
|
+
await this.persist(job);
|
|
84557
|
+
return;
|
|
84558
|
+
}
|
|
84559
|
+
for (const loc of frozen) {
|
|
84560
|
+
if (await this.stopped(job)) return;
|
|
84561
|
+
job.detail = `Ghost ledger: ${loc.id}`;
|
|
84562
|
+
await this.persist(job);
|
|
84563
|
+
const report = await this.deps.participants.walkLedger({
|
|
84564
|
+
locationId: loc.id,
|
|
84565
|
+
apply: true
|
|
84566
|
+
});
|
|
84567
|
+
job.ghostsForgotten += report.forgottenSegments;
|
|
84568
|
+
job.ghostBytesForgotten += report.forgottenBytes;
|
|
84569
|
+
await this.persist(job);
|
|
84570
|
+
}
|
|
84571
|
+
}
|
|
84572
|
+
async waitUntilIdle(read, job, detail) {
|
|
84573
|
+
const pollMs = this.deps.pollMs ?? 2e3;
|
|
84574
|
+
const sleep = this.deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
84575
|
+
for (; ; ) {
|
|
84576
|
+
const status = await read();
|
|
84577
|
+
job.detail = detail(status);
|
|
84578
|
+
await this.persist(job);
|
|
84579
|
+
if (!status.running) return status;
|
|
84580
|
+
await sleep(pollMs);
|
|
84581
|
+
}
|
|
84582
|
+
}
|
|
84583
|
+
async stopped(job) {
|
|
84584
|
+
if ((await this.status(job.jobId))?.cancelRequested === true) {
|
|
84585
|
+
await this.finish(job, "cancelled", null);
|
|
84586
|
+
return true;
|
|
84587
|
+
}
|
|
84588
|
+
return false;
|
|
84589
|
+
}
|
|
84590
|
+
async setPhase(job, phase, detail) {
|
|
84591
|
+
job.phase = phase;
|
|
84592
|
+
job.detail = detail;
|
|
84593
|
+
await this.persist(job);
|
|
84594
|
+
}
|
|
84595
|
+
async finish(job, phase, error) {
|
|
84596
|
+
job.phase = phase;
|
|
84597
|
+
job.error = error;
|
|
84598
|
+
job.finishedAt = this.deps.now();
|
|
84599
|
+
job.detail = phase === "done" ? "Cleanup finished" : job.detail;
|
|
84600
|
+
await this.persist(job);
|
|
84601
|
+
}
|
|
84602
|
+
async persist(job) {
|
|
84603
|
+
job.updatedAt = this.deps.now();
|
|
84604
|
+
this.active = job;
|
|
84605
|
+
await this.deps.state.set(job);
|
|
84606
|
+
}
|
|
84607
|
+
};
|
|
84197
84608
|
var SESSION_VOCABULARY = {
|
|
84198
84609
|
upload: {
|
|
84199
84610
|
idLabel: "uploadId",
|
|
@@ -84281,7 +84692,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84281
84692
|
* Reconciles both directions so operator edits survive a reboot:
|
|
84282
84693
|
* 1. hydrate — DB rows win over any early in-memory seed (restores
|
|
84283
84694
|
* operator config like `minFreePercent` that the pre-store boot
|
|
84284
|
-
* can't see)
|
|
84695
|
+
* can't see);
|
|
84285
84696
|
* 2. backfill — in-memory locations the DB doesn't have yet (the
|
|
84286
84697
|
* pre-store seed defaults on a fresh install) are persisted, so the
|
|
84287
84698
|
* store becomes the durable source of truth from here on.
|
|
@@ -84303,15 +84714,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84303
84714
|
const rows = await store.loadAll();
|
|
84304
84715
|
this.locationStore = store;
|
|
84305
84716
|
const dbIds = new Set(rows.map((r) => r.id));
|
|
84306
|
-
for (const loc of rows)
|
|
84307
|
-
const upgraded = !loc.isSystem && loc.id === `${loc.type}:default` ? {
|
|
84308
|
-
...loc,
|
|
84309
|
-
isSystem: true
|
|
84310
|
-
} : loc;
|
|
84311
|
-
this.locations.set(upgraded.id, upgraded);
|
|
84312
|
-
if (upgraded !== loc) store.upsert(upgraded).catch(() => {
|
|
84313
|
-
});
|
|
84314
|
-
}
|
|
84717
|
+
for (const loc of rows) this.locations.set(loc.id, loc);
|
|
84315
84718
|
const backfill = [...this.locations.values()].filter((l) => !dbIds.has(l.id));
|
|
84316
84719
|
for (const loc of backfill) store.upsert(loc).catch((err) => {
|
|
84317
84720
|
this.logger.warn("storage-orchestrator: attachStore backfill persist failed", { meta: {
|
|
@@ -84403,25 +84806,8 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84403
84806
|
async initialize() {
|
|
84404
84807
|
if (!this.locationStore) return;
|
|
84405
84808
|
const rows = await this.locationStore.loadAll();
|
|
84406
|
-
|
|
84407
|
-
|
|
84408
|
-
const upgradedLoc = {
|
|
84409
|
-
...loc,
|
|
84410
|
-
isSystem: true
|
|
84411
|
-
};
|
|
84412
|
-
this.locations.set(upgradedLoc.id, upgradedLoc);
|
|
84413
|
-
this.locationStore.upsert(upgradedLoc).catch((err) => {
|
|
84414
|
-
this.logger.warn("storage-orchestrator: isSystem upgrade persist failed", { meta: {
|
|
84415
|
-
id: upgradedLoc.id,
|
|
84416
|
-
error: err instanceof Error ? err.message : String(err)
|
|
84417
|
-
} });
|
|
84418
|
-
});
|
|
84419
|
-
upgraded++;
|
|
84420
|
-
} else this.locations.set(loc.id, loc);
|
|
84421
|
-
this.logger.info("storage-orchestrator: hydrated locations from store", { meta: {
|
|
84422
|
-
loaded: this.locations.size,
|
|
84423
|
-
isSystemUpgraded: upgraded
|
|
84424
|
-
} });
|
|
84809
|
+
for (const loc of rows) this.locations.set(loc.id, loc);
|
|
84810
|
+
this.logger.info("storage-orchestrator: hydrated locations from store", { meta: { loaded: this.locations.size } });
|
|
84425
84811
|
this.reportDisabledDefaults();
|
|
84426
84812
|
}
|
|
84427
84813
|
/**
|
|
@@ -84607,10 +84993,6 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84607
84993
|
...input,
|
|
84608
84994
|
nodeId: "hub"
|
|
84609
84995
|
};
|
|
84610
|
-
if (existing?.isSystem === true) input = {
|
|
84611
|
-
...input,
|
|
84612
|
-
isSystem: true
|
|
84613
|
-
};
|
|
84614
84996
|
input = {
|
|
84615
84997
|
...input,
|
|
84616
84998
|
...resolveEnabled(input, existing, this.hasAnyLocationOfType(input.type))
|
|
@@ -84657,21 +85039,22 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84657
85039
|
return next;
|
|
84658
85040
|
}
|
|
84659
85041
|
/**
|
|
84660
|
-
* Remove a location. Refuses
|
|
84661
|
-
*
|
|
84662
|
-
*
|
|
84663
|
-
*
|
|
84664
|
-
*
|
|
84665
|
-
*
|
|
84666
|
-
* routed to the logger — see `upsertLocation` for the rationale.
|
|
85042
|
+
* Remove a location. Refuses the last location of a type and the last
|
|
85043
|
+
* enabled location of a type. `isSystem` is informational — a frozen
|
|
85044
|
+
* recordings `:default` is deletable once a sibling is live. Deleting
|
|
85045
|
+
* the flagged default promotes an enabled sibling. Occupancy still
|
|
85046
|
+
* refuses unless `force` is set; force never overrides uniqueness /
|
|
85047
|
+
* last-enabled.
|
|
84667
85048
|
*/
|
|
84668
85049
|
async deleteLocation(id, options) {
|
|
84669
85050
|
const loc = this.locations.get(id);
|
|
84670
85051
|
if (!loc) throw new Error(`Storage location "${id}" not found`);
|
|
84671
|
-
|
|
84672
|
-
if (
|
|
84673
|
-
|
|
84674
|
-
}
|
|
85052
|
+
const ofType = [...this.locations.values()].filter((l) => l.type === loc.type);
|
|
85053
|
+
if (ofType.length <= 1) throw new Error(`Cannot delete "${id}" \u2014 it is the only location for type "${loc.type}"`);
|
|
85054
|
+
const enabledOfType = ofType.filter((l) => l.enabled !== false);
|
|
85055
|
+
if (loc.enabled !== false && enabledOfType.length <= 1) throw new Error(`Cannot delete "${id}" \u2014 it is the only enabled location for type "${loc.type}"`);
|
|
85056
|
+
const successor = loc.isDefault === true ? ofType.find((l) => l.id !== id && l.enabled !== false) : void 0;
|
|
85057
|
+
if (loc.isDefault === true && successor === void 0) throw new Error(`Cannot delete "${id}" \u2014 it is the only enabled location for type "${loc.type}"`);
|
|
84675
85058
|
const occupancy = await this.probeOccupancy(loc);
|
|
84676
85059
|
if (occupancy !== "empty") {
|
|
84677
85060
|
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`);
|
|
@@ -84681,6 +85064,21 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84681
85064
|
occupancy
|
|
84682
85065
|
} });
|
|
84683
85066
|
}
|
|
85067
|
+
if (successor !== void 0 && successor.isDefault !== true) {
|
|
85068
|
+
const now = Date.now();
|
|
85069
|
+
const promoted = {
|
|
85070
|
+
...successor,
|
|
85071
|
+
isDefault: true,
|
|
85072
|
+
updatedAt: now
|
|
85073
|
+
};
|
|
85074
|
+
this.locations.set(successor.id, promoted);
|
|
85075
|
+
if (this.locationStore) this.locationStore.upsert(promoted).catch((err) => {
|
|
85076
|
+
this.logger.error("storage-orchestrator: default promotion persist failed", { meta: {
|
|
85077
|
+
id: successor.id,
|
|
85078
|
+
error: err instanceof Error ? err.message : String(err)
|
|
85079
|
+
} });
|
|
85080
|
+
});
|
|
85081
|
+
}
|
|
84684
85082
|
this.locations.delete(id);
|
|
84685
85083
|
if (this.locationStore) this.locationStore.delete(id).catch((err) => {
|
|
84686
85084
|
this.logger.error("storage-orchestrator: delete persistence failed", { meta: {
|
|
@@ -84707,15 +85105,14 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84707
85105
|
}
|
|
84708
85106
|
}
|
|
84709
85107
|
/**
|
|
84710
|
-
* Remove
|
|
84711
|
-
* addon (stale defaults from a removed location type).
|
|
84712
|
-
*
|
|
84713
|
-
* operator owns them. Requires the registry to be set first.
|
|
85108
|
+
* Remove seed-shaped locations (`<type>:default`) whose type is no longer
|
|
85109
|
+
* declared by any addon (stale defaults from a removed location type).
|
|
85110
|
+
* Operator-added locations of an undeclared type are KEPT but warned.
|
|
84714
85111
|
*
|
|
84715
85112
|
* FAIL-SAFE: if the registry is EMPTY (no addon declared any location), we
|
|
84716
85113
|
* refuse to prune anything. An empty registry almost always means
|
|
84717
85114
|
* declarations failed to load (boot ordering, a stale install) — pruning
|
|
84718
|
-
* "everything undeclared" in that state would wipe every
|
|
85115
|
+
* "everything undeclared" in that state would wipe every seeded location
|
|
84719
85116
|
* (data/logs/recordings/…). Better to keep stale rows than destroy live ones.
|
|
84720
85117
|
*/
|
|
84721
85118
|
pruneUndeclaredSystemLocations() {
|
|
@@ -84726,7 +85123,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84726
85123
|
}
|
|
84727
85124
|
for (const [id, loc] of Array.from(this.locations)) {
|
|
84728
85125
|
if (this.registry.cardinalityOf(loc.type) !== null) continue;
|
|
84729
|
-
if (loc.
|
|
85126
|
+
if (loc.id === `${loc.type}:default`) {
|
|
84730
85127
|
this.locations.delete(id);
|
|
84731
85128
|
if (this.locationStore) this.locationStore.delete(id).catch((err) => {
|
|
84732
85129
|
this.logger.error("storage-orchestrator: prune persistence failed", { meta: {
|
|
@@ -84734,7 +85131,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84734
85131
|
error: err instanceof Error ? err.message : String(err)
|
|
84735
85132
|
} });
|
|
84736
85133
|
});
|
|
84737
|
-
this.logger.info("storage-orchestrator: pruned stale
|
|
85134
|
+
this.logger.info("storage-orchestrator: pruned stale seeded location", { meta: {
|
|
84738
85135
|
id,
|
|
84739
85136
|
type: loc.type
|
|
84740
85137
|
} });
|
|
@@ -84894,7 +85291,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
84894
85291
|
providerId: input.providerId,
|
|
84895
85292
|
config: { basePath: base },
|
|
84896
85293
|
isDefault: true,
|
|
84897
|
-
isSystem:
|
|
85294
|
+
isSystem: false
|
|
84898
85295
|
});
|
|
84899
85296
|
added++;
|
|
84900
85297
|
}
|
|
@@ -85076,6 +85473,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85076
85473
|
pressureTimer = null;
|
|
85077
85474
|
pressureSweepInFlight = false;
|
|
85078
85475
|
migration = null;
|
|
85476
|
+
cleanup = null;
|
|
85079
85477
|
/**
|
|
85080
85478
|
* Cached `providerId → nodeLocal` snapshot (SP1). Backs the orchestrator's
|
|
85081
85479
|
* synchronous `NodeLocalResolver` — `getProviderInfo()` is async, so we
|
|
@@ -85133,7 +85531,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85133
85531
|
const rows = type !== void 0 ? service.listLocations({ type }) : service.listLocations();
|
|
85134
85532
|
return Promise.all(rows.map(async (loc) => ({
|
|
85135
85533
|
...this.redacted(loc),
|
|
85136
|
-
capacity: await this.localCapacityOf(loc)
|
|
85534
|
+
capacity: loc.enabled === false ? null : await this.localCapacityOf(loc)
|
|
85137
85535
|
})));
|
|
85138
85536
|
},
|
|
85139
85537
|
getDefaultLocation: async ({ type }) => {
|
|
@@ -85301,6 +85699,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85301
85699
|
const migration = new StorageMigrationCoordinator({
|
|
85302
85700
|
locations: service,
|
|
85303
85701
|
state: this.state("storage-migration", require_dist10.StorageMigrationJobSchema.nullable(), null),
|
|
85702
|
+
history: this.state("storage-migration-history", zod.z.array(require_dist10.StorageMigrationJobSchema), []),
|
|
85304
85703
|
participants: {
|
|
85305
85704
|
pipeline: {
|
|
85306
85705
|
pause: async (leaseId) => {
|
|
@@ -85351,6 +85750,36 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85351
85750
|
deviceKeyOf: (locationId) => this.locationDeviceKey(locationId)
|
|
85352
85751
|
});
|
|
85353
85752
|
this.migration = migration;
|
|
85753
|
+
const cleanup = new StorageCleanupCoordinator({
|
|
85754
|
+
locations: service,
|
|
85755
|
+
state: this.state("storage-cleanup", require_dist10.StorageCleanupJobSchema.nullable(), null),
|
|
85756
|
+
participants: {
|
|
85757
|
+
startOrphan: async (restart) => {
|
|
85758
|
+
return parseStarted(await this.ctx.api.addons.custom.mutate({
|
|
85759
|
+
addonId: "pipeline-analytics",
|
|
85760
|
+
action: "retention.orphanAudit",
|
|
85761
|
+
input: {
|
|
85762
|
+
mode: "reclaim",
|
|
85763
|
+
restart,
|
|
85764
|
+
maxRowsPerScope: 2e4
|
|
85765
|
+
}
|
|
85766
|
+
}));
|
|
85767
|
+
},
|
|
85768
|
+
orphanStatus: async () => {
|
|
85769
|
+
return parseOrphanStatus(await this.ctx.api.addons.custom.mutate({
|
|
85770
|
+
addonId: "pipeline-analytics",
|
|
85771
|
+
action: "retention.orphanAuditStatus",
|
|
85772
|
+
input: {}
|
|
85773
|
+
}));
|
|
85774
|
+
},
|
|
85775
|
+
startDebugMedia: () => this.ctx.api.pipelineAnalytics.reclaimDebugMedia.mutate({ mode: "reclaim" }),
|
|
85776
|
+
debugMediaStatus: () => this.ctx.api.pipelineAnalytics.getMediaReclaimStatus.query({}),
|
|
85777
|
+
walkLedger: (input) => this.ctx.api.recording.reconcileLedgerAgainstDisk.mutate(input)
|
|
85778
|
+
},
|
|
85779
|
+
now: () => Date.now(),
|
|
85780
|
+
newId: () => (0, node_crypto.randomUUID)()
|
|
85781
|
+
});
|
|
85782
|
+
this.cleanup = cleanup;
|
|
85354
85783
|
const migrationProvider = {
|
|
85355
85784
|
plan: (input) => migration.plan(input),
|
|
85356
85785
|
start: async (input) => ({ jobId: await migration.start(input) }),
|
|
@@ -85358,7 +85787,11 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85358
85787
|
cancel: async ({ jobId }) => ({ cancelled: await migration.cancel(jobId) }),
|
|
85359
85788
|
movers: () => migration.movers(),
|
|
85360
85789
|
residue: () => migration.residue(),
|
|
85361
|
-
drain: async (input) => ({ jobId: await migration.drain(input) })
|
|
85790
|
+
drain: async (input) => ({ jobId: await migration.drain(input) }),
|
|
85791
|
+
cleanupStart: async (input) => ({ jobId: await cleanup.start(input) }),
|
|
85792
|
+
cleanupStatus: ({ jobId }) => cleanup.status(jobId),
|
|
85793
|
+
cleanupCancel: async ({ jobId }) => ({ cancelled: await cleanup.cancel(jobId) }),
|
|
85794
|
+
history: () => migration.history()
|
|
85362
85795
|
};
|
|
85363
85796
|
await this.seedFromDeclarations();
|
|
85364
85797
|
const eventBus = this.ctx.eventBus;
|
|
@@ -85603,11 +86036,14 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85603
86036
|
}
|
|
85604
86037
|
}
|
|
85605
86038
|
/**
|
|
85606
|
-
* Does this location still hold anything
|
|
85607
|
-
*
|
|
85608
|
-
*
|
|
85609
|
-
*
|
|
85610
|
-
*
|
|
86039
|
+
* Does this location still hold anything of ITS class?
|
|
86040
|
+
*
|
|
86041
|
+
* Shared roots (`/recordings` hosting high + low + events) are scored by
|
|
86042
|
+
* class subtree (`<camera>/high|mid`, `/low`, `/events`), not by a raw
|
|
86043
|
+
* `readdir` of the root — camera dirs and `.camstack-location` would
|
|
86044
|
+
* otherwise make every class look occupied. The walk stays shallow: one
|
|
86045
|
+
* dirent per camera, then first-entry of the named subtree. A `find` of
|
|
86046
|
+
* segments is precisely what must not happen here.
|
|
85611
86047
|
*
|
|
85612
86048
|
* **What it cannot see, stated rather than papered over:**
|
|
85613
86049
|
*
|
|
@@ -85616,9 +86052,10 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85616
86052
|
* `unknown`, never `empty`.
|
|
85617
86053
|
* - A location with no `basePath` — same answer.
|
|
85618
86054
|
* - The difference between "holds live footage" and "holds one stray
|
|
85619
|
-
* lock-file". It measures
|
|
85620
|
-
* a location holding orphan files that no index
|
|
85621
|
-
* the safe one, and `force` is the escape
|
|
86055
|
+
* lock-file". It measures ON-DISK entries of this class, not durable
|
|
86056
|
+
* rows, so it refuses a location holding orphan files that no index
|
|
86057
|
+
* names. That direction is the safe one, and `force` is the escape
|
|
86058
|
+
* hatch for it.
|
|
85622
86059
|
*
|
|
85623
86060
|
* A missing root (`ENOENT`) is `empty`, not `unknown`: an unmounted disk and
|
|
85624
86061
|
* a deleted directory are indistinguishable here, and if the record's own
|
|
@@ -85636,16 +86073,16 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85636
86073
|
if ((location.nodeId === void 0 || location.nodeId === "" ? HUB_NODE_ID : location.nodeId) !== (this.service?.getLocalNodeId() ?? HUB_NODE_ID)) return "unknown";
|
|
85637
86074
|
const basePath = this.locationBasePath(location.id);
|
|
85638
86075
|
if (basePath === null) return "unknown";
|
|
85639
|
-
|
|
85640
|
-
|
|
85641
|
-
|
|
85642
|
-
|
|
85643
|
-
|
|
85644
|
-
|
|
85645
|
-
|
|
85646
|
-
|
|
85647
|
-
|
|
85648
|
-
|
|
86076
|
+
const occupancy = await probeLocalDirectoryOccupancy({
|
|
86077
|
+
type: location.type,
|
|
86078
|
+
basePath
|
|
86079
|
+
});
|
|
86080
|
+
if (occupancy === "unknown") this.ctx.logger.warn("storage-orchestrator: could not read a location root to check it", { meta: {
|
|
86081
|
+
id: location.id,
|
|
86082
|
+
basePath,
|
|
86083
|
+
type: location.type
|
|
86084
|
+
} });
|
|
86085
|
+
return occupancy;
|
|
85649
86086
|
}
|
|
85650
86087
|
/** Free capacity (%) on a location's volume via `statfs`; 100 (guard inert) when unstattable. */
|
|
85651
86088
|
async locationFreePercent(locationId) {
|
|
@@ -85721,6 +86158,38 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
85721
86158
|
}
|
|
85722
86159
|
}
|
|
85723
86160
|
};
|
|
86161
|
+
function parseStarted(raw) {
|
|
86162
|
+
if (raw !== null && typeof raw === "object") {
|
|
86163
|
+
const o = raw;
|
|
86164
|
+
if (typeof o["started"] === "boolean" && typeof o["alreadyRunning"] === "boolean") return {
|
|
86165
|
+
started: o["started"],
|
|
86166
|
+
alreadyRunning: o["alreadyRunning"]
|
|
86167
|
+
};
|
|
86168
|
+
}
|
|
86169
|
+
return {
|
|
86170
|
+
started: false,
|
|
86171
|
+
alreadyRunning: false
|
|
86172
|
+
};
|
|
86173
|
+
}
|
|
86174
|
+
function parseOrphanStatus(raw) {
|
|
86175
|
+
if (raw !== null && typeof raw === "object") {
|
|
86176
|
+
const o = raw;
|
|
86177
|
+
return {
|
|
86178
|
+
running: o["running"] === true,
|
|
86179
|
+
complete: typeof o["complete"] === "boolean" ? o["complete"] : null,
|
|
86180
|
+
totalReclaimed: typeof o["totalReclaimed"] === "number" ? o["totalReclaimed"] : 0,
|
|
86181
|
+
totalBytesReclaimed: typeof o["totalBytesReclaimed"] === "number" ? o["totalBytesReclaimed"] : 0,
|
|
86182
|
+
error: typeof o["error"] === "string" ? o["error"] : null
|
|
86183
|
+
};
|
|
86184
|
+
}
|
|
86185
|
+
return {
|
|
86186
|
+
running: false,
|
|
86187
|
+
complete: true,
|
|
86188
|
+
totalReclaimed: 0,
|
|
86189
|
+
totalBytesReclaimed: 0,
|
|
86190
|
+
error: "orphan audit status unreadable"
|
|
86191
|
+
};
|
|
86192
|
+
}
|
|
85724
86193
|
exports.SqliteLocationStore = SqliteLocationStore;
|
|
85725
86194
|
exports.StorageMigrationCoordinator = StorageMigrationCoordinator;
|
|
85726
86195
|
exports.StorageOrchestratorAddon = StorageOrchestratorAddon;
|
|
@@ -85757,7 +86226,7 @@ var require_system_config_addon = __commonJS({
|
|
|
85757
86226
|
[Symbol.toStringTag]: { value: "Module" }
|
|
85758
86227
|
});
|
|
85759
86228
|
require_chunk_Cek0wNdY();
|
|
85760
|
-
var require_dist10 =
|
|
86229
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
85761
86230
|
var SECTION_TITLES = {
|
|
85762
86231
|
server: "Server",
|
|
85763
86232
|
auth: "Authentication"
|
|
@@ -103818,7 +104287,7 @@ var require_winston_logging = __commonJS({
|
|
|
103818
104287
|
[Symbol.toStringTag]: { value: "Module" }
|
|
103819
104288
|
});
|
|
103820
104289
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
103821
|
-
var require_dist10 =
|
|
104290
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
103822
104291
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
103823
104292
|
var node_path = __require("path");
|
|
103824
104293
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -105761,9 +106230,9 @@ var require_event_category_BaEgqJNv = __commonJS({
|
|
|
105761
106230
|
}
|
|
105762
106231
|
});
|
|
105763
106232
|
|
|
105764
|
-
// ../types/dist/sleep-
|
|
105765
|
-
var
|
|
105766
|
-
"../types/dist/sleep-
|
|
106233
|
+
// ../types/dist/sleep-DkBAyPva.js
|
|
106234
|
+
var require_sleep_DkBAyPva = __commonJS({
|
|
106235
|
+
"../types/dist/sleep-DkBAyPva.js"(exports) {
|
|
105767
106236
|
"use strict";
|
|
105768
106237
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
105769
106238
|
var zod = require_zod();
|
|
@@ -108436,8 +108905,6 @@ var require_sleep_CqVyhcl = __commonJS({
|
|
|
108436
108905
|
getTrack: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getTrack", "query", input),
|
|
108437
108906
|
listTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listTracks", "query", input),
|
|
108438
108907
|
listRecentTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRecentTracks", "query", input),
|
|
108439
|
-
listGroups: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listGroups", "query", input),
|
|
108440
|
-
getGroup: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getGroup", "query", input),
|
|
108441
108908
|
clearTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "clearTracks", "mutation", input),
|
|
108442
108909
|
getMotionEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getMotionEvents", "query", input),
|
|
108443
108910
|
getObjectEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getObjectEvents", "query", input),
|
|
@@ -109436,7 +109903,7 @@ var require_addon = __commonJS({
|
|
|
109436
109903
|
"use strict";
|
|
109437
109904
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
109438
109905
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
109439
|
-
var require_sleep =
|
|
109906
|
+
var require_sleep = require_sleep_DkBAyPva();
|
|
109440
109907
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
109441
109908
|
var CAP_INPUT_DEFAULTS = Object.freeze({
|
|
109442
109909
|
"addons": { "getLogs": { "limit": 100 } },
|
|
@@ -109550,7 +110017,6 @@ var require_addon = __commonJS({
|
|
|
109550
110017
|
"getMotionEvents": { "limit": 1e3 },
|
|
109551
110018
|
"getObjectEvents": { "limit": 1e3 },
|
|
109552
110019
|
"getSensorEvents": { "limit": 1e3 },
|
|
109553
|
-
"listGroups": { "limit": 40 },
|
|
109554
110020
|
"listRecentTracks": { "limit": 200 },
|
|
109555
110021
|
"reclaimDebugMedia": { "mode": "report" },
|
|
109556
110022
|
"searchObjectEvents": {
|
|
@@ -116320,12 +116786,12 @@ var require_dist2 = __commonJS({
|
|
|
116320
116786
|
}
|
|
116321
116787
|
});
|
|
116322
116788
|
|
|
116323
|
-
// ../system/dist/manifest-system-deps-
|
|
116324
|
-
var
|
|
116325
|
-
"../system/dist/manifest-system-deps-
|
|
116789
|
+
// ../system/dist/manifest-system-deps-Bi7oyXcN.js
|
|
116790
|
+
var require_manifest_system_deps_Bi7oyXcN = __commonJS({
|
|
116791
|
+
"../system/dist/manifest-system-deps-Bi7oyXcN.js"(exports) {
|
|
116326
116792
|
"use strict";
|
|
116327
116793
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
116328
|
-
|
|
116794
|
+
require_dist_DCdtLXgx();
|
|
116329
116795
|
var node_crypto = __require("crypto");
|
|
116330
116796
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
116331
116797
|
var _camstack_types_node = require_node();
|
|
@@ -128473,7 +128939,7 @@ var require_dist3 = __commonJS({
|
|
|
128473
128939
|
"use strict";
|
|
128474
128940
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
128475
128941
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
128476
|
-
var require_dist10 =
|
|
128942
|
+
var require_dist10 = require_dist_DCdtLXgx();
|
|
128477
128943
|
var require_builtins_alerts_alerts_addon = require_alerts_addon();
|
|
128478
128944
|
require_alerts();
|
|
128479
128945
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
@@ -128499,7 +128965,7 @@ var require_dist3 = __commonJS({
|
|
|
128499
128965
|
var require_builtins_winston_logging_index = require_winston_logging();
|
|
128500
128966
|
var require_file_data_plane = require_file_data_plane_DO8KbxCe();
|
|
128501
128967
|
var require_tls$1 = require_tls_BxQlomxd();
|
|
128502
|
-
var require_manifest_system_deps =
|
|
128968
|
+
var require_manifest_system_deps = require_manifest_system_deps_Bi7oyXcN();
|
|
128503
128969
|
var require_resource_monitor = require_resource_monitor_CdnzxBLP();
|
|
128504
128970
|
var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
|
|
128505
128971
|
var zod = require_zod();
|
|
@@ -209341,7 +209807,7 @@ var require_dist4 = __commonJS({
|
|
|
209341
209807
|
"use strict";
|
|
209342
209808
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
209343
209809
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
209344
|
-
var require_sleep =
|
|
209810
|
+
var require_sleep = require_sleep_DkBAyPva();
|
|
209345
209811
|
var require_canonical_hash = require_canonical_hash_DNV8S5ET();
|
|
209346
209812
|
var require_enums2 = require_enums();
|
|
209347
209813
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
@@ -210740,6 +211206,13 @@ var require_dist4 = __commonJS({
|
|
|
210740
211206
|
]);
|
|
210741
211207
|
var RelocateMediaInputSchema = zod.z.object({
|
|
210742
211208
|
toLocationId: zod.z.string(),
|
|
211209
|
+
/**
|
|
211210
|
+
* Restrict the pass to rows currently on this location. Omitted / `'*'` =
|
|
211211
|
+
* every row that is not already on `toLocationId` (the historical
|
|
211212
|
+
* behaviour). A named source is what a from→to migration needs: without it
|
|
211213
|
+
* "move events off disk 2" also emptied disk 1.
|
|
211214
|
+
*/
|
|
211215
|
+
fromLocationId: zod.z.string().optional(),
|
|
210743
211216
|
throttleMbps: zod.z.number().min(1).max(1e3).optional(),
|
|
210744
211217
|
/** Omitted = `move`, the pre-existing behaviour. */
|
|
210745
211218
|
mode: MediaRelocateModeSchema.optional()
|
|
@@ -210771,9 +211244,18 @@ var require_dist4 = __commonJS({
|
|
|
210771
211244
|
backups: zod.z.string().min(1).optional(),
|
|
210772
211245
|
galleryMedia: zod.z.string().min(1).optional()
|
|
210773
211246
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
211247
|
+
var StorageMigrationSourcesSchema = zod.z.object({
|
|
211248
|
+
recordings: zod.z.string().min(1).optional(),
|
|
211249
|
+
recordingsLow: zod.z.string().min(1).optional(),
|
|
211250
|
+
eventMedia: zod.z.string().min(1).optional(),
|
|
211251
|
+
backups: zod.z.string().min(1).optional(),
|
|
211252
|
+
galleryMedia: zod.z.string().min(1).optional()
|
|
211253
|
+
}).optional();
|
|
210774
211254
|
var StorageMigrationModeSchema = zod.z.enum(["blocking", "nonBlocking"]);
|
|
210775
211255
|
var StorageMigrationInputSchema = zod.z.object({
|
|
210776
211256
|
destinations: StorageMigrationDestinationsSchema,
|
|
211257
|
+
/** Omitted = each class's current default. */
|
|
211258
|
+
sources: StorageMigrationSourcesSchema,
|
|
210777
211259
|
throttleMbps: zod.z.number().min(1).max(1e3).optional(),
|
|
210778
211260
|
/** Omitted = `blocking`, which stays the default. */
|
|
210779
211261
|
mode: StorageMigrationModeSchema.optional()
|
|
@@ -210819,6 +211301,13 @@ var require_dist4 = __commonJS({
|
|
|
210819
211301
|
storageClass: StorageMigrationClassSchema,
|
|
210820
211302
|
fromLocationId: zod.z.string(),
|
|
210821
211303
|
toLocationId: zod.z.string(),
|
|
211304
|
+
/**
|
|
211305
|
+
* True when `from` was NOT the class default at plan time. The move still
|
|
211306
|
+
* copies bytes, but the default is left alone and the source is disabled
|
|
211307
|
+
* once the copy verifies. Absent on jobs planned before this field existed
|
|
211308
|
+
* — those jobs always repointed, which is `false`.
|
|
211309
|
+
*/
|
|
211310
|
+
freezeSource: zod.z.boolean().optional(),
|
|
210822
211311
|
moverJobId: zod.z.string().nullable(),
|
|
210823
211312
|
state: RelocateJobStateSchema.nullable(),
|
|
210824
211313
|
error: zod.z.string().nullable(),
|
|
@@ -210832,6 +211321,7 @@ var require_dist4 = __commonJS({
|
|
|
210832
211321
|
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
210833
211322
|
mode: StorageMigrationModeSchema,
|
|
210834
211323
|
destinations: StorageMigrationDestinationsSchema,
|
|
211324
|
+
sources: StorageMigrationSourcesSchema,
|
|
210835
211325
|
throttleMbps: zod.z.number(),
|
|
210836
211326
|
moves: zod.z.array(StorageMigrationMoveSchema),
|
|
210837
211327
|
pauseLeaseId: zod.z.string().nullable(),
|
|
@@ -210858,6 +211348,7 @@ var require_dist4 = __commonJS({
|
|
|
210858
211348
|
});
|
|
210859
211349
|
var StorageMigrationPlanSchema = zod.z.object({
|
|
210860
211350
|
destinations: StorageMigrationDestinationsSchema,
|
|
211351
|
+
sources: StorageMigrationSourcesSchema,
|
|
210861
211352
|
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
210862
211353
|
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
210863
211354
|
* it. */
|
|
@@ -210865,7 +211356,8 @@ var require_dist4 = __commonJS({
|
|
|
210865
211356
|
moves: zod.z.array(zod.z.object({
|
|
210866
211357
|
storageClass: StorageMigrationClassSchema,
|
|
210867
211358
|
fromLocationId: zod.z.string(),
|
|
210868
|
-
toLocationId: zod.z.string()
|
|
211359
|
+
toLocationId: zod.z.string(),
|
|
211360
|
+
freezeSource: zod.z.boolean().optional()
|
|
210869
211361
|
})),
|
|
210870
211362
|
findings: zod.z.array(StorageMigrationFindingSchema)
|
|
210871
211363
|
});
|
|
@@ -210977,9 +211469,42 @@ var require_dist4 = __commonJS({
|
|
|
210977
211469
|
var RelocatableMediaCountSchema = zod.z.object({ rows: zod.z.number().int().nonnegative() }).nullable();
|
|
210978
211470
|
var RelocatableMediaCountInputSchema = zod.z.object({
|
|
210979
211471
|
toLocationId: zod.z.string().min(1),
|
|
211472
|
+
/** Restrict the count to one source; omitted / `'*'` = every non-target row. */
|
|
211473
|
+
fromLocationId: zod.z.string().optional(),
|
|
210980
211474
|
/** Omitted = `move`. */
|
|
210981
211475
|
mode: MediaRelocateModeSchema.optional()
|
|
210982
211476
|
});
|
|
211477
|
+
var StorageCleanupPhaseSchema = zod.z.enum([
|
|
211478
|
+
"orphans",
|
|
211479
|
+
"debug-media",
|
|
211480
|
+
"ghost-ledger",
|
|
211481
|
+
"done",
|
|
211482
|
+
"failed",
|
|
211483
|
+
"cancelled"
|
|
211484
|
+
]);
|
|
211485
|
+
var StorageCleanupInputSchema = zod.z.object({
|
|
211486
|
+
/** Also walk motion stills / track filmstrips. Off by default. */
|
|
211487
|
+
includeDebugMedia: zod.z.boolean().optional()
|
|
211488
|
+
});
|
|
211489
|
+
var StorageCleanupJobSchema = zod.z.object({
|
|
211490
|
+
jobId: zod.z.string(),
|
|
211491
|
+
phase: StorageCleanupPhaseSchema,
|
|
211492
|
+
includeDebugMedia: zod.z.boolean(),
|
|
211493
|
+
orphansReclaimed: zod.z.number().int().nonnegative(),
|
|
211494
|
+
orphanBytesReclaimed: zod.z.number().int().nonnegative(),
|
|
211495
|
+
debugMediaReclaimed: zod.z.number().int().nonnegative(),
|
|
211496
|
+
debugMediaBytesReclaimed: zod.z.number().int().nonnegative(),
|
|
211497
|
+
ghostsForgotten: zod.z.number().int().nonnegative(),
|
|
211498
|
+
ghostBytesForgotten: zod.z.number().int().nonnegative(),
|
|
211499
|
+
/** Short operator-facing line: current collection, pass, or location. */
|
|
211500
|
+
detail: zod.z.string().nullable(),
|
|
211501
|
+
cancelRequested: zod.z.boolean(),
|
|
211502
|
+
startedAt: zod.z.number(),
|
|
211503
|
+
updatedAt: zod.z.number(),
|
|
211504
|
+
finishedAt: zod.z.number().nullable(),
|
|
211505
|
+
error: zod.z.string().nullable()
|
|
211506
|
+
});
|
|
211507
|
+
var StorageCleanupStatusInputSchema = zod.z.object({ jobId: zod.z.string().optional() });
|
|
210983
211508
|
var SUB_DETECTION_TYPES = ["face", "plate"];
|
|
210984
211509
|
var RECOGNITION_TYPES = [
|
|
210985
211510
|
"face",
|
|
@@ -216999,6 +217524,27 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
216999
217524
|
kind: "mutation",
|
|
217000
217525
|
auth: "admin"
|
|
217001
217526
|
}),
|
|
217527
|
+
/** Rename a room: replace the label in the registry IN PLACE and move
|
|
217528
|
+
* every device that carried it, as ONE server operation.
|
|
217529
|
+
*
|
|
217530
|
+
* The admin UI used to do this as `addLocation(to)` → N ×
|
|
217531
|
+
* `setLocation(device, to)` → `removeLocation(from)` from the browser.
|
|
217532
|
+
* Nothing bound those three together, so a closed tab left the fleet
|
|
217533
|
+
* split across two rooms — one of which the operator believed was gone.
|
|
217534
|
+
*
|
|
217535
|
+
* `from` is matched the way the registry matches everywhere else
|
|
217536
|
+
* (trimmed, case-insensitive) and need NOT be registered: the registry is
|
|
217537
|
+
* a suggestion list, and the devices that most need a rename are exactly
|
|
217538
|
+
* the ones carrying a label nobody registered. `to` renames onto an
|
|
217539
|
+
* existing room by MERGING into it, leaving no duplicate label. An empty
|
|
217540
|
+
* `to` throws before anything is written. */
|
|
217541
|
+
renameLocation: require_sleep.method(zod.z.object({
|
|
217542
|
+
from: zod.z.string(),
|
|
217543
|
+
to: zod.z.string()
|
|
217544
|
+
}), zod.z.object({ moved: zod.z.number() }), {
|
|
217545
|
+
kind: "mutation",
|
|
217546
|
+
auth: "admin"
|
|
217547
|
+
}),
|
|
217002
217548
|
/** Soft-disable / re-enable the device. Drivers consult
|
|
217003
217549
|
* `BaseDevice.disabled` to gate lifecycle hooks. */
|
|
217004
217550
|
setDisabled: require_sleep.method(zod.z.object({
|
|
@@ -223433,46 +223979,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
223433
223979
|
/** Cursor for the next page, or null when this page is the last. */
|
|
223434
223980
|
nextCursor: zod.z.string().nullable()
|
|
223435
223981
|
});
|
|
223436
|
-
var LIST_GROUPS_DEFAULT_LIMIT = 40;
|
|
223437
|
-
var LIST_GROUPS_MAX_LIMIT = 100;
|
|
223438
|
-
var AnalyticsGroupRecordSchema = zod.z.object({
|
|
223439
|
-
id: zod.z.string(),
|
|
223440
|
-
deviceId: zod.z.number().int(),
|
|
223441
|
-
openedAt: zod.z.number().int(),
|
|
223442
|
-
closedAt: zod.z.number().int(),
|
|
223443
|
-
timestamp: zod.z.number().int(),
|
|
223444
|
-
memberCount: zod.z.number().int(),
|
|
223445
|
-
memberTrackIds: zod.z.array(zod.z.string()).readonly(),
|
|
223446
|
-
className: zod.z.string(),
|
|
223447
|
-
classes: zod.z.array(zod.z.string()).readonly(),
|
|
223448
|
-
/** Relative event-media path, or null when the group has no picture yet. */
|
|
223449
|
-
mediaUrl: zod.z.string().nullable(),
|
|
223450
|
-
singleton: zod.z.boolean()
|
|
223451
|
-
});
|
|
223452
|
-
var AnalyticsGroupMemberSchema = zod.z.object({
|
|
223453
|
-
trackId: zod.z.string(),
|
|
223454
|
-
deviceId: zod.z.number().int(),
|
|
223455
|
-
className: zod.z.string(),
|
|
223456
|
-
firstSeen: zod.z.number().int(),
|
|
223457
|
-
lastSeen: zod.z.number().int(),
|
|
223458
|
-
mediaUrl: zod.z.string().nullable()
|
|
223459
|
-
});
|
|
223460
|
-
var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: zod.z.array(AnalyticsGroupMemberSchema).readonly() });
|
|
223461
|
-
var ListGroupsQueryInput = zod.z.object({
|
|
223462
|
-
/** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
|
|
223463
|
-
deviceIds: zod.z.array(zod.z.number()),
|
|
223464
|
-
/** Window lower bound on `closedAt` (inclusive). */
|
|
223465
|
-
since: zod.z.number().optional(),
|
|
223466
|
-
/** Window upper bound on `openedAt` (inclusive). */
|
|
223467
|
-
until: zod.z.number().optional(),
|
|
223468
|
-
limit: zod.z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
|
|
223469
|
-
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
223470
|
-
cursor: zod.z.string().optional()
|
|
223471
|
-
});
|
|
223472
|
-
var ListGroupsPageSchema = zod.z.object({
|
|
223473
|
-
groups: zod.z.array(AnalyticsGroupRecordSchema).readonly(),
|
|
223474
|
-
nextCursor: zod.z.string().nullable()
|
|
223475
|
-
});
|
|
223476
223982
|
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
223477
223983
|
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
223478
223984
|
var KeyEventQueryInput = zod.z.object({
|
|
@@ -223565,9 +224071,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
223565
224071
|
/** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
|
|
223566
224072
|
plates: zod.z.number().int(),
|
|
223567
224073
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
223568
|
-
embeddings: zod.z.number().int()
|
|
223569
|
-
/** Group membership + group rows removed with their last member (best-effort). */
|
|
223570
|
-
groups: zod.z.number().int()
|
|
224074
|
+
embeddings: zod.z.number().int()
|
|
223571
224075
|
});
|
|
223572
224076
|
var DiskReconcileCountsSchema = zod.z.object({
|
|
223573
224077
|
mediaDropped: zod.z.number().int(),
|
|
@@ -223780,16 +224284,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
223780
224284
|
* are not included (same contract as `listTracks`).
|
|
223781
224285
|
*/
|
|
223782
224286
|
listRecentTracks: require_sleep.method(RecentTracksQueryInput, RecentTracksPageSchema),
|
|
223783
|
-
/**
|
|
223784
|
-
* Batched co-moving group listing — the Groups feed. Same merge/cursor
|
|
223785
|
-
* contract as {@link listRecentTracks}. A group is a sealed partition of
|
|
223786
|
-
* one session; `getGroup` is the detail with members.
|
|
223787
|
-
*/
|
|
223788
|
-
listGroups: require_sleep.method(ListGroupsQueryInput, ListGroupsPageSchema),
|
|
223789
|
-
getGroup: require_sleep.method(zod.z.object({
|
|
223790
|
-
deviceId: zod.z.number(),
|
|
223791
|
-
groupId: zod.z.string().min(1)
|
|
223792
|
-
}), AnalyticsGroupDetailSchema.nullable()),
|
|
223793
224287
|
clearTracks: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
|
|
223794
224288
|
kind: "mutation",
|
|
223795
224289
|
auth: "admin"
|
|
@@ -226903,7 +227397,23 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
226903
227397
|
drain: require_sleep.method(StorageMigrationDrainInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
226904
227398
|
kind: "mutation",
|
|
226905
227399
|
auth: "admin"
|
|
226906
|
-
})
|
|
227400
|
+
}),
|
|
227401
|
+
/**
|
|
227402
|
+
* One operator cleanup of leftover analytics (DB + blobs) and ghost
|
|
227403
|
+
* ledger rows on frozen footage locations. Optional debug-media sweep.
|
|
227404
|
+
* Returns immediately; poll {@link cleanupStatus}.
|
|
227405
|
+
*/
|
|
227406
|
+
cleanupStart: require_sleep.method(StorageCleanupInputSchema, zod.z.object({ jobId: zod.z.string() }), {
|
|
227407
|
+
kind: "mutation",
|
|
227408
|
+
auth: "admin"
|
|
227409
|
+
}),
|
|
227410
|
+
cleanupStatus: require_sleep.method(StorageCleanupStatusInputSchema, StorageCleanupJobSchema.nullable(), { auth: "admin" }),
|
|
227411
|
+
cleanupCancel: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
|
|
227412
|
+
kind: "mutation",
|
|
227413
|
+
auth: "admin"
|
|
227414
|
+
}),
|
|
227415
|
+
/** Recent finished migration jobs, newest first. The live job is `status`. */
|
|
227416
|
+
history: require_sleep.method(zod.z.object({}), zod.z.array(StorageMigrationJobSchema).readonly(), { auth: "admin" })
|
|
226907
227417
|
}
|
|
226908
227418
|
};
|
|
226909
227419
|
var ProviderInfoSchema = zod.z.discriminatedUnion("shouldSaveDiskSpace", [zod.z.object({
|
|
@@ -233704,6 +234214,26 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
233704
234214
|
/** Ignore piles smaller than this (default 1 GB). */
|
|
233705
234215
|
minMoveGb: zod.z.number().min(0).optional()
|
|
233706
234216
|
});
|
|
234217
|
+
var RecordingDevicePlacementSchema = zod.z.object({
|
|
234218
|
+
deviceId: zod.z.number().int(),
|
|
234219
|
+
profile: zod.z.string(),
|
|
234220
|
+
locationId: zod.z.string()
|
|
234221
|
+
});
|
|
234222
|
+
var RecordingDevicePinSchema = zod.z.object({
|
|
234223
|
+
deviceId: zod.z.number().int(),
|
|
234224
|
+
/** Recordings-class location this camera is pinned to. */
|
|
234225
|
+
locationId: zod.z.string()
|
|
234226
|
+
});
|
|
234227
|
+
var RecordingPlacementViewSchema = zod.z.object({
|
|
234228
|
+
assignments: zod.z.array(RecordingDevicePlacementSchema),
|
|
234229
|
+
pins: zod.z.array(RecordingDevicePinSchema),
|
|
234230
|
+
defaultLocations: zod.z.record(zod.z.string(), zod.z.string())
|
|
234231
|
+
});
|
|
234232
|
+
var RecordingSetDevicePlacementInputSchema = zod.z.object({
|
|
234233
|
+
deviceId: zod.z.number().int(),
|
|
234234
|
+
/** `null` = Auto. Otherwise a `recordings:*` location id. */
|
|
234235
|
+
locationId: zod.z.string().nullable()
|
|
234236
|
+
});
|
|
233707
234237
|
var LocateSegmentResultSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
|
|
233708
234238
|
kind: zod.z.literal("segment"),
|
|
233709
234239
|
startMs: zod.z.number(),
|
|
@@ -234022,6 +234552,22 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
234022
234552
|
startStorageRebalance: require_sleep.method(RecordingRebalanceInputSchema, RecordingRebalancePlanSchema, {
|
|
234023
234553
|
kind: "mutation",
|
|
234024
234554
|
auth: "admin"
|
|
234555
|
+
}),
|
|
234556
|
+
/**
|
|
234557
|
+
* The placement plan in force plus operator pins. Drives the Locations
|
|
234558
|
+
* admin page: Auto vs a named recordings location, per camera.
|
|
234559
|
+
*/
|
|
234560
|
+
getPlacement: require_sleep.method(zod.z.object({}), RecordingPlacementViewSchema, {
|
|
234561
|
+
kind: "query",
|
|
234562
|
+
auth: "admin"
|
|
234563
|
+
}),
|
|
234564
|
+
/**
|
|
234565
|
+
* Pin a camera to a recordings location, or clear the pin (Auto). High and
|
|
234566
|
+
* mid follow the pin; low stays with the recordingsLow planner.
|
|
234567
|
+
*/
|
|
234568
|
+
setDevicePlacement: require_sleep.method(RecordingSetDevicePlacementInputSchema, zod.z.object({ ok: zod.z.literal(true) }), {
|
|
234569
|
+
kind: "mutation",
|
|
234570
|
+
auth: "admin"
|
|
234025
234571
|
})
|
|
234026
234572
|
}
|
|
234027
234573
|
};
|
|
@@ -241361,6 +241907,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
241361
241907
|
addonId: null,
|
|
241362
241908
|
access: "delete"
|
|
241363
241909
|
},
|
|
241910
|
+
"deviceManager.renameLocation": {
|
|
241911
|
+
capName: "device-manager",
|
|
241912
|
+
capScope: "system",
|
|
241913
|
+
addonId: null,
|
|
241914
|
+
access: "create"
|
|
241915
|
+
},
|
|
241364
241916
|
"deviceManager.runDeviceAction": {
|
|
241365
241917
|
capName: "device-manager",
|
|
241366
241918
|
capScope: "system",
|
|
@@ -243053,12 +243605,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
243053
243605
|
addonId: null,
|
|
243054
243606
|
access: "view"
|
|
243055
243607
|
},
|
|
243056
|
-
"pipelineAnalytics.getGroup": {
|
|
243057
|
-
capName: "pipeline-analytics",
|
|
243058
|
-
capScope: "device",
|
|
243059
|
-
addonId: null,
|
|
243060
|
-
access: "view"
|
|
243061
|
-
},
|
|
243062
243608
|
"pipelineAnalytics.getKeyEvents": {
|
|
243063
243609
|
capName: "pipeline-analytics",
|
|
243064
243610
|
capScope: "device",
|
|
@@ -243161,12 +243707,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
243161
243707
|
addonId: null,
|
|
243162
243708
|
access: "view"
|
|
243163
243709
|
},
|
|
243164
|
-
"pipelineAnalytics.listGroups": {
|
|
243165
|
-
capName: "pipeline-analytics",
|
|
243166
|
-
capScope: "device",
|
|
243167
|
-
addonId: null,
|
|
243168
|
-
access: "view"
|
|
243169
|
-
},
|
|
243170
243710
|
"pipelineAnalytics.listOpsLog": {
|
|
243171
243711
|
capName: "pipeline-analytics",
|
|
243172
243712
|
capScope: "device",
|
|
@@ -244181,6 +244721,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
244181
244721
|
addonId: null,
|
|
244182
244722
|
access: "view"
|
|
244183
244723
|
},
|
|
244724
|
+
"recording.getPlacement": {
|
|
244725
|
+
capName: "recording",
|
|
244726
|
+
capScope: "system",
|
|
244727
|
+
addonId: null,
|
|
244728
|
+
access: "view"
|
|
244729
|
+
},
|
|
244184
244730
|
"recording.getPlaybackManifest": {
|
|
244185
244731
|
capName: "recording",
|
|
244186
244732
|
capScope: "system",
|
|
@@ -244307,6 +244853,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
244307
244853
|
addonId: null,
|
|
244308
244854
|
access: "create"
|
|
244309
244855
|
},
|
|
244856
|
+
"recording.setDevicePlacement": {
|
|
244857
|
+
capName: "recording",
|
|
244858
|
+
capScope: "system",
|
|
244859
|
+
addonId: null,
|
|
244860
|
+
access: "create"
|
|
244861
|
+
},
|
|
244310
244862
|
"recording.startStorageMigrationMove": {
|
|
244311
244863
|
capName: "recording",
|
|
244312
244864
|
capScope: "system",
|
|
@@ -244751,12 +245303,36 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
244751
245303
|
addonId: null,
|
|
244752
245304
|
access: "create"
|
|
244753
245305
|
},
|
|
245306
|
+
"storageMigration.cleanupCancel": {
|
|
245307
|
+
capName: "storage-migration",
|
|
245308
|
+
capScope: "system",
|
|
245309
|
+
addonId: null,
|
|
245310
|
+
access: "create"
|
|
245311
|
+
},
|
|
245312
|
+
"storageMigration.cleanupStart": {
|
|
245313
|
+
capName: "storage-migration",
|
|
245314
|
+
capScope: "system",
|
|
245315
|
+
addonId: null,
|
|
245316
|
+
access: "create"
|
|
245317
|
+
},
|
|
245318
|
+
"storageMigration.cleanupStatus": {
|
|
245319
|
+
capName: "storage-migration",
|
|
245320
|
+
capScope: "system",
|
|
245321
|
+
addonId: null,
|
|
245322
|
+
access: "view"
|
|
245323
|
+
},
|
|
244754
245324
|
"storageMigration.drain": {
|
|
244755
245325
|
capName: "storage-migration",
|
|
244756
245326
|
capScope: "system",
|
|
244757
245327
|
addonId: null,
|
|
244758
245328
|
access: "create"
|
|
244759
245329
|
},
|
|
245330
|
+
"storageMigration.history": {
|
|
245331
|
+
capName: "storage-migration",
|
|
245332
|
+
capScope: "system",
|
|
245333
|
+
addonId: null,
|
|
245334
|
+
access: "view"
|
|
245335
|
+
},
|
|
244760
245336
|
"storageMigration.movers": {
|
|
244761
245337
|
capName: "storage-migration",
|
|
244762
245338
|
capScope: "system",
|
|
@@ -247011,11 +247587,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
247011
247587
|
form: "single",
|
|
247012
247588
|
optional: true
|
|
247013
247589
|
}],
|
|
247014
|
-
"pipelineAnalytics.getGroup": [{
|
|
247015
|
-
name: "deviceId",
|
|
247016
|
-
form: "single",
|
|
247017
|
-
optional: false
|
|
247018
|
-
}],
|
|
247019
247590
|
"pipelineAnalytics.getKeyEvents": [{
|
|
247020
247591
|
name: "deviceId",
|
|
247021
247592
|
form: "single",
|
|
@@ -247081,11 +247652,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
247081
247652
|
form: "single",
|
|
247082
247653
|
optional: false
|
|
247083
247654
|
}],
|
|
247084
|
-
"pipelineAnalytics.listGroups": [{
|
|
247085
|
-
name: "deviceIds",
|
|
247086
|
-
form: "array",
|
|
247087
|
-
optional: false
|
|
247088
|
-
}],
|
|
247089
247655
|
"pipelineAnalytics.listOpsLog": [{
|
|
247090
247656
|
name: "deviceId",
|
|
247091
247657
|
form: "single",
|
|
@@ -247501,6 +248067,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
247501
248067
|
form: "single",
|
|
247502
248068
|
optional: false
|
|
247503
248069
|
}],
|
|
248070
|
+
"recording.setDevicePlacement": [{
|
|
248071
|
+
name: "deviceId",
|
|
248072
|
+
form: "single",
|
|
248073
|
+
optional: false
|
|
248074
|
+
}],
|
|
247504
248075
|
"recording.startStorageMigrationMove": [{
|
|
247505
248076
|
name: "deviceId",
|
|
247506
248077
|
form: "single",
|
|
@@ -247970,6 +248541,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
247970
248541
|
"recording.renderGif",
|
|
247971
248542
|
"recording.rescanStorage",
|
|
247972
248543
|
"recording.setDeviceConfig",
|
|
248544
|
+
"recording.setDevicePlacement",
|
|
247973
248545
|
"recording.startStorageMigrationMove",
|
|
247974
248546
|
"recordingExport.createExport",
|
|
247975
248547
|
"recordingExport.listExports",
|
|
@@ -248560,6 +249132,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248560
249132
|
listLocations: (input) => dispatch("deviceManager", "listLocations", "query", input),
|
|
248561
249133
|
addLocation: (input) => dispatch("deviceManager", "addLocation", "mutation", input),
|
|
248562
249134
|
removeLocation: (input) => dispatch("deviceManager", "removeLocation", "mutation", input),
|
|
249135
|
+
renameLocation: (input) => dispatch("deviceManager", "renameLocation", "mutation", input),
|
|
248563
249136
|
listPersistedByAddon: (input) => dispatch("deviceManager", "listPersistedByAddon", "query", input),
|
|
248564
249137
|
listAll: (input) => dispatch("deviceManager", "listAll", "query", input),
|
|
248565
249138
|
getChildren: (input) => dispatch("deviceManager", "getChildren", "query", input),
|
|
@@ -248853,7 +249426,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248853
249426
|
reconcileLedgerAgainstDisk: (input) => dispatch("recording", "reconcileLedgerAgainstDisk", "mutation", input),
|
|
248854
249427
|
cancelRelocateJob: (input) => dispatch("recording", "cancelRelocateJob", "mutation", input),
|
|
248855
249428
|
planStorageRebalance: (input) => dispatch("recording", "planStorageRebalance", "query", input),
|
|
248856
|
-
startStorageRebalance: (input) => dispatch("recording", "startStorageRebalance", "mutation", input)
|
|
249429
|
+
startStorageRebalance: (input) => dispatch("recording", "startStorageRebalance", "mutation", input),
|
|
249430
|
+
getPlacement: (input) => dispatch("recording", "getPlacement", "query", input),
|
|
249431
|
+
setDevicePlacement: (input) => dispatch("recording", "setDevicePlacement", "mutation", input)
|
|
248857
249432
|
},
|
|
248858
249433
|
recordingExport: {
|
|
248859
249434
|
createExport: (input) => dispatch("recordingExport", "createExport", "mutation", input),
|
|
@@ -248917,7 +249492,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248917
249492
|
cancel: (input) => dispatch("storageMigration", "cancel", "mutation", input),
|
|
248918
249493
|
movers: (input) => dispatch("storageMigration", "movers", "query", input),
|
|
248919
249494
|
residue: (input) => dispatch("storageMigration", "residue", "query", input),
|
|
248920
|
-
drain: (input) => dispatch("storageMigration", "drain", "mutation", input)
|
|
249495
|
+
drain: (input) => dispatch("storageMigration", "drain", "mutation", input),
|
|
249496
|
+
cleanupStart: (input) => dispatch("storageMigration", "cleanupStart", "mutation", input),
|
|
249497
|
+
cleanupStatus: (input) => dispatch("storageMigration", "cleanupStatus", "query", input),
|
|
249498
|
+
cleanupCancel: (input) => dispatch("storageMigration", "cleanupCancel", "mutation", input),
|
|
249499
|
+
history: (input) => dispatch("storageMigration", "history", "query", input)
|
|
248921
249500
|
},
|
|
248922
249501
|
streamBroker: {
|
|
248923
249502
|
fetchEventMedia: (input) => dispatch("streamBroker", "fetchEventMedia", "mutation", input),
|
|
@@ -251703,9 +252282,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
251703
252282
|
exports.AlertSourceSchema = AlertSourceSchema;
|
|
251704
252283
|
exports.AlertStatusSchema = AlertStatusSchema;
|
|
251705
252284
|
exports.AmbientLightSensorStatusSchema = AmbientLightSensorStatusSchema;
|
|
251706
|
-
exports.AnalyticsGroupDetailSchema = AnalyticsGroupDetailSchema;
|
|
251707
|
-
exports.AnalyticsGroupMemberSchema = AnalyticsGroupMemberSchema;
|
|
251708
|
-
exports.AnalyticsGroupRecordSchema = AnalyticsGroupRecordSchema;
|
|
251709
252285
|
exports.ApiKeyRecordSchema = ApiKeyRecordSchema;
|
|
251710
252286
|
exports.ApiKeySummarySchema = ApiKeySummarySchema;
|
|
251711
252287
|
exports.ArchiveEntrySchema = ArchiveEntrySchema;
|
|
@@ -252070,8 +252646,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252070
252646
|
exports.LedgerWalkSkipReasonSchema = LedgerWalkSkipReasonSchema;
|
|
252071
252647
|
exports.LinkedDeviceSchema = LinkedDeviceSchema;
|
|
252072
252648
|
exports.LinkedDevicesModeSchema = LinkedDevicesModeSchema;
|
|
252073
|
-
exports.ListGroupsPageSchema = ListGroupsPageSchema;
|
|
252074
|
-
exports.ListGroupsQueryInput = ListGroupsQueryInput;
|
|
252075
252649
|
exports.LlmDefaultSchema = LlmDefaultSchema;
|
|
252076
252650
|
exports.LlmDefaultSelectorSchema = LlmDefaultSelectorSchema;
|
|
252077
252651
|
exports.LlmDownloadProgressSchema = LlmDownloadProgressSchema;
|
|
@@ -252534,6 +253108,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252534
253108
|
exports.StorageBeginDownloadResultSchema = BeginDownloadResultSchema;
|
|
252535
253109
|
exports.StorageBeginUploadInputSchema = BeginUploadInputSchema;
|
|
252536
253110
|
exports.StorageBeginUploadResultSchema = BeginUploadResultSchema;
|
|
253111
|
+
exports.StorageCleanupInputSchema = StorageCleanupInputSchema;
|
|
253112
|
+
exports.StorageCleanupJobSchema = StorageCleanupJobSchema;
|
|
253113
|
+
exports.StorageCleanupPhaseSchema = StorageCleanupPhaseSchema;
|
|
253114
|
+
exports.StorageCleanupStatusInputSchema = StorageCleanupStatusInputSchema;
|
|
252537
253115
|
exports.StorageEndDownloadInputSchema = EndDownloadInputSchema;
|
|
252538
253116
|
exports.StorageFinalizeUploadInputSchema = FinalizeUploadInputSchema;
|
|
252539
253117
|
exports.StorageLocationDeclarationSchema = StorageLocationDeclarationSchema;
|
|
@@ -252559,6 +253137,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252559
253137
|
exports.StorageMigrationPhaseSchema = StorageMigrationPhaseSchema;
|
|
252560
253138
|
exports.StorageMigrationPlanSchema = StorageMigrationPlanSchema;
|
|
252561
253139
|
exports.StorageMigrationResidueSchema = StorageMigrationResidueSchema;
|
|
253140
|
+
exports.StorageMigrationSourcesSchema = StorageMigrationSourcesSchema;
|
|
252562
253141
|
exports.StorageProviderInfoSchema = ProviderInfoSchema;
|
|
252563
253142
|
exports.StorageReadChunkInputSchema = ReadChunkInputSchema;
|
|
252564
253143
|
exports.StorageTestLocationResultSchema = TestLocationResultSchema;
|