@camstack/addon-osd-manager 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{MotionZonesSettings-DteO0vrm.mjs → MotionZonesSettings-flJ2MBtH.mjs} +1 -1
- package/dist/{PrivacyMaskSettings-VeD7Fy0-.mjs → PrivacyMaskSettings-DM3Imsdp.mjs} +2 -2
- package/dist/_stub.js +3349 -3012
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-BBrLl2CB.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-DPF0_skI.mjs} +4 -4
- package/dist/{_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D722amjy.mjs → _virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-y06ok-co.mjs} +1 -1
- package/dist/addon-osd-manager.css +1 -1
- package/dist/{hostInit-COP9TmCI.mjs → hostInit-B0N97tts.mjs} +3 -3
- package/dist/index.js +537 -48
- package/dist/index.mjs +537 -48
- package/dist/{player-overlays-CwbydND6.mjs → player-overlays-DjxfQys9.mjs} +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{trash-2-Ckik0Rau.mjs → trash-2-FWfrH-Em.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-Bx-1SwyE.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-BbeKMP0f.mjs} +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -7626,12 +7626,11 @@ var RecordingConfigSchema = object({
|
|
|
7626
7626
|
/**
|
|
7627
7627
|
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
7628
7628
|
*
|
|
7629
|
-
* One shape shared by the recorder
|
|
7630
|
-
*
|
|
7631
|
-
*
|
|
7632
|
-
*
|
|
7633
|
-
*
|
|
7634
|
-
* row on the owning addon's surface.
|
|
7629
|
+
* One shape shared by the recorder and pipeline-analytics internal movers.
|
|
7630
|
+
* The public admin surface is `storage-migration`; child jobs remain in RAM
|
|
7631
|
+
* because copy-if-absent, verify, delete and index/row repoint are resumable.
|
|
7632
|
+
* Each completed/failed run also lands one durable ops-log row on its owning
|
|
7633
|
+
* addon surface.
|
|
7635
7634
|
*/
|
|
7636
7635
|
var RelocateJobStateSchema = _enum([
|
|
7637
7636
|
"running",
|
|
@@ -7658,19 +7657,100 @@ var RelocateJobSchema = object({
|
|
|
7658
7657
|
finishedAt: number().nullable(),
|
|
7659
7658
|
error: string().nullable()
|
|
7660
7659
|
});
|
|
7660
|
+
/** Profile-derived footage selection used only by the migration coordinator:
|
|
7661
|
+
* `recordings` owns high+mid; `recordingsLow` owns low. */
|
|
7662
|
+
var RelocateFootageClassSchema = _enum(["recordings", "recordingsLow"]);
|
|
7661
7663
|
var RelocateFootageInputSchema = object({
|
|
7662
|
-
deviceId: number().optional(),
|
|
7663
7664
|
fromLocationId: string(),
|
|
7664
7665
|
toLocationId: string(),
|
|
7665
7666
|
entities: array(_enum(["segments"])).optional(),
|
|
7667
|
+
/** Limits relocation to the logical profile class. Omit only for the
|
|
7668
|
+
* pre-orchestration compatibility path. */
|
|
7669
|
+
footageClass: RelocateFootageClassSchema.optional(),
|
|
7666
7670
|
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
7667
7671
|
* never allowed to starve live writers. */
|
|
7668
7672
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7669
7673
|
});
|
|
7670
|
-
|
|
7671
|
-
|
|
7674
|
+
/** Internal, lease-scoped participant operation. It is intentionally separate
|
|
7675
|
+
* from persistent recording settings: a migration never changes
|
|
7676
|
+
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
7677
|
+
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
7678
|
+
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
7679
|
+
var StorageMigrationMediaMoveInputSchema = object({
|
|
7672
7680
|
toLocationId: string(),
|
|
7673
7681
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7682
|
+
}).extend({ leaseId: string().min(1) });
|
|
7683
|
+
/** The independently selectable logical storage classes. `recordings`
|
|
7684
|
+
* encompasses the high and mid segment profiles; `recordingsLow` is low
|
|
7685
|
+
* segments; `eventMedia` is post-analysis blobs. */
|
|
7686
|
+
var StorageMigrationClassSchema = _enum([
|
|
7687
|
+
"recordings",
|
|
7688
|
+
"recordingsLow",
|
|
7689
|
+
"eventMedia"
|
|
7690
|
+
]);
|
|
7691
|
+
/** A destination is always an existing, fully-qualified location id. The
|
|
7692
|
+
* migration API intentionally never changes a source location's `basePath`:
|
|
7693
|
+
* callers create a new `<type>:<slug>` location, then select it here. */
|
|
7694
|
+
var StorageMigrationDestinationsSchema = object({
|
|
7695
|
+
recordings: string().min(1).optional(),
|
|
7696
|
+
recordingsLow: string().min(1).optional(),
|
|
7697
|
+
eventMedia: string().min(1).optional()
|
|
7698
|
+
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
7699
|
+
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
7700
|
+
var StorageMigrationInputSchema = object({
|
|
7701
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7702
|
+
throttleMbps: number().min(1).max(1e3).optional()
|
|
7703
|
+
});
|
|
7704
|
+
/** The durable coordinator state machine. The only phase that changes default
|
|
7705
|
+
* locations is `repointing`, after every selected mover has completed and been
|
|
7706
|
+
* verified. */
|
|
7707
|
+
var StorageMigrationPhaseSchema = _enum([
|
|
7708
|
+
"planning",
|
|
7709
|
+
"pausing",
|
|
7710
|
+
"moving",
|
|
7711
|
+
"verifying",
|
|
7712
|
+
"repointing",
|
|
7713
|
+
"refreshing",
|
|
7714
|
+
"resuming",
|
|
7715
|
+
"done",
|
|
7716
|
+
"failed",
|
|
7717
|
+
"cancelled"
|
|
7718
|
+
]);
|
|
7719
|
+
var StorageMigrationParticipantSchema = _enum([
|
|
7720
|
+
"pipeline",
|
|
7721
|
+
"recorder",
|
|
7722
|
+
"analytics"
|
|
7723
|
+
]);
|
|
7724
|
+
var StorageMigrationMoveSchema = object({
|
|
7725
|
+
storageClass: StorageMigrationClassSchema,
|
|
7726
|
+
fromLocationId: string(),
|
|
7727
|
+
toLocationId: string(),
|
|
7728
|
+
moverJobId: string().nullable(),
|
|
7729
|
+
state: RelocateJobStateSchema.nullable(),
|
|
7730
|
+
error: string().nullable()
|
|
7731
|
+
});
|
|
7732
|
+
var StorageMigrationJobSchema = object({
|
|
7733
|
+
jobId: string(),
|
|
7734
|
+
phase: StorageMigrationPhaseSchema,
|
|
7735
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7736
|
+
throttleMbps: number(),
|
|
7737
|
+
moves: array(StorageMigrationMoveSchema),
|
|
7738
|
+
pauseLeaseId: string().nullable(),
|
|
7739
|
+
pausedParticipants: array(StorageMigrationParticipantSchema),
|
|
7740
|
+
repointed: boolean(),
|
|
7741
|
+
cancelRequested: boolean(),
|
|
7742
|
+
startedAt: number(),
|
|
7743
|
+
updatedAt: number(),
|
|
7744
|
+
finishedAt: number().nullable(),
|
|
7745
|
+
error: string().nullable()
|
|
7746
|
+
});
|
|
7747
|
+
var StorageMigrationPlanSchema = object({
|
|
7748
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7749
|
+
moves: array(object({
|
|
7750
|
+
storageClass: StorageMigrationClassSchema,
|
|
7751
|
+
fromLocationId: string(),
|
|
7752
|
+
toLocationId: string()
|
|
7753
|
+
}))
|
|
7674
7754
|
});
|
|
7675
7755
|
/**
|
|
7676
7756
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -18440,20 +18520,28 @@ var pipelineAnalyticsCapability = {
|
|
|
18440
18520
|
}),
|
|
18441
18521
|
/** The events ops-log rows (newest-first), optionally scoped to one camera.
|
|
18442
18522
|
* Backed by a declared pipeline-analytics SQLite collection. */
|
|
18443
|
-
/**
|
|
18444
|
-
*
|
|
18445
|
-
|
|
18446
|
-
* at the target are skipped, so a re-run resumes. Single-flight.
|
|
18447
|
-
*/
|
|
18448
|
-
relocateMedia: method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
18523
|
+
/** Internal migration-participant lease. It drains active MediaStore
|
|
18524
|
+
* writes and refuses new ones without changing analytics bindings. */
|
|
18525
|
+
pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
18449
18526
|
kind: "mutation",
|
|
18450
18527
|
auth: "admin"
|
|
18451
18528
|
}),
|
|
18452
|
-
|
|
18453
|
-
kind: "
|
|
18529
|
+
resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
18530
|
+
kind: "mutation",
|
|
18531
|
+
auth: "admin"
|
|
18532
|
+
}),
|
|
18533
|
+
/** Drops cached location roots after the storage coordinator repoints a
|
|
18534
|
+
* default so future event-media writes use the new root. */
|
|
18535
|
+
refreshStorageLocationsForMigration: method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
|
|
18536
|
+
kind: "mutation",
|
|
18454
18537
|
auth: "admin"
|
|
18455
18538
|
}),
|
|
18456
|
-
|
|
18539
|
+
startStorageMigrationMove: method(StorageMigrationMediaMoveInputSchema, object({ jobId: string() }), {
|
|
18540
|
+
kind: "mutation",
|
|
18541
|
+
auth: "admin"
|
|
18542
|
+
}),
|
|
18543
|
+
getStorageMigrationMoveStatus: method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }),
|
|
18544
|
+
cancelStorageMigrationMove: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
18457
18545
|
kind: "mutation",
|
|
18458
18546
|
auth: "admin"
|
|
18459
18547
|
}),
|
|
@@ -20502,6 +20590,16 @@ var pipelineOrchestratorCapability = {
|
|
|
20502
20590
|
nodeIdMode: "data",
|
|
20503
20591
|
exposesDeviceSettings: true,
|
|
20504
20592
|
methods: {
|
|
20593
|
+
/** Internal storage-migration participant lease. While held, dispatch
|
|
20594
|
+
* requests are accepted as pending but no new runner attachment starts. */
|
|
20595
|
+
pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
20596
|
+
kind: "mutation",
|
|
20597
|
+
auth: "admin"
|
|
20598
|
+
}),
|
|
20599
|
+
resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
20600
|
+
kind: "mutation",
|
|
20601
|
+
auth: "admin"
|
|
20602
|
+
}),
|
|
20505
20603
|
/**
|
|
20506
20604
|
* Pin a camera's pipeline to a specific agent (L1 affinity).
|
|
20507
20605
|
* The orchestrator re-evaluates the assignment immediately and persists
|
|
@@ -21643,6 +21741,28 @@ var storageEvictableCapability = {
|
|
|
21643
21741
|
}), EvictResultSchema, { kind: "mutation" })
|
|
21644
21742
|
}
|
|
21645
21743
|
};
|
|
21744
|
+
/**
|
|
21745
|
+
* The single operator-facing storage migration surface. It coordinates the
|
|
21746
|
+
* pipeline, recorder and post-analysis participants; callers never mutate a
|
|
21747
|
+
* camera recording config or invoke an individual mover directly.
|
|
21748
|
+
*/
|
|
21749
|
+
var storageMigrationCapability = {
|
|
21750
|
+
name: "storage-migration",
|
|
21751
|
+
scope: "system",
|
|
21752
|
+
mode: "singleton",
|
|
21753
|
+
methods: {
|
|
21754
|
+
plan: method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }),
|
|
21755
|
+
start: method(StorageMigrationInputSchema, object({ jobId: string() }), {
|
|
21756
|
+
kind: "mutation",
|
|
21757
|
+
auth: "admin"
|
|
21758
|
+
}),
|
|
21759
|
+
status: method(object({ jobId: string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }),
|
|
21760
|
+
cancel: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
21761
|
+
kind: "mutation",
|
|
21762
|
+
auth: "admin"
|
|
21763
|
+
})
|
|
21764
|
+
}
|
|
21765
|
+
};
|
|
21646
21766
|
var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
21647
21767
|
providerId: string().min(1),
|
|
21648
21768
|
displayName: string().min(1),
|
|
@@ -21791,6 +21911,28 @@ var TerminalProfileInfoSchema = object({
|
|
|
21791
21911
|
label: string(),
|
|
21792
21912
|
description: string().optional()
|
|
21793
21913
|
});
|
|
21914
|
+
/**
|
|
21915
|
+
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
21916
|
+
* an instance declares a camera.
|
|
21917
|
+
*/
|
|
21918
|
+
var TerminalInstanceInfoSchema = object({
|
|
21919
|
+
instanceId: string(),
|
|
21920
|
+
cameraStableId: string(),
|
|
21921
|
+
nodeId: string(),
|
|
21922
|
+
profileId: string(),
|
|
21923
|
+
profileLabel: string(),
|
|
21924
|
+
name: string(),
|
|
21925
|
+
enabled: boolean()
|
|
21926
|
+
});
|
|
21927
|
+
var TerminalLegacyCameraSchema = object({
|
|
21928
|
+
stableId: string(),
|
|
21929
|
+
nodeId: string(),
|
|
21930
|
+
profileId: string(),
|
|
21931
|
+
profileLabel: string(),
|
|
21932
|
+
name: string(),
|
|
21933
|
+
/** Only legacy monitor cameras can retain their historic stable identity. */
|
|
21934
|
+
adoptable: boolean()
|
|
21935
|
+
});
|
|
21794
21936
|
var TerminalOutputEventSchema = discriminatedUnion("kind", [object({
|
|
21795
21937
|
seq: number().int().positive(),
|
|
21796
21938
|
kind: literal("data"),
|
|
@@ -21810,10 +21952,9 @@ var TerminalOutputBatchSchema = object({
|
|
|
21810
21952
|
/**
|
|
21811
21953
|
* terminal-session — singleton system capability for interactive TTY sessions.
|
|
21812
21954
|
*
|
|
21813
|
-
*
|
|
21814
|
-
*
|
|
21815
|
-
*
|
|
21816
|
-
* change this contract.
|
|
21955
|
+
* Owns both live PTY lifecycle and durable Terminal instance management.
|
|
21956
|
+
* Profiles are allowlisted templates; an explicit instance is the only path
|
|
21957
|
+
* that declares a camera.
|
|
21817
21958
|
*/
|
|
21818
21959
|
var terminalSessionCapability = {
|
|
21819
21960
|
name: "terminal-session",
|
|
@@ -21822,6 +21963,37 @@ var terminalSessionCapability = {
|
|
|
21822
21963
|
methods: {
|
|
21823
21964
|
/** Pre-declared profiles the operator may open. */
|
|
21824
21965
|
listProfiles: method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
21966
|
+
/** Explicit durable Terminal instances, managed centrally on the hub. */
|
|
21967
|
+
listInstances: method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }),
|
|
21968
|
+
createInstance: method(object({
|
|
21969
|
+
targetNodeId: string().min(1),
|
|
21970
|
+
profileId: string().min(1),
|
|
21971
|
+
name: string().trim().min(1).max(160).optional()
|
|
21972
|
+
}), TerminalInstanceInfoSchema, {
|
|
21973
|
+
kind: "mutation",
|
|
21974
|
+
auth: "admin"
|
|
21975
|
+
}),
|
|
21976
|
+
deleteInstance: method(object({ instanceId: string().min(1) }), _void(), {
|
|
21977
|
+
kind: "mutation",
|
|
21978
|
+
auth: "admin"
|
|
21979
|
+
}),
|
|
21980
|
+
setInstanceEnabled: method(object({
|
|
21981
|
+
instanceId: string().min(1),
|
|
21982
|
+
enabled: boolean()
|
|
21983
|
+
}), TerminalInstanceInfoSchema, {
|
|
21984
|
+
kind: "mutation",
|
|
21985
|
+
auth: "admin"
|
|
21986
|
+
}),
|
|
21987
|
+
/** Existing automatic cameras are shown for explicit migration only. */
|
|
21988
|
+
listLegacyCameras: method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }),
|
|
21989
|
+
/** Explicitly adopt one legacy monitor camera, retaining its stable id. */
|
|
21990
|
+
adoptLegacyMonitor: method(object({
|
|
21991
|
+
stableId: string().min(1),
|
|
21992
|
+
name: string().trim().min(1).max(160).optional()
|
|
21993
|
+
}), TerminalInstanceInfoSchema, {
|
|
21994
|
+
kind: "mutation",
|
|
21995
|
+
auth: "admin"
|
|
21996
|
+
}),
|
|
21825
21997
|
/** Live sessions currently hosted by the provider. */
|
|
21826
21998
|
listSessions: method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }),
|
|
21827
21999
|
/**
|
|
@@ -21853,7 +22025,13 @@ var terminalSessionCapability = {
|
|
|
21853
22025
|
pullOutput: method(object({
|
|
21854
22026
|
sessionId: string(),
|
|
21855
22027
|
afterSeq: number().int().nonnegative(),
|
|
21856
|
-
waitMs: number().int().min(0).max(2e3).default(0)
|
|
22028
|
+
waitMs: number().int().min(0).max(2e3).default(0),
|
|
22029
|
+
/**
|
|
22030
|
+
* Wait when a just-opened session has no output yet. Kept opt-in so a
|
|
22031
|
+
* browser's initial repaint remains immediate; the camera snapshot
|
|
22032
|
+
* relay uses it to avoid encoding a blank startup frame.
|
|
22033
|
+
*/
|
|
22034
|
+
waitForOutput: boolean().optional()
|
|
21857
22035
|
}), TerminalOutputBatchSchema, {
|
|
21858
22036
|
kind: "mutation",
|
|
21859
22037
|
auth: "admin",
|
|
@@ -24802,6 +24980,7 @@ var FaceInfoSchema = object({
|
|
|
24802
24980
|
var FaceFilterEnum = _enum([
|
|
24803
24981
|
"unassigned",
|
|
24804
24982
|
"recognized",
|
|
24983
|
+
"identified",
|
|
24805
24984
|
"all"
|
|
24806
24985
|
]);
|
|
24807
24986
|
var MediaFileLiteSchema$1 = object({
|
|
@@ -24841,6 +25020,8 @@ var faceGalleryCapability = {
|
|
|
24841
25020
|
auth: "admin"
|
|
24842
25021
|
}),
|
|
24843
25022
|
listRecentFaces: method(object({
|
|
25023
|
+
/** Restrict to one camera. Absent keeps the cluster-wide gallery view. */
|
|
25024
|
+
deviceId: number().int().optional(),
|
|
24844
25025
|
limit: number().int().positive().optional(),
|
|
24845
25026
|
filter: FaceFilterEnum.optional(),
|
|
24846
25027
|
/**
|
|
@@ -27384,6 +27565,10 @@ var OsdSourceSchema = discriminatedUnion("kind", [
|
|
|
27384
27565
|
capName: string().min(1).max(64),
|
|
27385
27566
|
/** Dot path inside the slice, e.g. `detected`, `value`, `mode`. */
|
|
27386
27567
|
valuePath: string().min(1).max(64)
|
|
27568
|
+
}),
|
|
27569
|
+
object({
|
|
27570
|
+
kind: literal("latest-recognition"),
|
|
27571
|
+
recognition: _enum(["person", "plate"])
|
|
27387
27572
|
})
|
|
27388
27573
|
]);
|
|
27389
27574
|
var OsdSlotBindingSchema = object({
|
|
@@ -27522,6 +27707,21 @@ var osdManagerCapability = {
|
|
|
27522
27707
|
auth: "admin"
|
|
27523
27708
|
}),
|
|
27524
27709
|
/**
|
|
27710
|
+
* Replace one camera's binding configuration from another. Writable source
|
|
27711
|
+
* slots are mapped by ordinal onto writable target slots so different
|
|
27712
|
+
* provider slot ids do not make the copied configuration disappear.
|
|
27713
|
+
*/
|
|
27714
|
+
copyDeviceConfiguration: method(object({
|
|
27715
|
+
sourceDeviceId: number().int(),
|
|
27716
|
+
targetDeviceId: number().int()
|
|
27717
|
+
}), object({
|
|
27718
|
+
copied: number().int().nonnegative(),
|
|
27719
|
+
skipped: number().int().nonnegative()
|
|
27720
|
+
}), {
|
|
27721
|
+
kind: "mutation",
|
|
27722
|
+
auth: "admin"
|
|
27723
|
+
}),
|
|
27724
|
+
/**
|
|
27525
27725
|
* Render without writing. `binding` overrides the stored one so an
|
|
27526
27726
|
* editor can preview an unsaved change. Mutation kind only to carry
|
|
27527
27727
|
* the binding object safely; no side effects.
|
|
@@ -28759,12 +28959,6 @@ var recordingCapability = {
|
|
|
28759
28959
|
auth: "admin"
|
|
28760
28960
|
}),
|
|
28761
28961
|
/**
|
|
28762
|
-
* Move footage (recorded segments) from one recordings location to
|
|
28763
|
-
* another — the drain workflow's mover (entity-routing spec Phase 4).
|
|
28764
|
-
* Throttled copy → size-verify → delete source → index refresh; resumable
|
|
28765
|
-
* by construction (copy-if-absent). Single-flight: one job at a time.
|
|
28766
|
-
*/
|
|
28767
|
-
/**
|
|
28768
28962
|
* Render a short GIF from recorded footage around `aroundMs` (low profile,
|
|
28769
28963
|
* palette-free ffmpeg gif). Synchronous — the window is a few seconds of
|
|
28770
28964
|
* `low`, rendering in ~1-2s. Built for notification attachments: the
|
|
@@ -28816,16 +29010,28 @@ var recordingCapability = {
|
|
|
28816
29010
|
kind: "mutation",
|
|
28817
29011
|
auth: "admin"
|
|
28818
29012
|
}),
|
|
28819
|
-
|
|
29013
|
+
/** Internal migration-participant lease. Blocks new recorder attaches and
|
|
29014
|
+
* waits for writers to exit while their watchers index final segments. */
|
|
29015
|
+
pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
28820
29016
|
kind: "mutation",
|
|
28821
29017
|
auth: "admin"
|
|
28822
29018
|
}),
|
|
28823
|
-
|
|
28824
|
-
|
|
28825
|
-
|
|
29019
|
+
resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
29020
|
+
kind: "mutation",
|
|
29021
|
+
auth: "admin"
|
|
29022
|
+
}),
|
|
29023
|
+
/** Re-resolve location roots after the coordinator changes defaults. */
|
|
29024
|
+
refreshStorageLocationsForMigration: method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
|
|
29025
|
+
kind: "mutation",
|
|
28826
29026
|
auth: "admin"
|
|
28827
29027
|
}),
|
|
28828
|
-
|
|
29028
|
+
/** Internal mover, callable only by the storage-migration coordinator. */
|
|
29029
|
+
startStorageMigrationMove: method(StorageMigrationFootageMoveInputSchema, object({ jobId: string() }), {
|
|
29030
|
+
kind: "mutation",
|
|
29031
|
+
auth: "admin"
|
|
29032
|
+
}),
|
|
29033
|
+
getStorageMigrationMoveStatus: method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }),
|
|
29034
|
+
cancelStorageMigrationMove: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
28829
29035
|
kind: "mutation",
|
|
28830
29036
|
auth: "admin"
|
|
28831
29037
|
})
|
|
@@ -30780,6 +30986,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
30780
30986
|
ssoBridgeCapability,
|
|
30781
30987
|
storageCapability,
|
|
30782
30988
|
storageEvictableCapability,
|
|
30989
|
+
storageMigrationCapability,
|
|
30783
30990
|
storageProviderCapability,
|
|
30784
30991
|
streamBrokerCapability,
|
|
30785
30992
|
streamCatalogCapability,
|
|
@@ -33706,6 +33913,12 @@ Object.freeze({
|
|
|
33706
33913
|
addonId: null,
|
|
33707
33914
|
access: "delete"
|
|
33708
33915
|
},
|
|
33916
|
+
"osdManager.copyDeviceConfiguration": {
|
|
33917
|
+
capName: "osd-manager",
|
|
33918
|
+
capScope: "system",
|
|
33919
|
+
addonId: null,
|
|
33920
|
+
access: "create"
|
|
33921
|
+
},
|
|
33709
33922
|
"osdManager.getConditionSupport": {
|
|
33710
33923
|
capName: "osd-manager",
|
|
33711
33924
|
capScope: "system",
|
|
@@ -33802,7 +34015,7 @@ Object.freeze({
|
|
|
33802
34015
|
addonId: null,
|
|
33803
34016
|
access: "create"
|
|
33804
34017
|
},
|
|
33805
|
-
"pipelineAnalytics.
|
|
34018
|
+
"pipelineAnalytics.cancelStorageMigrationMove": {
|
|
33806
34019
|
capName: "pipeline-analytics",
|
|
33807
34020
|
capScope: "device",
|
|
33808
34021
|
addonId: null,
|
|
@@ -33874,12 +34087,6 @@ Object.freeze({
|
|
|
33874
34087
|
addonId: null,
|
|
33875
34088
|
access: "view"
|
|
33876
34089
|
},
|
|
33877
|
-
"pipelineAnalytics.getMediaRelocateStatus": {
|
|
33878
|
-
capName: "pipeline-analytics",
|
|
33879
|
-
capScope: "device",
|
|
33880
|
-
addonId: null,
|
|
33881
|
-
access: "view"
|
|
33882
|
-
},
|
|
33883
34090
|
"pipelineAnalytics.getMotionEvents": {
|
|
33884
34091
|
capName: "pipeline-analytics",
|
|
33885
34092
|
capScope: "device",
|
|
@@ -33916,6 +34123,12 @@ Object.freeze({
|
|
|
33916
34123
|
addonId: null,
|
|
33917
34124
|
access: "view"
|
|
33918
34125
|
},
|
|
34126
|
+
"pipelineAnalytics.getStorageMigrationMoveStatus": {
|
|
34127
|
+
capName: "pipeline-analytics",
|
|
34128
|
+
capScope: "device",
|
|
34129
|
+
addonId: null,
|
|
34130
|
+
access: "view"
|
|
34131
|
+
},
|
|
33919
34132
|
"pipelineAnalytics.getTrack": {
|
|
33920
34133
|
capName: "pipeline-analytics",
|
|
33921
34134
|
capScope: "device",
|
|
@@ -33994,6 +34207,12 @@ Object.freeze({
|
|
|
33994
34207
|
addonId: null,
|
|
33995
34208
|
access: "view"
|
|
33996
34209
|
},
|
|
34210
|
+
"pipelineAnalytics.pauseForStorageMigration": {
|
|
34211
|
+
capName: "pipeline-analytics",
|
|
34212
|
+
capScope: "device",
|
|
34213
|
+
addonId: null,
|
|
34214
|
+
access: "create"
|
|
34215
|
+
},
|
|
33997
34216
|
"pipelineAnalytics.proposeRetrainAnnotations": {
|
|
33998
34217
|
capName: "pipeline-analytics",
|
|
33999
34218
|
capScope: "device",
|
|
@@ -34024,7 +34243,7 @@ Object.freeze({
|
|
|
34024
34243
|
addonId: null,
|
|
34025
34244
|
access: "create"
|
|
34026
34245
|
},
|
|
34027
|
-
"pipelineAnalytics.
|
|
34246
|
+
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
34028
34247
|
capName: "pipeline-analytics",
|
|
34029
34248
|
capScope: "device",
|
|
34030
34249
|
addonId: null,
|
|
@@ -34036,6 +34255,12 @@ Object.freeze({
|
|
|
34036
34255
|
addonId: null,
|
|
34037
34256
|
access: "create"
|
|
34038
34257
|
},
|
|
34258
|
+
"pipelineAnalytics.resumeForStorageMigration": {
|
|
34259
|
+
capName: "pipeline-analytics",
|
|
34260
|
+
capScope: "device",
|
|
34261
|
+
addonId: null,
|
|
34262
|
+
access: "create"
|
|
34263
|
+
},
|
|
34039
34264
|
"pipelineAnalytics.saveRetrainAnnotations": {
|
|
34040
34265
|
capName: "pipeline-analytics",
|
|
34041
34266
|
capScope: "device",
|
|
@@ -34060,6 +34285,12 @@ Object.freeze({
|
|
|
34060
34285
|
addonId: null,
|
|
34061
34286
|
access: "create"
|
|
34062
34287
|
},
|
|
34288
|
+
"pipelineAnalytics.startStorageMigrationMove": {
|
|
34289
|
+
capName: "pipeline-analytics",
|
|
34290
|
+
capScope: "device",
|
|
34291
|
+
addonId: null,
|
|
34292
|
+
access: "create"
|
|
34293
|
+
},
|
|
34063
34294
|
"pipelineAnalytics.wipeAllAnalytics": {
|
|
34064
34295
|
capName: "pipeline-analytics",
|
|
34065
34296
|
capScope: "device",
|
|
@@ -34426,6 +34657,12 @@ Object.freeze({
|
|
|
34426
34657
|
addonId: null,
|
|
34427
34658
|
access: "view"
|
|
34428
34659
|
},
|
|
34660
|
+
"pipelineOrchestrator.pauseForStorageMigration": {
|
|
34661
|
+
capName: "pipeline-orchestrator",
|
|
34662
|
+
capScope: "system",
|
|
34663
|
+
addonId: null,
|
|
34664
|
+
access: "create"
|
|
34665
|
+
},
|
|
34429
34666
|
"pipelineOrchestrator.rebalance": {
|
|
34430
34667
|
capName: "pipeline-orchestrator",
|
|
34431
34668
|
capScope: "system",
|
|
@@ -34450,6 +34687,12 @@ Object.freeze({
|
|
|
34450
34687
|
addonId: null,
|
|
34451
34688
|
access: "view"
|
|
34452
34689
|
},
|
|
34690
|
+
"pipelineOrchestrator.resumeForStorageMigration": {
|
|
34691
|
+
capName: "pipeline-orchestrator",
|
|
34692
|
+
capScope: "system",
|
|
34693
|
+
addonId: null,
|
|
34694
|
+
access: "create"
|
|
34695
|
+
},
|
|
34453
34696
|
"pipelineOrchestrator.saveTemplate": {
|
|
34454
34697
|
capName: "pipeline-orchestrator",
|
|
34455
34698
|
capScope: "system",
|
|
@@ -34846,7 +35089,7 @@ Object.freeze({
|
|
|
34846
35089
|
addonId: null,
|
|
34847
35090
|
access: "create"
|
|
34848
35091
|
},
|
|
34849
|
-
"recording.
|
|
35092
|
+
"recording.cancelStorageMigrationMove": {
|
|
34850
35093
|
capName: "recording",
|
|
34851
35094
|
capScope: "system",
|
|
34852
35095
|
addonId: null,
|
|
@@ -34882,7 +35125,7 @@ Object.freeze({
|
|
|
34882
35125
|
addonId: null,
|
|
34883
35126
|
access: "view"
|
|
34884
35127
|
},
|
|
34885
|
-
"recording.
|
|
35128
|
+
"recording.getStorageMigrationMoveStatus": {
|
|
34886
35129
|
capName: "recording",
|
|
34887
35130
|
capScope: "system",
|
|
34888
35131
|
addonId: null,
|
|
@@ -34906,6 +35149,12 @@ Object.freeze({
|
|
|
34906
35149
|
addonId: null,
|
|
34907
35150
|
access: "view"
|
|
34908
35151
|
},
|
|
35152
|
+
"recording.pauseForStorageMigration": {
|
|
35153
|
+
capName: "recording",
|
|
35154
|
+
capScope: "system",
|
|
35155
|
+
addonId: null,
|
|
35156
|
+
access: "create"
|
|
35157
|
+
},
|
|
34909
35158
|
"recording.pruneFootage": {
|
|
34910
35159
|
capName: "recording",
|
|
34911
35160
|
capScope: "system",
|
|
@@ -34924,7 +35173,7 @@ Object.freeze({
|
|
|
34924
35173
|
addonId: null,
|
|
34925
35174
|
access: "view"
|
|
34926
35175
|
},
|
|
34927
|
-
"recording.
|
|
35176
|
+
"recording.refreshStorageLocationsForMigration": {
|
|
34928
35177
|
capName: "recording",
|
|
34929
35178
|
capScope: "system",
|
|
34930
35179
|
addonId: null,
|
|
@@ -34948,12 +35197,24 @@ Object.freeze({
|
|
|
34948
35197
|
addonId: null,
|
|
34949
35198
|
access: "create"
|
|
34950
35199
|
},
|
|
35200
|
+
"recording.resumeForStorageMigration": {
|
|
35201
|
+
capName: "recording",
|
|
35202
|
+
capScope: "system",
|
|
35203
|
+
addonId: null,
|
|
35204
|
+
access: "create"
|
|
35205
|
+
},
|
|
34951
35206
|
"recording.setDeviceConfig": {
|
|
34952
35207
|
capName: "recording",
|
|
34953
35208
|
capScope: "system",
|
|
34954
35209
|
addonId: null,
|
|
34955
35210
|
access: "create"
|
|
34956
35211
|
},
|
|
35212
|
+
"recording.startStorageMigrationMove": {
|
|
35213
|
+
capName: "recording",
|
|
35214
|
+
capScope: "system",
|
|
35215
|
+
addonId: null,
|
|
35216
|
+
access: "create"
|
|
35217
|
+
},
|
|
34957
35218
|
"recordingExport.cancelExport": {
|
|
34958
35219
|
capName: "recordingExport",
|
|
34959
35220
|
capScope: "system",
|
|
@@ -35344,6 +35605,30 @@ Object.freeze({
|
|
|
35344
35605
|
addonId: null,
|
|
35345
35606
|
access: "view"
|
|
35346
35607
|
},
|
|
35608
|
+
"storageMigration.cancel": {
|
|
35609
|
+
capName: "storage-migration",
|
|
35610
|
+
capScope: "system",
|
|
35611
|
+
addonId: null,
|
|
35612
|
+
access: "create"
|
|
35613
|
+
},
|
|
35614
|
+
"storageMigration.plan": {
|
|
35615
|
+
capName: "storage-migration",
|
|
35616
|
+
capScope: "system",
|
|
35617
|
+
addonId: null,
|
|
35618
|
+
access: "view"
|
|
35619
|
+
},
|
|
35620
|
+
"storageMigration.start": {
|
|
35621
|
+
capName: "storage-migration",
|
|
35622
|
+
capScope: "system",
|
|
35623
|
+
addonId: null,
|
|
35624
|
+
access: "create"
|
|
35625
|
+
},
|
|
35626
|
+
"storageMigration.status": {
|
|
35627
|
+
capName: "storage-migration",
|
|
35628
|
+
capScope: "system",
|
|
35629
|
+
addonId: null,
|
|
35630
|
+
access: "view"
|
|
35631
|
+
},
|
|
35347
35632
|
"storageProvider.abortUpload": {
|
|
35348
35633
|
capName: "storage-provider",
|
|
35349
35634
|
capScope: "system",
|
|
@@ -35722,12 +36007,42 @@ Object.freeze({
|
|
|
35722
36007
|
addonId: null,
|
|
35723
36008
|
access: "create"
|
|
35724
36009
|
},
|
|
36010
|
+
"terminalSession.adoptLegacyMonitor": {
|
|
36011
|
+
capName: "terminal-session",
|
|
36012
|
+
capScope: "system",
|
|
36013
|
+
addonId: null,
|
|
36014
|
+
access: "create"
|
|
36015
|
+
},
|
|
35725
36016
|
"terminalSession.close": {
|
|
35726
36017
|
capName: "terminal-session",
|
|
35727
36018
|
capScope: "system",
|
|
35728
36019
|
addonId: null,
|
|
35729
36020
|
access: "create"
|
|
35730
36021
|
},
|
|
36022
|
+
"terminalSession.createInstance": {
|
|
36023
|
+
capName: "terminal-session",
|
|
36024
|
+
capScope: "system",
|
|
36025
|
+
addonId: null,
|
|
36026
|
+
access: "create"
|
|
36027
|
+
},
|
|
36028
|
+
"terminalSession.deleteInstance": {
|
|
36029
|
+
capName: "terminal-session",
|
|
36030
|
+
capScope: "system",
|
|
36031
|
+
addonId: null,
|
|
36032
|
+
access: "delete"
|
|
36033
|
+
},
|
|
36034
|
+
"terminalSession.listInstances": {
|
|
36035
|
+
capName: "terminal-session",
|
|
36036
|
+
capScope: "system",
|
|
36037
|
+
addonId: null,
|
|
36038
|
+
access: "view"
|
|
36039
|
+
},
|
|
36040
|
+
"terminalSession.listLegacyCameras": {
|
|
36041
|
+
capName: "terminal-session",
|
|
36042
|
+
capScope: "system",
|
|
36043
|
+
addonId: null,
|
|
36044
|
+
access: "view"
|
|
36045
|
+
},
|
|
35731
36046
|
"terminalSession.listProfiles": {
|
|
35732
36047
|
capName: "terminal-session",
|
|
35733
36048
|
capScope: "system",
|
|
@@ -35758,6 +36073,12 @@ Object.freeze({
|
|
|
35758
36073
|
addonId: null,
|
|
35759
36074
|
access: "create"
|
|
35760
36075
|
},
|
|
36076
|
+
"terminalSession.setInstanceEnabled": {
|
|
36077
|
+
capName: "terminal-session",
|
|
36078
|
+
capScope: "system",
|
|
36079
|
+
addonId: null,
|
|
36080
|
+
access: "create"
|
|
36081
|
+
},
|
|
35761
36082
|
"terminalSession.writeInput": {
|
|
35762
36083
|
capName: "terminal-session",
|
|
35763
36084
|
capScope: "system",
|
|
@@ -36589,7 +36910,8 @@ var OsdBindingsStore = class {
|
|
|
36589
36910
|
* Widening it means giving `evaluateGate` the facts to answer it — a
|
|
36590
36911
|
* live detection subject would unlock `classes`, `zones`, `minConfidence`.
|
|
36591
36912
|
*/
|
|
36592
|
-
var OSD_SUPPORTED_CONDITIONS = ["
|
|
36913
|
+
var OSD_SUPPORTED_CONDITIONS = ["deviceState"];
|
|
36914
|
+
var OSD_RUNTIME_CONDITIONS = ["devices", ...OSD_SUPPORTED_CONDITIONS];
|
|
36593
36915
|
var OPEN = { open: true };
|
|
36594
36916
|
/**
|
|
36595
36917
|
* Which condition keys are set on `conditions` but outside the supported
|
|
@@ -36597,7 +36919,7 @@ var OPEN = { open: true };
|
|
|
36597
36919
|
*/
|
|
36598
36920
|
function unsupportedConditionKeys(conditions) {
|
|
36599
36921
|
if (conditions === void 0) return [];
|
|
36600
|
-
const supported = new Set(
|
|
36922
|
+
const supported = new Set(OSD_RUNTIME_CONDITIONS);
|
|
36601
36923
|
const present = [];
|
|
36602
36924
|
for (const [key, value] of Object.entries(conditions)) {
|
|
36603
36925
|
if (value === void 0) continue;
|
|
@@ -36840,6 +37162,10 @@ function resolveSource(binding, cameraDeviceId, facts) {
|
|
|
36840
37162
|
const source = binding.source;
|
|
36841
37163
|
if (source.kind === "static") return { value: { raw: source.text } };
|
|
36842
37164
|
if (source.kind === "clock") return { value: { raw: formatClock(facts.atMs, source.pattern, source.timezone) } };
|
|
37165
|
+
if (source.kind === "latest-recognition") {
|
|
37166
|
+
const value = facts.recognitionByDevice.get(cameraDeviceId)?.[source.recognition];
|
|
37167
|
+
return value === void 0 ? { reason: `no recognized ${source.recognition} has been persisted for device ${cameraDeviceId}` } : { value: { raw: value } };
|
|
37168
|
+
}
|
|
36843
37169
|
const deviceId = source.deviceId ?? cameraDeviceId;
|
|
36844
37170
|
const deviceState = facts.stateByDevice.get(deviceId);
|
|
36845
37171
|
if (deviceState === void 0) return { reason: `no state mirrored for device ${deviceId}` };
|
|
@@ -36963,6 +37289,10 @@ var OsdManager = class {
|
|
|
36963
37289
|
lastWritten = /* @__PURE__ */ new Map();
|
|
36964
37290
|
/** Cameras with at least one binding — the loop's work list. */
|
|
36965
37291
|
boundDevices = /* @__PURE__ */ new Set();
|
|
37292
|
+
recognitions = /* @__PURE__ */ new Map();
|
|
37293
|
+
recognitionHydration = /* @__PURE__ */ new Map();
|
|
37294
|
+
recognitionGeneration = /* @__PURE__ */ new Map();
|
|
37295
|
+
recognitionInvalidatedAt = /* @__PURE__ */ new Map();
|
|
36966
37296
|
timer = null;
|
|
36967
37297
|
constructor(deps) {
|
|
36968
37298
|
this.deps = deps;
|
|
@@ -36990,6 +37320,36 @@ var OsdManager = class {
|
|
|
36990
37320
|
this.lastWritten.clear();
|
|
36991
37321
|
}
|
|
36992
37322
|
/**
|
|
37323
|
+
* Keep recognition overlays event-fresh. The persisted-track hydration below
|
|
37324
|
+
* remains the restart/cold-start authority; lifecycle events only advance it.
|
|
37325
|
+
*/
|
|
37326
|
+
onTrackLifecycle(payload) {
|
|
37327
|
+
let changed = false;
|
|
37328
|
+
if (payload.label !== void 0 && (payload.bestClassName === "person" || payload.classes.includes("person"))) changed = this.mergeRecognition(payload.deviceId, "person", payload.label, payload.lastSeen, payload.firstSeen) || changed;
|
|
37329
|
+
if (payload.plateText !== void 0) changed = this.mergeRecognition(payload.deviceId, "plate", payload.plateText, payload.lastSeen, payload.firstSeen) || changed;
|
|
37330
|
+
if (!changed || !this.boundDevices.has(payload.deviceId)) return;
|
|
37331
|
+
this.renderDeviceInternal(payload.deviceId, null).catch((err) => {
|
|
37332
|
+
this.logger.warn("osd-manager: recognition-triggered render failed", {
|
|
37333
|
+
tags: { deviceId: payload.deviceId },
|
|
37334
|
+
meta: { error: String(err) }
|
|
37335
|
+
});
|
|
37336
|
+
});
|
|
37337
|
+
}
|
|
37338
|
+
/** Gallery rows are authoritative for corrections, assignments and deletion. */
|
|
37339
|
+
onRecognitionGalleryChanged(deviceId) {
|
|
37340
|
+
this.recognitionGeneration.set(deviceId, (this.recognitionGeneration.get(deviceId) ?? 0) + 1);
|
|
37341
|
+
this.recognitionInvalidatedAt.set(deviceId, this.now());
|
|
37342
|
+
this.recognitions.delete(deviceId);
|
|
37343
|
+
this.recognitionHydration.delete(deviceId);
|
|
37344
|
+
if (!this.boundDevices.has(deviceId)) return;
|
|
37345
|
+
this.renderDeviceInternal(deviceId, null).catch((err) => {
|
|
37346
|
+
this.logger.warn("osd-manager: gallery-triggered render failed", {
|
|
37347
|
+
tags: { deviceId },
|
|
37348
|
+
meta: { error: String(err) }
|
|
37349
|
+
});
|
|
37350
|
+
});
|
|
37351
|
+
}
|
|
37352
|
+
/**
|
|
36993
37353
|
* Reconcile the work list against the store rather than trusting an event
|
|
36994
37354
|
* to have arrived (D8). Cheap: one settings read per camera, on the tick
|
|
36995
37355
|
* cadence, not per frame.
|
|
@@ -37083,6 +37443,54 @@ var OsdManager = class {
|
|
|
37083
37443
|
});
|
|
37084
37444
|
return { success: true };
|
|
37085
37445
|
};
|
|
37446
|
+
copyDeviceConfiguration = async ({ sourceDeviceId, targetDeviceId }) => {
|
|
37447
|
+
if (sourceDeviceId === targetDeviceId) throw new Error("osd-manager: source and target camera must be different");
|
|
37448
|
+
const [sourceStatus, targetStatus, sourceBindings] = await Promise.all([
|
|
37449
|
+
this.deps.readOsdStatus(sourceDeviceId),
|
|
37450
|
+
this.deps.readOsdStatus(targetDeviceId),
|
|
37451
|
+
this.readBindings(sourceDeviceId)
|
|
37452
|
+
]);
|
|
37453
|
+
if (sourceStatus === null) throw new Error(`osd-manager: source device ${sourceDeviceId} exposes no overlay slots`);
|
|
37454
|
+
if (targetStatus === null) throw new Error(`osd-manager: target device ${targetDeviceId} exposes no overlay slots`);
|
|
37455
|
+
const sourceSlots = sourceStatus.overlays.filter((slot) => slot.readOnly !== true && sourceBindings[slot.id] !== void 0);
|
|
37456
|
+
if (sourceSlots.length === 0) throw new Error(`osd-manager: source device ${sourceDeviceId} has no configured writable slots`);
|
|
37457
|
+
const targetSlots = targetStatus.overlays.filter((slot) => slot.readOnly !== true);
|
|
37458
|
+
const copiedBindings = {};
|
|
37459
|
+
const copyCount = Math.min(sourceSlots.length, targetSlots.length);
|
|
37460
|
+
for (let index = 0; index < copyCount; index += 1) {
|
|
37461
|
+
const sourceSlot = sourceSlots[index];
|
|
37462
|
+
const targetSlot = targetSlots[index];
|
|
37463
|
+
if (sourceSlot === void 0 || targetSlot === void 0) continue;
|
|
37464
|
+
const binding = sourceBindings[sourceSlot.id];
|
|
37465
|
+
if (binding === void 0) continue;
|
|
37466
|
+
const conditions = binding.conditions;
|
|
37467
|
+
const normalizedConditions = conditions === void 0 ? void 0 : (() => {
|
|
37468
|
+
const { devices: _cameraScope, ...rest } = conditions;
|
|
37469
|
+
return Object.keys(rest).length === 0 ? void 0 : rest;
|
|
37470
|
+
})();
|
|
37471
|
+
copiedBindings[targetSlot.id] = {
|
|
37472
|
+
...binding,
|
|
37473
|
+
conditions: normalizedConditions
|
|
37474
|
+
};
|
|
37475
|
+
}
|
|
37476
|
+
await this.deps.bindings(targetDeviceId).set(copiedBindings);
|
|
37477
|
+
for (const key of [...this.lastWritten.keys()]) if (key.startsWith(`${targetDeviceId}:`)) this.lastWritten.delete(key);
|
|
37478
|
+
if (Object.keys(copiedBindings).length > 0) this.boundDevices.add(targetDeviceId);
|
|
37479
|
+
else this.boundDevices.delete(targetDeviceId);
|
|
37480
|
+
await this.renderDeviceInternal(targetDeviceId, null);
|
|
37481
|
+
this.logger.info("osd-manager: camera configuration copied", {
|
|
37482
|
+
tags: { deviceId: targetDeviceId },
|
|
37483
|
+
meta: {
|
|
37484
|
+
sourceDeviceId,
|
|
37485
|
+
copied: Object.keys(copiedBindings).length,
|
|
37486
|
+
skipped: Math.max(0, sourceSlots.length - targetSlots.length)
|
|
37487
|
+
}
|
|
37488
|
+
});
|
|
37489
|
+
return {
|
|
37490
|
+
copied: Object.keys(copiedBindings).length,
|
|
37491
|
+
skipped: Math.max(0, sourceSlots.length - targetSlots.length)
|
|
37492
|
+
};
|
|
37493
|
+
};
|
|
37086
37494
|
previewSlot = async ({ deviceId, slotId, binding }) => {
|
|
37087
37495
|
if (binding !== void 0) assertSupportedConditions(binding.conditions);
|
|
37088
37496
|
const effective = binding ?? (await this.readBindings(deviceId))[slotId] ?? null;
|
|
@@ -37157,6 +37565,7 @@ var OsdManager = class {
|
|
|
37157
37565
|
*/
|
|
37158
37566
|
async collectFacts(cameraDeviceId, bindings) {
|
|
37159
37567
|
const wanted = new Set([cameraDeviceId]);
|
|
37568
|
+
const needsRecognition = Object.values(bindings).some((binding) => binding.source.kind === "latest-recognition");
|
|
37160
37569
|
for (const binding of Object.values(bindings)) {
|
|
37161
37570
|
if (binding.source.kind === "device-state" && binding.source.deviceId !== void 0) wanted.add(binding.source.deviceId);
|
|
37162
37571
|
const gated = binding.conditions?.deviceState?.deviceId;
|
|
@@ -37175,12 +37584,59 @@ var OsdManager = class {
|
|
|
37175
37584
|
meta: { error: String(err) }
|
|
37176
37585
|
});
|
|
37177
37586
|
}
|
|
37587
|
+
if (needsRecognition) await this.hydrateRecognitions(cameraDeviceId);
|
|
37588
|
+
const recognitionByDevice = /* @__PURE__ */ new Map();
|
|
37589
|
+
const known = this.recognitions.get(cameraDeviceId);
|
|
37590
|
+
if (known !== void 0) recognitionByDevice.set(cameraDeviceId, {
|
|
37591
|
+
...known.person !== void 0 ? { person: known.person.text } : {},
|
|
37592
|
+
...known.plate !== void 0 ? { plate: known.plate.text } : {}
|
|
37593
|
+
});
|
|
37178
37594
|
return {
|
|
37179
37595
|
atMs: this.now(),
|
|
37180
37596
|
stateByDevice,
|
|
37597
|
+
recognitionByDevice,
|
|
37181
37598
|
deviceState: (id) => gateState.get(id)
|
|
37182
37599
|
};
|
|
37183
37600
|
}
|
|
37601
|
+
async hydrateRecognitions(deviceId) {
|
|
37602
|
+
const existing = this.recognitionHydration.get(deviceId);
|
|
37603
|
+
if (existing !== void 0) return existing;
|
|
37604
|
+
const generation = this.recognitionGeneration.get(deviceId) ?? 0;
|
|
37605
|
+
const hydration = (async () => {
|
|
37606
|
+
try {
|
|
37607
|
+
const latest = await this.deps.readLatestRecognitions(deviceId);
|
|
37608
|
+
if ((this.recognitionGeneration.get(deviceId) ?? 0) !== generation) return;
|
|
37609
|
+
if (latest.person !== void 0) this.mergeRecognition(deviceId, "person", latest.person.text, latest.person.atMs);
|
|
37610
|
+
if (latest.plate !== void 0) this.mergeRecognition(deviceId, "plate", latest.plate.text, latest.plate.atMs);
|
|
37611
|
+
} catch (err) {
|
|
37612
|
+
this.logger.warn("osd-manager: recognition history hydration failed", {
|
|
37613
|
+
tags: { deviceId },
|
|
37614
|
+
meta: { error: String(err) }
|
|
37615
|
+
});
|
|
37616
|
+
this.recognitionHydration.delete(deviceId);
|
|
37617
|
+
}
|
|
37618
|
+
})();
|
|
37619
|
+
this.recognitionHydration.set(deviceId, hydration);
|
|
37620
|
+
await hydration;
|
|
37621
|
+
}
|
|
37622
|
+
mergeRecognition(deviceId, kind, text, atMs, trackFirstSeen) {
|
|
37623
|
+
const normalized = text.trim();
|
|
37624
|
+
if (normalized === "") return false;
|
|
37625
|
+
const invalidatedAt = this.recognitionInvalidatedAt.get(deviceId);
|
|
37626
|
+
if (trackFirstSeen !== void 0 && invalidatedAt !== void 0 && trackFirstSeen <= invalidatedAt) return false;
|
|
37627
|
+
const current = this.recognitions.get(deviceId) ?? {};
|
|
37628
|
+
const previous = current[kind];
|
|
37629
|
+
if (previous !== void 0 && previous.atMs > atMs) return false;
|
|
37630
|
+
if (previous?.atMs === atMs && previous.text === normalized) return false;
|
|
37631
|
+
this.recognitions.set(deviceId, {
|
|
37632
|
+
...current,
|
|
37633
|
+
[kind]: {
|
|
37634
|
+
text: normalized,
|
|
37635
|
+
atMs
|
|
37636
|
+
}
|
|
37637
|
+
});
|
|
37638
|
+
return true;
|
|
37639
|
+
}
|
|
37184
37640
|
async readBindings(deviceId) {
|
|
37185
37641
|
try {
|
|
37186
37642
|
return await this.deps.bindings(deviceId).get();
|
|
@@ -37240,7 +37696,8 @@ var OsdManagerAddon = class extends BaseAddon {
|
|
|
37240
37696
|
icon: "monitor",
|
|
37241
37697
|
path: "/addon/osd-manager",
|
|
37242
37698
|
remoteName: "addon_osd_manager_page",
|
|
37243
|
-
bundle: "remoteEntry.js"
|
|
37699
|
+
bundle: "remoteEntry.js",
|
|
37700
|
+
section: "detection"
|
|
37244
37701
|
}];
|
|
37245
37702
|
constructor() {
|
|
37246
37703
|
super({ ...DEFAULTS });
|
|
@@ -37288,9 +37745,41 @@ var OsdManagerAddon = class extends BaseAddon {
|
|
|
37288
37745
|
const bindings = await ctx.api.deviceManager.getBindings.query({ deviceId });
|
|
37289
37746
|
return [...new Set(bindings.entries.map((e) => e.capName))];
|
|
37290
37747
|
},
|
|
37748
|
+
readLatestRecognitions: async (deviceId) => {
|
|
37749
|
+
const [faces, plates] = await Promise.all([ctx.api.faceGallery.listRecentFaces.query({
|
|
37750
|
+
deviceId,
|
|
37751
|
+
limit: 1,
|
|
37752
|
+
filter: "identified",
|
|
37753
|
+
includeCrops: false
|
|
37754
|
+
}), ctx.api.plateGallery.listPlates.query({
|
|
37755
|
+
deviceId,
|
|
37756
|
+
limit: 1
|
|
37757
|
+
})]);
|
|
37758
|
+
const face = faces[0];
|
|
37759
|
+
const plate = plates[0];
|
|
37760
|
+
return {
|
|
37761
|
+
...face?.identityName !== void 0 ? { person: {
|
|
37762
|
+
text: face.identityName,
|
|
37763
|
+
atMs: face.timestamp
|
|
37764
|
+
} } : {},
|
|
37765
|
+
...plate !== void 0 ? { plate: {
|
|
37766
|
+
text: plate.text,
|
|
37767
|
+
atMs: plate.timestamp
|
|
37768
|
+
} } : {}
|
|
37769
|
+
};
|
|
37770
|
+
},
|
|
37291
37771
|
bindings: (deviceId) => store.forDevice(deviceId)
|
|
37292
37772
|
});
|
|
37293
37773
|
this.manager = manager;
|
|
37774
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsTrackLifecycle }, (event) => {
|
|
37775
|
+
manager.onTrackLifecycle(event.data);
|
|
37776
|
+
});
|
|
37777
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsFaceGalleryChanged }, (event) => {
|
|
37778
|
+
manager.onRecognitionGalleryChanged(event.data.deviceId);
|
|
37779
|
+
});
|
|
37780
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsPlateGalleryChanged }, (event) => {
|
|
37781
|
+
manager.onRecognitionGalleryChanged(event.data.deviceId);
|
|
37782
|
+
});
|
|
37294
37783
|
await manager.start(Math.max(1, this.config.tickSeconds) * 1e3);
|
|
37295
37784
|
const pagesProvider = {
|
|
37296
37785
|
id: this.id,
|