@camstack/addon-pipeline 1.2.128 → 1.2.129
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/{addon-utils-BnprivSs.js → addon-utils-CKB-2oM9.js} +1 -1
- package/dist/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/detection-pipeline/index.js +241 -95
- package/dist/detection-pipeline/index.mjs +239 -93
- package/dist/{dist-HLAOw6Pe.mjs → dist-CMio-1qq.mjs} +47 -31
- package/dist/{dist-BZUXb5S5.js → dist-D9x2_csL.js} +47 -31
- package/dist/{event-loop-stall-monitor-BH-cL_hg.mjs → event-loop-stall-monitor-B9dxYxyf.mjs} +1 -1
- package/dist/{event-loop-stall-monitor-BdArVUlx.js → event-loop-stall-monitor-UW8nsiMb.js} +1 -1
- package/dist/{lazy-sharp-DTDXrhMG.js → lazy-sharp-DrLwLKpg.js} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +4 -4
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/{process-memory-CDPRLalN.mjs → process-memory-C6es8dMA.mjs} +1 -1
- package/dist/{process-memory-Dh1SyzdJ.js → process-memory-CSJ7-Wlp.js} +1 -1
- package/dist/recorder/index.js +2 -2
- package/dist/recorder/index.mjs +1 -1
- package/dist/{segment-demux-js-D-TLcHW5.mjs → segment-demux-js-BRCjXbI0.mjs} +1 -1
- package/dist/{segment-demux-js-DRutggd6.js → segment-demux-js-DiLDoV9_.js} +1 -1
- package/dist/session-decode/decode-worker-child.js +2 -2
- package/dist/session-decode/decode-worker-child.mjs +1 -1
- package/dist/stream-broker/_stub.js +1 -1
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BDR5z0Z9.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-1O99xPTr.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CxppPmXr.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-Dmw5LWmP.mjs → hostInit-8scvCWua.mjs} +2 -2
- package/dist/stream-broker/index.js +530 -154
- package/dist/stream-broker/index.mjs +530 -154
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-h7Smb_0i.mjs → worker-protocol-BHNWB9Ve.mjs} +1 -1
- package/dist/{worker-protocol-BxkCoVjw.js → worker-protocol-BmBYCioC.js} +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Cs8bmrWP.mjs +0 -26
|
@@ -2,9 +2,9 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_process_memory = require("../process-memory-
|
|
7
|
-
const require_addon_utils = require("../addon-utils-
|
|
5
|
+
const require_dist = require("../dist-D9x2_csL.js");
|
|
6
|
+
const require_process_memory = require("../process-memory-CSJ7-Wlp.js");
|
|
7
|
+
const require_addon_utils = require("../addon-utils-CKB-2oM9.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_dist.__toESM(node_path);
|
|
10
10
|
let node_fs = require("node:fs");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { A as audioAnalyzerCapability, Dt as hydrateSchema, J as mapAudioLabelToMacro, St as BaseAddon, _ as HF_BASE_URL, gt as errMsg, k as audioAnalysisCapability, lt as resolvePoolMemoryPolicy, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, x as PoolMemoryWatchdog } from "../dist-
|
|
3
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
2
|
+
import { A as audioAnalyzerCapability, Dt as hydrateSchema, J as mapAudioLabelToMacro, St as BaseAddon, _ as HF_BASE_URL, gt as errMsg, k as audioAnalysisCapability, lt as resolvePoolMemoryPolicy, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, x as PoolMemoryWatchdog } from "../dist-CMio-1qq.mjs";
|
|
3
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-C6es8dMA.mjs";
|
|
4
4
|
import { i as downloadFile } from "../addon-utils-CgBCF-mE.mjs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
6
6
|
import * as fs from "node:fs";
|
|
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-
|
|
7
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
8
|
-
const require_process_memory = require("../process-memory-
|
|
9
|
-
const require_addon_utils = require("../addon-utils-
|
|
5
|
+
const require_dist = require("../dist-D9x2_csL.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-UW8nsiMb.js");
|
|
7
|
+
const require_lazy_sharp = require("../lazy-sharp-DrLwLKpg.js");
|
|
8
|
+
const require_process_memory = require("../process-memory-CSJ7-Wlp.js");
|
|
9
|
+
const require_addon_utils = require("../addon-utils-CKB-2oM9.js");
|
|
10
10
|
let sharp = require("sharp");
|
|
11
11
|
sharp = require_dist.__toESM(sharp);
|
|
12
12
|
let node_child_process = require("node:child_process");
|
|
@@ -235,6 +235,94 @@ function pickBestRuntime(env, bestBackendHint) {
|
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
237
|
//#endregion
|
|
238
|
+
//#region src/detection-pipeline/engine/pool-provisioning.ts
|
|
239
|
+
/** The fields a {@link PoolProvisioningOverride} may carry, in table order. */
|
|
240
|
+
var OVERRIDABLE_KEYS = [
|
|
241
|
+
"concurrency",
|
|
242
|
+
"numWorkers",
|
|
243
|
+
"batchMode",
|
|
244
|
+
"windowMs",
|
|
245
|
+
"maxBatchSize",
|
|
246
|
+
"numStreams",
|
|
247
|
+
"intraOpThreads"
|
|
248
|
+
];
|
|
249
|
+
/** Backends that are not a runtime of their own and run on onnxruntime. */
|
|
250
|
+
var BACKEND_TO_RUNTIME = {
|
|
251
|
+
onnx: "onnx",
|
|
252
|
+
cpu: "onnx",
|
|
253
|
+
cuda: "onnx",
|
|
254
|
+
openvino: "openvino",
|
|
255
|
+
coreml: "coreml",
|
|
256
|
+
edgetpu: "edgetpu"
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* The registry runtime a device-pool backend provisions from. Unknown backends
|
|
260
|
+
* floor to `onnx` — the same floor `resolveDeviceEngine` applies to the model
|
|
261
|
+
* format, so a pool never comes up unprovisioned.
|
|
262
|
+
*/
|
|
263
|
+
function runtimeIdForBackend(backend) {
|
|
264
|
+
return BACKEND_TO_RUNTIME[backend] ?? "onnx";
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Resolve the provisioning for a pool running `engine`, applying the precedence
|
|
268
|
+
* documented at the top of this module. `engine.device` is not consulted today
|
|
269
|
+
* (see the module doc) but is part of the signature so a bench-backed
|
|
270
|
+
* per-device row lands here and nowhere else.
|
|
271
|
+
*/
|
|
272
|
+
function resolvePoolProvisioning(engine, override = {}) {
|
|
273
|
+
const runtime = runtimeIdForBackend(engine.backend);
|
|
274
|
+
const profile = tuningFor(runtime);
|
|
275
|
+
return {
|
|
276
|
+
runtime,
|
|
277
|
+
overriddenFields: OVERRIDABLE_KEYS.filter((k) => override[k] !== void 0),
|
|
278
|
+
concurrency: Math.max(1, override.concurrency ?? profile.concurrency),
|
|
279
|
+
numWorkers: Math.max(1, override.numWorkers ?? profile.numWorkers),
|
|
280
|
+
batchMode: override.batchMode ?? profile.batchMode,
|
|
281
|
+
windowMs: override.windowMs ?? profile.windowMs,
|
|
282
|
+
maxBatchSize: override.maxBatchSize ?? profile.maxBatchSize,
|
|
283
|
+
numStreams: override.numStreams ?? profile.numStreams,
|
|
284
|
+
intraOpThreads: override.intraOpThreads ?? profile.intraOpThreads
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function positiveNumber(value) {
|
|
288
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
289
|
+
}
|
|
290
|
+
function batchMode(value) {
|
|
291
|
+
return value === "none" || value === "list" || value === "window" ? value : void 0;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Read the operator override out of the detection addon's settings. Only a
|
|
295
|
+
* NON-AUTO value counts: the sliders persist `0` and the select persists `''`
|
|
296
|
+
* for "Auto (backend default)", and those must resolve to the runtime's
|
|
297
|
+
* registry value, not to a literal 0 worker threads.
|
|
298
|
+
*
|
|
299
|
+
* The result is deliberately sparse — an empty object means "nothing
|
|
300
|
+
* overridden", which is what lets a per-device pool provision from its own
|
|
301
|
+
* runtime instead of inheriting the node's.
|
|
302
|
+
*/
|
|
303
|
+
function readOperatorOverride(settings) {
|
|
304
|
+
const override = {};
|
|
305
|
+
const concurrency = positiveNumber(settings.concurrency);
|
|
306
|
+
if (concurrency !== void 0) override.concurrency = concurrency;
|
|
307
|
+
const numWorkers = positiveNumber(settings.numWorkers);
|
|
308
|
+
if (numWorkers !== void 0) override.numWorkers = numWorkers;
|
|
309
|
+
const mode = batchMode(settings.batchMode);
|
|
310
|
+
if (mode !== void 0) override.batchMode = mode;
|
|
311
|
+
const windowMs = positiveNumber(settings.windowMs);
|
|
312
|
+
if (windowMs !== void 0) override.windowMs = windowMs;
|
|
313
|
+
const maxBatchSize = positiveNumber(settings.maxBatchSize);
|
|
314
|
+
if (maxBatchSize !== void 0) override.maxBatchSize = maxBatchSize;
|
|
315
|
+
const numStreams = positiveNumber(settings.numStreams);
|
|
316
|
+
if (numStreams !== void 0) override.numStreams = numStreams;
|
|
317
|
+
const intraOpThreads = positiveNumber(settings.intraOpThreads);
|
|
318
|
+
if (intraOpThreads !== void 0) override.intraOpThreads = intraOpThreads;
|
|
319
|
+
return override;
|
|
320
|
+
}
|
|
321
|
+
/** Two overrides carry the same fields with the same values. */
|
|
322
|
+
function overridesEqual(a, b) {
|
|
323
|
+
return OVERRIDABLE_KEYS.every((k) => a[k] === b[k]);
|
|
324
|
+
}
|
|
325
|
+
//#endregion
|
|
238
326
|
//#region src/detection-pipeline/engine-store-keys.ts
|
|
239
327
|
/**
|
|
240
328
|
* Node-id normalisation for the detection pipeline.
|
|
@@ -445,6 +533,122 @@ function resolveDefaultDetectionModel(backend, device, format, getStepDef = requ
|
|
|
445
533
|
return require_event_loop_stall_monitor.getDefaultModelForFormatFromDef(def, format);
|
|
446
534
|
}
|
|
447
535
|
//#endregion
|
|
536
|
+
//#region src/detection-pipeline/device-override-mirror.ts
|
|
537
|
+
/**
|
|
538
|
+
* The per-device detection overrides, kept fresh OFF the frame path.
|
|
539
|
+
*
|
|
540
|
+
* ## The read this replaces
|
|
541
|
+
*
|
|
542
|
+
* `runPipeline` resolved a device's overrides by calling
|
|
543
|
+
* `settings.readDeviceStore(deviceId)` on **every inference frame**. Measured
|
|
544
|
+
* on the live hub 2026-08-25: `get detection-pipeline:addon-devices`, 1 143
|
|
545
|
+
* calls a minute at 0.44 rows per call — the disk asked, nineteen times a
|
|
546
|
+
* second, whether an operator has ever changed a threshold.
|
|
547
|
+
*
|
|
548
|
+
* ## Why this is not "a cache in the consumer" (D224)
|
|
549
|
+
*
|
|
550
|
+
* D224 forbids a SECOND authority over a fact that belongs to somebody else:
|
|
551
|
+
* the failure it records is a consumer caching a value whose write path does
|
|
552
|
+
* not run through that consumer, so an operator's own change is the one read
|
|
553
|
+
* the cache gets wrong.
|
|
554
|
+
*
|
|
555
|
+
* This addon OWNS the row. `<addonId>:addon-devices` is detection-pipeline's
|
|
556
|
+
* own store, and the only writers are this addon's `updateDeviceSettings` and
|
|
557
|
+
* its `clearDeviceOverrides` — both of which call {@link invalidate}. A write
|
|
558
|
+
* is therefore its own invalidation, exactly as D224 requires, and the window
|
|
559
|
+
* below governs only the case nobody writes through this process.
|
|
560
|
+
*
|
|
561
|
+
* ## The window, declared
|
|
562
|
+
*
|
|
563
|
+
* {@link DEVICE_OVERRIDE_STALE_MS} is what an operator's change costs on a node
|
|
564
|
+
* that did NOT serve the write — this addon runs per node, and a settings write
|
|
565
|
+
* lands on one of them. Thirty seconds is the trade: it removes 99.9% of the
|
|
566
|
+
* reads (one per device per window instead of one per frame) and it is short
|
|
567
|
+
* enough that "I moved the threshold and nothing happened" is not a support
|
|
568
|
+
* question. Ten minutes — {@link OPERATOR_WRITTEN_STALE_MS}, the constant for a
|
|
569
|
+
* cap whose value only an operator changes — is right for a POLLED reader that
|
|
570
|
+
* costs a camera round trip; this read costs one local SQLite `get`, and the
|
|
571
|
+
* cheap read buys a short window.
|
|
572
|
+
*
|
|
573
|
+
* A stale entry is SERVED and revalidated behind the caller, never awaited: a
|
|
574
|
+
* frame that waits for the settings store is a frame the pipeline dropped, and
|
|
575
|
+
* the reader is by definition about to ask again.
|
|
576
|
+
*/
|
|
577
|
+
/**
|
|
578
|
+
* How long a mirrored entry is served before a refresh is started behind the
|
|
579
|
+
* next reader. See the module doc for why it is 30 s and not ten minutes.
|
|
580
|
+
*/
|
|
581
|
+
var DEVICE_OVERRIDE_STALE_MS = 3e4;
|
|
582
|
+
/**
|
|
583
|
+
* How long a FAILED refresh is not retried.
|
|
584
|
+
*
|
|
585
|
+
* A refresh that throws leaves `fetchedAt` where it was, so without a cooldown
|
|
586
|
+
* every subsequent frame would start another one — a broken settings store
|
|
587
|
+
* would be hammered at frame rate by the very mechanism built to stop that.
|
|
588
|
+
*/
|
|
589
|
+
var DEVICE_OVERRIDE_MISS_COOLDOWN_MS = 5e3;
|
|
590
|
+
var DeviceOverrideMirror = class {
|
|
591
|
+
deps;
|
|
592
|
+
staleMs;
|
|
593
|
+
missCooldownMs;
|
|
594
|
+
entries = /* @__PURE__ */ new Map();
|
|
595
|
+
/** In-flight reads, so a burst of frames on a cold device costs ONE read and
|
|
596
|
+
* not one per frame — the exact failure this class exists to remove. */
|
|
597
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
598
|
+
now;
|
|
599
|
+
constructor(deps, staleMs = DEVICE_OVERRIDE_STALE_MS, missCooldownMs = DEVICE_OVERRIDE_MISS_COOLDOWN_MS) {
|
|
600
|
+
this.deps = deps;
|
|
601
|
+
this.staleMs = staleMs;
|
|
602
|
+
this.missCooldownMs = missCooldownMs;
|
|
603
|
+
this.now = deps.now ?? (() => Date.now());
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* The device's overrides.
|
|
607
|
+
*
|
|
608
|
+
* COLD awaits — the first frame on a camera has to get the real answer, and a
|
|
609
|
+
* default is exactly what "the operator lowered this threshold" looks like.
|
|
610
|
+
* WARM returns immediately, stale or not, and starts the refresh behind the
|
|
611
|
+
* caller.
|
|
612
|
+
*/
|
|
613
|
+
async resolve(deviceId) {
|
|
614
|
+
const entry = this.entries.get(deviceId);
|
|
615
|
+
if (entry === void 0) return this.load(deviceId);
|
|
616
|
+
if (this.now() - entry.fetchedAt >= this.staleMs) this.load(deviceId);
|
|
617
|
+
return entry.value;
|
|
618
|
+
}
|
|
619
|
+
/** Drop a device's entry. Called by every writer in this process, so an
|
|
620
|
+
* operator's own change is never served from the mirror. */
|
|
621
|
+
invalidate(deviceId) {
|
|
622
|
+
this.entries.delete(deviceId);
|
|
623
|
+
}
|
|
624
|
+
invalidateAll() {
|
|
625
|
+
this.entries.clear();
|
|
626
|
+
}
|
|
627
|
+
async load(deviceId) {
|
|
628
|
+
const pending = this.inFlight.get(deviceId);
|
|
629
|
+
if (pending !== void 0) return pending;
|
|
630
|
+
const run = this.deps.read(deviceId).then((value) => {
|
|
631
|
+
this.entries.set(deviceId, {
|
|
632
|
+
value,
|
|
633
|
+
fetchedAt: this.now()
|
|
634
|
+
});
|
|
635
|
+
return value;
|
|
636
|
+
}).catch((err) => {
|
|
637
|
+
this.deps.onRefreshFailed?.(deviceId, err);
|
|
638
|
+
const existing = this.entries.get(deviceId);
|
|
639
|
+
if (existing !== void 0) {
|
|
640
|
+
existing.fetchedAt = this.now() - this.staleMs + this.missCooldownMs;
|
|
641
|
+
return existing.value;
|
|
642
|
+
}
|
|
643
|
+
return {};
|
|
644
|
+
}).finally(() => {
|
|
645
|
+
this.inFlight.delete(deviceId);
|
|
646
|
+
});
|
|
647
|
+
this.inFlight.set(deviceId, run);
|
|
648
|
+
return run;
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
//#endregion
|
|
448
652
|
//#region src/detection-pipeline/engine/shared-inference-pool.ts
|
|
449
653
|
/**
|
|
450
654
|
* SharedInferencePool — TypeScript wrapper for inference_pool.py.
|
|
@@ -1987,94 +2191,6 @@ function deviceKeyOf(engine) {
|
|
|
1987
2191
|
return engine.device ? `${engine.backend}:${engine.device}` : engine.backend;
|
|
1988
2192
|
}
|
|
1989
2193
|
//#endregion
|
|
1990
|
-
//#region src/detection-pipeline/engine/pool-provisioning.ts
|
|
1991
|
-
/** The fields a {@link PoolProvisioningOverride} may carry, in table order. */
|
|
1992
|
-
var OVERRIDABLE_KEYS = [
|
|
1993
|
-
"concurrency",
|
|
1994
|
-
"numWorkers",
|
|
1995
|
-
"batchMode",
|
|
1996
|
-
"windowMs",
|
|
1997
|
-
"maxBatchSize",
|
|
1998
|
-
"numStreams",
|
|
1999
|
-
"intraOpThreads"
|
|
2000
|
-
];
|
|
2001
|
-
/** Backends that are not a runtime of their own and run on onnxruntime. */
|
|
2002
|
-
var BACKEND_TO_RUNTIME = {
|
|
2003
|
-
onnx: "onnx",
|
|
2004
|
-
cpu: "onnx",
|
|
2005
|
-
cuda: "onnx",
|
|
2006
|
-
openvino: "openvino",
|
|
2007
|
-
coreml: "coreml",
|
|
2008
|
-
edgetpu: "edgetpu"
|
|
2009
|
-
};
|
|
2010
|
-
/**
|
|
2011
|
-
* The registry runtime a device-pool backend provisions from. Unknown backends
|
|
2012
|
-
* floor to `onnx` — the same floor `resolveDeviceEngine` applies to the model
|
|
2013
|
-
* format, so a pool never comes up unprovisioned.
|
|
2014
|
-
*/
|
|
2015
|
-
function runtimeIdForBackend(backend) {
|
|
2016
|
-
return BACKEND_TO_RUNTIME[backend] ?? "onnx";
|
|
2017
|
-
}
|
|
2018
|
-
/**
|
|
2019
|
-
* Resolve the provisioning for a pool running `engine`, applying the precedence
|
|
2020
|
-
* documented at the top of this module. `engine.device` is not consulted today
|
|
2021
|
-
* (see the module doc) but is part of the signature so a bench-backed
|
|
2022
|
-
* per-device row lands here and nowhere else.
|
|
2023
|
-
*/
|
|
2024
|
-
function resolvePoolProvisioning(engine, override = {}) {
|
|
2025
|
-
const runtime = runtimeIdForBackend(engine.backend);
|
|
2026
|
-
const profile = tuningFor(runtime);
|
|
2027
|
-
return {
|
|
2028
|
-
runtime,
|
|
2029
|
-
overriddenFields: OVERRIDABLE_KEYS.filter((k) => override[k] !== void 0),
|
|
2030
|
-
concurrency: Math.max(1, override.concurrency ?? profile.concurrency),
|
|
2031
|
-
numWorkers: Math.max(1, override.numWorkers ?? profile.numWorkers),
|
|
2032
|
-
batchMode: override.batchMode ?? profile.batchMode,
|
|
2033
|
-
windowMs: override.windowMs ?? profile.windowMs,
|
|
2034
|
-
maxBatchSize: override.maxBatchSize ?? profile.maxBatchSize,
|
|
2035
|
-
numStreams: override.numStreams ?? profile.numStreams,
|
|
2036
|
-
intraOpThreads: override.intraOpThreads ?? profile.intraOpThreads
|
|
2037
|
-
};
|
|
2038
|
-
}
|
|
2039
|
-
function positiveNumber(value) {
|
|
2040
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
2041
|
-
}
|
|
2042
|
-
function batchMode(value) {
|
|
2043
|
-
return value === "none" || value === "list" || value === "window" ? value : void 0;
|
|
2044
|
-
}
|
|
2045
|
-
/**
|
|
2046
|
-
* Read the operator override out of the detection addon's settings. Only a
|
|
2047
|
-
* NON-AUTO value counts: the sliders persist `0` and the select persists `''`
|
|
2048
|
-
* for "Auto (backend default)", and those must resolve to the runtime's
|
|
2049
|
-
* registry value, not to a literal 0 worker threads.
|
|
2050
|
-
*
|
|
2051
|
-
* The result is deliberately sparse — an empty object means "nothing
|
|
2052
|
-
* overridden", which is what lets a per-device pool provision from its own
|
|
2053
|
-
* runtime instead of inheriting the node's.
|
|
2054
|
-
*/
|
|
2055
|
-
function readOperatorOverride(settings) {
|
|
2056
|
-
const override = {};
|
|
2057
|
-
const concurrency = positiveNumber(settings.concurrency);
|
|
2058
|
-
if (concurrency !== void 0) override.concurrency = concurrency;
|
|
2059
|
-
const numWorkers = positiveNumber(settings.numWorkers);
|
|
2060
|
-
if (numWorkers !== void 0) override.numWorkers = numWorkers;
|
|
2061
|
-
const mode = batchMode(settings.batchMode);
|
|
2062
|
-
if (mode !== void 0) override.batchMode = mode;
|
|
2063
|
-
const windowMs = positiveNumber(settings.windowMs);
|
|
2064
|
-
if (windowMs !== void 0) override.windowMs = windowMs;
|
|
2065
|
-
const maxBatchSize = positiveNumber(settings.maxBatchSize);
|
|
2066
|
-
if (maxBatchSize !== void 0) override.maxBatchSize = maxBatchSize;
|
|
2067
|
-
const numStreams = positiveNumber(settings.numStreams);
|
|
2068
|
-
if (numStreams !== void 0) override.numStreams = numStreams;
|
|
2069
|
-
const intraOpThreads = positiveNumber(settings.intraOpThreads);
|
|
2070
|
-
if (intraOpThreads !== void 0) override.intraOpThreads = intraOpThreads;
|
|
2071
|
-
return override;
|
|
2072
|
-
}
|
|
2073
|
-
/** Two overrides carry the same fields with the same values. */
|
|
2074
|
-
function overridesEqual(a, b) {
|
|
2075
|
-
return OVERRIDABLE_KEYS.every((k) => a[k] === b[k]);
|
|
2076
|
-
}
|
|
2077
|
-
//#endregion
|
|
2078
2194
|
//#region src/detection-pipeline/engine/engine-factory.ts
|
|
2079
2195
|
var BACKEND_TO_POOL_RUNTIME = {
|
|
2080
2196
|
coreml: "coreml",
|
|
@@ -6227,6 +6343,14 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
6227
6343
|
readDeviceStore;
|
|
6228
6344
|
/** Delete all per-device settings for a device (used by `clearDeviceOverrides`). */
|
|
6229
6345
|
clearDeviceStore;
|
|
6346
|
+
/**
|
|
6347
|
+
* The per-device overrides the FRAME path reads, kept fresh off that path.
|
|
6348
|
+
*
|
|
6349
|
+
* Public so the addon class can drop a device on its own
|
|
6350
|
+
* `updateDeviceSettings` — the write and the mirror have to be the same
|
|
6351
|
+
* process's, or the mirror becomes the second authority D224 forbids.
|
|
6352
|
+
*/
|
|
6353
|
+
deviceOverrides;
|
|
6230
6354
|
constructor(settings, modelsDir, logger, eventBus = null, detectionConfigSchemaSource = null, executorOptions = {}) {
|
|
6231
6355
|
this.modelsDir = modelsDir;
|
|
6232
6356
|
this.eventBus = eventBus;
|
|
@@ -6238,6 +6362,13 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
6238
6362
|
this.readDeviceStore = settings.readDeviceStore ?? (async () => ({}));
|
|
6239
6363
|
const clearDeviceStore = settings.clearDeviceStore;
|
|
6240
6364
|
this.clearDeviceStore = clearDeviceStore ? (deviceId) => clearDeviceStore.call(settings, deviceId) : async () => void 0;
|
|
6365
|
+
this.deviceOverrides = new DeviceOverrideMirror({
|
|
6366
|
+
read: (deviceId) => this.readDeviceStore(deviceId),
|
|
6367
|
+
onRefreshFailed: (deviceId, err) => this.log.warn("per-device detection overrides refresh failed — serving the last value", {
|
|
6368
|
+
tags: { deviceId },
|
|
6369
|
+
meta: { error: require_dist.errMsg(err) }
|
|
6370
|
+
})
|
|
6371
|
+
});
|
|
6241
6372
|
this.currentEngine = ONNX_FLOOR;
|
|
6242
6373
|
this.log.info("Engine pick pending (placeholder until probe / persisted selection)", { meta: {
|
|
6243
6374
|
runtime: this.currentEngine.runtime,
|
|
@@ -7422,7 +7553,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7422
7553
|
setupMs = performance.now() - wallT0 - decodeMs;
|
|
7423
7554
|
const isRuntime = Boolean(runtimeFrame || runtimeFrameRef);
|
|
7424
7555
|
const effectiveDeviceId = input.deviceId ?? 0;
|
|
7425
|
-
const deviceOverrides = effectiveDeviceId > 0 ? await this.
|
|
7556
|
+
const deviceOverrides = effectiveDeviceId > 0 ? await this.deviceOverrides.resolve(effectiveDeviceId) : {};
|
|
7426
7557
|
const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
|
|
7427
7558
|
const nativeCropProvider = this.buildNativeCropProviderFromRef(input.nativeCropRef) ?? this.buildNativeFaceCropProvider(input.frameHandle);
|
|
7428
7559
|
let cropZoneBbox;
|
|
@@ -8491,7 +8622,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8491
8622
|
if (!api) return 0;
|
|
8492
8623
|
let devices = [];
|
|
8493
8624
|
try {
|
|
8494
|
-
devices = await api.deviceManager.listAll.query({});
|
|
8625
|
+
devices = await api.deviceManager.listAll.query({ projection: "slim" });
|
|
8495
8626
|
} catch (err) {
|
|
8496
8627
|
this.log.warn("clearDeviceOverrides: device enumeration failed — skipping per-device clear", { meta: { error: require_dist.errMsg(err) } });
|
|
8497
8628
|
return 0;
|
|
@@ -8499,6 +8630,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8499
8630
|
let cleared = 0;
|
|
8500
8631
|
for (const device of devices) try {
|
|
8501
8632
|
await this.clearDeviceStore(device.id);
|
|
8633
|
+
this.deviceOverrides.invalidate(device.id);
|
|
8502
8634
|
cleared++;
|
|
8503
8635
|
} catch (err) {
|
|
8504
8636
|
this.log.warn("clearDeviceOverrides: failed to clear per-device overrides for device", {
|
|
@@ -9056,6 +9188,20 @@ function isProfileSliderKey(key) {
|
|
|
9056
9188
|
}
|
|
9057
9189
|
var DetectionPipelineAddon = class extends require_dist.BaseAddon {
|
|
9058
9190
|
provider = null;
|
|
9191
|
+
/**
|
|
9192
|
+
* An operator's own write drops the mirror the frame path reads.
|
|
9193
|
+
*
|
|
9194
|
+
* This override is the half of `device-override-mirror.ts` that keeps it from
|
|
9195
|
+
* being the second authority D224 forbids: `BaseAddon.updateDeviceSettings`
|
|
9196
|
+
* writes THIS addon's `<addonId>:addon-devices` row, so the write and the
|
|
9197
|
+
* mirror are in one process and the write invalidates. Without it the
|
|
9198
|
+
* operator's own change would be the one read the mirror got wrong, which is
|
|
9199
|
+
* the exact failure D224 records.
|
|
9200
|
+
*/
|
|
9201
|
+
async updateDeviceSettings(deviceId, patch) {
|
|
9202
|
+
await super.updateDeviceSettings(deviceId, patch);
|
|
9203
|
+
this.provider?.deviceOverrides.invalidate(deviceId);
|
|
9204
|
+
}
|
|
9059
9205
|
/** Last non-null probed hardware PER NODE — reused when the probe transiently
|
|
9060
9206
|
* returns null so offered backends / device lists don't collapse. Keyed by
|
|
9061
9207
|
* node because the hub addon probes other nodes when serving their config.
|