@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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $ as pickClusterStepModels, D as YAMNET_TO_MACRO, Dt as hydrateSchema, Et as createEvent, Ft as sleep, G as evaluateZoneRules, Gt as string, I as defaultDeviceFor$1, Kt as union, Lt as array, Mt as parseJsonUnknown, St as BaseAddon, Ut as object, V as detectionPipelineCapability, W as enumerateInferenceDevices, Z as overlayClusterStepSettings, c as DEFAULT_CLUSTER_STEP_MODELS, dt as runtimeDevices$1, et as pickClusterStepSettings, gt as errMsg, jt as nodePin, l as DEFAULT_CLUSTER_STEP_SETTINGS, lt as resolvePoolMemoryPolicy, mt as supportedRuntimes$1, p as DEVICE_BACKEND_TO_FORMAT, q as inferModelProvider, qt as EventCategory, rt as pipelineExecutorCapability, st as resolveClusterStepModelId, t as APPLE_SA_TO_MACRO, x as PoolMemoryWatchdog } from "../dist-
|
|
3
|
-
import { a as ALL_PIPELINE_STEPS, c as getDefaultModelForFormatFromDef, d as resolveModelForFormat, f as landmarkPrecisionVerdict, l as getStep, n as startEventLoopStallMonitor, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as getStepDefinition } from "../event-loop-stall-monitor-
|
|
2
|
+
import { $ as pickClusterStepModels, D as YAMNET_TO_MACRO, Dt as hydrateSchema, Et as createEvent, Ft as sleep, G as evaluateZoneRules, Gt as string, I as defaultDeviceFor$1, Kt as union, Lt as array, Mt as parseJsonUnknown, St as BaseAddon, Ut as object, V as detectionPipelineCapability, W as enumerateInferenceDevices, Z as overlayClusterStepSettings, c as DEFAULT_CLUSTER_STEP_MODELS, dt as runtimeDevices$1, et as pickClusterStepSettings, gt as errMsg, jt as nodePin, l as DEFAULT_CLUSTER_STEP_SETTINGS, lt as resolvePoolMemoryPolicy, mt as supportedRuntimes$1, p as DEVICE_BACKEND_TO_FORMAT, q as inferModelProvider, qt as EventCategory, rt as pipelineExecutorCapability, st as resolveClusterStepModelId, t as APPLE_SA_TO_MACRO, x as PoolMemoryWatchdog } from "../dist-CMio-1qq.mjs";
|
|
3
|
+
import { a as ALL_PIPELINE_STEPS, c as getDefaultModelForFormatFromDef, d as resolveModelForFormat, f as landmarkPrecisionVerdict, l as getStep, n as startEventLoopStallMonitor, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as getStepDefinition } from "../event-loop-stall-monitor-B9dxYxyf.mjs";
|
|
4
4
|
import { t as getSharp } from "../lazy-sharp-BtT5x-qP.mjs";
|
|
5
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
5
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-C6es8dMA.mjs";
|
|
6
6
|
import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-CgBCF-mE.mjs";
|
|
7
7
|
import sharp from "sharp";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
@@ -228,6 +228,94 @@ function pickBestRuntime(env, bestBackendHint) {
|
|
|
228
228
|
};
|
|
229
229
|
}
|
|
230
230
|
//#endregion
|
|
231
|
+
//#region src/detection-pipeline/engine/pool-provisioning.ts
|
|
232
|
+
/** The fields a {@link PoolProvisioningOverride} may carry, in table order. */
|
|
233
|
+
var OVERRIDABLE_KEYS = [
|
|
234
|
+
"concurrency",
|
|
235
|
+
"numWorkers",
|
|
236
|
+
"batchMode",
|
|
237
|
+
"windowMs",
|
|
238
|
+
"maxBatchSize",
|
|
239
|
+
"numStreams",
|
|
240
|
+
"intraOpThreads"
|
|
241
|
+
];
|
|
242
|
+
/** Backends that are not a runtime of their own and run on onnxruntime. */
|
|
243
|
+
var BACKEND_TO_RUNTIME = {
|
|
244
|
+
onnx: "onnx",
|
|
245
|
+
cpu: "onnx",
|
|
246
|
+
cuda: "onnx",
|
|
247
|
+
openvino: "openvino",
|
|
248
|
+
coreml: "coreml",
|
|
249
|
+
edgetpu: "edgetpu"
|
|
250
|
+
};
|
|
251
|
+
/**
|
|
252
|
+
* The registry runtime a device-pool backend provisions from. Unknown backends
|
|
253
|
+
* floor to `onnx` — the same floor `resolveDeviceEngine` applies to the model
|
|
254
|
+
* format, so a pool never comes up unprovisioned.
|
|
255
|
+
*/
|
|
256
|
+
function runtimeIdForBackend(backend) {
|
|
257
|
+
return BACKEND_TO_RUNTIME[backend] ?? "onnx";
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Resolve the provisioning for a pool running `engine`, applying the precedence
|
|
261
|
+
* documented at the top of this module. `engine.device` is not consulted today
|
|
262
|
+
* (see the module doc) but is part of the signature so a bench-backed
|
|
263
|
+
* per-device row lands here and nowhere else.
|
|
264
|
+
*/
|
|
265
|
+
function resolvePoolProvisioning(engine, override = {}) {
|
|
266
|
+
const runtime = runtimeIdForBackend(engine.backend);
|
|
267
|
+
const profile = tuningFor(runtime);
|
|
268
|
+
return {
|
|
269
|
+
runtime,
|
|
270
|
+
overriddenFields: OVERRIDABLE_KEYS.filter((k) => override[k] !== void 0),
|
|
271
|
+
concurrency: Math.max(1, override.concurrency ?? profile.concurrency),
|
|
272
|
+
numWorkers: Math.max(1, override.numWorkers ?? profile.numWorkers),
|
|
273
|
+
batchMode: override.batchMode ?? profile.batchMode,
|
|
274
|
+
windowMs: override.windowMs ?? profile.windowMs,
|
|
275
|
+
maxBatchSize: override.maxBatchSize ?? profile.maxBatchSize,
|
|
276
|
+
numStreams: override.numStreams ?? profile.numStreams,
|
|
277
|
+
intraOpThreads: override.intraOpThreads ?? profile.intraOpThreads
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function positiveNumber(value) {
|
|
281
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
282
|
+
}
|
|
283
|
+
function batchMode(value) {
|
|
284
|
+
return value === "none" || value === "list" || value === "window" ? value : void 0;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Read the operator override out of the detection addon's settings. Only a
|
|
288
|
+
* NON-AUTO value counts: the sliders persist `0` and the select persists `''`
|
|
289
|
+
* for "Auto (backend default)", and those must resolve to the runtime's
|
|
290
|
+
* registry value, not to a literal 0 worker threads.
|
|
291
|
+
*
|
|
292
|
+
* The result is deliberately sparse — an empty object means "nothing
|
|
293
|
+
* overridden", which is what lets a per-device pool provision from its own
|
|
294
|
+
* runtime instead of inheriting the node's.
|
|
295
|
+
*/
|
|
296
|
+
function readOperatorOverride(settings) {
|
|
297
|
+
const override = {};
|
|
298
|
+
const concurrency = positiveNumber(settings.concurrency);
|
|
299
|
+
if (concurrency !== void 0) override.concurrency = concurrency;
|
|
300
|
+
const numWorkers = positiveNumber(settings.numWorkers);
|
|
301
|
+
if (numWorkers !== void 0) override.numWorkers = numWorkers;
|
|
302
|
+
const mode = batchMode(settings.batchMode);
|
|
303
|
+
if (mode !== void 0) override.batchMode = mode;
|
|
304
|
+
const windowMs = positiveNumber(settings.windowMs);
|
|
305
|
+
if (windowMs !== void 0) override.windowMs = windowMs;
|
|
306
|
+
const maxBatchSize = positiveNumber(settings.maxBatchSize);
|
|
307
|
+
if (maxBatchSize !== void 0) override.maxBatchSize = maxBatchSize;
|
|
308
|
+
const numStreams = positiveNumber(settings.numStreams);
|
|
309
|
+
if (numStreams !== void 0) override.numStreams = numStreams;
|
|
310
|
+
const intraOpThreads = positiveNumber(settings.intraOpThreads);
|
|
311
|
+
if (intraOpThreads !== void 0) override.intraOpThreads = intraOpThreads;
|
|
312
|
+
return override;
|
|
313
|
+
}
|
|
314
|
+
/** Two overrides carry the same fields with the same values. */
|
|
315
|
+
function overridesEqual(a, b) {
|
|
316
|
+
return OVERRIDABLE_KEYS.every((k) => a[k] === b[k]);
|
|
317
|
+
}
|
|
318
|
+
//#endregion
|
|
231
319
|
//#region src/detection-pipeline/engine-store-keys.ts
|
|
232
320
|
/**
|
|
233
321
|
* Node-id normalisation for the detection pipeline.
|
|
@@ -438,6 +526,122 @@ function resolveDefaultDetectionModel(backend, device, format, getStepDef = getS
|
|
|
438
526
|
return getDefaultModelForFormatFromDef(def, format);
|
|
439
527
|
}
|
|
440
528
|
//#endregion
|
|
529
|
+
//#region src/detection-pipeline/device-override-mirror.ts
|
|
530
|
+
/**
|
|
531
|
+
* The per-device detection overrides, kept fresh OFF the frame path.
|
|
532
|
+
*
|
|
533
|
+
* ## The read this replaces
|
|
534
|
+
*
|
|
535
|
+
* `runPipeline` resolved a device's overrides by calling
|
|
536
|
+
* `settings.readDeviceStore(deviceId)` on **every inference frame**. Measured
|
|
537
|
+
* on the live hub 2026-08-25: `get detection-pipeline:addon-devices`, 1 143
|
|
538
|
+
* calls a minute at 0.44 rows per call — the disk asked, nineteen times a
|
|
539
|
+
* second, whether an operator has ever changed a threshold.
|
|
540
|
+
*
|
|
541
|
+
* ## Why this is not "a cache in the consumer" (D224)
|
|
542
|
+
*
|
|
543
|
+
* D224 forbids a SECOND authority over a fact that belongs to somebody else:
|
|
544
|
+
* the failure it records is a consumer caching a value whose write path does
|
|
545
|
+
* not run through that consumer, so an operator's own change is the one read
|
|
546
|
+
* the cache gets wrong.
|
|
547
|
+
*
|
|
548
|
+
* This addon OWNS the row. `<addonId>:addon-devices` is detection-pipeline's
|
|
549
|
+
* own store, and the only writers are this addon's `updateDeviceSettings` and
|
|
550
|
+
* its `clearDeviceOverrides` — both of which call {@link invalidate}. A write
|
|
551
|
+
* is therefore its own invalidation, exactly as D224 requires, and the window
|
|
552
|
+
* below governs only the case nobody writes through this process.
|
|
553
|
+
*
|
|
554
|
+
* ## The window, declared
|
|
555
|
+
*
|
|
556
|
+
* {@link DEVICE_OVERRIDE_STALE_MS} is what an operator's change costs on a node
|
|
557
|
+
* that did NOT serve the write — this addon runs per node, and a settings write
|
|
558
|
+
* lands on one of them. Thirty seconds is the trade: it removes 99.9% of the
|
|
559
|
+
* reads (one per device per window instead of one per frame) and it is short
|
|
560
|
+
* enough that "I moved the threshold and nothing happened" is not a support
|
|
561
|
+
* question. Ten minutes — {@link OPERATOR_WRITTEN_STALE_MS}, the constant for a
|
|
562
|
+
* cap whose value only an operator changes — is right for a POLLED reader that
|
|
563
|
+
* costs a camera round trip; this read costs one local SQLite `get`, and the
|
|
564
|
+
* cheap read buys a short window.
|
|
565
|
+
*
|
|
566
|
+
* A stale entry is SERVED and revalidated behind the caller, never awaited: a
|
|
567
|
+
* frame that waits for the settings store is a frame the pipeline dropped, and
|
|
568
|
+
* the reader is by definition about to ask again.
|
|
569
|
+
*/
|
|
570
|
+
/**
|
|
571
|
+
* How long a mirrored entry is served before a refresh is started behind the
|
|
572
|
+
* next reader. See the module doc for why it is 30 s and not ten minutes.
|
|
573
|
+
*/
|
|
574
|
+
var DEVICE_OVERRIDE_STALE_MS = 3e4;
|
|
575
|
+
/**
|
|
576
|
+
* How long a FAILED refresh is not retried.
|
|
577
|
+
*
|
|
578
|
+
* A refresh that throws leaves `fetchedAt` where it was, so without a cooldown
|
|
579
|
+
* every subsequent frame would start another one — a broken settings store
|
|
580
|
+
* would be hammered at frame rate by the very mechanism built to stop that.
|
|
581
|
+
*/
|
|
582
|
+
var DEVICE_OVERRIDE_MISS_COOLDOWN_MS = 5e3;
|
|
583
|
+
var DeviceOverrideMirror = class {
|
|
584
|
+
deps;
|
|
585
|
+
staleMs;
|
|
586
|
+
missCooldownMs;
|
|
587
|
+
entries = /* @__PURE__ */ new Map();
|
|
588
|
+
/** In-flight reads, so a burst of frames on a cold device costs ONE read and
|
|
589
|
+
* not one per frame — the exact failure this class exists to remove. */
|
|
590
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
591
|
+
now;
|
|
592
|
+
constructor(deps, staleMs = DEVICE_OVERRIDE_STALE_MS, missCooldownMs = DEVICE_OVERRIDE_MISS_COOLDOWN_MS) {
|
|
593
|
+
this.deps = deps;
|
|
594
|
+
this.staleMs = staleMs;
|
|
595
|
+
this.missCooldownMs = missCooldownMs;
|
|
596
|
+
this.now = deps.now ?? (() => Date.now());
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* The device's overrides.
|
|
600
|
+
*
|
|
601
|
+
* COLD awaits — the first frame on a camera has to get the real answer, and a
|
|
602
|
+
* default is exactly what "the operator lowered this threshold" looks like.
|
|
603
|
+
* WARM returns immediately, stale or not, and starts the refresh behind the
|
|
604
|
+
* caller.
|
|
605
|
+
*/
|
|
606
|
+
async resolve(deviceId) {
|
|
607
|
+
const entry = this.entries.get(deviceId);
|
|
608
|
+
if (entry === void 0) return this.load(deviceId);
|
|
609
|
+
if (this.now() - entry.fetchedAt >= this.staleMs) this.load(deviceId);
|
|
610
|
+
return entry.value;
|
|
611
|
+
}
|
|
612
|
+
/** Drop a device's entry. Called by every writer in this process, so an
|
|
613
|
+
* operator's own change is never served from the mirror. */
|
|
614
|
+
invalidate(deviceId) {
|
|
615
|
+
this.entries.delete(deviceId);
|
|
616
|
+
}
|
|
617
|
+
invalidateAll() {
|
|
618
|
+
this.entries.clear();
|
|
619
|
+
}
|
|
620
|
+
async load(deviceId) {
|
|
621
|
+
const pending = this.inFlight.get(deviceId);
|
|
622
|
+
if (pending !== void 0) return pending;
|
|
623
|
+
const run = this.deps.read(deviceId).then((value) => {
|
|
624
|
+
this.entries.set(deviceId, {
|
|
625
|
+
value,
|
|
626
|
+
fetchedAt: this.now()
|
|
627
|
+
});
|
|
628
|
+
return value;
|
|
629
|
+
}).catch((err) => {
|
|
630
|
+
this.deps.onRefreshFailed?.(deviceId, err);
|
|
631
|
+
const existing = this.entries.get(deviceId);
|
|
632
|
+
if (existing !== void 0) {
|
|
633
|
+
existing.fetchedAt = this.now() - this.staleMs + this.missCooldownMs;
|
|
634
|
+
return existing.value;
|
|
635
|
+
}
|
|
636
|
+
return {};
|
|
637
|
+
}).finally(() => {
|
|
638
|
+
this.inFlight.delete(deviceId);
|
|
639
|
+
});
|
|
640
|
+
this.inFlight.set(deviceId, run);
|
|
641
|
+
return run;
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
//#endregion
|
|
441
645
|
//#region src/detection-pipeline/engine/shared-inference-pool.ts
|
|
442
646
|
/**
|
|
443
647
|
* SharedInferencePool — TypeScript wrapper for inference_pool.py.
|
|
@@ -1980,94 +2184,6 @@ function deviceKeyOf(engine) {
|
|
|
1980
2184
|
return engine.device ? `${engine.backend}:${engine.device}` : engine.backend;
|
|
1981
2185
|
}
|
|
1982
2186
|
//#endregion
|
|
1983
|
-
//#region src/detection-pipeline/engine/pool-provisioning.ts
|
|
1984
|
-
/** The fields a {@link PoolProvisioningOverride} may carry, in table order. */
|
|
1985
|
-
var OVERRIDABLE_KEYS = [
|
|
1986
|
-
"concurrency",
|
|
1987
|
-
"numWorkers",
|
|
1988
|
-
"batchMode",
|
|
1989
|
-
"windowMs",
|
|
1990
|
-
"maxBatchSize",
|
|
1991
|
-
"numStreams",
|
|
1992
|
-
"intraOpThreads"
|
|
1993
|
-
];
|
|
1994
|
-
/** Backends that are not a runtime of their own and run on onnxruntime. */
|
|
1995
|
-
var BACKEND_TO_RUNTIME = {
|
|
1996
|
-
onnx: "onnx",
|
|
1997
|
-
cpu: "onnx",
|
|
1998
|
-
cuda: "onnx",
|
|
1999
|
-
openvino: "openvino",
|
|
2000
|
-
coreml: "coreml",
|
|
2001
|
-
edgetpu: "edgetpu"
|
|
2002
|
-
};
|
|
2003
|
-
/**
|
|
2004
|
-
* The registry runtime a device-pool backend provisions from. Unknown backends
|
|
2005
|
-
* floor to `onnx` — the same floor `resolveDeviceEngine` applies to the model
|
|
2006
|
-
* format, so a pool never comes up unprovisioned.
|
|
2007
|
-
*/
|
|
2008
|
-
function runtimeIdForBackend(backend) {
|
|
2009
|
-
return BACKEND_TO_RUNTIME[backend] ?? "onnx";
|
|
2010
|
-
}
|
|
2011
|
-
/**
|
|
2012
|
-
* Resolve the provisioning for a pool running `engine`, applying the precedence
|
|
2013
|
-
* documented at the top of this module. `engine.device` is not consulted today
|
|
2014
|
-
* (see the module doc) but is part of the signature so a bench-backed
|
|
2015
|
-
* per-device row lands here and nowhere else.
|
|
2016
|
-
*/
|
|
2017
|
-
function resolvePoolProvisioning(engine, override = {}) {
|
|
2018
|
-
const runtime = runtimeIdForBackend(engine.backend);
|
|
2019
|
-
const profile = tuningFor(runtime);
|
|
2020
|
-
return {
|
|
2021
|
-
runtime,
|
|
2022
|
-
overriddenFields: OVERRIDABLE_KEYS.filter((k) => override[k] !== void 0),
|
|
2023
|
-
concurrency: Math.max(1, override.concurrency ?? profile.concurrency),
|
|
2024
|
-
numWorkers: Math.max(1, override.numWorkers ?? profile.numWorkers),
|
|
2025
|
-
batchMode: override.batchMode ?? profile.batchMode,
|
|
2026
|
-
windowMs: override.windowMs ?? profile.windowMs,
|
|
2027
|
-
maxBatchSize: override.maxBatchSize ?? profile.maxBatchSize,
|
|
2028
|
-
numStreams: override.numStreams ?? profile.numStreams,
|
|
2029
|
-
intraOpThreads: override.intraOpThreads ?? profile.intraOpThreads
|
|
2030
|
-
};
|
|
2031
|
-
}
|
|
2032
|
-
function positiveNumber(value) {
|
|
2033
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
2034
|
-
}
|
|
2035
|
-
function batchMode(value) {
|
|
2036
|
-
return value === "none" || value === "list" || value === "window" ? value : void 0;
|
|
2037
|
-
}
|
|
2038
|
-
/**
|
|
2039
|
-
* Read the operator override out of the detection addon's settings. Only a
|
|
2040
|
-
* NON-AUTO value counts: the sliders persist `0` and the select persists `''`
|
|
2041
|
-
* for "Auto (backend default)", and those must resolve to the runtime's
|
|
2042
|
-
* registry value, not to a literal 0 worker threads.
|
|
2043
|
-
*
|
|
2044
|
-
* The result is deliberately sparse — an empty object means "nothing
|
|
2045
|
-
* overridden", which is what lets a per-device pool provision from its own
|
|
2046
|
-
* runtime instead of inheriting the node's.
|
|
2047
|
-
*/
|
|
2048
|
-
function readOperatorOverride(settings) {
|
|
2049
|
-
const override = {};
|
|
2050
|
-
const concurrency = positiveNumber(settings.concurrency);
|
|
2051
|
-
if (concurrency !== void 0) override.concurrency = concurrency;
|
|
2052
|
-
const numWorkers = positiveNumber(settings.numWorkers);
|
|
2053
|
-
if (numWorkers !== void 0) override.numWorkers = numWorkers;
|
|
2054
|
-
const mode = batchMode(settings.batchMode);
|
|
2055
|
-
if (mode !== void 0) override.batchMode = mode;
|
|
2056
|
-
const windowMs = positiveNumber(settings.windowMs);
|
|
2057
|
-
if (windowMs !== void 0) override.windowMs = windowMs;
|
|
2058
|
-
const maxBatchSize = positiveNumber(settings.maxBatchSize);
|
|
2059
|
-
if (maxBatchSize !== void 0) override.maxBatchSize = maxBatchSize;
|
|
2060
|
-
const numStreams = positiveNumber(settings.numStreams);
|
|
2061
|
-
if (numStreams !== void 0) override.numStreams = numStreams;
|
|
2062
|
-
const intraOpThreads = positiveNumber(settings.intraOpThreads);
|
|
2063
|
-
if (intraOpThreads !== void 0) override.intraOpThreads = intraOpThreads;
|
|
2064
|
-
return override;
|
|
2065
|
-
}
|
|
2066
|
-
/** Two overrides carry the same fields with the same values. */
|
|
2067
|
-
function overridesEqual(a, b) {
|
|
2068
|
-
return OVERRIDABLE_KEYS.every((k) => a[k] === b[k]);
|
|
2069
|
-
}
|
|
2070
|
-
//#endregion
|
|
2071
2187
|
//#region src/detection-pipeline/engine/engine-factory.ts
|
|
2072
2188
|
var BACKEND_TO_POOL_RUNTIME = {
|
|
2073
2189
|
coreml: "coreml",
|
|
@@ -6220,6 +6336,14 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
6220
6336
|
readDeviceStore;
|
|
6221
6337
|
/** Delete all per-device settings for a device (used by `clearDeviceOverrides`). */
|
|
6222
6338
|
clearDeviceStore;
|
|
6339
|
+
/**
|
|
6340
|
+
* The per-device overrides the FRAME path reads, kept fresh off that path.
|
|
6341
|
+
*
|
|
6342
|
+
* Public so the addon class can drop a device on its own
|
|
6343
|
+
* `updateDeviceSettings` — the write and the mirror have to be the same
|
|
6344
|
+
* process's, or the mirror becomes the second authority D224 forbids.
|
|
6345
|
+
*/
|
|
6346
|
+
deviceOverrides;
|
|
6223
6347
|
constructor(settings, modelsDir, logger, eventBus = null, detectionConfigSchemaSource = null, executorOptions = {}) {
|
|
6224
6348
|
this.modelsDir = modelsDir;
|
|
6225
6349
|
this.eventBus = eventBus;
|
|
@@ -6231,6 +6355,13 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
6231
6355
|
this.readDeviceStore = settings.readDeviceStore ?? (async () => ({}));
|
|
6232
6356
|
const clearDeviceStore = settings.clearDeviceStore;
|
|
6233
6357
|
this.clearDeviceStore = clearDeviceStore ? (deviceId) => clearDeviceStore.call(settings, deviceId) : async () => void 0;
|
|
6358
|
+
this.deviceOverrides = new DeviceOverrideMirror({
|
|
6359
|
+
read: (deviceId) => this.readDeviceStore(deviceId),
|
|
6360
|
+
onRefreshFailed: (deviceId, err) => this.log.warn("per-device detection overrides refresh failed — serving the last value", {
|
|
6361
|
+
tags: { deviceId },
|
|
6362
|
+
meta: { error: errMsg(err) }
|
|
6363
|
+
})
|
|
6364
|
+
});
|
|
6234
6365
|
this.currentEngine = ONNX_FLOOR;
|
|
6235
6366
|
this.log.info("Engine pick pending (placeholder until probe / persisted selection)", { meta: {
|
|
6236
6367
|
runtime: this.currentEngine.runtime,
|
|
@@ -7415,7 +7546,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7415
7546
|
setupMs = performance.now() - wallT0 - decodeMs;
|
|
7416
7547
|
const isRuntime = Boolean(runtimeFrame || runtimeFrameRef);
|
|
7417
7548
|
const effectiveDeviceId = input.deviceId ?? 0;
|
|
7418
|
-
const deviceOverrides = effectiveDeviceId > 0 ? await this.
|
|
7549
|
+
const deviceOverrides = effectiveDeviceId > 0 ? await this.deviceOverrides.resolve(effectiveDeviceId) : {};
|
|
7419
7550
|
const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
|
|
7420
7551
|
const nativeCropProvider = this.buildNativeCropProviderFromRef(input.nativeCropRef) ?? this.buildNativeFaceCropProvider(input.frameHandle);
|
|
7421
7552
|
let cropZoneBbox;
|
|
@@ -8484,7 +8615,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8484
8615
|
if (!api) return 0;
|
|
8485
8616
|
let devices = [];
|
|
8486
8617
|
try {
|
|
8487
|
-
devices = await api.deviceManager.listAll.query({});
|
|
8618
|
+
devices = await api.deviceManager.listAll.query({ projection: "slim" });
|
|
8488
8619
|
} catch (err) {
|
|
8489
8620
|
this.log.warn("clearDeviceOverrides: device enumeration failed — skipping per-device clear", { meta: { error: errMsg(err) } });
|
|
8490
8621
|
return 0;
|
|
@@ -8492,6 +8623,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8492
8623
|
let cleared = 0;
|
|
8493
8624
|
for (const device of devices) try {
|
|
8494
8625
|
await this.clearDeviceStore(device.id);
|
|
8626
|
+
this.deviceOverrides.invalidate(device.id);
|
|
8495
8627
|
cleared++;
|
|
8496
8628
|
} catch (err) {
|
|
8497
8629
|
this.log.warn("clearDeviceOverrides: failed to clear per-device overrides for device", {
|
|
@@ -9049,6 +9181,20 @@ function isProfileSliderKey(key) {
|
|
|
9049
9181
|
}
|
|
9050
9182
|
var DetectionPipelineAddon = class extends BaseAddon {
|
|
9051
9183
|
provider = null;
|
|
9184
|
+
/**
|
|
9185
|
+
* An operator's own write drops the mirror the frame path reads.
|
|
9186
|
+
*
|
|
9187
|
+
* This override is the half of `device-override-mirror.ts` that keeps it from
|
|
9188
|
+
* being the second authority D224 forbids: `BaseAddon.updateDeviceSettings`
|
|
9189
|
+
* writes THIS addon's `<addonId>:addon-devices` row, so the write and the
|
|
9190
|
+
* mirror are in one process and the write invalidates. Without it the
|
|
9191
|
+
* operator's own change would be the one read the mirror got wrong, which is
|
|
9192
|
+
* the exact failure D224 records.
|
|
9193
|
+
*/
|
|
9194
|
+
async updateDeviceSettings(deviceId, patch) {
|
|
9195
|
+
await super.updateDeviceSettings(deviceId, patch);
|
|
9196
|
+
this.provider?.deviceOverrides.invalidate(deviceId);
|
|
9197
|
+
}
|
|
9052
9198
|
/** Last non-null probed hardware PER NODE — reused when the probe transiently
|
|
9053
9199
|
* returns null so offered backends / device lists don't collapse. Keyed by
|
|
9054
9200
|
* node because the hub addon probes other nodes when serving their config.
|
|
@@ -8599,24 +8599,6 @@ var RecordingRetentionSchema = object({
|
|
|
8599
8599
|
maxSizeGb: number().min(0).optional()
|
|
8600
8600
|
});
|
|
8601
8601
|
/**
|
|
8602
|
-
* Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
|
|
8603
|
-
* sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
|
|
8604
|
-
* previews at. Five graduated steps; absent on a config = `standard` (the
|
|
8605
|
-
* shipped default, matching `sheet-geometry`/`sheet-composer`).
|
|
8606
|
-
*
|
|
8607
|
-
* Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
|
|
8608
|
-
* Each window's index sidecar carries its own tile dims, so a camera whose
|
|
8609
|
-
* preset changed over time renders every historical window at the dims it was
|
|
8610
|
-
* written with.
|
|
8611
|
-
*/
|
|
8612
|
-
var ScrubThumbnailPresetSchema = _enum([
|
|
8613
|
-
"minimal",
|
|
8614
|
-
"low",
|
|
8615
|
-
"standard",
|
|
8616
|
-
"high",
|
|
8617
|
-
"max"
|
|
8618
|
-
]);
|
|
8619
|
-
/**
|
|
8620
8602
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
8621
8603
|
*
|
|
8622
8604
|
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
@@ -8624,7 +8606,11 @@ var ScrubThumbnailPresetSchema = _enum([
|
|
|
8624
8606
|
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
8625
8607
|
*
|
|
8626
8608
|
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
8627
|
-
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30
|
|
8609
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
|
|
8610
|
+
* and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
|
|
8611
|
+
* deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
|
|
8612
|
+
* (D62: a switch that writes a store nobody reads is worse than no switch).
|
|
8613
|
+
* Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
|
|
8628
8614
|
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
8629
8615
|
* persist a band-less config, i.e. silently stop recording the camera.
|
|
8630
8616
|
*/
|
|
@@ -8647,14 +8633,7 @@ var RecordingConfigSchema = object({
|
|
|
8647
8633
|
* "off" is the absence of a covering band, never a band value.
|
|
8648
8634
|
*/
|
|
8649
8635
|
bands: array(RecordingBandSchema).default([]),
|
|
8650
|
-
retention: RecordingRetentionSchema.optional()
|
|
8651
|
-
/**
|
|
8652
|
-
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
8653
|
-
* timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
|
|
8654
|
-
* windows only — existing sheets are immutable, and each window's index
|
|
8655
|
-
* carries its own tile dims so mixed-preset history renders correctly.
|
|
8656
|
-
*/
|
|
8657
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
8636
|
+
retention: RecordingRetentionSchema.optional()
|
|
8658
8637
|
}).strict();
|
|
8659
8638
|
/**
|
|
8660
8639
|
* Derive the {@link RecordingStorageModeSchema} summary from the authoritative
|
|
@@ -12442,7 +12421,8 @@ method(object({
|
|
|
12442
12421
|
}), _void(), { kind: "mutation" }), method(object({
|
|
12443
12422
|
namespace: string().optional(),
|
|
12444
12423
|
collection: string(),
|
|
12445
|
-
filter: QueryFilterSchema.optional()
|
|
12424
|
+
filter: QueryFilterSchema.optional(),
|
|
12425
|
+
columns: array(string()).readonly().optional()
|
|
12446
12426
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12447
12427
|
namespace: string().optional(),
|
|
12448
12428
|
collection: string(),
|
|
@@ -12517,7 +12497,17 @@ method(_void(), EngineInfoSchema), method(object({
|
|
|
12517
12497
|
}), _void(), { kind: "mutation" }), method(object({
|
|
12518
12498
|
namespace: string().optional(),
|
|
12519
12499
|
collection: string(),
|
|
12520
|
-
filter: QueryFilterSchema.optional()
|
|
12500
|
+
filter: QueryFilterSchema.optional(),
|
|
12501
|
+
/**
|
|
12502
|
+
* SQL-level column projection — MUST mirror `settings-store.query`.
|
|
12503
|
+
*
|
|
12504
|
+
* This is the second schema the same call passes through, and Zod
|
|
12505
|
+
* objects STRIP what they do not declare: a field present on the door
|
|
12506
|
+
* and absent here does not error, it silently disappears one hop before
|
|
12507
|
+
* the engine, and the caller concludes the projection does nothing.
|
|
12508
|
+
* `data-door-schema-parity.spec.ts` is what keeps the two in step.
|
|
12509
|
+
*/
|
|
12510
|
+
columns: array(string()).readonly().optional()
|
|
12521
12511
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12522
12512
|
namespace: string().optional(),
|
|
12523
12513
|
collection: string(),
|
|
@@ -24161,7 +24151,27 @@ var MediaFileLiteSchema$1 = object({
|
|
|
24161
24151
|
sizeBytes: number(),
|
|
24162
24152
|
timestamp: number()
|
|
24163
24153
|
});
|
|
24164
|
-
method(
|
|
24154
|
+
method(object({
|
|
24155
|
+
/**
|
|
24156
|
+
* Inline {@link IdentitySchema.coverBase64} on every row.
|
|
24157
|
+
*
|
|
24158
|
+
* Default `false`, the same inversion `listRecentFaces` and
|
|
24159
|
+
* `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
|
|
24160
|
+
* why the burden belongs on the caller that WANTS the bytes). Measured
|
|
24161
|
+
* on the live hub the same day: four identities cost 40,979 B with the
|
|
24162
|
+
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
24163
|
+
* four times and the viewer holds at `staleTime: 30_000`.
|
|
24164
|
+
*
|
|
24165
|
+
* Nothing loses its avatar: `coverMediaKey` is already on every row and
|
|
24166
|
+
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
24167
|
+
*
|
|
24168
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
24169
|
+
* next train** — the hub router validates cap inputs against its own
|
|
24170
|
+
* compiled Zod and strips a key it does not know. Until then the
|
|
24171
|
+
* provider sees `undefined`, which resolves to `false`: the cheap shape
|
|
24172
|
+
* is what ships, and the opt-in becomes reachable when the train lands.
|
|
24173
|
+
*/
|
|
24174
|
+
includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
|
|
24165
24175
|
kind: "mutation",
|
|
24166
24176
|
auth: "admin"
|
|
24167
24177
|
}), method(object({
|
|
@@ -26372,7 +26382,13 @@ method(object({
|
|
|
26372
26382
|
}), method(object({ plateId: string() }), _void(), {
|
|
26373
26383
|
kind: "mutation",
|
|
26374
26384
|
auth: "admin"
|
|
26375
|
-
}), method(
|
|
26385
|
+
}), method(object({
|
|
26386
|
+
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
26387
|
+
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
26388
|
+
* option; `coverMediaKey` + the `event-media` plane carry the picture.
|
|
26389
|
+
* INPUT field: stripped by the hub router until the train ships, which
|
|
26390
|
+
* resolves to `false` and is exactly the intended default. */
|
|
26391
|
+
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
26376
26392
|
kind: "mutation",
|
|
26377
26393
|
auth: "admin"
|
|
26378
26394
|
}), method(object({
|
|
@@ -8622,24 +8622,6 @@ var RecordingRetentionSchema = object({
|
|
|
8622
8622
|
maxSizeGb: number().min(0).optional()
|
|
8623
8623
|
});
|
|
8624
8624
|
/**
|
|
8625
|
-
* Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
|
|
8626
|
-
* sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
|
|
8627
|
-
* previews at. Five graduated steps; absent on a config = `standard` (the
|
|
8628
|
-
* shipped default, matching `sheet-geometry`/`sheet-composer`).
|
|
8629
|
-
*
|
|
8630
|
-
* Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
|
|
8631
|
-
* Each window's index sidecar carries its own tile dims, so a camera whose
|
|
8632
|
-
* preset changed over time renders every historical window at the dims it was
|
|
8633
|
-
* written with.
|
|
8634
|
-
*/
|
|
8635
|
-
var ScrubThumbnailPresetSchema = _enum([
|
|
8636
|
-
"minimal",
|
|
8637
|
-
"low",
|
|
8638
|
-
"standard",
|
|
8639
|
-
"high",
|
|
8640
|
-
"max"
|
|
8641
|
-
]);
|
|
8642
|
-
/**
|
|
8643
8625
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
8644
8626
|
*
|
|
8645
8627
|
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
@@ -8647,7 +8629,11 @@ var ScrubThumbnailPresetSchema = _enum([
|
|
|
8647
8629
|
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
8648
8630
|
*
|
|
8649
8631
|
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
8650
|
-
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30
|
|
8632
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
|
|
8633
|
+
* and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
|
|
8634
|
+
* deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
|
|
8635
|
+
* (D62: a switch that writes a store nobody reads is worse than no switch).
|
|
8636
|
+
* Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
|
|
8651
8637
|
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
8652
8638
|
* persist a band-less config, i.e. silently stop recording the camera.
|
|
8653
8639
|
*/
|
|
@@ -8670,14 +8656,7 @@ var RecordingConfigSchema = object({
|
|
|
8670
8656
|
* "off" is the absence of a covering band, never a band value.
|
|
8671
8657
|
*/
|
|
8672
8658
|
bands: array(RecordingBandSchema).default([]),
|
|
8673
|
-
retention: RecordingRetentionSchema.optional()
|
|
8674
|
-
/**
|
|
8675
|
-
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
8676
|
-
* timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
|
|
8677
|
-
* windows only — existing sheets are immutable, and each window's index
|
|
8678
|
-
* carries its own tile dims so mixed-preset history renders correctly.
|
|
8679
|
-
*/
|
|
8680
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
8659
|
+
retention: RecordingRetentionSchema.optional()
|
|
8681
8660
|
}).strict();
|
|
8682
8661
|
/**
|
|
8683
8662
|
* Derive the {@link RecordingStorageModeSchema} summary from the authoritative
|
|
@@ -12465,7 +12444,8 @@ method(object({
|
|
|
12465
12444
|
}), _void(), { kind: "mutation" }), method(object({
|
|
12466
12445
|
namespace: string().optional(),
|
|
12467
12446
|
collection: string(),
|
|
12468
|
-
filter: QueryFilterSchema.optional()
|
|
12447
|
+
filter: QueryFilterSchema.optional(),
|
|
12448
|
+
columns: array(string()).readonly().optional()
|
|
12469
12449
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12470
12450
|
namespace: string().optional(),
|
|
12471
12451
|
collection: string(),
|
|
@@ -12540,7 +12520,17 @@ method(_void(), EngineInfoSchema), method(object({
|
|
|
12540
12520
|
}), _void(), { kind: "mutation" }), method(object({
|
|
12541
12521
|
namespace: string().optional(),
|
|
12542
12522
|
collection: string(),
|
|
12543
|
-
filter: QueryFilterSchema.optional()
|
|
12523
|
+
filter: QueryFilterSchema.optional(),
|
|
12524
|
+
/**
|
|
12525
|
+
* SQL-level column projection — MUST mirror `settings-store.query`.
|
|
12526
|
+
*
|
|
12527
|
+
* This is the second schema the same call passes through, and Zod
|
|
12528
|
+
* objects STRIP what they do not declare: a field present on the door
|
|
12529
|
+
* and absent here does not error, it silently disappears one hop before
|
|
12530
|
+
* the engine, and the caller concludes the projection does nothing.
|
|
12531
|
+
* `data-door-schema-parity.spec.ts` is what keeps the two in step.
|
|
12532
|
+
*/
|
|
12533
|
+
columns: array(string()).readonly().optional()
|
|
12544
12534
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12545
12535
|
namespace: string().optional(),
|
|
12546
12536
|
collection: string(),
|
|
@@ -24184,7 +24174,27 @@ var MediaFileLiteSchema$1 = object({
|
|
|
24184
24174
|
sizeBytes: number(),
|
|
24185
24175
|
timestamp: number()
|
|
24186
24176
|
});
|
|
24187
|
-
method(
|
|
24177
|
+
method(object({
|
|
24178
|
+
/**
|
|
24179
|
+
* Inline {@link IdentitySchema.coverBase64} on every row.
|
|
24180
|
+
*
|
|
24181
|
+
* Default `false`, the same inversion `listRecentFaces` and
|
|
24182
|
+
* `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
|
|
24183
|
+
* why the burden belongs on the caller that WANTS the bytes). Measured
|
|
24184
|
+
* on the live hub the same day: four identities cost 40,979 B with the
|
|
24185
|
+
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
24186
|
+
* four times and the viewer holds at `staleTime: 30_000`.
|
|
24187
|
+
*
|
|
24188
|
+
* Nothing loses its avatar: `coverMediaKey` is already on every row and
|
|
24189
|
+
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
24190
|
+
*
|
|
24191
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
24192
|
+
* next train** — the hub router validates cap inputs against its own
|
|
24193
|
+
* compiled Zod and strips a key it does not know. Until then the
|
|
24194
|
+
* provider sees `undefined`, which resolves to `false`: the cheap shape
|
|
24195
|
+
* is what ships, and the opt-in becomes reachable when the train lands.
|
|
24196
|
+
*/
|
|
24197
|
+
includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()), method(object({ name: string().min(1) }), IdentitySchema, {
|
|
24188
24198
|
kind: "mutation",
|
|
24189
24199
|
auth: "admin"
|
|
24190
24200
|
}), method(object({
|
|
@@ -26395,7 +26405,13 @@ method(object({
|
|
|
26395
26405
|
}), method(object({ plateId: string() }), _void(), {
|
|
26396
26406
|
kind: "mutation",
|
|
26397
26407
|
auth: "admin"
|
|
26398
|
-
}), method(
|
|
26408
|
+
}), method(object({
|
|
26409
|
+
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
26410
|
+
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
26411
|
+
* option; `coverMediaKey` + the `event-media` plane carry the picture.
|
|
26412
|
+
* INPUT field: stripped by the hub router until the train ships, which
|
|
26413
|
+
* resolves to `false` and is exactly the intended default. */
|
|
26414
|
+
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
26399
26415
|
kind: "mutation",
|
|
26400
26416
|
auth: "admin"
|
|
26401
26417
|
}), method(object({
|
package/dist/{event-loop-stall-monitor-BH-cL_hg.mjs → event-loop-stall-monitor-B9dxYxyf.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { K as hfModelUrl, a as COCO_80_LABELS, j as audioKindId, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-
|
|
1
|
+
import { K as hfModelUrl, a as COCO_80_LABELS, j as audioKindId, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-CMio-1qq.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { PerformanceObserver } from "node:perf_hooks";
|
|
4
4
|
//#region src/detection-pipeline/registry/model-catalogs.ts
|