@camstack/addon-osd-manager 0.1.2 → 0.1.4
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/MaskShapeCanvas-BEVxAjNq.mjs +13806 -0
- package/dist/MotionZonesSettings-DteO0vrm.mjs +309 -0
- package/dist/PrivacyMaskSettings-VeD7Fy0-.mjs +290 -0
- package/dist/_stub.js +16641 -0
- package/dist/_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-CL-YG2or.mjs +156 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_sdk__loadShare__.js-plrwWXXt.mjs +25 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D722amjy.mjs +26 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DmzTg7Gl.mjs +25 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_trpc_mf_1_client__loadShare__.js-C7omKvJr.mjs +25 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.js-BpP33rwB.mjs +26 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react__loadShare__.js-Bs1t18EM.mjs +70 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DalfdIDw.mjs +26 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_2_dom__loadShare__.js-C0K4h_0e.mjs +25 -0
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-Dhy3m6Ij.mjs +25 -0
- package/dist/addon-osd-manager.css +3 -0
- package/dist/hostInit-BCB8KzuM.mjs +129 -0
- package/dist/index.js +271 -2
- package/dist/index.mjs +271 -2
- package/dist/player-overlays-CwbydND6.mjs +163 -0
- package/dist/remoteEntry.js +2 -0
- package/dist/remoteEntry.ssr.js +33 -0
- package/dist/rolldown-runtime-HEgqtunE.mjs +20 -0
- package/dist/trash-2-Ckik0Rau.mjs +49 -0
- package/dist/virtualExposes-BgZ5Cn7S.mjs +27 -0
- package/dist/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-CdG2yVd0.mjs +2857 -0
- package/dist/virtual_mf-exposes-ssr___mfe_internal__addon_osd_manager_page__remoteEntry_js-Bgw9YZ5T.mjs +10 -0
- package/package.json +35 -4
package/dist/index.js
CHANGED
|
@@ -21791,6 +21791,22 @@ var TerminalProfileInfoSchema = object({
|
|
|
21791
21791
|
label: string(),
|
|
21792
21792
|
description: string().optional()
|
|
21793
21793
|
});
|
|
21794
|
+
var TerminalOutputEventSchema = discriminatedUnion("kind", [object({
|
|
21795
|
+
seq: number().int().positive(),
|
|
21796
|
+
kind: literal("data"),
|
|
21797
|
+
data: string()
|
|
21798
|
+
}), object({
|
|
21799
|
+
seq: number().int().positive(),
|
|
21800
|
+
kind: literal("exit"),
|
|
21801
|
+
exitCode: number().int(),
|
|
21802
|
+
signal: number().int().optional()
|
|
21803
|
+
})]);
|
|
21804
|
+
var TerminalOutputBatchSchema = object({
|
|
21805
|
+
cursor: number().int().nonnegative(),
|
|
21806
|
+
reset: boolean(),
|
|
21807
|
+
snapshot: string().optional(),
|
|
21808
|
+
events: array(TerminalOutputEventSchema).readonly()
|
|
21809
|
+
});
|
|
21794
21810
|
/**
|
|
21795
21811
|
* terminal-session — singleton system capability for interactive TTY sessions.
|
|
21796
21812
|
*
|
|
@@ -21829,6 +21845,28 @@ var terminalSessionCapability = {
|
|
|
21829
21845
|
kind: "mutation",
|
|
21830
21846
|
auth: "admin"
|
|
21831
21847
|
}),
|
|
21848
|
+
/**
|
|
21849
|
+
* Pull ordered output after a cursor. This capability transport is what
|
|
21850
|
+
* makes remote-agent terminals possible; `reset + snapshot` repairs a
|
|
21851
|
+
* caller that fell behind the bounded replay window.
|
|
21852
|
+
*/
|
|
21853
|
+
pullOutput: method(object({
|
|
21854
|
+
sessionId: string(),
|
|
21855
|
+
afterSeq: number().int().nonnegative(),
|
|
21856
|
+
waitMs: number().int().min(0).max(2e3).default(0)
|
|
21857
|
+
}), TerminalOutputBatchSchema, {
|
|
21858
|
+
kind: "mutation",
|
|
21859
|
+
auth: "admin",
|
|
21860
|
+
timeoutMs: 15e3
|
|
21861
|
+
}),
|
|
21862
|
+
/** Write terminal input through the node-routable capability plane. */
|
|
21863
|
+
writeInput: method(object({
|
|
21864
|
+
sessionId: string(),
|
|
21865
|
+
data: string().max(64 * 1024)
|
|
21866
|
+
}), _void(), {
|
|
21867
|
+
kind: "mutation",
|
|
21868
|
+
auth: "admin"
|
|
21869
|
+
}),
|
|
21832
21870
|
/** Terminate a live session and release its pty. */
|
|
21833
21871
|
close: method(object({ sessionId: string() }), _void(), {
|
|
21834
21872
|
kind: "mutation",
|
|
@@ -24764,6 +24802,7 @@ var FaceInfoSchema = object({
|
|
|
24764
24802
|
var FaceFilterEnum = _enum([
|
|
24765
24803
|
"unassigned",
|
|
24766
24804
|
"recognized",
|
|
24805
|
+
"identified",
|
|
24767
24806
|
"all"
|
|
24768
24807
|
]);
|
|
24769
24808
|
var MediaFileLiteSchema$1 = object({
|
|
@@ -24803,6 +24842,8 @@ var faceGalleryCapability = {
|
|
|
24803
24842
|
auth: "admin"
|
|
24804
24843
|
}),
|
|
24805
24844
|
listRecentFaces: method(object({
|
|
24845
|
+
/** Restrict to one camera. Absent keeps the cluster-wide gallery view. */
|
|
24846
|
+
deviceId: number().int().optional(),
|
|
24806
24847
|
limit: number().int().positive().optional(),
|
|
24807
24848
|
filter: FaceFilterEnum.optional(),
|
|
24808
24849
|
/**
|
|
@@ -27346,6 +27387,10 @@ var OsdSourceSchema = discriminatedUnion("kind", [
|
|
|
27346
27387
|
capName: string().min(1).max(64),
|
|
27347
27388
|
/** Dot path inside the slice, e.g. `detected`, `value`, `mode`. */
|
|
27348
27389
|
valuePath: string().min(1).max(64)
|
|
27390
|
+
}),
|
|
27391
|
+
object({
|
|
27392
|
+
kind: literal("latest-recognition"),
|
|
27393
|
+
recognition: _enum(["person", "plate"])
|
|
27349
27394
|
})
|
|
27350
27395
|
]);
|
|
27351
27396
|
var OsdSlotBindingSchema = object({
|
|
@@ -27484,6 +27529,21 @@ var osdManagerCapability = {
|
|
|
27484
27529
|
auth: "admin"
|
|
27485
27530
|
}),
|
|
27486
27531
|
/**
|
|
27532
|
+
* Replace one camera's binding configuration from another. Writable source
|
|
27533
|
+
* slots are mapped by ordinal onto writable target slots so different
|
|
27534
|
+
* provider slot ids do not make the copied configuration disappear.
|
|
27535
|
+
*/
|
|
27536
|
+
copyDeviceConfiguration: method(object({
|
|
27537
|
+
sourceDeviceId: number().int(),
|
|
27538
|
+
targetDeviceId: number().int()
|
|
27539
|
+
}), object({
|
|
27540
|
+
copied: number().int().nonnegative(),
|
|
27541
|
+
skipped: number().int().nonnegative()
|
|
27542
|
+
}), {
|
|
27543
|
+
kind: "mutation",
|
|
27544
|
+
auth: "admin"
|
|
27545
|
+
}),
|
|
27546
|
+
/**
|
|
27487
27547
|
* Render without writing. `binding` overrides the stored one so an
|
|
27488
27548
|
* editor can preview an unsaved change. Mutation kind only to carry
|
|
27489
27549
|
* the binding object safely; no side effects.
|
|
@@ -33668,6 +33728,12 @@ Object.freeze({
|
|
|
33668
33728
|
addonId: null,
|
|
33669
33729
|
access: "delete"
|
|
33670
33730
|
},
|
|
33731
|
+
"osdManager.copyDeviceConfiguration": {
|
|
33732
|
+
capName: "osd-manager",
|
|
33733
|
+
capScope: "system",
|
|
33734
|
+
addonId: null,
|
|
33735
|
+
access: "create"
|
|
33736
|
+
},
|
|
33671
33737
|
"osdManager.getConditionSupport": {
|
|
33672
33738
|
capName: "osd-manager",
|
|
33673
33739
|
capScope: "system",
|
|
@@ -35708,12 +35774,24 @@ Object.freeze({
|
|
|
35708
35774
|
addonId: null,
|
|
35709
35775
|
access: "create"
|
|
35710
35776
|
},
|
|
35777
|
+
"terminalSession.pullOutput": {
|
|
35778
|
+
capName: "terminal-session",
|
|
35779
|
+
capScope: "system",
|
|
35780
|
+
addonId: null,
|
|
35781
|
+
access: "create"
|
|
35782
|
+
},
|
|
35711
35783
|
"terminalSession.resize": {
|
|
35712
35784
|
capName: "terminal-session",
|
|
35713
35785
|
capScope: "system",
|
|
35714
35786
|
addonId: null,
|
|
35715
35787
|
access: "create"
|
|
35716
35788
|
},
|
|
35789
|
+
"terminalSession.writeInput": {
|
|
35790
|
+
capName: "terminal-session",
|
|
35791
|
+
capScope: "system",
|
|
35792
|
+
addonId: null,
|
|
35793
|
+
access: "create"
|
|
35794
|
+
},
|
|
35717
35795
|
"toast.onToast": {
|
|
35718
35796
|
capName: "toast",
|
|
35719
35797
|
capScope: "system",
|
|
@@ -36539,7 +36617,8 @@ var OsdBindingsStore = class {
|
|
|
36539
36617
|
* Widening it means giving `evaluateGate` the facts to answer it — a
|
|
36540
36618
|
* live detection subject would unlock `classes`, `zones`, `minConfidence`.
|
|
36541
36619
|
*/
|
|
36542
|
-
var OSD_SUPPORTED_CONDITIONS = ["
|
|
36620
|
+
var OSD_SUPPORTED_CONDITIONS = ["deviceState"];
|
|
36621
|
+
var OSD_RUNTIME_CONDITIONS = ["devices", ...OSD_SUPPORTED_CONDITIONS];
|
|
36543
36622
|
var OPEN = { open: true };
|
|
36544
36623
|
/**
|
|
36545
36624
|
* Which condition keys are set on `conditions` but outside the supported
|
|
@@ -36547,7 +36626,7 @@ var OPEN = { open: true };
|
|
|
36547
36626
|
*/
|
|
36548
36627
|
function unsupportedConditionKeys(conditions) {
|
|
36549
36628
|
if (conditions === void 0) return [];
|
|
36550
|
-
const supported = new Set(
|
|
36629
|
+
const supported = new Set(OSD_RUNTIME_CONDITIONS);
|
|
36551
36630
|
const present = [];
|
|
36552
36631
|
for (const [key, value] of Object.entries(conditions)) {
|
|
36553
36632
|
if (value === void 0) continue;
|
|
@@ -36790,6 +36869,10 @@ function resolveSource(binding, cameraDeviceId, facts) {
|
|
|
36790
36869
|
const source = binding.source;
|
|
36791
36870
|
if (source.kind === "static") return { value: { raw: source.text } };
|
|
36792
36871
|
if (source.kind === "clock") return { value: { raw: formatClock(facts.atMs, source.pattern, source.timezone) } };
|
|
36872
|
+
if (source.kind === "latest-recognition") {
|
|
36873
|
+
const value = facts.recognitionByDevice.get(cameraDeviceId)?.[source.recognition];
|
|
36874
|
+
return value === void 0 ? { reason: `no recognized ${source.recognition} has been persisted for device ${cameraDeviceId}` } : { value: { raw: value } };
|
|
36875
|
+
}
|
|
36793
36876
|
const deviceId = source.deviceId ?? cameraDeviceId;
|
|
36794
36877
|
const deviceState = facts.stateByDevice.get(deviceId);
|
|
36795
36878
|
if (deviceState === void 0) return { reason: `no state mirrored for device ${deviceId}` };
|
|
@@ -36913,6 +36996,10 @@ var OsdManager = class {
|
|
|
36913
36996
|
lastWritten = /* @__PURE__ */ new Map();
|
|
36914
36997
|
/** Cameras with at least one binding — the loop's work list. */
|
|
36915
36998
|
boundDevices = /* @__PURE__ */ new Set();
|
|
36999
|
+
recognitions = /* @__PURE__ */ new Map();
|
|
37000
|
+
recognitionHydration = /* @__PURE__ */ new Map();
|
|
37001
|
+
recognitionGeneration = /* @__PURE__ */ new Map();
|
|
37002
|
+
recognitionInvalidatedAt = /* @__PURE__ */ new Map();
|
|
36916
37003
|
timer = null;
|
|
36917
37004
|
constructor(deps) {
|
|
36918
37005
|
this.deps = deps;
|
|
@@ -36940,6 +37027,36 @@ var OsdManager = class {
|
|
|
36940
37027
|
this.lastWritten.clear();
|
|
36941
37028
|
}
|
|
36942
37029
|
/**
|
|
37030
|
+
* Keep recognition overlays event-fresh. The persisted-track hydration below
|
|
37031
|
+
* remains the restart/cold-start authority; lifecycle events only advance it.
|
|
37032
|
+
*/
|
|
37033
|
+
onTrackLifecycle(payload) {
|
|
37034
|
+
let changed = false;
|
|
37035
|
+
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;
|
|
37036
|
+
if (payload.plateText !== void 0) changed = this.mergeRecognition(payload.deviceId, "plate", payload.plateText, payload.lastSeen, payload.firstSeen) || changed;
|
|
37037
|
+
if (!changed || !this.boundDevices.has(payload.deviceId)) return;
|
|
37038
|
+
this.renderDeviceInternal(payload.deviceId, null).catch((err) => {
|
|
37039
|
+
this.logger.warn("osd-manager: recognition-triggered render failed", {
|
|
37040
|
+
tags: { deviceId: payload.deviceId },
|
|
37041
|
+
meta: { error: String(err) }
|
|
37042
|
+
});
|
|
37043
|
+
});
|
|
37044
|
+
}
|
|
37045
|
+
/** Gallery rows are authoritative for corrections, assignments and deletion. */
|
|
37046
|
+
onRecognitionGalleryChanged(deviceId) {
|
|
37047
|
+
this.recognitionGeneration.set(deviceId, (this.recognitionGeneration.get(deviceId) ?? 0) + 1);
|
|
37048
|
+
this.recognitionInvalidatedAt.set(deviceId, this.now());
|
|
37049
|
+
this.recognitions.delete(deviceId);
|
|
37050
|
+
this.recognitionHydration.delete(deviceId);
|
|
37051
|
+
if (!this.boundDevices.has(deviceId)) return;
|
|
37052
|
+
this.renderDeviceInternal(deviceId, null).catch((err) => {
|
|
37053
|
+
this.logger.warn("osd-manager: gallery-triggered render failed", {
|
|
37054
|
+
tags: { deviceId },
|
|
37055
|
+
meta: { error: String(err) }
|
|
37056
|
+
});
|
|
37057
|
+
});
|
|
37058
|
+
}
|
|
37059
|
+
/**
|
|
36943
37060
|
* Reconcile the work list against the store rather than trusting an event
|
|
36944
37061
|
* to have arrived (D8). Cheap: one settings read per camera, on the tick
|
|
36945
37062
|
* cadence, not per frame.
|
|
@@ -37033,6 +37150,54 @@ var OsdManager = class {
|
|
|
37033
37150
|
});
|
|
37034
37151
|
return { success: true };
|
|
37035
37152
|
};
|
|
37153
|
+
copyDeviceConfiguration = async ({ sourceDeviceId, targetDeviceId }) => {
|
|
37154
|
+
if (sourceDeviceId === targetDeviceId) throw new Error("osd-manager: source and target camera must be different");
|
|
37155
|
+
const [sourceStatus, targetStatus, sourceBindings] = await Promise.all([
|
|
37156
|
+
this.deps.readOsdStatus(sourceDeviceId),
|
|
37157
|
+
this.deps.readOsdStatus(targetDeviceId),
|
|
37158
|
+
this.readBindings(sourceDeviceId)
|
|
37159
|
+
]);
|
|
37160
|
+
if (sourceStatus === null) throw new Error(`osd-manager: source device ${sourceDeviceId} exposes no overlay slots`);
|
|
37161
|
+
if (targetStatus === null) throw new Error(`osd-manager: target device ${targetDeviceId} exposes no overlay slots`);
|
|
37162
|
+
const sourceSlots = sourceStatus.overlays.filter((slot) => slot.readOnly !== true && sourceBindings[slot.id] !== void 0);
|
|
37163
|
+
if (sourceSlots.length === 0) throw new Error(`osd-manager: source device ${sourceDeviceId} has no configured writable slots`);
|
|
37164
|
+
const targetSlots = targetStatus.overlays.filter((slot) => slot.readOnly !== true);
|
|
37165
|
+
const copiedBindings = {};
|
|
37166
|
+
const copyCount = Math.min(sourceSlots.length, targetSlots.length);
|
|
37167
|
+
for (let index = 0; index < copyCount; index += 1) {
|
|
37168
|
+
const sourceSlot = sourceSlots[index];
|
|
37169
|
+
const targetSlot = targetSlots[index];
|
|
37170
|
+
if (sourceSlot === void 0 || targetSlot === void 0) continue;
|
|
37171
|
+
const binding = sourceBindings[sourceSlot.id];
|
|
37172
|
+
if (binding === void 0) continue;
|
|
37173
|
+
const conditions = binding.conditions;
|
|
37174
|
+
const normalizedConditions = conditions === void 0 ? void 0 : (() => {
|
|
37175
|
+
const { devices: _cameraScope, ...rest } = conditions;
|
|
37176
|
+
return Object.keys(rest).length === 0 ? void 0 : rest;
|
|
37177
|
+
})();
|
|
37178
|
+
copiedBindings[targetSlot.id] = {
|
|
37179
|
+
...binding,
|
|
37180
|
+
conditions: normalizedConditions
|
|
37181
|
+
};
|
|
37182
|
+
}
|
|
37183
|
+
await this.deps.bindings(targetDeviceId).set(copiedBindings);
|
|
37184
|
+
for (const key of [...this.lastWritten.keys()]) if (key.startsWith(`${targetDeviceId}:`)) this.lastWritten.delete(key);
|
|
37185
|
+
if (Object.keys(copiedBindings).length > 0) this.boundDevices.add(targetDeviceId);
|
|
37186
|
+
else this.boundDevices.delete(targetDeviceId);
|
|
37187
|
+
await this.renderDeviceInternal(targetDeviceId, null);
|
|
37188
|
+
this.logger.info("osd-manager: camera configuration copied", {
|
|
37189
|
+
tags: { deviceId: targetDeviceId },
|
|
37190
|
+
meta: {
|
|
37191
|
+
sourceDeviceId,
|
|
37192
|
+
copied: Object.keys(copiedBindings).length,
|
|
37193
|
+
skipped: Math.max(0, sourceSlots.length - targetSlots.length)
|
|
37194
|
+
}
|
|
37195
|
+
});
|
|
37196
|
+
return {
|
|
37197
|
+
copied: Object.keys(copiedBindings).length,
|
|
37198
|
+
skipped: Math.max(0, sourceSlots.length - targetSlots.length)
|
|
37199
|
+
};
|
|
37200
|
+
};
|
|
37036
37201
|
previewSlot = async ({ deviceId, slotId, binding }) => {
|
|
37037
37202
|
if (binding !== void 0) assertSupportedConditions(binding.conditions);
|
|
37038
37203
|
const effective = binding ?? (await this.readBindings(deviceId))[slotId] ?? null;
|
|
@@ -37107,6 +37272,7 @@ var OsdManager = class {
|
|
|
37107
37272
|
*/
|
|
37108
37273
|
async collectFacts(cameraDeviceId, bindings) {
|
|
37109
37274
|
const wanted = new Set([cameraDeviceId]);
|
|
37275
|
+
const needsRecognition = Object.values(bindings).some((binding) => binding.source.kind === "latest-recognition");
|
|
37110
37276
|
for (const binding of Object.values(bindings)) {
|
|
37111
37277
|
if (binding.source.kind === "device-state" && binding.source.deviceId !== void 0) wanted.add(binding.source.deviceId);
|
|
37112
37278
|
const gated = binding.conditions?.deviceState?.deviceId;
|
|
@@ -37125,12 +37291,59 @@ var OsdManager = class {
|
|
|
37125
37291
|
meta: { error: String(err) }
|
|
37126
37292
|
});
|
|
37127
37293
|
}
|
|
37294
|
+
if (needsRecognition) await this.hydrateRecognitions(cameraDeviceId);
|
|
37295
|
+
const recognitionByDevice = /* @__PURE__ */ new Map();
|
|
37296
|
+
const known = this.recognitions.get(cameraDeviceId);
|
|
37297
|
+
if (known !== void 0) recognitionByDevice.set(cameraDeviceId, {
|
|
37298
|
+
...known.person !== void 0 ? { person: known.person.text } : {},
|
|
37299
|
+
...known.plate !== void 0 ? { plate: known.plate.text } : {}
|
|
37300
|
+
});
|
|
37128
37301
|
return {
|
|
37129
37302
|
atMs: this.now(),
|
|
37130
37303
|
stateByDevice,
|
|
37304
|
+
recognitionByDevice,
|
|
37131
37305
|
deviceState: (id) => gateState.get(id)
|
|
37132
37306
|
};
|
|
37133
37307
|
}
|
|
37308
|
+
async hydrateRecognitions(deviceId) {
|
|
37309
|
+
const existing = this.recognitionHydration.get(deviceId);
|
|
37310
|
+
if (existing !== void 0) return existing;
|
|
37311
|
+
const generation = this.recognitionGeneration.get(deviceId) ?? 0;
|
|
37312
|
+
const hydration = (async () => {
|
|
37313
|
+
try {
|
|
37314
|
+
const latest = await this.deps.readLatestRecognitions(deviceId);
|
|
37315
|
+
if ((this.recognitionGeneration.get(deviceId) ?? 0) !== generation) return;
|
|
37316
|
+
if (latest.person !== void 0) this.mergeRecognition(deviceId, "person", latest.person.text, latest.person.atMs);
|
|
37317
|
+
if (latest.plate !== void 0) this.mergeRecognition(deviceId, "plate", latest.plate.text, latest.plate.atMs);
|
|
37318
|
+
} catch (err) {
|
|
37319
|
+
this.logger.warn("osd-manager: recognition history hydration failed", {
|
|
37320
|
+
tags: { deviceId },
|
|
37321
|
+
meta: { error: String(err) }
|
|
37322
|
+
});
|
|
37323
|
+
this.recognitionHydration.delete(deviceId);
|
|
37324
|
+
}
|
|
37325
|
+
})();
|
|
37326
|
+
this.recognitionHydration.set(deviceId, hydration);
|
|
37327
|
+
await hydration;
|
|
37328
|
+
}
|
|
37329
|
+
mergeRecognition(deviceId, kind, text, atMs, trackFirstSeen) {
|
|
37330
|
+
const normalized = text.trim();
|
|
37331
|
+
if (normalized === "") return false;
|
|
37332
|
+
const invalidatedAt = this.recognitionInvalidatedAt.get(deviceId);
|
|
37333
|
+
if (trackFirstSeen !== void 0 && invalidatedAt !== void 0 && trackFirstSeen <= invalidatedAt) return false;
|
|
37334
|
+
const current = this.recognitions.get(deviceId) ?? {};
|
|
37335
|
+
const previous = current[kind];
|
|
37336
|
+
if (previous !== void 0 && previous.atMs > atMs) return false;
|
|
37337
|
+
if (previous?.atMs === atMs && previous.text === normalized) return false;
|
|
37338
|
+
this.recognitions.set(deviceId, {
|
|
37339
|
+
...current,
|
|
37340
|
+
[kind]: {
|
|
37341
|
+
text: normalized,
|
|
37342
|
+
atMs
|
|
37343
|
+
}
|
|
37344
|
+
});
|
|
37345
|
+
return true;
|
|
37346
|
+
}
|
|
37134
37347
|
async readBindings(deviceId) {
|
|
37135
37348
|
try {
|
|
37136
37349
|
return await this.deps.bindings(deviceId).get();
|
|
@@ -37175,7 +37388,24 @@ function cacheKey(deviceId, slotId) {
|
|
|
37175
37388
|
*/
|
|
37176
37389
|
var DEFAULTS = { tickSeconds: DEFAULT_TICK_MS / 1e3 };
|
|
37177
37390
|
var OsdManagerAddon = class extends BaseAddon {
|
|
37391
|
+
id = "osd-manager";
|
|
37178
37392
|
manager = null;
|
|
37393
|
+
/**
|
|
37394
|
+
* Module-Federation page declaration surfaced via the `addon-pages-source`
|
|
37395
|
+
* collection cap. Mirrors the manifest `pages[]` entry — admin-ui's
|
|
37396
|
+
* `<AddonPageLoader>` loads `addon_osd_manager_page/page` from
|
|
37397
|
+
* `/api/addon-pages/osd-manager/remoteEntry.js`. Modeled directly on
|
|
37398
|
+
* `addon-benchmark` / `addon-model-studio` (docs/roadmap.md 4d).
|
|
37399
|
+
*/
|
|
37400
|
+
pages = [{
|
|
37401
|
+
id: "osd-manager",
|
|
37402
|
+
label: "OSD Manager",
|
|
37403
|
+
icon: "monitor",
|
|
37404
|
+
path: "/addon/osd-manager",
|
|
37405
|
+
remoteName: "addon_osd_manager_page",
|
|
37406
|
+
bundle: "remoteEntry.js",
|
|
37407
|
+
section: "detection"
|
|
37408
|
+
}];
|
|
37179
37409
|
constructor() {
|
|
37180
37410
|
super({ ...DEFAULTS });
|
|
37181
37411
|
}
|
|
@@ -37222,13 +37452,52 @@ var OsdManagerAddon = class extends BaseAddon {
|
|
|
37222
37452
|
const bindings = await ctx.api.deviceManager.getBindings.query({ deviceId });
|
|
37223
37453
|
return [...new Set(bindings.entries.map((e) => e.capName))];
|
|
37224
37454
|
},
|
|
37455
|
+
readLatestRecognitions: async (deviceId) => {
|
|
37456
|
+
const [faces, plates] = await Promise.all([ctx.api.faceGallery.listRecentFaces.query({
|
|
37457
|
+
deviceId,
|
|
37458
|
+
limit: 1,
|
|
37459
|
+
filter: "identified",
|
|
37460
|
+
includeCrops: false
|
|
37461
|
+
}), ctx.api.plateGallery.listPlates.query({
|
|
37462
|
+
deviceId,
|
|
37463
|
+
limit: 1
|
|
37464
|
+
})]);
|
|
37465
|
+
const face = faces[0];
|
|
37466
|
+
const plate = plates[0];
|
|
37467
|
+
return {
|
|
37468
|
+
...face?.identityName !== void 0 ? { person: {
|
|
37469
|
+
text: face.identityName,
|
|
37470
|
+
atMs: face.timestamp
|
|
37471
|
+
} } : {},
|
|
37472
|
+
...plate !== void 0 ? { plate: {
|
|
37473
|
+
text: plate.text,
|
|
37474
|
+
atMs: plate.timestamp
|
|
37475
|
+
} } : {}
|
|
37476
|
+
};
|
|
37477
|
+
},
|
|
37225
37478
|
bindings: (deviceId) => store.forDevice(deviceId)
|
|
37226
37479
|
});
|
|
37227
37480
|
this.manager = manager;
|
|
37481
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsTrackLifecycle }, (event) => {
|
|
37482
|
+
manager.onTrackLifecycle(event.data);
|
|
37483
|
+
});
|
|
37484
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsFaceGalleryChanged }, (event) => {
|
|
37485
|
+
manager.onRecognitionGalleryChanged(event.data.deviceId);
|
|
37486
|
+
});
|
|
37487
|
+
this.subscribe({ category: EventCategory.PipelineAnalyticsPlateGalleryChanged }, (event) => {
|
|
37488
|
+
manager.onRecognitionGalleryChanged(event.data.deviceId);
|
|
37489
|
+
});
|
|
37228
37490
|
await manager.start(Math.max(1, this.config.tickSeconds) * 1e3);
|
|
37491
|
+
const pagesProvider = {
|
|
37492
|
+
id: this.id,
|
|
37493
|
+
listPages: () => this.pages
|
|
37494
|
+
};
|
|
37229
37495
|
return [{
|
|
37230
37496
|
capability: osdManagerCapability,
|
|
37231
37497
|
provider: manager
|
|
37498
|
+
}, {
|
|
37499
|
+
capability: addonPagesSourceCapability,
|
|
37500
|
+
provider: pagesProvider
|
|
37232
37501
|
}];
|
|
37233
37502
|
}
|
|
37234
37503
|
async onConfigChanged() {
|