@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.mjs
CHANGED
|
@@ -7622,12 +7622,11 @@ var RecordingConfigSchema = object({
|
|
|
7622
7622
|
/**
|
|
7623
7623
|
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
7624
7624
|
*
|
|
7625
|
-
* One shape shared by the recorder
|
|
7626
|
-
*
|
|
7627
|
-
*
|
|
7628
|
-
*
|
|
7629
|
-
*
|
|
7630
|
-
* row on the owning addon's surface.
|
|
7625
|
+
* One shape shared by the recorder and pipeline-analytics internal movers.
|
|
7626
|
+
* The public admin surface is `storage-migration`; child jobs remain in RAM
|
|
7627
|
+
* because copy-if-absent, verify, delete and index/row repoint are resumable.
|
|
7628
|
+
* Each completed/failed run also lands one durable ops-log row on its owning
|
|
7629
|
+
* addon surface.
|
|
7631
7630
|
*/
|
|
7632
7631
|
var RelocateJobStateSchema = _enum([
|
|
7633
7632
|
"running",
|
|
@@ -7654,19 +7653,100 @@ var RelocateJobSchema = object({
|
|
|
7654
7653
|
finishedAt: number().nullable(),
|
|
7655
7654
|
error: string().nullable()
|
|
7656
7655
|
});
|
|
7656
|
+
/** Profile-derived footage selection used only by the migration coordinator:
|
|
7657
|
+
* `recordings` owns high+mid; `recordingsLow` owns low. */
|
|
7658
|
+
var RelocateFootageClassSchema = _enum(["recordings", "recordingsLow"]);
|
|
7657
7659
|
var RelocateFootageInputSchema = object({
|
|
7658
|
-
deviceId: number().optional(),
|
|
7659
7660
|
fromLocationId: string(),
|
|
7660
7661
|
toLocationId: string(),
|
|
7661
7662
|
entities: array(_enum(["segments"])).optional(),
|
|
7663
|
+
/** Limits relocation to the logical profile class. Omit only for the
|
|
7664
|
+
* pre-orchestration compatibility path. */
|
|
7665
|
+
footageClass: RelocateFootageClassSchema.optional(),
|
|
7662
7666
|
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
7663
7667
|
* never allowed to starve live writers. */
|
|
7664
7668
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7665
7669
|
});
|
|
7666
|
-
|
|
7667
|
-
|
|
7670
|
+
/** Internal, lease-scoped participant operation. It is intentionally separate
|
|
7671
|
+
* from persistent recording settings: a migration never changes
|
|
7672
|
+
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
7673
|
+
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
7674
|
+
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
7675
|
+
var StorageMigrationMediaMoveInputSchema = object({
|
|
7668
7676
|
toLocationId: string(),
|
|
7669
7677
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7678
|
+
}).extend({ leaseId: string().min(1) });
|
|
7679
|
+
/** The independently selectable logical storage classes. `recordings`
|
|
7680
|
+
* encompasses the high and mid segment profiles; `recordingsLow` is low
|
|
7681
|
+
* segments; `eventMedia` is post-analysis blobs. */
|
|
7682
|
+
var StorageMigrationClassSchema = _enum([
|
|
7683
|
+
"recordings",
|
|
7684
|
+
"recordingsLow",
|
|
7685
|
+
"eventMedia"
|
|
7686
|
+
]);
|
|
7687
|
+
/** A destination is always an existing, fully-qualified location id. The
|
|
7688
|
+
* migration API intentionally never changes a source location's `basePath`:
|
|
7689
|
+
* callers create a new `<type>:<slug>` location, then select it here. */
|
|
7690
|
+
var StorageMigrationDestinationsSchema = object({
|
|
7691
|
+
recordings: string().min(1).optional(),
|
|
7692
|
+
recordingsLow: string().min(1).optional(),
|
|
7693
|
+
eventMedia: string().min(1).optional()
|
|
7694
|
+
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
7695
|
+
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
7696
|
+
var StorageMigrationInputSchema = object({
|
|
7697
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7698
|
+
throttleMbps: number().min(1).max(1e3).optional()
|
|
7699
|
+
});
|
|
7700
|
+
/** The durable coordinator state machine. The only phase that changes default
|
|
7701
|
+
* locations is `repointing`, after every selected mover has completed and been
|
|
7702
|
+
* verified. */
|
|
7703
|
+
var StorageMigrationPhaseSchema = _enum([
|
|
7704
|
+
"planning",
|
|
7705
|
+
"pausing",
|
|
7706
|
+
"moving",
|
|
7707
|
+
"verifying",
|
|
7708
|
+
"repointing",
|
|
7709
|
+
"refreshing",
|
|
7710
|
+
"resuming",
|
|
7711
|
+
"done",
|
|
7712
|
+
"failed",
|
|
7713
|
+
"cancelled"
|
|
7714
|
+
]);
|
|
7715
|
+
var StorageMigrationParticipantSchema = _enum([
|
|
7716
|
+
"pipeline",
|
|
7717
|
+
"recorder",
|
|
7718
|
+
"analytics"
|
|
7719
|
+
]);
|
|
7720
|
+
var StorageMigrationMoveSchema = object({
|
|
7721
|
+
storageClass: StorageMigrationClassSchema,
|
|
7722
|
+
fromLocationId: string(),
|
|
7723
|
+
toLocationId: string(),
|
|
7724
|
+
moverJobId: string().nullable(),
|
|
7725
|
+
state: RelocateJobStateSchema.nullable(),
|
|
7726
|
+
error: string().nullable()
|
|
7727
|
+
});
|
|
7728
|
+
var StorageMigrationJobSchema = object({
|
|
7729
|
+
jobId: string(),
|
|
7730
|
+
phase: StorageMigrationPhaseSchema,
|
|
7731
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7732
|
+
throttleMbps: number(),
|
|
7733
|
+
moves: array(StorageMigrationMoveSchema),
|
|
7734
|
+
pauseLeaseId: string().nullable(),
|
|
7735
|
+
pausedParticipants: array(StorageMigrationParticipantSchema),
|
|
7736
|
+
repointed: boolean(),
|
|
7737
|
+
cancelRequested: boolean(),
|
|
7738
|
+
startedAt: number(),
|
|
7739
|
+
updatedAt: number(),
|
|
7740
|
+
finishedAt: number().nullable(),
|
|
7741
|
+
error: string().nullable()
|
|
7742
|
+
});
|
|
7743
|
+
var StorageMigrationPlanSchema = object({
|
|
7744
|
+
destinations: StorageMigrationDestinationsSchema,
|
|
7745
|
+
moves: array(object({
|
|
7746
|
+
storageClass: StorageMigrationClassSchema,
|
|
7747
|
+
fromLocationId: string(),
|
|
7748
|
+
toLocationId: string()
|
|
7749
|
+
}))
|
|
7670
7750
|
});
|
|
7671
7751
|
/**
|
|
7672
7752
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -18436,20 +18516,28 @@ var pipelineAnalyticsCapability = {
|
|
|
18436
18516
|
}),
|
|
18437
18517
|
/** The events ops-log rows (newest-first), optionally scoped to one camera.
|
|
18438
18518
|
* Backed by a declared pipeline-analytics SQLite collection. */
|
|
18439
|
-
/**
|
|
18440
|
-
*
|
|
18441
|
-
|
|
18442
|
-
* at the target are skipped, so a re-run resumes. Single-flight.
|
|
18443
|
-
*/
|
|
18444
|
-
relocateMedia: method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
18519
|
+
/** Internal migration-participant lease. It drains active MediaStore
|
|
18520
|
+
* writes and refuses new ones without changing analytics bindings. */
|
|
18521
|
+
pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
18445
18522
|
kind: "mutation",
|
|
18446
18523
|
auth: "admin"
|
|
18447
18524
|
}),
|
|
18448
|
-
|
|
18449
|
-
kind: "
|
|
18525
|
+
resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
18526
|
+
kind: "mutation",
|
|
18527
|
+
auth: "admin"
|
|
18528
|
+
}),
|
|
18529
|
+
/** Drops cached location roots after the storage coordinator repoints a
|
|
18530
|
+
* default so future event-media writes use the new root. */
|
|
18531
|
+
refreshStorageLocationsForMigration: method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
|
|
18532
|
+
kind: "mutation",
|
|
18450
18533
|
auth: "admin"
|
|
18451
18534
|
}),
|
|
18452
|
-
|
|
18535
|
+
startStorageMigrationMove: method(StorageMigrationMediaMoveInputSchema, object({ jobId: string() }), {
|
|
18536
|
+
kind: "mutation",
|
|
18537
|
+
auth: "admin"
|
|
18538
|
+
}),
|
|
18539
|
+
getStorageMigrationMoveStatus: method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }),
|
|
18540
|
+
cancelStorageMigrationMove: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
18453
18541
|
kind: "mutation",
|
|
18454
18542
|
auth: "admin"
|
|
18455
18543
|
}),
|
|
@@ -20498,6 +20586,16 @@ var pipelineOrchestratorCapability = {
|
|
|
20498
20586
|
nodeIdMode: "data",
|
|
20499
20587
|
exposesDeviceSettings: true,
|
|
20500
20588
|
methods: {
|
|
20589
|
+
/** Internal storage-migration participant lease. While held, dispatch
|
|
20590
|
+
* requests are accepted as pending but no new runner attachment starts. */
|
|
20591
|
+
pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
20592
|
+
kind: "mutation",
|
|
20593
|
+
auth: "admin"
|
|
20594
|
+
}),
|
|
20595
|
+
resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
20596
|
+
kind: "mutation",
|
|
20597
|
+
auth: "admin"
|
|
20598
|
+
}),
|
|
20501
20599
|
/**
|
|
20502
20600
|
* Pin a camera's pipeline to a specific agent (L1 affinity).
|
|
20503
20601
|
* The orchestrator re-evaluates the assignment immediately and persists
|
|
@@ -21639,6 +21737,28 @@ var storageEvictableCapability = {
|
|
|
21639
21737
|
}), EvictResultSchema, { kind: "mutation" })
|
|
21640
21738
|
}
|
|
21641
21739
|
};
|
|
21740
|
+
/**
|
|
21741
|
+
* The single operator-facing storage migration surface. It coordinates the
|
|
21742
|
+
* pipeline, recorder and post-analysis participants; callers never mutate a
|
|
21743
|
+
* camera recording config or invoke an individual mover directly.
|
|
21744
|
+
*/
|
|
21745
|
+
var storageMigrationCapability = {
|
|
21746
|
+
name: "storage-migration",
|
|
21747
|
+
scope: "system",
|
|
21748
|
+
mode: "singleton",
|
|
21749
|
+
methods: {
|
|
21750
|
+
plan: method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin" }),
|
|
21751
|
+
start: method(StorageMigrationInputSchema, object({ jobId: string() }), {
|
|
21752
|
+
kind: "mutation",
|
|
21753
|
+
auth: "admin"
|
|
21754
|
+
}),
|
|
21755
|
+
status: method(object({ jobId: string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }),
|
|
21756
|
+
cancel: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
21757
|
+
kind: "mutation",
|
|
21758
|
+
auth: "admin"
|
|
21759
|
+
})
|
|
21760
|
+
}
|
|
21761
|
+
};
|
|
21642
21762
|
var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
21643
21763
|
providerId: string().min(1),
|
|
21644
21764
|
displayName: string().min(1),
|
|
@@ -21787,6 +21907,28 @@ var TerminalProfileInfoSchema = object({
|
|
|
21787
21907
|
label: string(),
|
|
21788
21908
|
description: string().optional()
|
|
21789
21909
|
});
|
|
21910
|
+
/**
|
|
21911
|
+
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
21912
|
+
* an instance declares a camera.
|
|
21913
|
+
*/
|
|
21914
|
+
var TerminalInstanceInfoSchema = object({
|
|
21915
|
+
instanceId: string(),
|
|
21916
|
+
cameraStableId: string(),
|
|
21917
|
+
nodeId: string(),
|
|
21918
|
+
profileId: string(),
|
|
21919
|
+
profileLabel: string(),
|
|
21920
|
+
name: string(),
|
|
21921
|
+
enabled: boolean()
|
|
21922
|
+
});
|
|
21923
|
+
var TerminalLegacyCameraSchema = object({
|
|
21924
|
+
stableId: string(),
|
|
21925
|
+
nodeId: string(),
|
|
21926
|
+
profileId: string(),
|
|
21927
|
+
profileLabel: string(),
|
|
21928
|
+
name: string(),
|
|
21929
|
+
/** Only legacy monitor cameras can retain their historic stable identity. */
|
|
21930
|
+
adoptable: boolean()
|
|
21931
|
+
});
|
|
21790
21932
|
var TerminalOutputEventSchema = discriminatedUnion("kind", [object({
|
|
21791
21933
|
seq: number().int().positive(),
|
|
21792
21934
|
kind: literal("data"),
|
|
@@ -21806,10 +21948,9 @@ var TerminalOutputBatchSchema = object({
|
|
|
21806
21948
|
/**
|
|
21807
21949
|
* terminal-session — singleton system capability for interactive TTY sessions.
|
|
21808
21950
|
*
|
|
21809
|
-
*
|
|
21810
|
-
*
|
|
21811
|
-
*
|
|
21812
|
-
* change this contract.
|
|
21951
|
+
* Owns both live PTY lifecycle and durable Terminal instance management.
|
|
21952
|
+
* Profiles are allowlisted templates; an explicit instance is the only path
|
|
21953
|
+
* that declares a camera.
|
|
21813
21954
|
*/
|
|
21814
21955
|
var terminalSessionCapability = {
|
|
21815
21956
|
name: "terminal-session",
|
|
@@ -21818,6 +21959,37 @@ var terminalSessionCapability = {
|
|
|
21818
21959
|
methods: {
|
|
21819
21960
|
/** Pre-declared profiles the operator may open. */
|
|
21820
21961
|
listProfiles: method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
21962
|
+
/** Explicit durable Terminal instances, managed centrally on the hub. */
|
|
21963
|
+
listInstances: method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }),
|
|
21964
|
+
createInstance: method(object({
|
|
21965
|
+
targetNodeId: string().min(1),
|
|
21966
|
+
profileId: string().min(1),
|
|
21967
|
+
name: string().trim().min(1).max(160).optional()
|
|
21968
|
+
}), TerminalInstanceInfoSchema, {
|
|
21969
|
+
kind: "mutation",
|
|
21970
|
+
auth: "admin"
|
|
21971
|
+
}),
|
|
21972
|
+
deleteInstance: method(object({ instanceId: string().min(1) }), _void(), {
|
|
21973
|
+
kind: "mutation",
|
|
21974
|
+
auth: "admin"
|
|
21975
|
+
}),
|
|
21976
|
+
setInstanceEnabled: method(object({
|
|
21977
|
+
instanceId: string().min(1),
|
|
21978
|
+
enabled: boolean()
|
|
21979
|
+
}), TerminalInstanceInfoSchema, {
|
|
21980
|
+
kind: "mutation",
|
|
21981
|
+
auth: "admin"
|
|
21982
|
+
}),
|
|
21983
|
+
/** Existing automatic cameras are shown for explicit migration only. */
|
|
21984
|
+
listLegacyCameras: method(_void(), array(TerminalLegacyCameraSchema).readonly(), { auth: "admin" }),
|
|
21985
|
+
/** Explicitly adopt one legacy monitor camera, retaining its stable id. */
|
|
21986
|
+
adoptLegacyMonitor: method(object({
|
|
21987
|
+
stableId: string().min(1),
|
|
21988
|
+
name: string().trim().min(1).max(160).optional()
|
|
21989
|
+
}), TerminalInstanceInfoSchema, {
|
|
21990
|
+
kind: "mutation",
|
|
21991
|
+
auth: "admin"
|
|
21992
|
+
}),
|
|
21821
21993
|
/** Live sessions currently hosted by the provider. */
|
|
21822
21994
|
listSessions: method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }),
|
|
21823
21995
|
/**
|
|
@@ -21849,7 +22021,13 @@ var terminalSessionCapability = {
|
|
|
21849
22021
|
pullOutput: method(object({
|
|
21850
22022
|
sessionId: string(),
|
|
21851
22023
|
afterSeq: number().int().nonnegative(),
|
|
21852
|
-
waitMs: number().int().min(0).max(2e3).default(0)
|
|
22024
|
+
waitMs: number().int().min(0).max(2e3).default(0),
|
|
22025
|
+
/**
|
|
22026
|
+
* Wait when a just-opened session has no output yet. Kept opt-in so a
|
|
22027
|
+
* browser's initial repaint remains immediate; the camera snapshot
|
|
22028
|
+
* relay uses it to avoid encoding a blank startup frame.
|
|
22029
|
+
*/
|
|
22030
|
+
waitForOutput: boolean().optional()
|
|
21853
22031
|
}), TerminalOutputBatchSchema, {
|
|
21854
22032
|
kind: "mutation",
|
|
21855
22033
|
auth: "admin",
|
|
@@ -24798,6 +24976,7 @@ var FaceInfoSchema = object({
|
|
|
24798
24976
|
var FaceFilterEnum = _enum([
|
|
24799
24977
|
"unassigned",
|
|
24800
24978
|
"recognized",
|
|
24979
|
+
"identified",
|
|
24801
24980
|
"all"
|
|
24802
24981
|
]);
|
|
24803
24982
|
var MediaFileLiteSchema$1 = object({
|
|
@@ -24837,6 +25016,8 @@ var faceGalleryCapability = {
|
|
|
24837
25016
|
auth: "admin"
|
|
24838
25017
|
}),
|
|
24839
25018
|
listRecentFaces: method(object({
|
|
25019
|
+
/** Restrict to one camera. Absent keeps the cluster-wide gallery view. */
|
|
25020
|
+
deviceId: number().int().optional(),
|
|
24840
25021
|
limit: number().int().positive().optional(),
|
|
24841
25022
|
filter: FaceFilterEnum.optional(),
|
|
24842
25023
|
/**
|
|
@@ -27380,6 +27561,10 @@ var OsdSourceSchema = discriminatedUnion("kind", [
|
|
|
27380
27561
|
capName: string().min(1).max(64),
|
|
27381
27562
|
/** Dot path inside the slice, e.g. `detected`, `value`, `mode`. */
|
|
27382
27563
|
valuePath: string().min(1).max(64)
|
|
27564
|
+
}),
|
|
27565
|
+
object({
|
|
27566
|
+
kind: literal("latest-recognition"),
|
|
27567
|
+
recognition: _enum(["person", "plate"])
|
|
27383
27568
|
})
|
|
27384
27569
|
]);
|
|
27385
27570
|
var OsdSlotBindingSchema = object({
|
|
@@ -27518,6 +27703,21 @@ var osdManagerCapability = {
|
|
|
27518
27703
|
auth: "admin"
|
|
27519
27704
|
}),
|
|
27520
27705
|
/**
|
|
27706
|
+
* Replace one camera's binding configuration from another. Writable source
|
|
27707
|
+
* slots are mapped by ordinal onto writable target slots so different
|
|
27708
|
+
* provider slot ids do not make the copied configuration disappear.
|
|
27709
|
+
*/
|
|
27710
|
+
copyDeviceConfiguration: method(object({
|
|
27711
|
+
sourceDeviceId: number().int(),
|
|
27712
|
+
targetDeviceId: number().int()
|
|
27713
|
+
}), object({
|
|
27714
|
+
copied: number().int().nonnegative(),
|
|
27715
|
+
skipped: number().int().nonnegative()
|
|
27716
|
+
}), {
|
|
27717
|
+
kind: "mutation",
|
|
27718
|
+
auth: "admin"
|
|
27719
|
+
}),
|
|
27720
|
+
/**
|
|
27521
27721
|
* Render without writing. `binding` overrides the stored one so an
|
|
27522
27722
|
* editor can preview an unsaved change. Mutation kind only to carry
|
|
27523
27723
|
* the binding object safely; no side effects.
|
|
@@ -28755,12 +28955,6 @@ var recordingCapability = {
|
|
|
28755
28955
|
auth: "admin"
|
|
28756
28956
|
}),
|
|
28757
28957
|
/**
|
|
28758
|
-
* Move footage (recorded segments) from one recordings location to
|
|
28759
|
-
* another — the drain workflow's mover (entity-routing spec Phase 4).
|
|
28760
|
-
* Throttled copy → size-verify → delete source → index refresh; resumable
|
|
28761
|
-
* by construction (copy-if-absent). Single-flight: one job at a time.
|
|
28762
|
-
*/
|
|
28763
|
-
/**
|
|
28764
28958
|
* Render a short GIF from recorded footage around `aroundMs` (low profile,
|
|
28765
28959
|
* palette-free ffmpeg gif). Synchronous — the window is a few seconds of
|
|
28766
28960
|
* `low`, rendering in ~1-2s. Built for notification attachments: the
|
|
@@ -28812,16 +29006,28 @@ var recordingCapability = {
|
|
|
28812
29006
|
kind: "mutation",
|
|
28813
29007
|
auth: "admin"
|
|
28814
29008
|
}),
|
|
28815
|
-
|
|
29009
|
+
/** Internal migration-participant lease. Blocks new recorder attaches and
|
|
29010
|
+
* waits for writers to exit while their watchers index final segments. */
|
|
29011
|
+
pauseForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
28816
29012
|
kind: "mutation",
|
|
28817
29013
|
auth: "admin"
|
|
28818
29014
|
}),
|
|
28819
|
-
|
|
28820
|
-
|
|
28821
|
-
|
|
29015
|
+
resumeForStorageMigration: method(StorageMigrationLeaseInputSchema, object({ resumed: literal(true) }), {
|
|
29016
|
+
kind: "mutation",
|
|
29017
|
+
auth: "admin"
|
|
29018
|
+
}),
|
|
29019
|
+
/** Re-resolve location roots after the coordinator changes defaults. */
|
|
29020
|
+
refreshStorageLocationsForMigration: method(StorageMigrationLeaseInputSchema, object({ refreshed: literal(true) }), {
|
|
29021
|
+
kind: "mutation",
|
|
28822
29022
|
auth: "admin"
|
|
28823
29023
|
}),
|
|
28824
|
-
|
|
29024
|
+
/** Internal mover, callable only by the storage-migration coordinator. */
|
|
29025
|
+
startStorageMigrationMove: method(StorageMigrationFootageMoveInputSchema, object({ jobId: string() }), {
|
|
29026
|
+
kind: "mutation",
|
|
29027
|
+
auth: "admin"
|
|
29028
|
+
}),
|
|
29029
|
+
getStorageMigrationMoveStatus: method(object({ jobId: string() }), RelocateJobSchema.nullable(), { auth: "admin" }),
|
|
29030
|
+
cancelStorageMigrationMove: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
28825
29031
|
kind: "mutation",
|
|
28826
29032
|
auth: "admin"
|
|
28827
29033
|
})
|
|
@@ -30776,6 +30982,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
30776
30982
|
ssoBridgeCapability,
|
|
30777
30983
|
storageCapability,
|
|
30778
30984
|
storageEvictableCapability,
|
|
30985
|
+
storageMigrationCapability,
|
|
30779
30986
|
storageProviderCapability,
|
|
30780
30987
|
streamBrokerCapability,
|
|
30781
30988
|
streamCatalogCapability,
|
|
@@ -33702,6 +33909,12 @@ Object.freeze({
|
|
|
33702
33909
|
addonId: null,
|
|
33703
33910
|
access: "delete"
|
|
33704
33911
|
},
|
|
33912
|
+
"osdManager.copyDeviceConfiguration": {
|
|
33913
|
+
capName: "osd-manager",
|
|
33914
|
+
capScope: "system",
|
|
33915
|
+
addonId: null,
|
|
33916
|
+
access: "create"
|
|
33917
|
+
},
|
|
33705
33918
|
"osdManager.getConditionSupport": {
|
|
33706
33919
|
capName: "osd-manager",
|
|
33707
33920
|
capScope: "system",
|
|
@@ -33798,7 +34011,7 @@ Object.freeze({
|
|
|
33798
34011
|
addonId: null,
|
|
33799
34012
|
access: "create"
|
|
33800
34013
|
},
|
|
33801
|
-
"pipelineAnalytics.
|
|
34014
|
+
"pipelineAnalytics.cancelStorageMigrationMove": {
|
|
33802
34015
|
capName: "pipeline-analytics",
|
|
33803
34016
|
capScope: "device",
|
|
33804
34017
|
addonId: null,
|
|
@@ -33870,12 +34083,6 @@ Object.freeze({
|
|
|
33870
34083
|
addonId: null,
|
|
33871
34084
|
access: "view"
|
|
33872
34085
|
},
|
|
33873
|
-
"pipelineAnalytics.getMediaRelocateStatus": {
|
|
33874
|
-
capName: "pipeline-analytics",
|
|
33875
|
-
capScope: "device",
|
|
33876
|
-
addonId: null,
|
|
33877
|
-
access: "view"
|
|
33878
|
-
},
|
|
33879
34086
|
"pipelineAnalytics.getMotionEvents": {
|
|
33880
34087
|
capName: "pipeline-analytics",
|
|
33881
34088
|
capScope: "device",
|
|
@@ -33912,6 +34119,12 @@ Object.freeze({
|
|
|
33912
34119
|
addonId: null,
|
|
33913
34120
|
access: "view"
|
|
33914
34121
|
},
|
|
34122
|
+
"pipelineAnalytics.getStorageMigrationMoveStatus": {
|
|
34123
|
+
capName: "pipeline-analytics",
|
|
34124
|
+
capScope: "device",
|
|
34125
|
+
addonId: null,
|
|
34126
|
+
access: "view"
|
|
34127
|
+
},
|
|
33915
34128
|
"pipelineAnalytics.getTrack": {
|
|
33916
34129
|
capName: "pipeline-analytics",
|
|
33917
34130
|
capScope: "device",
|
|
@@ -33990,6 +34203,12 @@ Object.freeze({
|
|
|
33990
34203
|
addonId: null,
|
|
33991
34204
|
access: "view"
|
|
33992
34205
|
},
|
|
34206
|
+
"pipelineAnalytics.pauseForStorageMigration": {
|
|
34207
|
+
capName: "pipeline-analytics",
|
|
34208
|
+
capScope: "device",
|
|
34209
|
+
addonId: null,
|
|
34210
|
+
access: "create"
|
|
34211
|
+
},
|
|
33993
34212
|
"pipelineAnalytics.proposeRetrainAnnotations": {
|
|
33994
34213
|
capName: "pipeline-analytics",
|
|
33995
34214
|
capScope: "device",
|
|
@@ -34020,7 +34239,7 @@ Object.freeze({
|
|
|
34020
34239
|
addonId: null,
|
|
34021
34240
|
access: "create"
|
|
34022
34241
|
},
|
|
34023
|
-
"pipelineAnalytics.
|
|
34242
|
+
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
34024
34243
|
capName: "pipeline-analytics",
|
|
34025
34244
|
capScope: "device",
|
|
34026
34245
|
addonId: null,
|
|
@@ -34032,6 +34251,12 @@ Object.freeze({
|
|
|
34032
34251
|
addonId: null,
|
|
34033
34252
|
access: "create"
|
|
34034
34253
|
},
|
|
34254
|
+
"pipelineAnalytics.resumeForStorageMigration": {
|
|
34255
|
+
capName: "pipeline-analytics",
|
|
34256
|
+
capScope: "device",
|
|
34257
|
+
addonId: null,
|
|
34258
|
+
access: "create"
|
|
34259
|
+
},
|
|
34035
34260
|
"pipelineAnalytics.saveRetrainAnnotations": {
|
|
34036
34261
|
capName: "pipeline-analytics",
|
|
34037
34262
|
capScope: "device",
|
|
@@ -34056,6 +34281,12 @@ Object.freeze({
|
|
|
34056
34281
|
addonId: null,
|
|
34057
34282
|
access: "create"
|
|
34058
34283
|
},
|
|
34284
|
+
"pipelineAnalytics.startStorageMigrationMove": {
|
|
34285
|
+
capName: "pipeline-analytics",
|
|
34286
|
+
capScope: "device",
|
|
34287
|
+
addonId: null,
|
|
34288
|
+
access: "create"
|
|
34289
|
+
},
|
|
34059
34290
|
"pipelineAnalytics.wipeAllAnalytics": {
|
|
34060
34291
|
capName: "pipeline-analytics",
|
|
34061
34292
|
capScope: "device",
|
|
@@ -34422,6 +34653,12 @@ Object.freeze({
|
|
|
34422
34653
|
addonId: null,
|
|
34423
34654
|
access: "view"
|
|
34424
34655
|
},
|
|
34656
|
+
"pipelineOrchestrator.pauseForStorageMigration": {
|
|
34657
|
+
capName: "pipeline-orchestrator",
|
|
34658
|
+
capScope: "system",
|
|
34659
|
+
addonId: null,
|
|
34660
|
+
access: "create"
|
|
34661
|
+
},
|
|
34425
34662
|
"pipelineOrchestrator.rebalance": {
|
|
34426
34663
|
capName: "pipeline-orchestrator",
|
|
34427
34664
|
capScope: "system",
|
|
@@ -34446,6 +34683,12 @@ Object.freeze({
|
|
|
34446
34683
|
addonId: null,
|
|
34447
34684
|
access: "view"
|
|
34448
34685
|
},
|
|
34686
|
+
"pipelineOrchestrator.resumeForStorageMigration": {
|
|
34687
|
+
capName: "pipeline-orchestrator",
|
|
34688
|
+
capScope: "system",
|
|
34689
|
+
addonId: null,
|
|
34690
|
+
access: "create"
|
|
34691
|
+
},
|
|
34449
34692
|
"pipelineOrchestrator.saveTemplate": {
|
|
34450
34693
|
capName: "pipeline-orchestrator",
|
|
34451
34694
|
capScope: "system",
|
|
@@ -34842,7 +35085,7 @@ Object.freeze({
|
|
|
34842
35085
|
addonId: null,
|
|
34843
35086
|
access: "create"
|
|
34844
35087
|
},
|
|
34845
|
-
"recording.
|
|
35088
|
+
"recording.cancelStorageMigrationMove": {
|
|
34846
35089
|
capName: "recording",
|
|
34847
35090
|
capScope: "system",
|
|
34848
35091
|
addonId: null,
|
|
@@ -34878,7 +35121,7 @@ Object.freeze({
|
|
|
34878
35121
|
addonId: null,
|
|
34879
35122
|
access: "view"
|
|
34880
35123
|
},
|
|
34881
|
-
"recording.
|
|
35124
|
+
"recording.getStorageMigrationMoveStatus": {
|
|
34882
35125
|
capName: "recording",
|
|
34883
35126
|
capScope: "system",
|
|
34884
35127
|
addonId: null,
|
|
@@ -34902,6 +35145,12 @@ Object.freeze({
|
|
|
34902
35145
|
addonId: null,
|
|
34903
35146
|
access: "view"
|
|
34904
35147
|
},
|
|
35148
|
+
"recording.pauseForStorageMigration": {
|
|
35149
|
+
capName: "recording",
|
|
35150
|
+
capScope: "system",
|
|
35151
|
+
addonId: null,
|
|
35152
|
+
access: "create"
|
|
35153
|
+
},
|
|
34905
35154
|
"recording.pruneFootage": {
|
|
34906
35155
|
capName: "recording",
|
|
34907
35156
|
capScope: "system",
|
|
@@ -34920,7 +35169,7 @@ Object.freeze({
|
|
|
34920
35169
|
addonId: null,
|
|
34921
35170
|
access: "view"
|
|
34922
35171
|
},
|
|
34923
|
-
"recording.
|
|
35172
|
+
"recording.refreshStorageLocationsForMigration": {
|
|
34924
35173
|
capName: "recording",
|
|
34925
35174
|
capScope: "system",
|
|
34926
35175
|
addonId: null,
|
|
@@ -34944,12 +35193,24 @@ Object.freeze({
|
|
|
34944
35193
|
addonId: null,
|
|
34945
35194
|
access: "create"
|
|
34946
35195
|
},
|
|
35196
|
+
"recording.resumeForStorageMigration": {
|
|
35197
|
+
capName: "recording",
|
|
35198
|
+
capScope: "system",
|
|
35199
|
+
addonId: null,
|
|
35200
|
+
access: "create"
|
|
35201
|
+
},
|
|
34947
35202
|
"recording.setDeviceConfig": {
|
|
34948
35203
|
capName: "recording",
|
|
34949
35204
|
capScope: "system",
|
|
34950
35205
|
addonId: null,
|
|
34951
35206
|
access: "create"
|
|
34952
35207
|
},
|
|
35208
|
+
"recording.startStorageMigrationMove": {
|
|
35209
|
+
capName: "recording",
|
|
35210
|
+
capScope: "system",
|
|
35211
|
+
addonId: null,
|
|
35212
|
+
access: "create"
|
|
35213
|
+
},
|
|
34953
35214
|
"recordingExport.cancelExport": {
|
|
34954
35215
|
capName: "recordingExport",
|
|
34955
35216
|
capScope: "system",
|
|
@@ -35340,6 +35601,30 @@ Object.freeze({
|
|
|
35340
35601
|
addonId: null,
|
|
35341
35602
|
access: "view"
|
|
35342
35603
|
},
|
|
35604
|
+
"storageMigration.cancel": {
|
|
35605
|
+
capName: "storage-migration",
|
|
35606
|
+
capScope: "system",
|
|
35607
|
+
addonId: null,
|
|
35608
|
+
access: "create"
|
|
35609
|
+
},
|
|
35610
|
+
"storageMigration.plan": {
|
|
35611
|
+
capName: "storage-migration",
|
|
35612
|
+
capScope: "system",
|
|
35613
|
+
addonId: null,
|
|
35614
|
+
access: "view"
|
|
35615
|
+
},
|
|
35616
|
+
"storageMigration.start": {
|
|
35617
|
+
capName: "storage-migration",
|
|
35618
|
+
capScope: "system",
|
|
35619
|
+
addonId: null,
|
|
35620
|
+
access: "create"
|
|
35621
|
+
},
|
|
35622
|
+
"storageMigration.status": {
|
|
35623
|
+
capName: "storage-migration",
|
|
35624
|
+
capScope: "system",
|
|
35625
|
+
addonId: null,
|
|
35626
|
+
access: "view"
|
|
35627
|
+
},
|
|
35343
35628
|
"storageProvider.abortUpload": {
|
|
35344
35629
|
capName: "storage-provider",
|
|
35345
35630
|
capScope: "system",
|
|
@@ -35718,12 +36003,42 @@ Object.freeze({
|
|
|
35718
36003
|
addonId: null,
|
|
35719
36004
|
access: "create"
|
|
35720
36005
|
},
|
|
36006
|
+
"terminalSession.adoptLegacyMonitor": {
|
|
36007
|
+
capName: "terminal-session",
|
|
36008
|
+
capScope: "system",
|
|
36009
|
+
addonId: null,
|
|
36010
|
+
access: "create"
|
|
36011
|
+
},
|
|
35721
36012
|
"terminalSession.close": {
|
|
35722
36013
|
capName: "terminal-session",
|
|
35723
36014
|
capScope: "system",
|
|
35724
36015
|
addonId: null,
|
|
35725
36016
|
access: "create"
|
|
35726
36017
|
},
|
|
36018
|
+
"terminalSession.createInstance": {
|
|
36019
|
+
capName: "terminal-session",
|
|
36020
|
+
capScope: "system",
|
|
36021
|
+
addonId: null,
|
|
36022
|
+
access: "create"
|
|
36023
|
+
},
|
|
36024
|
+
"terminalSession.deleteInstance": {
|
|
36025
|
+
capName: "terminal-session",
|
|
36026
|
+
capScope: "system",
|
|
36027
|
+
addonId: null,
|
|
36028
|
+
access: "delete"
|
|
36029
|
+
},
|
|
36030
|
+
"terminalSession.listInstances": {
|
|
36031
|
+
capName: "terminal-session",
|
|
36032
|
+
capScope: "system",
|
|
36033
|
+
addonId: null,
|
|
36034
|
+
access: "view"
|
|
36035
|
+
},
|
|
36036
|
+
"terminalSession.listLegacyCameras": {
|
|
36037
|
+
capName: "terminal-session",
|
|
36038
|
+
capScope: "system",
|
|
36039
|
+
addonId: null,
|
|
36040
|
+
access: "view"
|
|
36041
|
+
},
|
|
35727
36042
|
"terminalSession.listProfiles": {
|
|
35728
36043
|
capName: "terminal-session",
|
|
35729
36044
|
capScope: "system",
|
|
@@ -35754,6 +36069,12 @@ Object.freeze({
|
|
|
35754
36069
|
addonId: null,
|
|
35755
36070
|
access: "create"
|
|
35756
36071
|
},
|
|
36072
|
+
"terminalSession.setInstanceEnabled": {
|
|
36073
|
+
capName: "terminal-session",
|
|
36074
|
+
capScope: "system",
|
|
36075
|
+
addonId: null,
|
|
36076
|
+
access: "create"
|
|
36077
|
+
},
|
|
35757
36078
|
"terminalSession.writeInput": {
|
|
35758
36079
|
capName: "terminal-session",
|
|
35759
36080
|
capScope: "system",
|
|
@@ -36585,7 +36906,8 @@ var OsdBindingsStore = class {
|
|
|
36585
36906
|
* Widening it means giving `evaluateGate` the facts to answer it — a
|
|
36586
36907
|
* live detection subject would unlock `classes`, `zones`, `minConfidence`.
|
|
36587
36908
|
*/
|
|
36588
|
-
var OSD_SUPPORTED_CONDITIONS = ["
|
|
36909
|
+
var OSD_SUPPORTED_CONDITIONS = ["deviceState"];
|
|
36910
|
+
var OSD_RUNTIME_CONDITIONS = ["devices", ...OSD_SUPPORTED_CONDITIONS];
|
|
36589
36911
|
var OPEN = { open: true };
|
|
36590
36912
|
/**
|
|
36591
36913
|
* Which condition keys are set on `conditions` but outside the supported
|
|
@@ -36593,7 +36915,7 @@ var OPEN = { open: true };
|
|
|
36593
36915
|
*/
|
|
36594
36916
|
function unsupportedConditionKeys(conditions) {
|
|
36595
36917
|
if (conditions === void 0) return [];
|
|
36596
|
-
const supported = new Set(
|
|
36918
|
+
const supported = new Set(OSD_RUNTIME_CONDITIONS);
|
|
36597
36919
|
const present = [];
|
|
36598
36920
|
for (const [key, value] of Object.entries(conditions)) {
|
|
36599
36921
|
if (value === void 0) continue;
|
|
@@ -36836,6 +37158,10 @@ function resolveSource(binding, cameraDeviceId, facts) {
|
|
|
36836
37158
|
const source = binding.source;
|
|
36837
37159
|
if (source.kind === "static") return { value: { raw: source.text } };
|
|
36838
37160
|
if (source.kind === "clock") return { value: { raw: formatClock(facts.atMs, source.pattern, source.timezone) } };
|
|
37161
|
+
if (source.kind === "latest-recognition") {
|
|
37162
|
+
const value = facts.recognitionByDevice.get(cameraDeviceId)?.[source.recognition];
|
|
37163
|
+
return value === void 0 ? { reason: `no recognized ${source.recognition} has been persisted for device ${cameraDeviceId}` } : { value: { raw: value } };
|
|
37164
|
+
}
|
|
36839
37165
|
const deviceId = source.deviceId ?? cameraDeviceId;
|
|
36840
37166
|
const deviceState = facts.stateByDevice.get(deviceId);
|
|
36841
37167
|
if (deviceState === void 0) return { reason: `no state mirrored for device ${deviceId}` };
|
|
@@ -36959,6 +37285,10 @@ var OsdManager = class {
|
|
|
36959
37285
|
lastWritten = /* @__PURE__ */ new Map();
|
|
36960
37286
|
/** Cameras with at least one binding — the loop's work list. */
|
|
36961
37287
|
boundDevices = /* @__PURE__ */ new Set();
|
|
37288
|
+
recognitions = /* @__PURE__ */ new Map();
|
|
37289
|
+
recognitionHydration = /* @__PURE__ */ new Map();
|
|
37290
|
+
recognitionGeneration = /* @__PURE__ */ new Map();
|
|
37291
|
+
recognitionInvalidatedAt = /* @__PURE__ */ new Map();
|
|
36962
37292
|
timer = null;
|
|
36963
37293
|
constructor(deps) {
|
|
36964
37294
|
this.deps = deps;
|
|
@@ -36986,6 +37316,36 @@ var OsdManager = class {
|
|
|
36986
37316
|
this.lastWritten.clear();
|
|
36987
37317
|
}
|
|
36988
37318
|
/**
|
|
37319
|
+
* Keep recognition overlays event-fresh. The persisted-track hydration below
|
|
37320
|
+
* remains the restart/cold-start authority; lifecycle events only advance it.
|
|
37321
|
+
*/
|
|
37322
|
+
onTrackLifecycle(payload) {
|
|
37323
|
+
let changed = false;
|
|
37324
|
+
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;
|
|
37325
|
+
if (payload.plateText !== void 0) changed = this.mergeRecognition(payload.deviceId, "plate", payload.plateText, payload.lastSeen, payload.firstSeen) || changed;
|
|
37326
|
+
if (!changed || !this.boundDevices.has(payload.deviceId)) return;
|
|
37327
|
+
this.renderDeviceInternal(payload.deviceId, null).catch((err) => {
|
|
37328
|
+
this.logger.warn("osd-manager: recognition-triggered render failed", {
|
|
37329
|
+
tags: { deviceId: payload.deviceId },
|
|
37330
|
+
meta: { error: String(err) }
|
|
37331
|
+
});
|
|
37332
|
+
});
|
|
37333
|
+
}
|
|
37334
|
+
/** Gallery rows are authoritative for corrections, assignments and deletion. */
|
|
37335
|
+
onRecognitionGalleryChanged(deviceId) {
|
|
37336
|
+
this.recognitionGeneration.set(deviceId, (this.recognitionGeneration.get(deviceId) ?? 0) + 1);
|
|
37337
|
+
this.recognitionInvalidatedAt.set(deviceId, this.now());
|
|
37338
|
+
this.recognitions.delete(deviceId);
|
|
37339
|
+
this.recognitionHydration.delete(deviceId);
|
|
37340
|
+
if (!this.boundDevices.has(deviceId)) return;
|
|
37341
|
+
this.renderDeviceInternal(deviceId, null).catch((err) => {
|
|
37342
|
+
this.logger.warn("osd-manager: gallery-triggered render failed", {
|
|
37343
|
+
tags: { deviceId },
|
|
37344
|
+
meta: { error: String(err) }
|
|
37345
|
+
});
|
|
37346
|
+
});
|
|
37347
|
+
}
|
|
37348
|
+
/**
|
|
36989
37349
|
* Reconcile the work list against the store rather than trusting an event
|
|
36990
37350
|
* to have arrived (D8). Cheap: one settings read per camera, on the tick
|
|
36991
37351
|
* cadence, not per frame.
|
|
@@ -37079,6 +37439,54 @@ var OsdManager = class {
|
|
|
37079
37439
|
});
|
|
37080
37440
|
return { success: true };
|
|
37081
37441
|
};
|
|
37442
|
+
copyDeviceConfiguration = async ({ sourceDeviceId, targetDeviceId }) => {
|
|
37443
|
+
if (sourceDeviceId === targetDeviceId) throw new Error("osd-manager: source and target camera must be different");
|
|
37444
|
+
const [sourceStatus, targetStatus, sourceBindings] = await Promise.all([
|
|
37445
|
+
this.deps.readOsdStatus(sourceDeviceId),
|
|
37446
|
+
this.deps.readOsdStatus(targetDeviceId),
|
|
37447
|
+
this.readBindings(sourceDeviceId)
|
|
37448
|
+
]);
|
|
37449
|
+
if (sourceStatus === null) throw new Error(`osd-manager: source device ${sourceDeviceId} exposes no overlay slots`);
|
|
37450
|
+
if (targetStatus === null) throw new Error(`osd-manager: target device ${targetDeviceId} exposes no overlay slots`);
|
|
37451
|
+
const sourceSlots = sourceStatus.overlays.filter((slot) => slot.readOnly !== true && sourceBindings[slot.id] !== void 0);
|
|
37452
|
+
if (sourceSlots.length === 0) throw new Error(`osd-manager: source device ${sourceDeviceId} has no configured writable slots`);
|
|
37453
|
+
const targetSlots = targetStatus.overlays.filter((slot) => slot.readOnly !== true);
|
|
37454
|
+
const copiedBindings = {};
|
|
37455
|
+
const copyCount = Math.min(sourceSlots.length, targetSlots.length);
|
|
37456
|
+
for (let index = 0; index < copyCount; index += 1) {
|
|
37457
|
+
const sourceSlot = sourceSlots[index];
|
|
37458
|
+
const targetSlot = targetSlots[index];
|
|
37459
|
+
if (sourceSlot === void 0 || targetSlot === void 0) continue;
|
|
37460
|
+
const binding = sourceBindings[sourceSlot.id];
|
|
37461
|
+
if (binding === void 0) continue;
|
|
37462
|
+
const conditions = binding.conditions;
|
|
37463
|
+
const normalizedConditions = conditions === void 0 ? void 0 : (() => {
|
|
37464
|
+
const { devices: _cameraScope, ...rest } = conditions;
|
|
37465
|
+
return Object.keys(rest).length === 0 ? void 0 : rest;
|
|
37466
|
+
})();
|
|
37467
|
+
copiedBindings[targetSlot.id] = {
|
|
37468
|
+
...binding,
|
|
37469
|
+
conditions: normalizedConditions
|
|
37470
|
+
};
|
|
37471
|
+
}
|
|
37472
|
+
await this.deps.bindings(targetDeviceId).set(copiedBindings);
|
|
37473
|
+
for (const key of [...this.lastWritten.keys()]) if (key.startsWith(`${targetDeviceId}:`)) this.lastWritten.delete(key);
|
|
37474
|
+
if (Object.keys(copiedBindings).length > 0) this.boundDevices.add(targetDeviceId);
|
|
37475
|
+
else this.boundDevices.delete(targetDeviceId);
|
|
37476
|
+
await this.renderDeviceInternal(targetDeviceId, null);
|
|
37477
|
+
this.logger.info("osd-manager: camera configuration copied", {
|
|
37478
|
+
tags: { deviceId: targetDeviceId },
|
|
37479
|
+
meta: {
|
|
37480
|
+
sourceDeviceId,
|
|
37481
|
+
copied: Object.keys(copiedBindings).length,
|
|
37482
|
+
skipped: Math.max(0, sourceSlots.length - targetSlots.length)
|
|
37483
|
+
}
|
|
37484
|
+
});
|
|
37485
|
+
return {
|
|
37486
|
+
copied: Object.keys(copiedBindings).length,
|
|
37487
|
+
skipped: Math.max(0, sourceSlots.length - targetSlots.length)
|
|
37488
|
+
};
|
|
37489
|
+
};
|
|
37082
37490
|
previewSlot = async ({ deviceId, slotId, binding }) => {
|
|
37083
37491
|
if (binding !== void 0) assertSupportedConditions(binding.conditions);
|
|
37084
37492
|
const effective = binding ?? (await this.readBindings(deviceId))[slotId] ?? null;
|
|
@@ -37153,6 +37561,7 @@ var OsdManager = class {
|
|
|
37153
37561
|
*/
|
|
37154
37562
|
async collectFacts(cameraDeviceId, bindings) {
|
|
37155
37563
|
const wanted = new Set([cameraDeviceId]);
|
|
37564
|
+
const needsRecognition = Object.values(bindings).some((binding) => binding.source.kind === "latest-recognition");
|
|
37156
37565
|
for (const binding of Object.values(bindings)) {
|
|
37157
37566
|
if (binding.source.kind === "device-state" && binding.source.deviceId !== void 0) wanted.add(binding.source.deviceId);
|
|
37158
37567
|
const gated = binding.conditions?.deviceState?.deviceId;
|
|
@@ -37171,12 +37580,59 @@ var OsdManager = class {
|
|
|
37171
37580
|
meta: { error: String(err) }
|
|
37172
37581
|
});
|
|
37173
37582
|
}
|
|
37583
|
+
if (needsRecognition) await this.hydrateRecognitions(cameraDeviceId);
|
|
37584
|
+
const recognitionByDevice = /* @__PURE__ */ new Map();
|
|
37585
|
+
const known = this.recognitions.get(cameraDeviceId);
|
|
37586
|
+
if (known !== void 0) recognitionByDevice.set(cameraDeviceId, {
|
|
37587
|
+
...known.person !== void 0 ? { person: known.person.text } : {},
|
|
37588
|
+
...known.plate !== void 0 ? { plate: known.plate.text } : {}
|
|
37589
|
+
});
|
|
37174
37590
|
return {
|
|
37175
37591
|
atMs: this.now(),
|
|
37176
37592
|
stateByDevice,
|
|
37593
|
+
recognitionByDevice,
|
|
37177
37594
|
deviceState: (id) => gateState.get(id)
|
|
37178
37595
|
};
|
|
37179
37596
|
}
|
|
37597
|
+
async hydrateRecognitions(deviceId) {
|
|
37598
|
+
const existing = this.recognitionHydration.get(deviceId);
|
|
37599
|
+
if (existing !== void 0) return existing;
|
|
37600
|
+
const generation = this.recognitionGeneration.get(deviceId) ?? 0;
|
|
37601
|
+
const hydration = (async () => {
|
|
37602
|
+
try {
|
|
37603
|
+
const latest = await this.deps.readLatestRecognitions(deviceId);
|
|
37604
|
+
if ((this.recognitionGeneration.get(deviceId) ?? 0) !== generation) return;
|
|
37605
|
+
if (latest.person !== void 0) this.mergeRecognition(deviceId, "person", latest.person.text, latest.person.atMs);
|
|
37606
|
+
if (latest.plate !== void 0) this.mergeRecognition(deviceId, "plate", latest.plate.text, latest.plate.atMs);
|
|
37607
|
+
} catch (err) {
|
|
37608
|
+
this.logger.warn("osd-manager: recognition history hydration failed", {
|
|
37609
|
+
tags: { deviceId },
|
|
37610
|
+
meta: { error: String(err) }
|
|
37611
|
+
});
|
|
37612
|
+
this.recognitionHydration.delete(deviceId);
|
|
37613
|
+
}
|
|
37614
|
+
})();
|
|
37615
|
+
this.recognitionHydration.set(deviceId, hydration);
|
|
37616
|
+
await hydration;
|
|
37617
|
+
}
|
|
37618
|
+
mergeRecognition(deviceId, kind, text, atMs, trackFirstSeen) {
|
|
37619
|
+
const normalized = text.trim();
|
|
37620
|
+
if (normalized === "") return false;
|
|
37621
|
+
const invalidatedAt = this.recognitionInvalidatedAt.get(deviceId);
|
|
37622
|
+
if (trackFirstSeen !== void 0 && invalidatedAt !== void 0 && trackFirstSeen <= invalidatedAt) return false;
|
|
37623
|
+
const current = this.recognitions.get(deviceId) ?? {};
|
|
37624
|
+
const previous = current[kind];
|
|
37625
|
+
if (previous !== void 0 && previous.atMs > atMs) return false;
|
|
37626
|
+
if (previous?.atMs === atMs && previous.text === normalized) return false;
|
|
37627
|
+
this.recognitions.set(deviceId, {
|
|
37628
|
+
...current,
|
|
37629
|
+
[kind]: {
|
|
37630
|
+
text: normalized,
|
|
37631
|
+
atMs
|
|
37632
|
+
}
|
|
37633
|
+
});
|
|
37634
|
+
return true;
|
|
37635
|
+
}
|
|
37180
37636
|
async readBindings(deviceId) {
|
|
37181
37637
|
try {
|
|
37182
37638
|
return await this.deps.bindings(deviceId).get();
|
|
@@ -37236,7 +37692,8 @@ var OsdManagerAddon = class extends BaseAddon {
|
|
|
37236
37692
|
icon: "monitor",
|
|
37237
37693
|
path: "/addon/osd-manager",
|
|
37238
37694
|
remoteName: "addon_osd_manager_page",
|
|
37239
|
-
bundle: "remoteEntry.js"
|
|
37695
|
+
bundle: "remoteEntry.js",
|
|
37696
|
+
section: "detection"
|
|
37240
37697
|
}];
|
|
37241
37698
|
constructor() {
|
|
37242
37699
|
super({ ...DEFAULTS });
|
|
@@ -37284,9 +37741,41 @@ var OsdManagerAddon = class extends BaseAddon {
|
|
|
37284
37741
|
const bindings = await ctx.api.deviceManager.getBindings.query({ deviceId });
|
|
37285
37742
|
return [...new Set(bindings.entries.map((e) => e.capName))];
|
|
37286
37743
|
},
|
|
37744
|
+
readLatestRecognitions: async (deviceId) => {
|
|
37745
|
+
const [faces, plates] = await Promise.all([ctx.api.faceGallery.listRecentFaces.query({
|
|
37746
|
+
deviceId,
|
|
37747
|
+
limit: 1,
|
|
37748
|
+
filter: "identified",
|
|
37749
|
+
includeCrops: false
|
|
37750
|
+
}), ctx.api.plateGallery.listPlates.query({
|
|
37751
|
+
deviceId,
|
|
37752
|
+
limit: 1
|
|
37753
|
+
})]);
|
|
37754
|
+
const face = faces[0];
|
|
37755
|
+
const plate = plates[0];
|
|
37756
|
+
return {
|
|
37757
|
+
...face?.identityName !== void 0 ? { person: {
|
|
37758
|
+
text: face.identityName,
|
|
37759
|
+
atMs: face.timestamp
|
|
37760
|
+
} } : {},
|
|
37761
|
+
...plate !== void 0 ? { plate: {
|
|
37762
|
+
text: plate.text,
|
|
37763
|
+
atMs: plate.timestamp
|
|
37764
|
+
} } : {}
|
|
37765
|
+
};
|
|
37766
|
+
},
|
|
37287
37767
|
bindings: (deviceId) => store.forDevice(deviceId)
|
|
37288
37768
|
});
|
|
37289
37769
|
this.manager = manager;
|
|
37770
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsTrackLifecycle }, (event) => {
|
|
37771
|
+
manager.onTrackLifecycle(event.data);
|
|
37772
|
+
});
|
|
37773
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsFaceGalleryChanged }, (event) => {
|
|
37774
|
+
manager.onRecognitionGalleryChanged(event.data.deviceId);
|
|
37775
|
+
});
|
|
37776
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsPlateGalleryChanged }, (event) => {
|
|
37777
|
+
manager.onRecognitionGalleryChanged(event.data.deviceId);
|
|
37778
|
+
});
|
|
37290
37779
|
await manager.start(Math.max(1, this.config.tickSeconds) * 1e3);
|
|
37291
37780
|
const pagesProvider = {
|
|
37292
37781
|
id: this.id,
|