@camstack/addon-pipeline 1.2.338 → 1.2.340

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.
Files changed (34) hide show
  1. package/dist/audio-analyzer/index.js +22 -30
  2. package/dist/audio-analyzer/index.mjs +23 -31
  3. package/dist/{custom-model-catalog-CN6WPGB8.mjs → custom-model-catalog-BOnN63HU.mjs} +5 -1448
  4. package/dist/{custom-model-catalog-BYJyfhgj.js → custom-model-catalog-Cjbll1Sf.js} +18 -1461
  5. package/dist/detection-pipeline/index.js +208 -17
  6. package/dist/detection-pipeline/index.mjs +232 -41
  7. package/dist/{dist-WIL4yeyi.js → dist-BWigCRRN.js} +324 -51
  8. package/dist/{dist-CdmlJu1J.mjs → dist-CsA6fY6I.mjs} +311 -50
  9. package/dist/model-catalogs-BFBf8sHb.js +1522 -0
  10. package/dist/model-catalogs-D7JXV0_i.mjs +1445 -0
  11. package/dist/motion-wasm/index.js +1 -1
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/{node-CEtew1DU.mjs → node-BZ29vHq2.mjs} +1 -1
  14. package/dist/{node-DCFClFJ1.js → node-D52HHrVZ.js} +1 -1
  15. package/dist/pipeline-runner/index.js +3 -3
  16. package/dist/pipeline-runner/index.mjs +3 -3
  17. package/dist/{process-memory-Bsj_b---.js → process-memory-C9U6dKxS.js} +1 -1
  18. package/dist/{process-memory-maZfOnev.mjs → process-memory-DOEeg2pL.mjs} +1 -1
  19. package/dist/recorder/index.js +6 -2
  20. package/dist/recorder/index.mjs +6 -2
  21. package/dist/{segment-demux-js-CXmBf_nf.js → segment-demux-js-CMZSmwMp.js} +1 -1
  22. package/dist/{segment-demux-js-DnPcYYbc.mjs → segment-demux-js-DDgwrz-e.mjs} +1 -1
  23. package/dist/stream-broker/_stub.js +2 -2
  24. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BdsJXZcP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-6JIjr_ur.mjs} +2 -2
  25. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js--yC-aoPc.mjs +26 -0
  26. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Bt8aa0wk.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-B-hhg2sP.mjs} +1 -1
  27. package/dist/stream-broker/demux-worker-child.js +1 -1
  28. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  29. package/dist/stream-broker/{hostInit-BU5SBy0i.mjs → hostInit-Ck1wQfKk.mjs} +2 -2
  30. package/dist/stream-broker/index.js +3 -3
  31. package/dist/stream-broker/index.mjs +3 -3
  32. package/dist/stream-broker/remoteEntry.js +1 -1
  33. package/package.json +1 -1
  34. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-1Y-WK-Zy.mjs +0 -26
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-WIL4yeyi.js");
7
- const require_node = require("../node-DCFClFJ1.js");
8
- const require_custom_model_catalog = require("../custom-model-catalog-BYJyfhgj.js");
6
+ const require_dist = require("../dist-BWigCRRN.js");
7
+ const require_node = require("../node-D52HHrVZ.js");
8
+ const require_custom_model_catalog = require("../custom-model-catalog-Cjbll1Sf.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-Bsj_b---.js");
10
+ const require_process_memory = require("../process-memory-C9U6dKxS.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -346,6 +346,138 @@ function normalizeEngineNodeId(rawNodeId) {
346
346
  return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
347
347
  }
348
348
  //#endregion
349
+ //#region src/detection-pipeline/model-bound-device-overrides.ts
350
+ /**
351
+ * Best settings (D745), the executor leg: list — and optionally remove — the
352
+ * MODEL-BOUND thresholds stored in this addon's per-camera settings (the
353
+ * object-detection root's `bindsToModel` keys and their binding keys, D738).
354
+ * Every other key of a camera's store is kept.
355
+ *
356
+ * The device store only MERGES on write, so a removal is clear + write of the
357
+ * kept keys — the idiom `migrate-hardware-state.ts` uses. Both run in this
358
+ * process, serialized per camera; a write that fails after the clear restores
359
+ * the original row, and the camera is reported `refused` rather than clean. A
360
+ * store that cannot be read is `refused` too: a failed read is never "nothing
361
+ * to clear" (D393).
362
+ */
363
+ function errMsg(err) {
364
+ return err instanceof Error ? err.message : String(err);
365
+ }
366
+ /** The stored keys among `boundKeys` (values and bindings), sorted. */
367
+ function presentBoundKeys(row, boundKeys) {
368
+ return boundKeys.flatMap((k) => [k, require_dist.modelBindingKey(k)]).filter((k) => k in row).toSorted();
369
+ }
370
+ async function clearModelBoundDeviceOverrides(deps, input) {
371
+ const ids = input.deviceIds ?? await deps.listDeviceIds();
372
+ const entries = [];
373
+ const refused = [];
374
+ for (const deviceId of [...ids].toSorted((a, b) => a - b)) {
375
+ let row;
376
+ try {
377
+ row = await deps.readDeviceStore(deviceId);
378
+ } catch (err) {
379
+ refused.push({
380
+ deviceId,
381
+ reason: `read failed: ${errMsg(err)}`
382
+ });
383
+ continue;
384
+ }
385
+ const keys = presentBoundKeys(row, deps.boundKeys);
386
+ if (keys.length === 0) continue;
387
+ if (input.dryRun) {
388
+ entries.push({
389
+ deviceId,
390
+ keys
391
+ });
392
+ continue;
393
+ }
394
+ const kept = { ...row };
395
+ for (const k of keys) delete kept[k];
396
+ try {
397
+ await deps.clearDeviceStore(deviceId);
398
+ } catch (err) {
399
+ refused.push({
400
+ deviceId,
401
+ reason: `clear failed: ${errMsg(err)}`
402
+ });
403
+ continue;
404
+ }
405
+ try {
406
+ if (Object.keys(kept).length > 0) await deps.writeDeviceStore(deviceId, kept);
407
+ entries.push({
408
+ deviceId,
409
+ keys
410
+ });
411
+ } catch (err) {
412
+ await deps.writeDeviceStore(deviceId, row).catch(() => void 0);
413
+ refused.push({
414
+ deviceId,
415
+ reason: `write failed, row restored: ${errMsg(err)}`
416
+ });
417
+ } finally {
418
+ deps.invalidate(deviceId);
419
+ }
420
+ }
421
+ return {
422
+ entries,
423
+ refused
424
+ };
425
+ }
426
+ //#endregion
427
+ //#region src/detection-pipeline/model-format-facts.ts
428
+ /**
429
+ * Two per-format facts `getSchema` reports beside `downloaded`, for Model
430
+ * Studio → Installed (one row per model × format on a node).
431
+ *
432
+ * - {@link modelOnDiskState} — `current` / `stale` / `missing`. `downloaded`
433
+ * alone is `current`; it cannot tell a copy that is on disk but not proven
434
+ * at its catalog revision (D743/D744) from no copy at all, and those are
435
+ * different answers to "what does this node hold" — a stale copy is still
436
+ * bytes on the disk, still reclaimable, and is replaced on its next ensure.
437
+ * - {@link formatPrecision} — the numeric precision of the BUILD, only when
438
+ * the build says so. An unsuffixed OpenVINO IR is FP16 for one family and
439
+ * FP32 for another (`scripts/build-camstack-models.py`), so this answers
440
+ * `undefined` rather than guess.
441
+ *
442
+ * Kept in the addon, not in `@camstack/system` / `@camstack/types`: both are
443
+ * host-resolved at runtime, so a new value there would reach an addon only
444
+ * with a server release, and this addon would fail to load on an older hub.
445
+ */
446
+ /** What this node holds for one (model, format). */
447
+ function modelOnDiskState(modelsDir, entry, format) {
448
+ if (entry.formats[format] === void 0) return "missing";
449
+ if ((0, _camstack_system_addon_utils.isModelDownloaded)(modelsDir, entry, format)) return "current";
450
+ const modelPath = (0, _camstack_system_addon_utils.getModelFilePath)(modelsDir, entry, format);
451
+ return modelPath !== null && node_fs.existsSync(modelPath) ? "stale" : "missing";
452
+ }
453
+ var PRECISION_TOKEN = /(?:^|[-_.])(int8|fp16|fp32)(?=[-_.]|$)/i;
454
+ /** The artefact's file name, without the directory. */
455
+ function artefactName(url) {
456
+ return url.split("/").pop() ?? url;
457
+ }
458
+ /** Precision a token in the artefact name states (`…-int8.xml`, `…_int8_edgetpu.tflite`). */
459
+ function precisionFromName(name) {
460
+ const token = PRECISION_TOKEN.exec(name)?.[1]?.toLowerCase();
461
+ if (token === "int8" || token === "fp16" || token === "fp32") return token;
462
+ }
463
+ /**
464
+ * The precision of one format's build, or `undefined` when nothing states it.
465
+ * In order: a token in the file name; an `int8` variant group (every format of
466
+ * an INT8 variant is quantised); an EdgeTPU build (the compiler accepts only
467
+ * full-integer models); a Core ML build hosted on the CamStack mirror (every
468
+ * CamStack Core ML export is FP16 — D743). Nothing else is assumed.
469
+ */
470
+ function formatPrecision(entry, format) {
471
+ const formatEntry = entry.formats[format];
472
+ if (formatEntry === void 0) return void 0;
473
+ const name = artefactName(formatEntry.url);
474
+ const named = precisionFromName(name);
475
+ if (named !== void 0) return named;
476
+ if (entry.group?.precision === "int8") return "int8";
477
+ if (format === "tflite" && /edgetpu/i.test(name)) return "int8";
478
+ if (format === "coreml" && formatEntry.url.startsWith(require_dist.hfModelUrl("camstack/camstack-models", ""))) return "fp16";
479
+ }
480
+ //#endregion
349
481
  //#region src/shared/cluster-model-source.ts
350
482
  /**
351
483
  * Where the runner gets the ONE cluster model choice per cluster-scoped step.
@@ -7521,7 +7653,7 @@ function buildNode(step, getEngine, resolveModel, onMissingVariant, resolved) {
7521
7653
  const modelEntry = resolveModelEntry(definition, variant.modelId, resolveModel);
7522
7654
  const schema = require_custom_model_catalog.getStep(step.addonId).getConfigSchema(modelEntry);
7523
7655
  const schemaDefaults = collectSchemaDefaults(schema);
7524
- const operatorSettings = require_dist.applyModelBoundSettings(step.settings, collectModelBoundKeys(schema), variant.modelId);
7656
+ const operatorSettings = require_dist.applyModelBoundSettings(step.settings, require_dist.collectModelBoundKeys(schema), variant.modelId);
7525
7657
  const mergedSettings = {
7526
7658
  ...schemaDefaults,
7527
7659
  ...operatorSettings
@@ -7560,13 +7692,6 @@ function collectSchemaDefaults(schema) {
7560
7692
  walkFieldsForDefaults(schema, out);
7561
7693
  return out;
7562
7694
  }
7563
- /** The keys of every `bindsToModel` field of a schema, groups flattened (D738). */
7564
- function collectModelBoundKeys(fields) {
7565
- return fields.flatMap((field) => {
7566
- if (field.type === "group") return collectModelBoundKeys(field.fields);
7567
- return "key" in field && "bindsToModel" in field && field.bindsToModel === true ? [field.key] : [];
7568
- });
7569
- }
7570
7695
  /**
7571
7696
  * The operator settings of `stepId` as the model that RUNS sees them (D738):
7572
7697
  * a model-bound value made for another model is dropped and binding keys are
@@ -7575,7 +7700,7 @@ function collectModelBoundKeys(fields) {
7575
7700
  * same binding as the layers `buildNode` merges.
7576
7701
  */
7577
7702
  function resolveOperatorSettingsForModel(stepId, settings, runningModelId) {
7578
- return require_dist.applyModelBoundSettings(settings, collectModelBoundKeys(require_custom_model_catalog.getStep(stepId).getConfigSchema()), runningModelId) ?? {};
7703
+ return require_dist.applyModelBoundSettings(settings, require_dist.collectModelBoundKeys(require_custom_model_catalog.getStep(stepId).getConfigSchema()), runningModelId) ?? {};
7579
7704
  }
7580
7705
  function walkFieldsForDefaults(fields, out) {
7581
7706
  for (const field of fields) {
@@ -8429,6 +8554,8 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8429
8554
  readDeviceStore;
8430
8555
  /** Delete all per-device settings for a device (used by `clearDeviceOverrides`). */
8431
8556
  clearDeviceStore;
8557
+ /** Merge a patch into one device's settings (Best settings' keep-the-rest rewrite, D745). */
8558
+ writeDeviceStore;
8432
8559
  /**
8433
8560
  * The per-device overrides the FRAME path reads, kept fresh off that path.
8434
8561
  *
@@ -8448,6 +8575,8 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8448
8575
  this.readDeviceStore = settings.readDeviceStore ?? (async () => ({}));
8449
8576
  const clearDeviceStore = settings.clearDeviceStore;
8450
8577
  this.clearDeviceStore = clearDeviceStore ? (deviceId) => clearDeviceStore.call(settings, deviceId) : async () => void 0;
8578
+ const writeDeviceStore = settings.writeDeviceStore;
8579
+ this.writeDeviceStore = writeDeviceStore ? (deviceId, patch) => writeDeviceStore.call(settings, deviceId, patch) : async () => void 0;
8451
8580
  this.deviceOverrides = new DeviceOverrideMirror({
8452
8581
  read: (deviceId) => this.readDeviceStore(deviceId),
8453
8582
  onRefreshFailed: (deviceId, err) => this.log.warn("per-device detection overrides refresh failed — serving the last value", {
@@ -8463,6 +8592,25 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8463
8592
  } });
8464
8593
  }
8465
8594
  /**
8595
+ * Record the revision of every catalog model already on this node whose
8596
+ * weight file hashes to it (D744), so the model listing reports those copies
8597
+ * as downloaded without fetching them again. Background and offline: it
8598
+ * reads files only. A copy holding other bytes is left for `ensureModel`,
8599
+ * which fetches it the next time something needs it.
8600
+ */
8601
+ adoptHostedModelRevisions() {
8602
+ const entries = require_custom_model_catalog.ALL_PIPELINE_STEPS.flatMap((s) => s.definition.models);
8603
+ (0, _camstack_system_addon_utils.adoptModelRevisions)(this.modelsDir, entries).then((report) => {
8604
+ if (report.adopted.length === 0 && report.stale.length === 0) return;
8605
+ this.log.info("Model copies checked against their mirror revision", { meta: {
8606
+ adopted: report.adopted.length,
8607
+ stale: report.stale
8608
+ } });
8609
+ }, (err) => {
8610
+ this.log.warn("Model revision check failed — copies are proven on their next download", { meta: { error: require_dist.errMsg(err) } });
8611
+ });
8612
+ }
8613
+ /**
8466
8614
  * Call after construction. The node-default engine is always DERIVED live
8467
8615
  * from this node's own hardware (there is no persisted operator override
8468
8616
  * anymore — the elected single-engine cascade was removed). Defer the derive
@@ -8471,6 +8619,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8471
8619
  async init() {
8472
8620
  this.needsAutoPick = true;
8473
8621
  this.log.info("Node-default engine derive deferred to setApi()");
8622
+ this.adoptHostedModelRevisions();
8474
8623
  if (!this.poolMemoryGuard) {
8475
8624
  this.poolMemoryGuard = createDetectionPoolMemoryGuard({
8476
8625
  listPools: () => this.listGuardedPools(),
@@ -11006,6 +11155,41 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
11006
11155
  };
11007
11156
  }
11008
11157
  /**
11158
+ * Best settings (D745): list — or, unless `dryRun`, remove — the model-bound
11159
+ * thresholds of the per-camera detector store. See
11160
+ * `model-bound-device-overrides.ts`.
11161
+ */
11162
+ async clearModelBoundDeviceOverrides(input) {
11163
+ const result = await clearModelBoundDeviceOverrides({
11164
+ listDeviceIds: async () => {
11165
+ const api = this.addonCtx?.api;
11166
+ if (!api) throw new Error("clearModelBoundDeviceOverrides: ctx.api unavailable");
11167
+ return (await api.deviceManager.listAll.query({ projection: "slim" })).map((d) => d.id);
11168
+ },
11169
+ readDeviceStore: (deviceId) => this.readDeviceStore(deviceId),
11170
+ clearDeviceStore: (deviceId) => this.clearDeviceStore(deviceId),
11171
+ writeDeviceStore: (deviceId, patch) => this.writeDeviceStore(deviceId, patch),
11172
+ invalidate: (deviceId) => this.deviceOverrides.invalidate(deviceId),
11173
+ boundKeys: require_dist.collectModelBoundKeys(require_custom_model_catalog.getStep("object-detection").getConfigSchema())
11174
+ }, input);
11175
+ if (!input.dryRun) for (const entry of result.entries) this.log.info("best settings: per-camera detector thresholds cleared", {
11176
+ tags: { deviceId: entry.deviceId },
11177
+ meta: {
11178
+ deviceId: entry.deviceId,
11179
+ keys: entry.keys
11180
+ }
11181
+ });
11182
+ for (const r of result.refused) this.log.warn("best settings: per-camera detector thresholds not cleared", {
11183
+ tags: { deviceId: r.deviceId },
11184
+ meta: {
11185
+ deviceId: r.deviceId,
11186
+ reason: r.reason,
11187
+ dryRun: input.dryRun
11188
+ }
11189
+ });
11190
+ return result;
11191
+ }
11192
+ /**
11009
11193
  * Clear the per-device pipeline-step overrides for every known device.
11010
11194
  * Returns the count of devices whose store was cleared. There is no
11011
11195
  * bulk-list primitive over the per-device store, so devices are
@@ -11266,10 +11450,17 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
11266
11450
  models: availableModels.map((m) => ({
11267
11451
  id: m.id,
11268
11452
  name: m.name,
11269
- formats: Object.fromEntries(Object.entries(m.formats).map(([f, entry]) => [f, {
11270
- downloaded: (0, _camstack_system_addon_utils.isModelDownloaded)(modelsDir, m, f),
11271
- sizeMB: entry.sizeMB
11272
- }])),
11453
+ formats: Object.fromEntries(Object.entries(m.formats).map(([f, entry]) => {
11454
+ const format = f;
11455
+ const onDisk = modelOnDiskState(modelsDir, m, format);
11456
+ const precision = formatPrecision(m, format);
11457
+ return [f, {
11458
+ downloaded: onDisk === "current",
11459
+ sizeMB: entry.sizeMB,
11460
+ onDisk,
11461
+ ...precision !== void 0 ? { precision } : {}
11462
+ }];
11463
+ })),
11273
11464
  ...m.group ? { group: m.group } : {},
11274
11465
  ...m.legacy !== void 0 ? { legacy: m.legacy } : {},
11275
11466
  provider: m.provider ?? "camstack",