@camstack/addon-pipeline 1.1.53 → 1.1.54

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 (33) hide show
  1. package/dist/audio-analyzer/index.js +1 -1
  2. package/dist/audio-analyzer/index.mjs +1 -1
  3. package/dist/detection-pipeline/index.js +146 -7
  4. package/dist/detection-pipeline/index.mjs +146 -7
  5. package/dist/{dist-DWb62H5U.js → dist-BbaoC680.js} +110 -7
  6. package/dist/{dist-BalxNwOt.mjs → dist-CEcTeu1h.mjs} +110 -7
  7. package/dist/motion-wasm/index.js +1 -1
  8. package/dist/motion-wasm/index.mjs +1 -1
  9. package/dist/pipeline-runner/index.js +114 -5
  10. package/dist/pipeline-runner/index.mjs +114 -5
  11. package/dist/recorder/index.js +1 -1
  12. package/dist/recorder/index.mjs +1 -1
  13. package/dist/{remote-source-plane-BCJW5CvF.mjs → remote-source-plane-CNCqC_XG.mjs} +1 -1
  14. package/dist/{remote-source-plane-CZpzIVro.js → remote-source-plane-vN45KFSm.js} +1 -1
  15. package/dist/session-decode/decode-worker-child.js +319 -35
  16. package/dist/session-decode/decode-worker-child.mjs +319 -35
  17. package/dist/stream-broker/_stub.js +2 -2
  18. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DIN3CcRP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-HS0tc6Sa.mjs} +3 -3
  19. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B3gTdHEh.mjs +26 -0
  20. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-C9fwKMfg.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-B_v5r5ya.mjs} +1 -1
  21. package/dist/stream-broker/{hostInit-CGUEq--X.mjs → hostInit-DgohfEDA.mjs} +3 -3
  22. package/dist/stream-broker/index.js +2 -2
  23. package/dist/stream-broker/index.mjs +2 -2
  24. package/dist/stream-broker/remoteEntry.js +1 -1
  25. package/dist/{worker-protocol-pk7qdYXt.mjs → worker-protocol-DGIt_waM.mjs} +6 -0
  26. package/dist/{worker-protocol-BCfO8gUF.js → worker-protocol-DkL6GDxe.js} +6 -0
  27. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-CqOe8eYa.js → MaskShapeCanvas-DI4BY7W2-CA2Hd6xx.js} +1 -1
  28. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-CZyLeUnd.js → MotionZonesSettings-NcxxQN8r-DUN1VeC7.js} +1 -1
  29. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-Cn0hGZnu.js → PrivacyMaskSettings-APgPLF7p-BqZIAU5s.js} +1 -1
  30. package/embed-dist/assets/{index-DRl4XYjA.js → index-CMkYypxB.js} +10 -10
  31. package/embed-dist/index.html +1 -1
  32. package/package.json +1 -1
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-o4tu_xuc.mjs +0 -26
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-D6vf50IK.js");
6
- const require_dist = require("../dist-DWb62H5U.js");
6
+ const require_dist = require("../dist-BbaoC680.js");
7
7
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
8
8
  const require_model_download_service_C_IHWnXx = require("../model-download-service-C-IHWnXx-BLXzxpRB.js");
9
9
  let node_fs = require("node:fs");
@@ -1,5 +1,5 @@
1
1
  import { t as __require } from "../chunk-BdkLduGY.mjs";
2
- import { C as mapAudioLabelToMacro, I as errMsg, L as BaseAddon, U as hydrateSchema, h as audioAnalyzerCapability, l as HF_BASE_URL, m as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG } from "../dist-BalxNwOt.mjs";
2
+ import { C as mapAudioLabelToMacro, I as errMsg, L as BaseAddon, U as hydrateSchema, h as audioAnalyzerCapability, l as HF_BASE_URL, m as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG } from "../dist-CEcTeu1h.mjs";
3
3
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
4
4
  import { r as downloadFile } from "../model-download-service-C-IHWnXx-BPy6aoAx.mjs";
5
5
  import * as fs from "node:fs";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-D6vf50IK.js");
6
- const require_dist = require("../dist-DWb62H5U.js");
6
+ const require_dist = require("../dist-BbaoC680.js");
7
7
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
8
8
  const require_model_download_service_C_IHWnXx = require("../model-download-service-C-IHWnXx-BLXzxpRB.js");
9
9
  let _camstack_shm_ring = require("@camstack/shm-ring");
@@ -3723,6 +3723,93 @@ function bboxShortSide(bbox) {
3723
3723
  return Math.min(bbox[2] - bbox[0], bbox[3] - bbox[1]);
3724
3724
  }
3725
3725
  /**
3726
+ * Padded region (clamped to the frame) around a face bbox — the area a native
3727
+ * crop must cover so the warp has room around a tilted / edge face. Mirrors the
3728
+ * padding {@link alignFaceCrop} applies internally (`padRatio` default 0.4), so
3729
+ * the native and fallback paths sample the same neighbourhood.
3730
+ */
3731
+ function paddedFaceRegion(faceBbox, imageWidth, imageHeight, padRatio = .4) {
3732
+ const bw = faceBbox[2] - faceBbox[0];
3733
+ const bh = faceBbox[3] - faceBbox[1];
3734
+ const padX = bw * padRatio;
3735
+ const padY = bh * padRatio;
3736
+ return {
3737
+ left: Math.max(0, Math.floor(faceBbox[0] - padX)),
3738
+ top: Math.max(0, Math.floor(faceBbox[1] - padY)),
3739
+ right: Math.min(imageWidth, Math.ceil(faceBbox[2] + padX)),
3740
+ bottom: Math.min(imageHeight, Math.ceil(faceBbox[3] + padY))
3741
+ };
3742
+ }
3743
+ /**
3744
+ * Warp a raw RGB crop of `region` (native-resolution pixels of exactly that
3745
+ * detection-space region) so `landmarksImageSpace` land on the ArcFace
3746
+ * template. Landmarks are mapped from image space into the crop's local pixel
3747
+ * space by the per-axis region→crop scale (handles `maxWidth` downscale of the
3748
+ * native crop). Channels default to RGB (3) — the format the decode worker's
3749
+ * native surface produces.
3750
+ */
3751
+ async function alignFaceCropFromRgb(rgb, region, landmarksImageSpace, opts = {}) {
3752
+ const outSize = opts.outSize ?? 112;
3753
+ const quality = opts.quality ?? 95;
3754
+ const channels = opts.channels ?? 3;
3755
+ const regionW = region.right - region.left;
3756
+ const regionH = region.bottom - region.top;
3757
+ if (regionW < 1 || regionH < 1) throw new Error(`alignFaceCropFromRgb: degenerate region ${regionW}x${regionH}`);
3758
+ if (rgb.width < 2 || rgb.height < 2) throw new Error(`alignFaceCropFromRgb: degenerate crop ${rgb.width}x${rgb.height}`);
3759
+ const scaleX = rgb.width / regionW;
3760
+ const scaleY = rgb.height / regionH;
3761
+ const localLandmarks = landmarksImageSpace.map((l) => ({
3762
+ x: (l.x - region.left) * scaleX,
3763
+ y: (l.y - region.top) * scaleY
3764
+ }));
3765
+ const aligned = warpToTemplate({
3766
+ data: rgb.bytes,
3767
+ width: rgb.width,
3768
+ height: rgb.height,
3769
+ channels
3770
+ }, localLandmarks, opts.template ?? ARCFACE_TEMPLATE_112, outSize);
3771
+ return {
3772
+ jpeg: await (0, sharp.default)(Buffer.from(aligned.data), { raw: {
3773
+ width: aligned.width,
3774
+ height: aligned.height,
3775
+ channels: aligned.channels
3776
+ } }).jpeg({ quality }).toBuffer(),
3777
+ width: aligned.width,
3778
+ height: aligned.height
3779
+ };
3780
+ }
3781
+ /**
3782
+ * Produce a landmark-aligned face crop, preferring a NATIVE-resolution crop
3783
+ * (design B — the quality win) and FALLING BACK to today's downscaled
3784
+ * full-frame alignment on any native miss/error (never worse than before).
3785
+ *
3786
+ * The native path requests the padded face region from `nativeCropProvider`
3787
+ * (a best-effort local cap round-trip bound to this frame), warps the native
3788
+ * pixels; the fallback path re-uses {@link alignFaceCrop} on the downscaled
3789
+ * JPEG. ArcFace input is a fixed `outSize`×`outSize` either way — only the crop
3790
+ * SOURCE changes, so model cost is unchanged.
3791
+ */
3792
+ async function buildAlignedFaceCrop(args) {
3793
+ if (args.nativeCropProvider) try {
3794
+ const region = paddedFaceRegion(args.faceBbox, args.imageWidth, args.imageHeight);
3795
+ const roi = {
3796
+ x: region.left / args.imageWidth,
3797
+ y: region.top / args.imageHeight,
3798
+ w: (region.right - region.left) / args.imageWidth,
3799
+ h: (region.bottom - region.top) / args.imageHeight
3800
+ };
3801
+ const native = await args.nativeCropProvider(roi, args.nativeMaxWidth);
3802
+ if (native && native.width >= 2 && native.height >= 2 && native.bytes.length >= native.width * native.height * 3) return {
3803
+ ...await alignFaceCropFromRgb(native, region, args.landmarksImageSpace, { outSize: args.outSize }),
3804
+ source: "native"
3805
+ };
3806
+ } catch {}
3807
+ return {
3808
+ ...await alignFaceCrop(args.fullFrameJpeg, args.faceBbox, args.landmarksImageSpace, args.imageWidth, args.imageHeight, { outSize: args.outSize }),
3809
+ source: "fallback"
3810
+ };
3811
+ }
3812
+ /**
3726
3813
  * Produce an aligned 112x112 JPEG of a face from the full-frame JPEG and the
3727
3814
  * face's 5 landmarks (in absolute image-space coordinates). Decodes a padded
3728
3815
  * region around the face bbox to raw RGB, warps to the ArcFace template, and
@@ -4149,6 +4236,14 @@ function formatTopResult(output) {
4149
4236
  * resolution — a deeper change tracked separately.
4150
4237
  */
4151
4238
  var DEFAULT_MIN_FACE_SIZE_PX = 28;
4239
+ /**
4240
+ * Cap (px) on the width of the NATIVE face crop fetched for embedding (design
4241
+ * B). The arcface input is a fixed 112² warp, so a wider native crop buys no
4242
+ * embedding quality past a modest margin but does inflate the per-face transport
4243
+ * of the best-effort native-crop round-trip. 320px keeps a distant face well
4244
+ * above the downscaled detection resolution while bounding the crop payload.
4245
+ */
4246
+ var NATIVE_FACE_CROP_MAX_WIDTH = 320;
4152
4247
  var PipelineExecutor = class {
4153
4248
  opts;
4154
4249
  constructor(opts) {
@@ -4178,7 +4273,7 @@ var PipelineExecutor = class {
4178
4273
  *
4179
4274
  * @returns FrameResult + optional trace
4180
4275
  */
4181
- async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts) {
4276
+ async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts, nativeFaceCropProvider) {
4182
4277
  const startMs = Date.now();
4183
4278
  const verbosity = runOpts?.traceVerbosity ?? "off";
4184
4279
  const traceBuilder = new ExecutionTraceBuilder(verbosity, deviceId, imageWidth, imageHeight, this.opts.engineRuntime);
@@ -4216,7 +4311,7 @@ var PipelineExecutor = class {
4216
4311
  continue;
4217
4312
  }
4218
4313
  try {
4219
- await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg);
4314
+ await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, nativeFaceCropProvider);
4220
4315
  } catch (err) {
4221
4316
  this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
4222
4317
  tags: { deviceId },
@@ -4318,7 +4413,7 @@ var PipelineExecutor = class {
4318
4413
  });
4319
4414
  return output;
4320
4415
  }
4321
- async executeChildren(children, parentDetection, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg) {
4416
+ async executeChildren(children, parentDetection, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, nativeFaceCropProvider) {
4322
4417
  for (const child of children) {
4323
4418
  if (!this.matchesInputClasses(parentDetection.macroClass, child.inputClasses)) continue;
4324
4419
  const minParentScore = child.settings?.minParentScore ?? child.definition?.defaultMinParentScore;
@@ -4345,7 +4440,18 @@ var PipelineExecutor = class {
4345
4440
  }
4346
4441
  const lms = parentDetection.landmarks;
4347
4442
  if (lms && lms.length >= 5) {
4348
- const aligned = await alignFaceCrop(fullFrameJpeg, parentDetection.bbox, lms, imageWidth, imageHeight, { outSize: modelEntry.inputSize.width });
4443
+ const aligned = await buildAlignedFaceCrop({
4444
+ fullFrameJpeg,
4445
+ faceBbox: parentDetection.bbox,
4446
+ landmarksImageSpace: lms,
4447
+ imageWidth,
4448
+ imageHeight,
4449
+ outSize: modelEntry.inputSize.width,
4450
+ ...nativeFaceCropProvider ? {
4451
+ nativeCropProvider: nativeFaceCropProvider,
4452
+ nativeMaxWidth: NATIVE_FACE_CROP_MAX_WIDTH
4453
+ } : {}
4454
+ });
4349
4455
  cropJpegBuf = aligned.jpeg;
4350
4456
  cropW = aligned.width;
4351
4457
  cropH = aligned.height;
@@ -4379,7 +4485,7 @@ var PipelineExecutor = class {
4379
4485
  y: l.y + py1
4380
4486
  }));
4381
4487
  }
4382
- await this.executeChildren(child.children, detail, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg);
4488
+ await this.executeChildren(child.children, detail, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, nativeFaceCropProvider);
4383
4489
  }
4384
4490
  }
4385
4491
  } catch (err) {
@@ -5871,6 +5977,38 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5871
5977
  debug: { totalInferenceMs: 0 }
5872
5978
  };
5873
5979
  }
5980
+ /**
5981
+ * Build the design-B native-face-crop provider for a runtime frame. Present
5982
+ * ONLY when the frame arrived as a retention `frameHandle` (the key the owning
5983
+ * pipeline-runner registered the frame's native surface under) and the sibling
5984
+ * `pipeline-runner` cap is reachable via `ctx.api`. Each call is a best-effort
5985
+ * round-trip pinned to the frame's OWNING node (`nodePin(handle.nodeId)` — the
5986
+ * node that decoded it, i.e. THIS node for a local frame, never a cross-node
5987
+ * hop) that returns the native ROI or `null` on a miss; the executor then
5988
+ * falls back to the downscaled crop, so behaviour is never worse than before.
5989
+ */
5990
+ buildNativeFaceCropProvider(handle) {
5991
+ if (!handle) return void 0;
5992
+ const api = this.addonCtx?.api;
5993
+ if (!api) return void 0;
5994
+ return async (roi, maxWidth) => {
5995
+ try {
5996
+ const native = await api.pipelineRunner.getNativeCrop.query({
5997
+ handle,
5998
+ bbox: roi,
5999
+ ...maxWidth !== void 0 ? { maxWidth } : {}
6000
+ }, require_dist.nodePin(handle.nodeId));
6001
+ if (!native || native.width <= 0 || native.height <= 0) return null;
6002
+ return {
6003
+ bytes: native.bytes,
6004
+ width: native.width,
6005
+ height: native.height
6006
+ };
6007
+ } catch {
6008
+ return null;
6009
+ }
6010
+ };
6011
+ }
5874
6012
  async runPipeline(input, onProgress) {
5875
6013
  const nodeId = this.addonCtx?.kernel?.localNodeId ?? "hub";
5876
6014
  const sessionId = input.sessionId ?? `run-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
@@ -6127,7 +6265,8 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
6127
6265
  const effectiveDeviceId = input.deviceId ?? 0;
6128
6266
  const deviceOverrides = effectiveDeviceId > 0 ? await this.readDeviceStore(effectiveDeviceId) : {};
6129
6267
  const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
6130
- const { result, trace } = await executor.run(effectiveTree, rootInput, jpegProvider, imageWidth, imageHeight, effectiveDeviceId, { traceVerbosity: isRuntime ? this.eventBus ? "summary" : "off" : "full" });
6268
+ const nativeFaceCropProvider = this.buildNativeFaceCropProvider(input.frameHandle);
6269
+ const { result, trace } = await executor.run(effectiveTree, rootInput, jpegProvider, imageWidth, imageHeight, effectiveDeviceId, { traceVerbosity: isRuntime ? this.eventBus ? "summary" : "off" : "full" }, nativeFaceCropProvider);
6131
6270
  if (isRuntime) {
6132
6271
  if (trace && this.eventBus) this.eventBus.emit(require_dist.createEvent(require_dist.EventCategory.PipelineTrace, {
6133
6272
  type: "device",
@@ -1,5 +1,5 @@
1
1
  import { t as __require } from "../chunk-BdkLduGY.mjs";
2
- import { H as createEvent, I as errMsg, L as BaseAddon, O as pipelineExecutorCapability, P as supportedRuntimes$1, S as hfModelUrl, U as hydrateSchema, V as EventCategory, X as sleep, a as COCO_TO_MACRO, b as detectionPipelineCapability, f as YAMNET_TO_MACRO, i as COCO_80_LABELS, j as runtimeDevices$1, q as parseJsonUnknown, r as AUDIO_MACRO_LABELS, t as APPLE_SA_TO_MACRO, v as defaultDeviceFor$1, x as evaluateZoneRules } from "../dist-BalxNwOt.mjs";
2
+ import { D as nodePin, H as createEvent, I as errMsg, L as BaseAddon, O as pipelineExecutorCapability, P as supportedRuntimes$1, S as hfModelUrl, U as hydrateSchema, V as EventCategory, X as sleep, a as COCO_TO_MACRO, b as detectionPipelineCapability, f as YAMNET_TO_MACRO, i as COCO_80_LABELS, j as runtimeDevices$1, q as parseJsonUnknown, r as AUDIO_MACRO_LABELS, t as APPLE_SA_TO_MACRO, v as defaultDeviceFor$1, x as evaluateZoneRules } from "../dist-CEcTeu1h.mjs";
3
3
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
4
4
  import { a as isModelDownloaded, i as ensureModel, n as deleteModelFromDisk } from "../model-download-service-C-IHWnXx-BPy6aoAx.mjs";
5
5
  import { FrameRingReaderCache } from "@camstack/shm-ring";
@@ -3715,6 +3715,93 @@ function bboxShortSide(bbox) {
3715
3715
  return Math.min(bbox[2] - bbox[0], bbox[3] - bbox[1]);
3716
3716
  }
3717
3717
  /**
3718
+ * Padded region (clamped to the frame) around a face bbox — the area a native
3719
+ * crop must cover so the warp has room around a tilted / edge face. Mirrors the
3720
+ * padding {@link alignFaceCrop} applies internally (`padRatio` default 0.4), so
3721
+ * the native and fallback paths sample the same neighbourhood.
3722
+ */
3723
+ function paddedFaceRegion(faceBbox, imageWidth, imageHeight, padRatio = .4) {
3724
+ const bw = faceBbox[2] - faceBbox[0];
3725
+ const bh = faceBbox[3] - faceBbox[1];
3726
+ const padX = bw * padRatio;
3727
+ const padY = bh * padRatio;
3728
+ return {
3729
+ left: Math.max(0, Math.floor(faceBbox[0] - padX)),
3730
+ top: Math.max(0, Math.floor(faceBbox[1] - padY)),
3731
+ right: Math.min(imageWidth, Math.ceil(faceBbox[2] + padX)),
3732
+ bottom: Math.min(imageHeight, Math.ceil(faceBbox[3] + padY))
3733
+ };
3734
+ }
3735
+ /**
3736
+ * Warp a raw RGB crop of `region` (native-resolution pixels of exactly that
3737
+ * detection-space region) so `landmarksImageSpace` land on the ArcFace
3738
+ * template. Landmarks are mapped from image space into the crop's local pixel
3739
+ * space by the per-axis region→crop scale (handles `maxWidth` downscale of the
3740
+ * native crop). Channels default to RGB (3) — the format the decode worker's
3741
+ * native surface produces.
3742
+ */
3743
+ async function alignFaceCropFromRgb(rgb, region, landmarksImageSpace, opts = {}) {
3744
+ const outSize = opts.outSize ?? 112;
3745
+ const quality = opts.quality ?? 95;
3746
+ const channels = opts.channels ?? 3;
3747
+ const regionW = region.right - region.left;
3748
+ const regionH = region.bottom - region.top;
3749
+ if (regionW < 1 || regionH < 1) throw new Error(`alignFaceCropFromRgb: degenerate region ${regionW}x${regionH}`);
3750
+ if (rgb.width < 2 || rgb.height < 2) throw new Error(`alignFaceCropFromRgb: degenerate crop ${rgb.width}x${rgb.height}`);
3751
+ const scaleX = rgb.width / regionW;
3752
+ const scaleY = rgb.height / regionH;
3753
+ const localLandmarks = landmarksImageSpace.map((l) => ({
3754
+ x: (l.x - region.left) * scaleX,
3755
+ y: (l.y - region.top) * scaleY
3756
+ }));
3757
+ const aligned = warpToTemplate({
3758
+ data: rgb.bytes,
3759
+ width: rgb.width,
3760
+ height: rgb.height,
3761
+ channels
3762
+ }, localLandmarks, opts.template ?? ARCFACE_TEMPLATE_112, outSize);
3763
+ return {
3764
+ jpeg: await sharp(Buffer.from(aligned.data), { raw: {
3765
+ width: aligned.width,
3766
+ height: aligned.height,
3767
+ channels: aligned.channels
3768
+ } }).jpeg({ quality }).toBuffer(),
3769
+ width: aligned.width,
3770
+ height: aligned.height
3771
+ };
3772
+ }
3773
+ /**
3774
+ * Produce a landmark-aligned face crop, preferring a NATIVE-resolution crop
3775
+ * (design B — the quality win) and FALLING BACK to today's downscaled
3776
+ * full-frame alignment on any native miss/error (never worse than before).
3777
+ *
3778
+ * The native path requests the padded face region from `nativeCropProvider`
3779
+ * (a best-effort local cap round-trip bound to this frame), warps the native
3780
+ * pixels; the fallback path re-uses {@link alignFaceCrop} on the downscaled
3781
+ * JPEG. ArcFace input is a fixed `outSize`×`outSize` either way — only the crop
3782
+ * SOURCE changes, so model cost is unchanged.
3783
+ */
3784
+ async function buildAlignedFaceCrop(args) {
3785
+ if (args.nativeCropProvider) try {
3786
+ const region = paddedFaceRegion(args.faceBbox, args.imageWidth, args.imageHeight);
3787
+ const roi = {
3788
+ x: region.left / args.imageWidth,
3789
+ y: region.top / args.imageHeight,
3790
+ w: (region.right - region.left) / args.imageWidth,
3791
+ h: (region.bottom - region.top) / args.imageHeight
3792
+ };
3793
+ const native = await args.nativeCropProvider(roi, args.nativeMaxWidth);
3794
+ if (native && native.width >= 2 && native.height >= 2 && native.bytes.length >= native.width * native.height * 3) return {
3795
+ ...await alignFaceCropFromRgb(native, region, args.landmarksImageSpace, { outSize: args.outSize }),
3796
+ source: "native"
3797
+ };
3798
+ } catch {}
3799
+ return {
3800
+ ...await alignFaceCrop(args.fullFrameJpeg, args.faceBbox, args.landmarksImageSpace, args.imageWidth, args.imageHeight, { outSize: args.outSize }),
3801
+ source: "fallback"
3802
+ };
3803
+ }
3804
+ /**
3718
3805
  * Produce an aligned 112x112 JPEG of a face from the full-frame JPEG and the
3719
3806
  * face's 5 landmarks (in absolute image-space coordinates). Decodes a padded
3720
3807
  * region around the face bbox to raw RGB, warps to the ArcFace template, and
@@ -4141,6 +4228,14 @@ function formatTopResult(output) {
4141
4228
  * resolution — a deeper change tracked separately.
4142
4229
  */
4143
4230
  var DEFAULT_MIN_FACE_SIZE_PX = 28;
4231
+ /**
4232
+ * Cap (px) on the width of the NATIVE face crop fetched for embedding (design
4233
+ * B). The arcface input is a fixed 112² warp, so a wider native crop buys no
4234
+ * embedding quality past a modest margin but does inflate the per-face transport
4235
+ * of the best-effort native-crop round-trip. 320px keeps a distant face well
4236
+ * above the downscaled detection resolution while bounding the crop payload.
4237
+ */
4238
+ var NATIVE_FACE_CROP_MAX_WIDTH = 320;
4144
4239
  var PipelineExecutor = class {
4145
4240
  opts;
4146
4241
  constructor(opts) {
@@ -4170,7 +4265,7 @@ var PipelineExecutor = class {
4170
4265
  *
4171
4266
  * @returns FrameResult + optional trace
4172
4267
  */
4173
- async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts) {
4268
+ async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts, nativeFaceCropProvider) {
4174
4269
  const startMs = Date.now();
4175
4270
  const verbosity = runOpts?.traceVerbosity ?? "off";
4176
4271
  const traceBuilder = new ExecutionTraceBuilder(verbosity, deviceId, imageWidth, imageHeight, this.opts.engineRuntime);
@@ -4208,7 +4303,7 @@ var PipelineExecutor = class {
4208
4303
  continue;
4209
4304
  }
4210
4305
  try {
4211
- await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg);
4306
+ await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, nativeFaceCropProvider);
4212
4307
  } catch (err) {
4213
4308
  this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
4214
4309
  tags: { deviceId },
@@ -4310,7 +4405,7 @@ var PipelineExecutor = class {
4310
4405
  });
4311
4406
  return output;
4312
4407
  }
4313
- async executeChildren(children, parentDetection, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg) {
4408
+ async executeChildren(children, parentDetection, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, nativeFaceCropProvider) {
4314
4409
  for (const child of children) {
4315
4410
  if (!this.matchesInputClasses(parentDetection.macroClass, child.inputClasses)) continue;
4316
4411
  const minParentScore = child.settings?.minParentScore ?? child.definition?.defaultMinParentScore;
@@ -4337,7 +4432,18 @@ var PipelineExecutor = class {
4337
4432
  }
4338
4433
  const lms = parentDetection.landmarks;
4339
4434
  if (lms && lms.length >= 5) {
4340
- const aligned = await alignFaceCrop(fullFrameJpeg, parentDetection.bbox, lms, imageWidth, imageHeight, { outSize: modelEntry.inputSize.width });
4435
+ const aligned = await buildAlignedFaceCrop({
4436
+ fullFrameJpeg,
4437
+ faceBbox: parentDetection.bbox,
4438
+ landmarksImageSpace: lms,
4439
+ imageWidth,
4440
+ imageHeight,
4441
+ outSize: modelEntry.inputSize.width,
4442
+ ...nativeFaceCropProvider ? {
4443
+ nativeCropProvider: nativeFaceCropProvider,
4444
+ nativeMaxWidth: NATIVE_FACE_CROP_MAX_WIDTH
4445
+ } : {}
4446
+ });
4341
4447
  cropJpegBuf = aligned.jpeg;
4342
4448
  cropW = aligned.width;
4343
4449
  cropH = aligned.height;
@@ -4371,7 +4477,7 @@ var PipelineExecutor = class {
4371
4477
  y: l.y + py1
4372
4478
  }));
4373
4479
  }
4374
- await this.executeChildren(child.children, detail, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg);
4480
+ await this.executeChildren(child.children, detail, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, nativeFaceCropProvider);
4375
4481
  }
4376
4482
  }
4377
4483
  } catch (err) {
@@ -5863,6 +5969,38 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5863
5969
  debug: { totalInferenceMs: 0 }
5864
5970
  };
5865
5971
  }
5972
+ /**
5973
+ * Build the design-B native-face-crop provider for a runtime frame. Present
5974
+ * ONLY when the frame arrived as a retention `frameHandle` (the key the owning
5975
+ * pipeline-runner registered the frame's native surface under) and the sibling
5976
+ * `pipeline-runner` cap is reachable via `ctx.api`. Each call is a best-effort
5977
+ * round-trip pinned to the frame's OWNING node (`nodePin(handle.nodeId)` — the
5978
+ * node that decoded it, i.e. THIS node for a local frame, never a cross-node
5979
+ * hop) that returns the native ROI or `null` on a miss; the executor then
5980
+ * falls back to the downscaled crop, so behaviour is never worse than before.
5981
+ */
5982
+ buildNativeFaceCropProvider(handle) {
5983
+ if (!handle) return void 0;
5984
+ const api = this.addonCtx?.api;
5985
+ if (!api) return void 0;
5986
+ return async (roi, maxWidth) => {
5987
+ try {
5988
+ const native = await api.pipelineRunner.getNativeCrop.query({
5989
+ handle,
5990
+ bbox: roi,
5991
+ ...maxWidth !== void 0 ? { maxWidth } : {}
5992
+ }, nodePin(handle.nodeId));
5993
+ if (!native || native.width <= 0 || native.height <= 0) return null;
5994
+ return {
5995
+ bytes: native.bytes,
5996
+ width: native.width,
5997
+ height: native.height
5998
+ };
5999
+ } catch {
6000
+ return null;
6001
+ }
6002
+ };
6003
+ }
5866
6004
  async runPipeline(input, onProgress) {
5867
6005
  const nodeId = this.addonCtx?.kernel?.localNodeId ?? "hub";
5868
6006
  const sessionId = input.sessionId ?? `run-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
@@ -6119,7 +6257,8 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
6119
6257
  const effectiveDeviceId = input.deviceId ?? 0;
6120
6258
  const deviceOverrides = effectiveDeviceId > 0 ? await this.readDeviceStore(effectiveDeviceId) : {};
6121
6259
  const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
6122
- const { result, trace } = await executor.run(effectiveTree, rootInput, jpegProvider, imageWidth, imageHeight, effectiveDeviceId, { traceVerbosity: isRuntime ? this.eventBus ? "summary" : "off" : "full" });
6260
+ const nativeFaceCropProvider = this.buildNativeFaceCropProvider(input.frameHandle);
6261
+ const { result, trace } = await executor.run(effectiveTree, rootInput, jpegProvider, imageWidth, imageHeight, effectiveDeviceId, { traceVerbosity: isRuntime ? this.eventBus ? "summary" : "off" : "full" }, nativeFaceCropProvider);
6123
6262
  if (isRuntime) {
6124
6263
  if (trace && this.eventBus) this.eventBus.emit(createEvent(EventCategory.PipelineTrace, {
6125
6264
  type: "device",
@@ -4627,7 +4627,7 @@ function _instanceof(cls, params = {}) {
4627
4627
  return inst;
4628
4628
  }
4629
4629
  //#endregion
4630
- //#region ../types/dist/sleep-b4Jf2n33.mjs
4630
+ //#region ../types/dist/sleep-BC9Yqte7.mjs
4631
4631
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4632
4632
  EventCategory["SystemBoot"] = "system.boot";
4633
4633
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -11890,6 +11890,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(ZoneSchema).read
11890
11890
  auth: "admin"
11891
11891
  }), object({ zones: array(ZoneSchema).readonly() });
11892
11892
  /**
11893
+ * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
11894
+ * decode worker resolves it against the RETAINED native frame's real pixel dims,
11895
+ * so the caller supplies only the detection-res bbox divided by the detection
11896
+ * dims — no native resolution to plumb.
11897
+ */
11898
+ var NativeCropBboxSchema = object({
11899
+ x: number(),
11900
+ y: number(),
11901
+ w: number(),
11902
+ h: number()
11903
+ });
11904
+ /** Result of a best-effort native-resolution crop (`getNativeCrop`). */
11905
+ var NativeCropResultSchema = object({
11906
+ /** Packed rgb (24-bit) pixels of the crop. */
11907
+ bytes: _instanceof(Uint8Array),
11908
+ width: number().int().positive(),
11909
+ height: number().int().positive()
11910
+ });
11911
+ /**
11893
11912
  * Per-camera tunable ranges + defaults. Single source of truth used
11894
11913
  * by both the Zod data schema (validation + default fallback) and
11895
11914
  * the device settings UI (slider min/max/step). Touch one place and
@@ -12193,7 +12212,22 @@ var pipelineRunnerCapability = {
12193
12212
  /** All per-camera metrics in one round-trip. */
12194
12213
  getAllCameraMetrics: method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()),
12195
12214
  /** List the deviceIds currently attached to this runner. */
12196
- getLocalCameras: method(_void(), array(number()).readonly())
12215
+ getLocalCameras: method(_void(), array(number()).readonly()),
12216
+ /**
12217
+ * Best-effort NATIVE-resolution crop of a retention-ring frame. Given the
12218
+ * `FrameHandle` that rode an inference-result event and a normalized `bbox`,
12219
+ * the runner asks the decode worker still holding that frame's NATIVE
12220
+ * surface to GPU/CPU-crop ONLY the ROI at native res and download just the
12221
+ * crop. Returns `null` on a miss (handle not registered, or the worker's
12222
+ * tiny native-retention ring already evicted the frame) — the caller falls
12223
+ * back to a detection-frame crop. Routed to the frame's owning node by
12224
+ * `handle.nodeId`; NEVER ships a full native frame.
12225
+ */
12226
+ getNativeCrop: method(object({
12227
+ handle: FrameHandleSchema,
12228
+ bbox: NativeCropBboxSchema,
12229
+ maxWidth: number().int().positive().optional()
12230
+ }), NativeCropResultSchema.nullable())
12197
12231
  }
12198
12232
  };
12199
12233
  object({
@@ -16443,7 +16477,17 @@ var TrackSchema = object({
16443
16477
  /** Cumulative normalized distance travelled (0..1 units = full frame width). */
16444
16478
  totalDistance: number(),
16445
16479
  state: TrackStateSchema,
16446
- active: boolean()
16480
+ active: boolean(),
16481
+ /** Deterministic key-event importance score in [0,1] (server-computed at
16482
+ * track expiry, recomputed on late label). Absent on legacy rows written
16483
+ * before scoring shipped — consumers degrade to absence / compute-on-read. */
16484
+ importance: number().optional(),
16485
+ /** Id of the track's highest-confidence ObjectEvent (its representative
16486
+ * "best" frame). Absent when the track produced no object events. */
16487
+ bestEventId: string().optional(),
16488
+ /** Tag of the importance sub-signal that dominated the score
16489
+ * (identity|dwell|proximity|class|confidence|travel|zone). */
16490
+ importanceReason: string().optional()
16447
16491
  });
16448
16492
  var BaseEventFields = {
16449
16493
  id: string(),
@@ -16508,8 +16552,18 @@ var ObjectEventSchema = object({
16508
16552
  frameHeight: number().optional(),
16509
16553
  /** MediaStore key for the crop attached to this event (if any). */
16510
16554
  mediaKey: string().optional(),
16555
+ /** Design B: MediaStore key of the track's native-resolution key frame (the
16556
+ * best-detection full frame). Resolve via the event-media data-plane
16557
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
16558
+ * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
16559
+ * sources — consumers fall back to `mediaKey` (the tight crop). */
16560
+ keyFrameMediaKey: string().optional(),
16511
16561
  /** Populated by B5 (recording playback URL for this event). */
16512
- mediaUrl: string().optional()
16562
+ mediaUrl: string().optional(),
16563
+ /** The parent track's key-event importance [0,1], propagated to every object
16564
+ * event of the track (so an event row can be sorted by importance without a
16565
+ * track join). Absent on legacy rows / before the track was scored. */
16566
+ importance: number().optional()
16513
16567
  });
16514
16568
  var AudioEventSchema = object({
16515
16569
  ...BaseEventFields,
@@ -16533,7 +16587,8 @@ var MediaFileKindEnum = _enum([
16533
16587
  "fullFrame",
16534
16588
  "fullFrameBoxed",
16535
16589
  "faceCrop",
16536
- "plateCrop"
16590
+ "plateCrop",
16591
+ "keyFrame"
16537
16592
  ]);
16538
16593
  var MediaFileSchema = object({
16539
16594
  key: string(),
@@ -16554,6 +16609,32 @@ var DeviceEventQueryInput = object({
16554
16609
  projection: _enum(["full", "slim"]).optional()
16555
16610
  });
16556
16611
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16612
+ var KeyEventQueryInput = object({
16613
+ deviceId: number(),
16614
+ /** Window lower bound (track firstSeen ≥ since). */
16615
+ since: number(),
16616
+ /** Window upper bound (track firstSeen ≤ until). */
16617
+ until: number(),
16618
+ limit: number().int().min(1).max(200).default(50),
16619
+ /** Drop tracks scoring below this importance. */
16620
+ minImportance: number().min(0).max(1).optional(),
16621
+ /** Restrict to a single class (e.g. 'person'). */
16622
+ classFilter: string().optional()
16623
+ });
16624
+ var KeyEventSchema = object({
16625
+ /** The representative event id (the track's best ObjectEvent, else its trackId). */
16626
+ id: string(),
16627
+ trackId: string(),
16628
+ /** Track start time (firstSeen). */
16629
+ timestamp: number(),
16630
+ className: string(),
16631
+ label: string().optional(),
16632
+ importance: number(),
16633
+ /** Highest-confidence ObjectEvent id for the track (empty when none). */
16634
+ bestEventId: string(),
16635
+ /** Track lifetime in ms (lastSeen - firstSeen). */
16636
+ windowMs: number().optional()
16637
+ });
16557
16638
  var TrackedDetectionSchema = object({
16558
16639
  trackId: string(),
16559
16640
  className: string(),
@@ -16583,7 +16664,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16583
16664
  }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
16584
16665
  kind: "mutation",
16585
16666
  auth: "admin"
16586
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({
16667
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16587
16668
  deviceId: number(),
16588
16669
  since: number(),
16589
16670
  until: number(),
@@ -18595,7 +18676,17 @@ var FaceInfoSchema = object({
18595
18676
  recognizedIdentityId: string().optional(),
18596
18677
  identityName: string().optional(),
18597
18678
  assigned: boolean(),
18598
- base64: string().optional()
18679
+ base64: string().optional(),
18680
+ /** Design B: the face bbox (pixel space) on the key frame — lets a detail
18681
+ * view draw the box over the native `keyFrameMediaKey` frame. Absent on
18682
+ * legacy rows written before design B. */
18683
+ faceBbox: BoundingBoxSchema.optional(),
18684
+ /** Design B: MediaStore key of the track's native-resolution key frame.
18685
+ * Fetch the native JPEG via the event-media data-plane
18686
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
18687
+ * track produced no key frame (e.g. native/onboard source) — the UI falls
18688
+ * back to the inline `base64` face crop. */
18689
+ keyFrameMediaKey: string().optional()
18599
18690
  });
18600
18691
  var FaceFilterEnum = _enum([
18601
18692
  "unassigned",
@@ -22747,6 +22838,12 @@ Object.freeze({
22747
22838
  addonId: null,
22748
22839
  access: "view"
22749
22840
  },
22841
+ "pipelineAnalytics.getKeyEvents": {
22842
+ capName: "pipeline-analytics",
22843
+ capScope: "device",
22844
+ addonId: null,
22845
+ access: "view"
22846
+ },
22750
22847
  "pipelineAnalytics.getMotionEvents": {
22751
22848
  capName: "pipeline-analytics",
22752
22849
  capScope: "device",
@@ -23275,6 +23372,12 @@ Object.freeze({
23275
23372
  addonId: null,
23276
23373
  access: "view"
23277
23374
  },
23375
+ "pipelineRunner.getNativeCrop": {
23376
+ capName: "pipeline-runner",
23377
+ capScope: "system",
23378
+ addonId: null,
23379
+ access: "view"
23380
+ },
23278
23381
  "pipelineRunner.reportMotion": {
23279
23382
  capName: "pipeline-runner",
23280
23383
  capScope: "system",