@camstack/addon-pipeline 1.2.204 → 1.2.205

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 +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/{default-detection-model-ClY8fk-K.mjs → default-detection-model-23wBHkOQ.mjs} +1 -1
  4. package/dist/{default-detection-model-CfIEdJop.js → default-detection-model-BGsoboIK.js} +1 -1
  5. package/dist/detection-pipeline/index.js +5 -5
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-Czm3CW8M.js → dist-CR3_dWir.js} +17 -7
  8. package/dist/{dist-B5x2ogXC.mjs → dist-FaCzok3C.mjs} +17 -7
  9. package/dist/{lazy-sharp-AhHg_Hb-.js → lazy-sharp-CKXcDP-V.js} +1 -1
  10. package/dist/motion-wasm/index.js +296 -18
  11. package/dist/motion-wasm/index.mjs +295 -17
  12. package/dist/{node-u0M7kQe-.js → node-Re3uLz8K.js} +1 -1
  13. package/dist/{node-Bx76sJbU.mjs → node-f4fUlGHQ.mjs} +1 -1
  14. package/dist/pipeline-runner/index.js +5 -5
  15. package/dist/pipeline-runner/index.mjs +4 -4
  16. package/dist/{process-memory-D5JcMSDA.js → process-memory-DNheSoSc.js} +1 -1
  17. package/dist/{process-memory-iiE4Q2mt.mjs → process-memory-MC7wcxqk.mjs} +1 -1
  18. package/dist/recorder/index.js +2 -2
  19. package/dist/recorder/index.mjs +2 -2
  20. package/dist/{segment-demux-js-CSt1T2Vi.js → segment-demux-js-CQYpP1SU.js} +1 -1
  21. package/dist/{segment-demux-js-BcbB_hcJ.mjs → segment-demux-js-DUpovUKi.mjs} +1 -1
  22. package/dist/session-decode/decode-worker-child.js +2 -2
  23. package/dist/session-decode/decode-worker-child.mjs +1 -1
  24. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BSWELhoJ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-D_m12d-s.mjs} +3 -3
  25. package/dist/stream-broker/demux-worker-child.js +1 -1
  26. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  27. package/dist/stream-broker/{hostInit-BJlv_j8i.mjs → hostInit-Dfu865rx.mjs} +3 -3
  28. package/dist/stream-broker/index.js +3 -3
  29. package/dist/stream-broker/index.mjs +3 -3
  30. package/dist/stream-broker/remoteEntry.js +1 -1
  31. package/dist/{worker-protocol-ClwpoGoP.mjs → worker-protocol-Dz6_u2y6.mjs} +1 -1
  32. package/dist/{worker-protocol-B4C4seRh.js → worker-protocol-lIjbPNbH.js} +1 -1
  33. package/package.json +1 -1
@@ -1,7 +1,182 @@
1
- import { Jt as hydrateSchema, Kt as DeviceType, Ut as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability } from "../dist-B5x2ogXC.mjs";
1
+ import { Jt as hydrateSchema, Kt as DeviceType, Ut as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability } from "../dist-FaCzok3C.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
+ //#region src/motion-wasm/region-grouping.ts
6
+ /**
7
+ * Default area bar, as a fraction of the motion view.
8
+ *
9
+ * Chosen from the measured separation between true-positive group areas and
10
+ * quiet-footage group areas — see `docs/benchmarks/motion-region-area.md`.
11
+ * On the 320×180 production motion view this is ~490 px, against the 1500 px
12
+ * absolute filter it replaces.
13
+ */
14
+ var DEFAULT_MIN_AREA_FRACTION = .0085;
15
+ /**
16
+ * The DEFAULT is the rule that shipped before D394: a 1500 px absolute bar per
17
+ * component. The measured rule is per-camera opt-in (`minArea: 0`), because
18
+ * the measurement says duty cycle rises between ×1.45 and ×2.82 and ten fleet
19
+ * cameras turn that into recorded hours that cannot be measured from their own
20
+ * footage. The end state is still one relative constant for the fleet; the
21
+ * path there is one camera at a time.
22
+ */
23
+ var DEFAULT_MIN_AREA = 1500;
24
+ /**
25
+ * Default storm bar. A group of changed pixels covering more than this
26
+ * fraction of the view is not a subject — it is weather, an exposure step or
27
+ * an IR cut. See the storm section of `docs/benchmarks/motion-region-area.md`.
28
+ */
29
+ var DEFAULT_MAX_COVERAGE_FRACTION = .5;
30
+ /** The bar in pixels: the absolute one when set, the relative rule otherwise. */
31
+ function resolveMinGroupArea(config) {
32
+ if (config.minArea > 0) return config.minArea;
33
+ const area = Math.max(0, config.viewWidth) * Math.max(0, config.viewHeight);
34
+ return Math.round(config.minAreaFraction * area);
35
+ }
36
+ function grow(region, radius) {
37
+ const cx = region.x + region.w / 2;
38
+ const cy = region.y + region.h / 2;
39
+ const halfW = Math.max(region.w, radius) / 2;
40
+ const halfH = Math.max(region.h, radius) / 2;
41
+ return {
42
+ x0: cx - halfW,
43
+ y0: cy - halfH,
44
+ x1: cx + halfW,
45
+ y1: cy + halfH
46
+ };
47
+ }
48
+ function overlaps(a, b) {
49
+ return a.x0 < b.x1 && b.x0 < a.x1 && a.y0 < b.y1 && b.y0 < a.y1;
50
+ }
51
+ /**
52
+ * Merge fragments into subjects and judge each subject on its own summed area.
53
+ *
54
+ * Groups come back in the order of their first member, so the frame's reading
55
+ * order is stable across calls — a UI overlay does not reshuffle.
56
+ *
57
+ * A group over `maxCoverageFraction` is a storm and does not pass as a group;
58
+ * its components are then judged individually, so a subject the storm merged
59
+ * with is not silenced along with it.
60
+ *
61
+ * A positive `config.minArea` short-circuits all of it and runs the pre-D394
62
+ * rule instead — see {@link RegionGroupingConfig.minArea}.
63
+ */
64
+ function groupMotionRegions(regions, config) {
65
+ if (regions.length === 0) return {
66
+ groups: [],
67
+ passed: [],
68
+ suppressedByCoverage: 0
69
+ };
70
+ if (config.minArea > 0) {
71
+ const legacy = regions.map((r) => ({
72
+ x: r.x,
73
+ y: r.y,
74
+ w: r.w,
75
+ h: r.h,
76
+ pixels: r.pixels,
77
+ members: 1
78
+ }));
79
+ return {
80
+ groups: legacy,
81
+ passed: legacy.filter((g) => g.pixels >= config.minArea),
82
+ suppressedByCoverage: 0
83
+ };
84
+ }
85
+ const radius = Math.max(1, Math.floor(Math.min(config.viewWidth, config.viewHeight) / Math.max(1, config.mergeRadiusDivisor)));
86
+ const grown = regions.map((r) => grow(r, radius));
87
+ const parent = regions.map((_, i) => i);
88
+ const find = (i) => {
89
+ let root = i;
90
+ while (parent[root] !== root) root = parent[root];
91
+ let cur = i;
92
+ while (parent[cur] !== root) {
93
+ const next = parent[cur];
94
+ parent[cur] = root;
95
+ cur = next;
96
+ }
97
+ return root;
98
+ };
99
+ for (let i = 0; i < regions.length; i++) for (let j = i + 1; j < regions.length; j++) {
100
+ if (!overlaps(grown[i], grown[j])) continue;
101
+ const ri = find(i);
102
+ const rj = find(j);
103
+ if (ri !== rj) parent[rj] = ri;
104
+ }
105
+ const byRoot = /* @__PURE__ */ new Map();
106
+ const order = [];
107
+ for (let i = 0; i < regions.length; i++) {
108
+ const region = regions[i];
109
+ const root = find(i);
110
+ const existing = byRoot.get(root);
111
+ if (!existing) {
112
+ order.push(root);
113
+ byRoot.set(root, {
114
+ x0: region.x,
115
+ y0: region.y,
116
+ x1: region.x + region.w,
117
+ y1: region.y + region.h,
118
+ pixels: region.pixels,
119
+ members: 1
120
+ });
121
+ continue;
122
+ }
123
+ existing.x0 = Math.min(existing.x0, region.x);
124
+ existing.y0 = Math.min(existing.y0, region.y);
125
+ existing.x1 = Math.max(existing.x1, region.x + region.w);
126
+ existing.y1 = Math.max(existing.y1, region.y + region.h);
127
+ existing.pixels += region.pixels;
128
+ existing.members += 1;
129
+ }
130
+ const groups = order.map((root) => {
131
+ const a = byRoot.get(root);
132
+ return {
133
+ x: a.x0,
134
+ y: a.y0,
135
+ w: a.x1 - a.x0,
136
+ h: a.y1 - a.y0,
137
+ pixels: a.pixels,
138
+ members: a.members
139
+ };
140
+ });
141
+ const bar = resolveMinGroupArea(config);
142
+ const viewArea = Math.max(0, config.viewWidth) * Math.max(0, config.viewHeight);
143
+ const stormBar = config.maxCoverageFraction >= 1 ? Infinity : config.maxCoverageFraction * viewArea;
144
+ const membersByGroup = /* @__PURE__ */ new Map();
145
+ for (let i = 0; i < regions.length; i++) {
146
+ const root = find(i);
147
+ const list = membersByGroup.get(root) ?? [];
148
+ list.push(regions[i]);
149
+ membersByGroup.set(root, list);
150
+ }
151
+ const passed = [];
152
+ let suppressedByCoverage = 0;
153
+ for (let g = 0; g < groups.length; g++) {
154
+ const group = groups[g];
155
+ if (group.pixels < bar) continue;
156
+ if (group.pixels <= stormBar) {
157
+ passed.push(group);
158
+ continue;
159
+ }
160
+ suppressedByCoverage += 1;
161
+ for (const member of membersByGroup.get(order[g]) ?? []) {
162
+ if (member.pixels < bar || member.pixels > stormBar) continue;
163
+ passed.push({
164
+ x: member.x,
165
+ y: member.y,
166
+ w: member.w,
167
+ h: member.h,
168
+ pixels: member.pixels,
169
+ members: 1
170
+ });
171
+ }
172
+ }
173
+ return {
174
+ groups,
175
+ passed,
176
+ suppressedByCoverage
177
+ };
178
+ }
179
+ //#endregion
5
180
  //#region src/motion-wasm/wasm-motion-detector.ts
6
181
  /**
7
182
  * WasmMotionDetector — loads the AssemblyScript WASM module and provides
@@ -9,18 +184,33 @@ import { join } from "node:path";
9
184
  *
10
185
  * Pipeline: blur → diff → threshold → dilate → CCL → bounding boxes
11
186
  * All in one WASM call, ~3ms for 640×360 grayscale frames.
187
+ *
188
+ * The area filter that follows is NOT applied per connected component — see
189
+ * {@link groupMotionRegions}. Fragments of one subject are merged first and the
190
+ * bar is applied to the merged subject, relative to the motion view. D394.
191
+ */
192
+ /**
193
+ * The one place the motion defaults live. The addon's schema defaults read
194
+ * from here — two copies of this object drifted apart once already (3000 here
195
+ * against 1500 in the addon), and the addon's copy is the one that ran.
12
196
  */
13
- var DEFAULT_CONFIG$1 = {
197
+ var DEFAULT_CONFIG = {
14
198
  threshold: 45,
15
199
  blurRadius: 1,
16
200
  dilateRadius: 4,
17
- minArea: 3e3
201
+ minArea: DEFAULT_MIN_AREA,
202
+ minAreaFraction: DEFAULT_MIN_AREA_FRACTION,
203
+ mergeRadiusDivisor: 6,
204
+ maxCoverageFraction: DEFAULT_MAX_COVERAGE_FRACTION
18
205
  };
19
206
  var WasmMotionDetector = class {
20
207
  wasm = null;
21
208
  prevOffset = 0;
22
209
  currOffset = 0;
23
210
  regionOffset = 0;
211
+ /** The motion view the regions are expressed in — the relative bar's denominator. */
212
+ width = 0;
213
+ height = 0;
24
214
  /** Load the WASM module. Call once before detect(). */
25
215
  async load() {
26
216
  const wasmBytes = readFileSync(join(__dirname, "..", "..", "wasm", "motion.wasm"));
@@ -44,10 +234,25 @@ var WasmMotionDetector = class {
44
234
  }
45
235
  this.wasm = exports;
46
236
  }
237
+ /**
238
+ * Initialize for these frame dimensions when they are not already the ones
239
+ * the WASM is sized for. One detector instance serves every camera on the
240
+ * node, so two cameras with different views interleaving would otherwise
241
+ * leave the WASM sized for whichever one called `init` last — and, since
242
+ * D394, would divide the relative area bar by the wrong view. `init` only
243
+ * recomputes offsets and grows memory, so a call that changes nothing is
244
+ * skipped and a call that does is cheap.
245
+ */
246
+ ensureSize(w, h) {
247
+ if (this.width === w && this.height === h) return;
248
+ this.init(w, h);
249
+ }
47
250
  /** Initialize for given frame dimensions. Call when resolution changes. */
48
251
  init(w, h) {
49
252
  if (!this.wasm) throw new Error("WASM not loaded — call load() first");
50
253
  this.wasm.init(w, h);
254
+ this.width = w;
255
+ this.height = h;
51
256
  this.prevOffset = this.wasm.getPrevOffset();
52
257
  this.currOffset = this.wasm.getCurrOffset();
53
258
  this.regionOffset = this.wasm.getRegionOffset();
@@ -58,12 +263,12 @@ var WasmMotionDetector = class {
58
263
  * @param prevGray - previous frame (Uint8Array, width×height)
59
264
  * @param currGray - current frame (Uint8Array, width×height)
60
265
  * @param config - detection parameters (optional, uses defaults)
61
- * @returns raw (all CCL regions) + filtered (passing minArea) regions
266
+ * @returns raw CCL regions, the subjects they merge into, and the survivors
62
267
  */
63
268
  detect(prevGray, currGray, config = {}) {
64
269
  if (!this.wasm) throw new Error("WASM not loaded");
65
270
  const cfg = {
66
- ...DEFAULT_CONFIG$1,
271
+ ...DEFAULT_CONFIG,
67
272
  ...config
68
273
  };
69
274
  const mem = new Uint8Array(this.wasm.memory.buffer);
@@ -72,7 +277,9 @@ var WasmMotionDetector = class {
72
277
  const numRegions = this.wasm.detectMotion(cfg.threshold, cfg.blurRadius, cfg.dilateRadius, 0);
73
278
  if (numRegions === 0) return {
74
279
  raw: [],
75
- filtered: []
280
+ filtered: [],
281
+ groups: [],
282
+ suppressedByCoverage: 0
76
283
  };
77
284
  const view = new DataView(this.wasm.memory.buffer);
78
285
  const raw = [];
@@ -86,9 +293,19 @@ var WasmMotionDetector = class {
86
293
  pixels: view.getInt32(base + 16, true)
87
294
  });
88
295
  }
296
+ const grouped = groupMotionRegions(raw, {
297
+ viewWidth: this.width,
298
+ viewHeight: this.height,
299
+ mergeRadiusDivisor: cfg.mergeRadiusDivisor,
300
+ minAreaFraction: cfg.minAreaFraction,
301
+ minArea: cfg.minArea,
302
+ maxCoverageFraction: cfg.maxCoverageFraction
303
+ });
89
304
  return {
90
305
  raw,
91
- filtered: raw.filter((r) => r.pixels >= cfg.minArea)
306
+ filtered: grouped.passed,
307
+ groups: grouped.groups,
308
+ suppressedByCoverage: grouped.suppressedByCoverage
92
309
  };
93
310
  }
94
311
  };
@@ -117,25 +334,27 @@ function gateMotionRegions(regions, zones, rules, frameWidth, frameHeight) {
117
334
  *
118
335
  * Settings redesign Phase 3: motion-wasm has ONLY device-level settings
119
336
  * (all four fields were `scope: 'device'` in the legacy schema — every
120
- * camera tunes threshold/minArea/blurRadius/dilateRadius independently
337
+ * camera tunes threshold/subject size/blurRadius/dilateRadius independently
121
338
  * for its scene). So the addon implements `getDeviceSettings` /
122
339
  * `updateDeviceSettings` and nothing else. Fresh cameras with no
123
340
  * overrides get the schema defaults via `hydrateSchema()` at read time.
124
341
  * There is no cluster-wide "default threshold" knob — if operators want
125
342
  * to change the baseline, they edit the schema defaults in code.
126
343
  */
127
- var DEFAULT_CONFIG = {
128
- threshold: 45,
129
- blurRadius: 1,
130
- dilateRadius: 4,
131
- minArea: 1500
132
- };
133
344
  var MotionWasmAddon = class MotionWasmAddon extends BaseAddon {
134
345
  detector = null;
135
346
  cameras = /* @__PURE__ */ new Map();
136
347
  deviceConfigCache = /* @__PURE__ */ new Map();
137
348
  static DEVICE_CONFIG_TTL_MS = 6e4;
138
349
  /**
350
+ * Last logged "which rule is this camera on" signature, per camera. The
351
+ * operator's gesture for D394 is a settings write, and a settings write is
352
+ * invisible: this is how they confirm it took, on the next analysed frame.
353
+ * Keyed and logged only on CHANGE, so it costs one line per camera per
354
+ * change rather than one per TTL expiry.
355
+ */
356
+ loggedRule = /* @__PURE__ */ new Map();
357
+ /**
139
358
  * Per-device {@link DeviceProxy} used for zone gating. Built lazily
140
359
  * on first analyze() for a device; the proxy's reactive state
141
360
  * handles (`state.zones`, `state.zoneRules`) keep their `.value`
@@ -252,7 +471,16 @@ var MotionWasmAddon = class MotionWasmAddon extends BaseAddon {
252
471
  }
253
472
  state = this.cameras.get(cameraId);
254
473
  const deviceCfg = await this.getDeviceConfig(cameraId);
255
- const { raw, filtered } = this.detector.detect(state.prevGray, gray, deviceCfg);
474
+ this.detector.ensureSize(width, height);
475
+ const { raw, filtered, suppressedByCoverage } = this.detector.detect(state.prevGray, gray, deviceCfg);
476
+ if (suppressedByCoverage > 0) this.ctx.logger.info("motion storm suppressed", {
477
+ tags: { deviceId: Number(cameraId) },
478
+ meta: {
479
+ groups: suppressedByCoverage,
480
+ maxCoverageFraction: deviceCfg.maxCoverageFraction,
481
+ view: `${width}x${height}`
482
+ }
483
+ });
256
484
  state.prevGray = Buffer.from(gray);
257
485
  const toRegion = (r) => ({
258
486
  bbox: {
@@ -343,28 +571,48 @@ var MotionWasmAddon = class MotionWasmAddon extends BaseAddon {
343
571
  threshold: typeof flat["threshold"] === "number" ? flat["threshold"] : DEFAULT_CONFIG.threshold,
344
572
  blurRadius: typeof flat["blurRadius"] === "number" ? flat["blurRadius"] : DEFAULT_CONFIG.blurRadius,
345
573
  dilateRadius: typeof flat["dilateRadius"] === "number" ? flat["dilateRadius"] : DEFAULT_CONFIG.dilateRadius,
346
- minArea: typeof flat["minArea"] === "number" ? flat["minArea"] : DEFAULT_CONFIG.minArea
574
+ minArea: typeof flat["minArea"] === "number" ? flat["minArea"] : DEFAULT_CONFIG.minArea,
575
+ minAreaFraction: typeof flat["minAreaFraction"] === "number" ? flat["minAreaFraction"] : DEFAULT_CONFIG.minAreaFraction,
576
+ mergeRadiusDivisor: typeof flat["mergeRadiusDivisor"] === "number" ? flat["mergeRadiusDivisor"] : DEFAULT_CONFIG.mergeRadiusDivisor,
577
+ maxCoverageFraction: typeof flat["maxCoverageFraction"] === "number" ? flat["maxCoverageFraction"] : DEFAULT_CONFIG.maxCoverageFraction
347
578
  };
348
579
  this.deviceConfigCache.set(cameraId, {
349
580
  config: resolved,
350
581
  fetchedAt: now
351
582
  });
583
+ const rule = resolved.minArea > 0 ? "legacy-per-region" : "merged-relative";
584
+ const signature = rule === "legacy-per-region" ? `${rule}:${resolved.minArea}` : `${rule}:${resolved.minAreaFraction}:${resolved.maxCoverageFraction}`;
585
+ if (this.loggedRule.get(cameraId) !== signature) {
586
+ this.loggedRule.set(cameraId, signature);
587
+ this.ctx.logger.info("motion area rule resolved", {
588
+ tags: { deviceId: Number(cameraId) },
589
+ meta: {
590
+ rule,
591
+ minArea: resolved.minArea,
592
+ minAreaFraction: resolved.minAreaFraction,
593
+ maxCoverageFraction: resolved.maxCoverageFraction
594
+ }
595
+ });
596
+ }
352
597
  return resolved;
353
598
  }
354
599
  async removeCamera({ deviceId }) {
355
600
  const key = String(deviceId);
356
601
  this.cameras.delete(key);
357
602
  this.deviceConfigCache.delete(key);
603
+ this.loggedRule.delete(key);
358
604
  this.releaseProxy(deviceId);
359
605
  }
360
606
  async reset() {
361
607
  this.cameras.clear();
362
608
  this.deviceConfigCache.clear();
609
+ this.loggedRule.clear();
363
610
  for (const id of this.proxies.keys()) this.releaseProxy(id);
364
611
  }
365
612
  async onShutdown() {
366
613
  this.cameras.clear();
367
614
  this.deviceConfigCache.clear();
615
+ this.loggedRule.clear();
368
616
  for (const id of this.proxies.keys()) this.releaseProxy(id);
369
617
  this.detector = null;
370
618
  }
@@ -391,11 +639,26 @@ var MotionWasmAddon = class MotionWasmAddon extends BaseAddon {
391
639
  includes: "analyzer"
392
640
  }
393
641
  },
642
+ {
643
+ type: "slider",
644
+ key: "minAreaFraction",
645
+ label: "Min Subject Size",
646
+ description: "Smallest subject that triggers motion, as a share of the analysed view. Fragments of one subject are merged before this is applied, so a partly hidden animal counts once at its full size. Only in effect when Min Area is 0.",
647
+ min: .001,
648
+ max: .05,
649
+ step: 5e-4,
650
+ default: DEFAULT_CONFIG.minAreaFraction,
651
+ showValue: true,
652
+ showWhen: {
653
+ field: "motionSources",
654
+ includes: "analyzer"
655
+ }
656
+ },
394
657
  {
395
658
  type: "number",
396
659
  key: "minArea",
397
660
  label: "Min Area",
398
- description: "Minimum pixel area of a motion region to trigger detection",
661
+ description: "Absolute pixel bar, applied to each motion region on its own. This is how motion has always worked, and it stays the default. Set it to 0 to move THIS camera to Min Subject Size, which merges the fragments of one subject before measuring it and keeps its meaning at any resolution — expect more motion, so move one camera at a time.",
399
662
  min: 0,
400
663
  max: 5e4,
401
664
  step: 100,
@@ -406,6 +669,21 @@ var MotionWasmAddon = class MotionWasmAddon extends BaseAddon {
406
669
  includes: "analyzer"
407
670
  }
408
671
  },
672
+ {
673
+ type: "slider",
674
+ key: "maxCoverageFraction",
675
+ label: "Storm Cutoff",
676
+ description: "A merged region whose changed pixels cover more of the view than this is weather, an IR cut or an exposure step, not a subject, and does not fire motion. A real mover inside the storm still fires on its own region. Only in effect when Min Area is 0; 1 disables the cutoff.",
677
+ min: .2,
678
+ max: 1,
679
+ step: .05,
680
+ default: DEFAULT_CONFIG.maxCoverageFraction,
681
+ showValue: true,
682
+ showWhen: {
683
+ field: "motionSources",
684
+ includes: "analyzer"
685
+ }
686
+ },
409
687
  {
410
688
  type: "slider",
411
689
  key: "blurRadius",
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-Czm3CW8M.js");
1
+ const require_dist = require("./dist-CR3_dWir.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_dist.__toESM(node_fs, 1);
@@ -1,4 +1,4 @@
1
- import { It as errMsg, Rt as Fmp4BoxSplitter, Vt as isSoftwareDecode, zt as buildFfmpegArgs } from "./dist-B5x2ogXC.mjs";
1
+ import { It as errMsg, Rt as Fmp4BoxSplitter, Vt as isSoftwareDecode, zt as buildFfmpegArgs } from "./dist-FaCzok3C.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { realpathSync } from "node:fs";
4
4
  import path from "node:path";
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-Czm3CW8M.js");
6
- const require_node = require("../node-u0M7kQe-.js");
7
- const require_default_detection_model = require("../default-detection-model-CfIEdJop.js");
8
- const require_worker_protocol = require("../worker-protocol-B4C4seRh.js");
5
+ const require_dist = require("../dist-CR3_dWir.js");
6
+ const require_node = require("../node-Re3uLz8K.js");
7
+ const require_default_detection_model = require("../default-detection-model-BGsoboIK.js");
8
+ const require_worker_protocol = require("../worker-protocol-lIjbPNbH.js");
9
9
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
10
- const require_lazy_sharp = require("../lazy-sharp-AhHg_Hb-.js");
10
+ const require_lazy_sharp = require("../lazy-sharp-CKXcDP-V.js");
11
11
  const require_restream_intent = require("../restream-intent-B1Difcnq.js");
12
12
  const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
13
13
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
@@ -1,7 +1,7 @@
1
- import { $ as failureContributionCapability, It as errMsg, Qt as nodePin, R as customAction, U as deriveDetailCropRect, Ut as BaseAddon, V as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, an as boolean, bt as pipelineRunnerCapability, cn as literal, hn as EventCategory, in as array, it as loadContributionCapability, ln as number, m as DEVICE_BACKEND_TO_FORMAT, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as string, qt as createEvent, rn as _enum, sn as lazy, u as DEFAULT_DETAIL_CROP_CONVENTION, un as object, vt as pickNativeLeaseOverride } from "../dist-B5x2ogXC.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-Bx76sJbU.mjs";
3
- import { i as resolveFrameViewGeometry, l as getStepDefinition, r as localFrameRegistry } from "../default-detection-model-ClY8fk-K.mjs";
4
- import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-ClwpoGoP.mjs";
1
+ import { $ as failureContributionCapability, It as errMsg, Qt as nodePin, R as customAction, U as deriveDetailCropRect, Ut as BaseAddon, V as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, an as boolean, bt as pipelineRunnerCapability, cn as literal, hn as EventCategory, in as array, it as loadContributionCapability, ln as number, m as DEVICE_BACKEND_TO_FORMAT, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as string, qt as createEvent, rn as _enum, sn as lazy, u as DEFAULT_DETAIL_CROP_CONVENTION, un as object, vt as pickNativeLeaseOverride } from "../dist-FaCzok3C.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-f4fUlGHQ.mjs";
3
+ import { i as resolveFrameViewGeometry, l as getStepDefinition, r as localFrameRegistry } from "../default-detection-model-23wBHkOQ.mjs";
4
+ import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-Dz6_u2y6.mjs";
5
5
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
6
6
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
7
7
  import { a as preRollRequestOf, o as withDetectionIntent, t as DETECTION_PRE_ROLL_REQUEST_MS } from "../restream-intent-DWe2kInY.mjs";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-Czm3CW8M.js");
1
+ const require_dist = require("./dist-CR3_dWir.js");
2
2
  let node_fs = require("node:fs");
3
3
  node_fs = require_dist.__toESM(node_fs);
4
4
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { mt as parseProcStatus } from "./dist-B5x2ogXC.mjs";
1
+ import { mt as parseProcStatus } from "./dist-FaCzok3C.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  //#region src/shared/node-topology-platform.ts
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-Czm3CW8M.js");
6
- const require_node = require("../node-u0M7kQe-.js");
5
+ const require_dist = require("../dist-CR3_dWir.js");
6
+ const require_node = require("../node-Re3uLz8K.js");
7
7
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
8
8
  const require_restream_intent = require("../restream-intent-B1Difcnq.js");
9
9
  const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
@@ -1,5 +1,5 @@
1
- import { At as storageEvictableCapability, Ct as recordingSignalCapability, D as RecordingSignalStatusSchema, E as RecordingConfigSchema, Et as resolveLocationMode, Gt as DeviceFeature, H as deriveBatteryPresence, It as errMsg, Jt as hydrateSchema, Kt as DeviceType, Nt as stripRetiredBandPreBufferSec, Ot as resolveRecordingProfiles, P as batteryCapability, Q as evictionPolicyOfLocation, Qt as nodePin, R as customAction, St as recordingExportCapability, T as RECORDING_EXPORT_MAX_READ_BYTES, Ut as BaseAddon, V as defineCustomActions, W as deriveRecordingMode, Y as evaluateSensorEdge, Z as evictionPolicyForMode, an as boolean, ct as mayReadLocation, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, dn as preprocess, dt as modeMayWrite, et as gbToBytes, fn as record, g as ExportRecordSchema, hn as EventCategory, i as BatteryStatusSchema, in as array, it as loadContributionCapability, jt as storageOccupancyCapability, ln as number, lt as mayWriteToLocation, nn as sleep$1, pn as string, rn as _enum, rt as isFirstLevelMacroClass, tn as selectAssignedProfileSlots, un as object, ut as migrateLegacyDeviceSignalConfig, x as OpsLogEntrySchema, xt as recordingCapability } from "../dist-B5x2ogXC.mjs";
2
- import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-Bx76sJbU.mjs";
1
+ import { At as storageEvictableCapability, Ct as recordingSignalCapability, D as RecordingSignalStatusSchema, E as RecordingConfigSchema, Et as resolveLocationMode, Gt as DeviceFeature, H as deriveBatteryPresence, It as errMsg, Jt as hydrateSchema, Kt as DeviceType, Nt as stripRetiredBandPreBufferSec, Ot as resolveRecordingProfiles, P as batteryCapability, Q as evictionPolicyOfLocation, Qt as nodePin, R as customAction, St as recordingExportCapability, T as RECORDING_EXPORT_MAX_READ_BYTES, Ut as BaseAddon, V as defineCustomActions, W as deriveRecordingMode, Y as evaluateSensorEdge, Z as evictionPolicyForMode, an as boolean, ct as mayReadLocation, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, dn as preprocess, dt as modeMayWrite, et as gbToBytes, fn as record, g as ExportRecordSchema, hn as EventCategory, i as BatteryStatusSchema, in as array, it as loadContributionCapability, jt as storageOccupancyCapability, ln as number, lt as mayWriteToLocation, nn as sleep$1, pn as string, rn as _enum, rt as isFirstLevelMacroClass, tn as selectAssignedProfileSlots, un as object, ut as migrateLegacyDeviceSignalConfig, x as OpsLogEntrySchema, xt as recordingCapability } from "../dist-FaCzok3C.mjs";
2
+ import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-f4fUlGHQ.mjs";
3
3
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
4
4
  import { c as PREBUFFER_MAX_MS, r as RECORDING_PRE_ROLL_REQUEST_MS, s as withRecordingIntent } from "../restream-intent-DWe2kInY.mjs";
5
5
  import { n as startEventLoopStallMonitor } from "../event-loop-stall-monitor-DXLNBMkY.mjs";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-Czm3CW8M.js");
1
+ const require_dist = require("./dist-CR3_dWir.js");
2
2
  let node_child_process = require("node:child_process");
3
3
  //#region ../../node_modules/mp4box/dist/mp4box.all.js
4
4
  var require_mp4box_all = /* @__PURE__ */ require_dist.__commonJSMin(((exports) => {
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
- import { It as errMsg } from "./dist-B5x2ogXC.mjs";
2
+ import { It as errMsg } from "./dist-FaCzok3C.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region ../../node_modules/mp4box/dist/mp4box.all.js
5
5
  var require_mp4box_all = /* @__PURE__ */ __commonJSMin(((exports) => {
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_worker_protocol = require("../worker-protocol-B4C4seRh.js");
3
- const require_lazy_sharp = require("../lazy-sharp-AhHg_Hb-.js");
2
+ const require_worker_protocol = require("../worker-protocol-lIjbPNbH.js");
3
+ const require_lazy_sharp = require("../lazy-sharp-CKXcDP-V.js");
4
4
  //#region src/session-decode/color-conversion.ts
5
5
  /**
6
6
  * Explicit YUV→RGB colorspace/range resolution for the session-decode worker.
@@ -1,4 +1,4 @@
1
- import { i as formatNativeLeaseKnobs, n as isWorkerRequest, o as resolveNativeLeaseKnobs, r as logLevelForLine } from "../worker-protocol-ClwpoGoP.mjs";
1
+ import { i as formatNativeLeaseKnobs, n as isWorkerRequest, o as resolveNativeLeaseKnobs, r as logLevelForLine } from "../worker-protocol-Dz6_u2y6.mjs";
2
2
  import { n as setSharpWarnSink, r as hostExternalEntryUrls, t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  //#region src/session-decode/color-conversion.ts
4
4
  /**
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
3
3
  var e = {
4
4
  "@camstack/sdk": {
5
5
  name: "@camstack/sdk",
6
- version: "1.2.84",
6
+ version: "1.2.85",
7
7
  scope: ["default"],
8
8
  loaded: !1,
9
9
  from: "addon_stream_broker_widgets",
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.164",
21
+ version: "1.2.165",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_stream_broker_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.132",
36
+ version: "1.2.133",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_stream_broker_widgets",
@@ -1,4 +1,4 @@
1
- const require_segment_demux_js = require("../segment-demux-js-CSt1T2Vi.js");
1
+ const require_segment_demux_js = require("../segment-demux-js-CQYpP1SU.js");
2
2
  let node_worker_threads = require("node:worker_threads");
3
3
  //#region src/stream-broker/recorded/demux-worker-child.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as demuxSegmentFullJs } from "../segment-demux-js-BcbB_hcJ.mjs";
1
+ import { t as demuxSegmentFullJs } from "../segment-demux-js-DUpovUKi.mjs";
2
2
  import { parentPort } from "node:worker_threads";
3
3
  //#region src/stream-broker/recorded/demux-worker-child.ts
4
4
  /**
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.2.164",
39
+ version: "1.2.165",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -45,7 +45,7 @@ async function r() {
45
45
  }
46
46
  },
47
47
  "@camstack/sdk": {
48
- version: "1.2.84",
48
+ version: "1.2.85",
49
49
  scope: "default",
50
50
  shareConfig: {
51
51
  singleton: !0,
@@ -81,7 +81,7 @@ async function r() {
81
81
  }
82
82
  },
83
83
  "@camstack/ui-library": {
84
- version: "1.2.132",
84
+ version: "1.2.133",
85
85
  scope: "default",
86
86
  shareConfig: {
87
87
  singleton: !0,
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-Czm3CW8M.js");
6
- const require_node = require("../node-u0M7kQe-.js");
5
+ const require_dist = require("../dist-CR3_dWir.js");
6
+ const require_node = require("../node-Re3uLz8K.js");
7
7
  const require_restream_intent = require("../restream-intent-B1Difcnq.js");
8
8
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
9
9
  const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
10
- const require_segment_demux_js = require("../segment-demux-js-CSt1T2Vi.js");
10
+ const require_segment_demux_js = require("../segment-demux-js-CQYpP1SU.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_dist.__toESM(node_os);
13
13
  let node_crypto = require("node:crypto");