@camstack/addon-pipeline 1.2.31 → 1.2.37

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 (70) hide show
  1. package/dist/detection-pipeline/index.js +999 -978
  2. package/dist/detection-pipeline/index.mjs +999 -978
  3. package/dist/pipeline-runner/index.js +30 -4
  4. package/dist/pipeline-runner/index.mjs +30 -4
  5. package/dist/{step-definitions-BkY9_IM6.mjs → step-definitions-C8tk9fPJ.mjs} +11 -2
  6. package/dist/{step-definitions-gC-Ovglc.js → step-definitions-i8O-hxyI.js} +16 -1
  7. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BUXeX-vb.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C5m4hC2K.mjs} +3 -3
  8. package/dist/stream-broker/{hostInit-DJ3h-b1X.mjs → hostInit-WXFrgppm.mjs} +3 -3
  9. package/dist/stream-broker/remoteEntry.js +1 -1
  10. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-B0DyP46h.js → MaskShapeCanvas-DI4BY7W2-Dx-Vrpyt.js} +1 -1
  11. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-CzGSy_EO.js → MotionZonesSettings-NcxxQN8r-9D-BWwQP.js} +1 -1
  12. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-CEgMcOOW.js → PrivacyMaskSettings-APgPLF7p-HvAetfA4.js} +1 -1
  13. package/embed-dist/assets/{index-CHXOWKHF.js → index-9Ob2YrIf.js} +5 -5
  14. package/embed-dist/index.html +1 -1
  15. package/package.json +1 -1
  16. package/python/__pycache__/inference_pool.cpython-312.pyc +0 -0
  17. package/python/__pycache__/inference_pool.cpython-313.pyc +0 -0
  18. package/python/__pycache__/inference_pool.cpython-314.pyc +0 -0
  19. package/python/__pycache__/test_inference_pool_backpressure.cpython-314.pyc +0 -0
  20. package/python/__pycache__/test_inference_pool_coreml_cache.cpython-314.pyc +0 -0
  21. package/python/__pycache__/test_inference_pool_device_selection.cpython-314.pyc +0 -0
  22. package/python/__pycache__/test_inference_pool_layout.cpython-314.pyc +0 -0
  23. package/python/__pycache__/test_inference_pool_preprocess.cpython-314.pyc +0 -0
  24. package/python/__pycache__/yamnet_audio.cpython-314.pyc +0 -0
  25. package/python/postprocessors/__pycache__/__init__.cpython-312.pyc +0 -0
  26. package/python/postprocessors/__pycache__/__init__.cpython-313.pyc +0 -0
  27. package/python/postprocessors/__pycache__/__init__.cpython-314.pyc +0 -0
  28. package/python/postprocessors/__pycache__/_safety.cpython-313.pyc +0 -0
  29. package/python/postprocessors/__pycache__/arcface.cpython-312.pyc +0 -0
  30. package/python/postprocessors/__pycache__/arcface.cpython-313.pyc +0 -0
  31. package/python/postprocessors/__pycache__/arcface.cpython-314.pyc +0 -0
  32. package/python/postprocessors/__pycache__/clip.cpython-312.pyc +0 -0
  33. package/python/postprocessors/__pycache__/clip.cpython-313.pyc +0 -0
  34. package/python/postprocessors/__pycache__/clip.cpython-314.pyc +0 -0
  35. package/python/postprocessors/__pycache__/ctc.cpython-312.pyc +0 -0
  36. package/python/postprocessors/__pycache__/ctc.cpython-313.pyc +0 -0
  37. package/python/postprocessors/__pycache__/ctc.cpython-314.pyc +0 -0
  38. package/python/postprocessors/__pycache__/saliency.cpython-312.pyc +0 -0
  39. package/python/postprocessors/__pycache__/saliency.cpython-313.pyc +0 -0
  40. package/python/postprocessors/__pycache__/saliency.cpython-314.pyc +0 -0
  41. package/python/postprocessors/__pycache__/scrfd.cpython-312.pyc +0 -0
  42. package/python/postprocessors/__pycache__/scrfd.cpython-313.pyc +0 -0
  43. package/python/postprocessors/__pycache__/scrfd.cpython-314.pyc +0 -0
  44. package/python/postprocessors/__pycache__/softmax.cpython-312.pyc +0 -0
  45. package/python/postprocessors/__pycache__/softmax.cpython-313.pyc +0 -0
  46. package/python/postprocessors/__pycache__/softmax.cpython-314.pyc +0 -0
  47. package/python/postprocessors/__pycache__/ssd.cpython-312.pyc +0 -0
  48. package/python/postprocessors/__pycache__/ssd.cpython-313.pyc +0 -0
  49. package/python/postprocessors/__pycache__/ssd.cpython-314.pyc +0 -0
  50. package/python/postprocessors/__pycache__/test_clip.cpython-312-pytest-9.1.1.pyc +0 -0
  51. package/python/postprocessors/__pycache__/test_clip.cpython-313-pytest-9.1.1.pyc +0 -0
  52. package/python/postprocessors/__pycache__/test_ctc.cpython-312-pytest-9.1.1.pyc +0 -0
  53. package/python/postprocessors/__pycache__/test_ctc.cpython-312.pyc +0 -0
  54. package/python/postprocessors/__pycache__/test_ctc.cpython-313-pytest-9.1.1.pyc +0 -0
  55. package/python/postprocessors/__pycache__/test_ctc.cpython-313.pyc +0 -0
  56. package/python/postprocessors/__pycache__/test_saliency.cpython-312-pytest-9.1.1.pyc +0 -0
  57. package/python/postprocessors/__pycache__/test_saliency.cpython-313-pytest-9.1.1.pyc +0 -0
  58. package/python/postprocessors/__pycache__/test_softmax.cpython-312-pytest-9.1.1.pyc +0 -0
  59. package/python/postprocessors/__pycache__/test_yolo_nms.cpython-312-pytest-9.1.1.pyc +0 -0
  60. package/python/postprocessors/__pycache__/test_yolo_nms.cpython-39.pyc +0 -0
  61. package/python/postprocessors/__pycache__/yamnet.cpython-312.pyc +0 -0
  62. package/python/postprocessors/__pycache__/yamnet.cpython-313.pyc +0 -0
  63. package/python/postprocessors/__pycache__/yamnet.cpython-314.pyc +0 -0
  64. package/python/postprocessors/__pycache__/yolo.cpython-312.pyc +0 -0
  65. package/python/postprocessors/__pycache__/yolo.cpython-313.pyc +0 -0
  66. package/python/postprocessors/__pycache__/yolo.cpython-314.pyc +0 -0
  67. package/python/postprocessors/__pycache__/yolo.cpython-39.pyc +0 -0
  68. package/python/postprocessors/__pycache__/yolo_seg.cpython-312.pyc +0 -0
  69. package/python/postprocessors/__pycache__/yolo_seg.cpython-313.pyc +0 -0
  70. package/python/postprocessors/__pycache__/yolo_seg.cpython-314.pyc +0 -0
@@ -7,7 +7,7 @@ const require_dist = require("../dist-BvFLZyhW.js");
7
7
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
8
8
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
9
9
  const require_worker_protocol = require("../worker-protocol-DextwlTX.js");
10
- const require_step_definitions = require("../step-definitions-gC-Ovglc.js");
10
+ const require_step_definitions = require("../step-definitions-i8O-hxyI.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_child_process = require("node:child_process");
@@ -2645,6 +2645,28 @@ function pickWeightedLeastLoaded(devices) {
2645
2645
  });
2646
2646
  }
2647
2647
  /**
2648
+ * Build the `canRun` predicate for ONE enrichment dispatch. The step and its
2649
+ * enabled descendants ride the SAME `runPipeline` call — one pool, one format
2650
+ * (detail-subtree contract: "its inherited children ride the same call → same
2651
+ * device") — so a format can run the dispatch only when EVERY catalog-known
2652
+ * step in the subtree ships a build for it. Gating only the subtree TOP let a
2653
+ * `face-detection` with a tflite build stay on the Coral while its
2654
+ * `face-embedding` child (no tflite build anywhere) doomed the call.
2655
+ * Unknown/custom addonIds (`getStepDef` → null) have no catalog to gate on
2656
+ * and never block. `getStepDef` is injected — this module stays catalog-free.
2657
+ */
2658
+ function buildSubtreeCanRun(step, getStepDef) {
2659
+ const defs = [];
2660
+ const walk = (s) => {
2661
+ if (s.enabled === false) return;
2662
+ const def = getStepDef(s.addonId);
2663
+ if (def !== null) defs.push(def);
2664
+ for (const child of s.children ?? []) walk(child);
2665
+ };
2666
+ walk(step);
2667
+ return (format) => defs.every((def) => def.models.some((m) => m.formats[format]));
2668
+ }
2669
+ /**
2648
2670
  * Resolve the device one enrichment step runs on. See the module header for the
2649
2671
  * decision table. Pure — never throws, no I/O.
2650
2672
  */
@@ -3727,8 +3749,7 @@ var PipelineRunnerAddon = class extends require_dist.BaseAddon {
3727
3749
  maxSessions: d.maxSessions,
3728
3750
  attachedCameras: attachedByKey.get(d.deviceKey) ?? 0
3729
3751
  }));
3730
- const def = tryGetStepDefinition(step.addonId);
3731
- const canRun = (format) => def === null || def.models.some((m) => m.formats[format]);
3752
+ const canRun = buildSubtreeCanRun(step, tryGetStepDefinition);
3732
3753
  const result = resolveStepDevice({
3733
3754
  effectiveDeviceKey,
3734
3755
  devices,
@@ -4346,7 +4367,12 @@ var PipelineRunnerAddon = class extends require_dist.BaseAddon {
4346
4367
  });
4347
4368
  } catch (err) {
4348
4369
  const msg = require_dist.errMsg(err);
4349
- log.error("runInference failed", { meta: { error: msg } });
4370
+ log.error("runInference failed", { meta: {
4371
+ error: msg,
4372
+ nodeId: this.nodeId,
4373
+ steps: dispatchSteps.map((s) => s.addonId).join(","),
4374
+ ...camConfig?.deviceKey ? { deviceKey: camConfig.deviceKey } : {}
4375
+ } });
4350
4376
  return null;
4351
4377
  }
4352
4378
  }
@@ -2,7 +2,7 @@ import { B as errMsg, G as createEvent, M as pipelineRunnerCapability, S as defi
2
2
  import { n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-BeHi78PZ.mjs";
3
3
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
4
4
  import { t as isWorkerReply } from "../worker-protocol-D7RzZIla.mjs";
5
- import { a as getStepDefinition } from "../step-definitions-BkY9_IM6.mjs";
5
+ import { o as getStepDefinition } from "../step-definitions-C8tk9fPJ.mjs";
6
6
  import * as os from "node:os";
7
7
  import { fork } from "node:child_process";
8
8
  import { fileURLToPath } from "node:url";
@@ -2638,6 +2638,28 @@ function pickWeightedLeastLoaded(devices) {
2638
2638
  });
2639
2639
  }
2640
2640
  /**
2641
+ * Build the `canRun` predicate for ONE enrichment dispatch. The step and its
2642
+ * enabled descendants ride the SAME `runPipeline` call — one pool, one format
2643
+ * (detail-subtree contract: "its inherited children ride the same call → same
2644
+ * device") — so a format can run the dispatch only when EVERY catalog-known
2645
+ * step in the subtree ships a build for it. Gating only the subtree TOP let a
2646
+ * `face-detection` with a tflite build stay on the Coral while its
2647
+ * `face-embedding` child (no tflite build anywhere) doomed the call.
2648
+ * Unknown/custom addonIds (`getStepDef` → null) have no catalog to gate on
2649
+ * and never block. `getStepDef` is injected — this module stays catalog-free.
2650
+ */
2651
+ function buildSubtreeCanRun(step, getStepDef) {
2652
+ const defs = [];
2653
+ const walk = (s) => {
2654
+ if (s.enabled === false) return;
2655
+ const def = getStepDef(s.addonId);
2656
+ if (def !== null) defs.push(def);
2657
+ for (const child of s.children ?? []) walk(child);
2658
+ };
2659
+ walk(step);
2660
+ return (format) => defs.every((def) => def.models.some((m) => m.formats[format]));
2661
+ }
2662
+ /**
2641
2663
  * Resolve the device one enrichment step runs on. See the module header for the
2642
2664
  * decision table. Pure — never throws, no I/O.
2643
2665
  */
@@ -3720,8 +3742,7 @@ var PipelineRunnerAddon = class extends BaseAddon {
3720
3742
  maxSessions: d.maxSessions,
3721
3743
  attachedCameras: attachedByKey.get(d.deviceKey) ?? 0
3722
3744
  }));
3723
- const def = tryGetStepDefinition(step.addonId);
3724
- const canRun = (format) => def === null || def.models.some((m) => m.formats[format]);
3745
+ const canRun = buildSubtreeCanRun(step, tryGetStepDefinition);
3725
3746
  const result = resolveStepDevice({
3726
3747
  effectiveDeviceKey,
3727
3748
  devices,
@@ -4339,7 +4360,12 @@ var PipelineRunnerAddon = class extends BaseAddon {
4339
4360
  });
4340
4361
  } catch (err) {
4341
4362
  const msg = errMsg(err);
4342
- log.error("runInference failed", { meta: { error: msg } });
4363
+ log.error("runInference failed", { meta: {
4364
+ error: msg,
4365
+ nodeId: this.nodeId,
4366
+ steps: dispatchSteps.map((s) => s.addonId).join(","),
4367
+ ...camConfig?.deviceKey ? { deviceKey: camConfig.deviceKey } : {}
4368
+ } });
4343
4369
  return null;
4344
4370
  }
4345
4371
  }
@@ -1759,7 +1759,16 @@ function getStepDefinition(stepId) {
1759
1759
  * build — an unloadable case flagged elsewhere, not resolved here.
1760
1760
  */
1761
1761
  function getDefaultModelForFormat(stepId, format) {
1762
- const def = getStepDefinition(stepId);
1762
+ return getDefaultModelForFormatFromDef(getStepDefinition(stepId), format);
1763
+ }
1764
+ /**
1765
+ * {@link getDefaultModelForFormat} over an explicit {@link StepDefinition} —
1766
+ * the def-based seam callers with an INJECTED catalog use
1767
+ * (`resolveDefaultDetectionModel`'s `getStepDef` parameter must flow into the
1768
+ * fallback too, or a test-injected catalog silently falls back to the real
1769
+ * one). Identical resolution order; see the doc above.
1770
+ */
1771
+ function getDefaultModelForFormatFromDef(def, format) {
1763
1772
  const hasFormatBuild = (modelId) => def.models.find((m) => m.id === modelId)?.formats[format] !== void 0;
1764
1773
  const declaredForFormat = def.defaultModelIdByFormat?.[format];
1765
1774
  if (declaredForFormat !== void 0 && hasFormatBuild(declaredForFormat)) return declaredForFormat;
@@ -1798,4 +1807,4 @@ function resolveModelForFormat(stepId, chosenModelId, format) {
1798
1807
  return getDefaultModelForFormat(stepId, format);
1799
1808
  }
1800
1809
  //#endregion
1801
- export { getStepDefinition as a, getStep as i, ALL_STEPS as n, resolveModelForFormat as o, getDefaultModelForFormat as r, ALL_PIPELINE_STEPS as t };
1810
+ export { getStep as a, getDefaultModelForFormatFromDef as i, ALL_STEPS as n, getStepDefinition as o, getDefaultModelForFormat as r, resolveModelForFormat as s, ALL_PIPELINE_STEPS as t };
@@ -1759,7 +1759,16 @@ function getStepDefinition(stepId) {
1759
1759
  * build — an unloadable case flagged elsewhere, not resolved here.
1760
1760
  */
1761
1761
  function getDefaultModelForFormat(stepId, format) {
1762
- const def = getStepDefinition(stepId);
1762
+ return getDefaultModelForFormatFromDef(getStepDefinition(stepId), format);
1763
+ }
1764
+ /**
1765
+ * {@link getDefaultModelForFormat} over an explicit {@link StepDefinition} —
1766
+ * the def-based seam callers with an INJECTED catalog use
1767
+ * (`resolveDefaultDetectionModel`'s `getStepDef` parameter must flow into the
1768
+ * fallback too, or a test-injected catalog silently falls back to the real
1769
+ * one). Identical resolution order; see the doc above.
1770
+ */
1771
+ function getDefaultModelForFormatFromDef(def, format) {
1763
1772
  const hasFormatBuild = (modelId) => def.models.find((m) => m.id === modelId)?.formats[format] !== void 0;
1764
1773
  const declaredForFormat = def.defaultModelIdByFormat?.[format];
1765
1774
  if (declaredForFormat !== void 0 && hasFormatBuild(declaredForFormat)) return declaredForFormat;
@@ -1816,6 +1825,12 @@ Object.defineProperty(exports, "getDefaultModelForFormat", {
1816
1825
  return getDefaultModelForFormat;
1817
1826
  }
1818
1827
  });
1828
+ Object.defineProperty(exports, "getDefaultModelForFormatFromDef", {
1829
+ enumerable: true,
1830
+ get: function() {
1831
+ return getDefaultModelForFormatFromDef;
1832
+ }
1833
+ });
1819
1834
  Object.defineProperty(exports, "getStep", {
1820
1835
  enumerable: true,
1821
1836
  get: function() {
@@ -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.7",
6
+ version: "1.2.8",
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.18",
21
+ version: "1.2.19",
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.14",
36
+ version: "1.2.15",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_stream_broker_widgets",
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.2.18",
39
+ version: "1.2.19",
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.7",
48
+ version: "1.2.8",
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.14",
84
+ version: "1.2.15",
85
85
  scope: "default",
86
86
  shareConfig: {
87
87
  singleton: !0,
@@ -30,7 +30,7 @@ async function d(e) {
30
30
  }
31
31
  }
32
32
  async function f() {
33
- return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BUXeX-vb.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C5m4hC2K.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
@@ -1,4 +1,4 @@
1
- import{d as e,f as t,g as n,h as r,m as i,p as a}from"./index-CHXOWKHF.js";var o=n(t()),s=n(e(),1),c=Math.PI/180;function l(){return typeof window<`u`&&({}.toString.call(window)===`[object Window]`||{}.toString.call(window)===`[object global]`)}var u=typeof global<`u`?global:typeof window<`u`?window:typeof WorkerGlobalScope<`u`?self:{},d={_global:u,version:`10.3.0`,isBrowser:l(),isUnminified:/param/.test(function(e){}.toString()),dblClickWindow:400,getAngle(e){return d.angleDeg?e*c:e},enableTrace:!1,pointerEventsEnabled:!0,autoDrawEnabled:!0,hitOnDragEnabled:!1,capturePointerEventsEnabled:!1,_mouseListenClick:!1,_touchListenClick:!1,_pointerListenClick:!1,_mouseInDblClickWindow:!1,_touchInDblClickWindow:!1,_pointerInDblClickWindow:!1,_mouseDblClickPointerId:null,_touchDblClickPointerId:null,_pointerDblClickPointerId:null,_renderBackend:`web`,legacyTextRendering:!1,pixelRatio:typeof window<`u`&&window.devicePixelRatio||1,dragDistance:3,angleDeg:!0,showWarnings:!0,dragButtons:[0,1],isDragging(){return d.DD.isDragging},isTransforming(){return d.Transformer?.isTransforming()??!1},isDragReady(){return!!d.DD.node},releaseCanvasOnDestroy:!0,document:u.document,_injectGlobal(e){u.Konva!==void 0&&console.error(`Several Konva instances detected. It is not recommended to use multiple Konva instances in the same environment.`),u.Konva=e}},f=e=>{d[e.prototype.getClassName()]=e};d._injectGlobal(d);var p=`Konva.js unsupported environment.
1
+ import{d as e,f as t,g as n,h as r,m as i,p as a}from"./index-9Ob2YrIf.js";var o=n(t()),s=n(e(),1),c=Math.PI/180;function l(){return typeof window<`u`&&({}.toString.call(window)===`[object Window]`||{}.toString.call(window)===`[object global]`)}var u=typeof global<`u`?global:typeof window<`u`?window:typeof WorkerGlobalScope<`u`?self:{},d={_global:u,version:`10.3.0`,isBrowser:l(),isUnminified:/param/.test(function(e){}.toString()),dblClickWindow:400,getAngle(e){return d.angleDeg?e*c:e},enableTrace:!1,pointerEventsEnabled:!0,autoDrawEnabled:!0,hitOnDragEnabled:!1,capturePointerEventsEnabled:!1,_mouseListenClick:!1,_touchListenClick:!1,_pointerListenClick:!1,_mouseInDblClickWindow:!1,_touchInDblClickWindow:!1,_pointerInDblClickWindow:!1,_mouseDblClickPointerId:null,_touchDblClickPointerId:null,_pointerDblClickPointerId:null,_renderBackend:`web`,legacyTextRendering:!1,pixelRatio:typeof window<`u`&&window.devicePixelRatio||1,dragDistance:3,angleDeg:!0,showWarnings:!0,dragButtons:[0,1],isDragging(){return d.DD.isDragging},isTransforming(){return d.Transformer?.isTransforming()??!1},isDragReady(){return!!d.DD.node},releaseCanvasOnDestroy:!0,document:u.document,_injectGlobal(e){u.Konva!==void 0&&console.error(`Several Konva instances detected. It is not recommended to use multiple Konva instances in the same environment.`),u.Konva=e}},f=e=>{d[e.prototype.getClassName()]=e};d._injectGlobal(d);var p=`Konva.js unsupported environment.
2
2
 
3
3
  Looks like you are trying to use Konva.js in Node.js environment. because "document" object is undefined.
4
4
 
@@ -1 +1 @@
1
- import{a as e,c as t,d as n,f as r,g as i,l as a,o,r as s,s as c,u as l}from"./index-CHXOWKHF.js";import{MaskShapeCanvas as u}from"./MaskShapeCanvas-DI4BY7W2-B0DyP46h.js";var d=i(r(),1),f=i(n(),1),p=o(`grid-2x2`,[[`path`,{d:`M12 3v18`,key:`108xh3`}],[`path`,{d:`M3 12h18`,key:`1i2n21`}],[`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`,key:`h1oib`}]]),m=110,h=`motion-zones`,g=0,_=[1,2,3],v=1,y=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,b=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function x(e,t,n){let r=t*n,i=Array.from({length:r});for(let t=0;t<r;t+=1)i[t]=e[t]===!0;return i}function S(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(e[n]!==t[n])return!1;return!0}function C(e,t){return Math.ceil(e/t)}function w(e,t,n){return Math.min(n-1,Math.floor((e+.5)/t*n))}function T(e,t,n,r){let i=C(t,r),a=C(n,r),o=Array.from({length:i*a},()=>!1);for(let r=0;r<n;r+=1){let s=w(r,n,a);for(let n=0;n<t;n+=1)e[r*t+n]===!0&&(o[s*i+w(n,t,i)]=!0)}return o}function E(e,t,n,r){let i=C(t,r),a=C(n,r),o=Array.from({length:t*n},()=>!1);for(let r=0;r<n;r+=1){let s=w(r,n,a);for(let n=0;n<t;n+=1)o[r*t+n]=e[s*i+w(n,t,i)]===!0}return o}function D({deviceId:n}){let r=t(l().trpcClient,n),[i,o]=(0,d.useState)(null),[w,D]=(0,d.useState)(!1),[O,k]=(0,d.useState)(null),[A,j]=(0,d.useState)(null),[M,N]=(0,d.useState)(v),[P,F]=(0,d.useState)(!1),[I,L]=(0,d.useState)(!1),R=(0,d.useRef)(!1);(0,d.useEffect)(()=>{if(!r)return;let e=!1;return R.current=!1,o(null),D(!1),k(null),j(null),N(v),L(!1),(async()=>{try{let t=await r.motionZones?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(o(t),R.current)return;let n=await r.motionZones?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);R.current=!0;let i=n.regions.find(e=>e.shape.kind===`grid`),a=x(i?i.shape.cells:[],t.grid.width,t.grid.height);j(a),k(T(a,t.grid.width,t.grid.height,v))}catch(t){if(e)return;c(t)?D(!0):console.error(`Motion Zones load failed`,t)}})(),()=>{e=!0}},[r]);let z=i?i.grid.width:0,B=i?i.grid.height:0,V=C(z,M),H=C(B,M),U=(0,d.useMemo)(()=>O&&i?E(O,z,B,M):null,[O,i,z,B,M]),W=(0,d.useMemo)(()=>U!==null&&A!==null&&!S(U,A),[U,A]),G=(0,d.useMemo)(()=>U?U.reduce((e,t)=>t?e+1:e,0):0,[U]),K=z*B,q=V*H,J=(0,d.useCallback)(e=>{q>0&&k(Array.from({length:q},()=>e))},[q]),Y=(0,d.useCallback)(()=>{k(e=>e&&e.map(e=>!e))},[]),X=(0,d.useCallback)(()=>{A&&i&&k(T(A,z,B,M))},[A,i,z,B,M]),Z=(0,d.useCallback)(e=>{e===M||!i||k(t=>{if(!t)return N(e),t;let n=T(E(t,z,B,M),z,B,e);return N(e),n})},[M,i,z,B]),Q=(0,d.useMemo)(()=>i&&O?[{id:g,shape:{kind:`grid`,gridWidth:V,gridHeight:H,cells:[...O]}}]:[],[i,O,V,H]),$=(0,d.useCallback)((e,t)=>{t.kind===`grid`&&k(t.cells)},[]),ee=(0,d.useCallback)(async()=>{if(!(!r||!O||!i)){F(!0);try{let e=E(O,i.grid.width,i.grid.height,M),t={kind:`grid`,gridWidth:i.grid.width,gridHeight:i.grid.height,cells:e};await r.motionZones?.setZone({patch:{regions:[{id:g,enabled:!0,shape:t}]}});let n=await r.motionZones?.getStatus({});if(n){let e=n.regions.find(e=>e.shape.kind===`grid`),t=x(e?e.shape.cells:[],i.grid.width,i.grid.height);j(t),k(T(t,i.grid.width,i.grid.height,M))}}catch(e){console.error(`Motion Zones save failed`,e)}finally{F(!1)}}},[r,O,i,M]);a((0,d.useMemo)(()=>I&&!w&&i&&O?{id:h,order:m,node:(0,f.jsx)(u,{transparent:!0,items:Q,supportedShapes:[`grid`],grid:{width:V,height:H},selectedId:g,onSelect:()=>{},onShapeChange:$,onDrawComplete:()=>{},drawingKind:null})}:null,[I,w,i,O,Q,$,V,H]));let te=!w&&i!==null&&O!==null;return r?(0,f.jsx)(e,{title:`Motion Zones`,icon:(0,f.jsx)(p,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,f.jsx)(`div`,{className:`flex flex-col gap-3`,children:w?(0,f.jsx)(`p`,{className:`${s} leading-relaxed`,children:`This camera doesn't expose an on-board motion zones grid.`}):te?(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`p`,{className:`${s} leading-relaxed`,children:[`Toggle `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Edit grid`}),` to paint the region directly on the live frame, then `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Save`}),` to push the mask to the camera. Pick a bigger`,` `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Cell size`}),` for quicker, broad-stroke painting — it's resampled to the camera's native `,i.grid.width,`×`,i.grid.height,` grid on save (×1 is the finest).`]}),(0,f.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,f.jsx)(`button`,{type:`button`,onClick:()=>L(e=>!e),disabled:P,"aria-pressed":I,className:I?b:y,children:I?`Done editing`:`Edit grid`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>J(!0),disabled:P,className:y,children:`All on`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>J(!1),disabled:P,className:y,children:`All off`}),(0,f.jsx)(`button`,{type:`button`,onClick:Y,disabled:P,className:y,children:`Invert`}),(0,f.jsxs)(`div`,{className:`flex items-center gap-1 ml-1`,role:`group`,"aria-label":`Cell size`,children:[(0,f.jsx)(`span`,{className:`${s} mr-0.5`,children:`Cell size`}),_.map(e=>(0,f.jsxs)(`button`,{type:`button`,onClick:()=>Z(e),disabled:P,"aria-pressed":M===e,title:e===1?`Camera grid ${z}×${B} (finest)`:`${C(z,e)}×${C(B,e)} painting grid · cells ×${e} bigger`,className:M===e?b:y,children:[`×`,e]},e))]}),(0,f.jsxs)(`span`,{className:`${s} ml-1 tabular-nums`,children:[G,` / `,K,` cells · `,i.grid.width,`×`,i.grid.height,M===1?``:` · paint ${V}×${H}`]}),(0,f.jsx)(`span`,{className:`flex-1`}),(0,f.jsx)(`button`,{type:`button`,onClick:X,disabled:P||!W,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:`Revert`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>void ee(),disabled:P||!W,className:b,children:P?`Saving…`:`Save`})]})]}):(0,f.jsx)(`p`,{className:`${s} leading-relaxed`,children:`Loading the camera's grid…`})})}):null}export{D as MotionZonesSettings};
1
+ import{a as e,c as t,d as n,f as r,g as i,l as a,o,r as s,s as c,u as l}from"./index-9Ob2YrIf.js";import{MaskShapeCanvas as u}from"./MaskShapeCanvas-DI4BY7W2-Dx-Vrpyt.js";var d=i(r(),1),f=i(n(),1),p=o(`grid-2x2`,[[`path`,{d:`M12 3v18`,key:`108xh3`}],[`path`,{d:`M3 12h18`,key:`1i2n21`}],[`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`,key:`h1oib`}]]),m=110,h=`motion-zones`,g=0,_=[1,2,3],v=1,y=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,b=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function x(e,t,n){let r=t*n,i=Array.from({length:r});for(let t=0;t<r;t+=1)i[t]=e[t]===!0;return i}function S(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(e[n]!==t[n])return!1;return!0}function C(e,t){return Math.ceil(e/t)}function w(e,t,n){return Math.min(n-1,Math.floor((e+.5)/t*n))}function T(e,t,n,r){let i=C(t,r),a=C(n,r),o=Array.from({length:i*a},()=>!1);for(let r=0;r<n;r+=1){let s=w(r,n,a);for(let n=0;n<t;n+=1)e[r*t+n]===!0&&(o[s*i+w(n,t,i)]=!0)}return o}function E(e,t,n,r){let i=C(t,r),a=C(n,r),o=Array.from({length:t*n},()=>!1);for(let r=0;r<n;r+=1){let s=w(r,n,a);for(let n=0;n<t;n+=1)o[r*t+n]=e[s*i+w(n,t,i)]===!0}return o}function D({deviceId:n}){let r=t(l().trpcClient,n),[i,o]=(0,d.useState)(null),[w,D]=(0,d.useState)(!1),[O,k]=(0,d.useState)(null),[A,j]=(0,d.useState)(null),[M,N]=(0,d.useState)(v),[P,F]=(0,d.useState)(!1),[I,L]=(0,d.useState)(!1),R=(0,d.useRef)(!1);(0,d.useEffect)(()=>{if(!r)return;let e=!1;return R.current=!1,o(null),D(!1),k(null),j(null),N(v),L(!1),(async()=>{try{let t=await r.motionZones?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(o(t),R.current)return;let n=await r.motionZones?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);R.current=!0;let i=n.regions.find(e=>e.shape.kind===`grid`),a=x(i?i.shape.cells:[],t.grid.width,t.grid.height);j(a),k(T(a,t.grid.width,t.grid.height,v))}catch(t){if(e)return;c(t)?D(!0):console.error(`Motion Zones load failed`,t)}})(),()=>{e=!0}},[r]);let z=i?i.grid.width:0,B=i?i.grid.height:0,V=C(z,M),H=C(B,M),U=(0,d.useMemo)(()=>O&&i?E(O,z,B,M):null,[O,i,z,B,M]),W=(0,d.useMemo)(()=>U!==null&&A!==null&&!S(U,A),[U,A]),G=(0,d.useMemo)(()=>U?U.reduce((e,t)=>t?e+1:e,0):0,[U]),K=z*B,q=V*H,J=(0,d.useCallback)(e=>{q>0&&k(Array.from({length:q},()=>e))},[q]),Y=(0,d.useCallback)(()=>{k(e=>e&&e.map(e=>!e))},[]),X=(0,d.useCallback)(()=>{A&&i&&k(T(A,z,B,M))},[A,i,z,B,M]),Z=(0,d.useCallback)(e=>{e===M||!i||k(t=>{if(!t)return N(e),t;let n=T(E(t,z,B,M),z,B,e);return N(e),n})},[M,i,z,B]),Q=(0,d.useMemo)(()=>i&&O?[{id:g,shape:{kind:`grid`,gridWidth:V,gridHeight:H,cells:[...O]}}]:[],[i,O,V,H]),$=(0,d.useCallback)((e,t)=>{t.kind===`grid`&&k(t.cells)},[]),ee=(0,d.useCallback)(async()=>{if(!(!r||!O||!i)){F(!0);try{let e=E(O,i.grid.width,i.grid.height,M),t={kind:`grid`,gridWidth:i.grid.width,gridHeight:i.grid.height,cells:e};await r.motionZones?.setZone({patch:{regions:[{id:g,enabled:!0,shape:t}]}});let n=await r.motionZones?.getStatus({});if(n){let e=n.regions.find(e=>e.shape.kind===`grid`),t=x(e?e.shape.cells:[],i.grid.width,i.grid.height);j(t),k(T(t,i.grid.width,i.grid.height,M))}}catch(e){console.error(`Motion Zones save failed`,e)}finally{F(!1)}}},[r,O,i,M]);a((0,d.useMemo)(()=>I&&!w&&i&&O?{id:h,order:m,node:(0,f.jsx)(u,{transparent:!0,items:Q,supportedShapes:[`grid`],grid:{width:V,height:H},selectedId:g,onSelect:()=>{},onShapeChange:$,onDrawComplete:()=>{},drawingKind:null})}:null,[I,w,i,O,Q,$,V,H]));let te=!w&&i!==null&&O!==null;return r?(0,f.jsx)(e,{title:`Motion Zones`,icon:(0,f.jsx)(p,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,f.jsx)(`div`,{className:`flex flex-col gap-3`,children:w?(0,f.jsx)(`p`,{className:`${s} leading-relaxed`,children:`This camera doesn't expose an on-board motion zones grid.`}):te?(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`p`,{className:`${s} leading-relaxed`,children:[`Toggle `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Edit grid`}),` to paint the region directly on the live frame, then `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Save`}),` to push the mask to the camera. Pick a bigger`,` `,(0,f.jsx)(`strong`,{className:`text-foreground`,children:`Cell size`}),` for quicker, broad-stroke painting — it's resampled to the camera's native `,i.grid.width,`×`,i.grid.height,` grid on save (×1 is the finest).`]}),(0,f.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,f.jsx)(`button`,{type:`button`,onClick:()=>L(e=>!e),disabled:P,"aria-pressed":I,className:I?b:y,children:I?`Done editing`:`Edit grid`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>J(!0),disabled:P,className:y,children:`All on`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>J(!1),disabled:P,className:y,children:`All off`}),(0,f.jsx)(`button`,{type:`button`,onClick:Y,disabled:P,className:y,children:`Invert`}),(0,f.jsxs)(`div`,{className:`flex items-center gap-1 ml-1`,role:`group`,"aria-label":`Cell size`,children:[(0,f.jsx)(`span`,{className:`${s} mr-0.5`,children:`Cell size`}),_.map(e=>(0,f.jsxs)(`button`,{type:`button`,onClick:()=>Z(e),disabled:P,"aria-pressed":M===e,title:e===1?`Camera grid ${z}×${B} (finest)`:`${C(z,e)}×${C(B,e)} painting grid · cells ×${e} bigger`,className:M===e?b:y,children:[`×`,e]},e))]}),(0,f.jsxs)(`span`,{className:`${s} ml-1 tabular-nums`,children:[G,` / `,K,` cells · `,i.grid.width,`×`,i.grid.height,M===1?``:` · paint ${V}×${H}`]}),(0,f.jsx)(`span`,{className:`flex-1`}),(0,f.jsx)(`button`,{type:`button`,onClick:X,disabled:P||!W,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:`Revert`}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>void ee(),disabled:P||!W,className:b,children:P?`Saving…`:`Save`})]})]}):(0,f.jsx)(`p`,{className:`${s} leading-relaxed`,children:`Loading the camera's grid…`})})}):null}export{D as MotionZonesSettings};
@@ -1 +1 @@
1
- import{a as e,c as t,d as n,f as r,g as i,i as a,l as o,n as s,o as c,r as l,s as u,t as d,u as ee}from"./index-CHXOWKHF.js";import{MaskShapeCanvas as te}from"./MaskShapeCanvas-DI4BY7W2-B0DyP46h.js";var f=i(r(),1),p=i(n(),1),m=c(`hexagon`,[[`path`,{d:`M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z`,key:`yt0hxn`}]]),h=120,g=`privacy-mask`,_=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,v=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function y(e){return e.kind===`rect`||e.kind===`polygon`?e:null}function b(e){let t=new Set(e.map(e=>e.id)),n=0;for(;t.has(n);)n+=1;return n}function x(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(JSON.stringify(e[n])!==JSON.stringify(t[n]))return!1;return!0}function S({deviceId:n}){let r=t(ee().trpcClient,n),[i,c]=(0,f.useState)(null),[S,C]=(0,f.useState)(!1),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(null),[O,k]=(0,f.useState)(!1),[A,j]=(0,f.useState)(!1),[M,N]=(0,f.useState)(null),[P,F]=(0,f.useState)(null),I=(0,f.useRef)(!1);(0,f.useEffect)(()=>{if(!r)return;let e=!1;return I.current=!1,c(null),C(!1),T(null),D(null),j(!1),N(null),F(null),(async()=>{try{let t=await r.privacyMask?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(c(t),I.current)return;let n=await r.privacyMask?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);I.current=!0;let i={enabled:n.enabled,regions:n.regions};D(i),T(i)}catch(t){if(e)return;u(t)?C(!0):console.error(`Privacy Mask load failed`,t)}})(),()=>{e=!0}},[r]);let L=(0,f.useMemo)(()=>w!==null&&E!==null&&(w.enabled!==E.enabled||!x(w.regions,E.regions)),[w,E]),R=w?w.regions.length:0,z=i?i.maxRegions:0,B=(0,f.useRef)(0);(0,f.useEffect)(()=>{B.current=z},[z]);let V=z>0&&R>=z,H=(0,f.useCallback)(()=>{T(e=>e&&{...e,enabled:!e.enabled})},[]),U=(0,f.useCallback)(e=>{N(typeof e==`number`?e:null)},[]),W=(0,f.useMemo)(()=>w?w.regions.map(e=>({id:e.id,shape:e.shape,enabled:e.enabled,label:`Zone ${String(e.id)}`})):[],[w]),G=(0,f.useCallback)((e,t)=>{let n=y(t);n&&T(t=>t&&{...t,regions:t.regions.map(t=>t.id===e?{...t,shape:n}:t)})},[]),K=(0,f.useCallback)(e=>{let t=y(e);t&&(F(null),T(e=>{if(!e)return e;let n=B.current;if(n>0&&e.regions.length>=n)return e;let r=b(e.regions),i={id:r,enabled:!0,shape:t};return N(r),{...e,regions:[...e.regions,i]}}))},[]),q=(0,f.useCallback)(e=>{j(!0),N(null),F(e)},[]),J=(0,f.useCallback)(e=>{j(!0),F(null),N(e)},[]),Y=(0,f.useCallback)(e=>{N(t=>t===e?null:t),T(t=>t&&{...t,regions:t.regions.filter(t=>t.id!==e)})},[]),X=(0,f.useCallback)(()=>{F(null),N(null),E&&T({enabled:E.enabled,regions:E.regions})},[E]),Z=(0,f.useCallback)(async()=>{if(!(!r||!w)){k(!0);try{await r.privacyMask?.setMask({patch:{enabled:w.enabled,regions:[...w.regions]}});let e=await r.privacyMask?.getStatus({});if(e){let t={enabled:e.enabled,regions:e.regions};D(t),T(t)}}catch(e){console.error(`Privacy Mask save failed`,e)}finally{k(!1)}}},[r,w]),ne=(0,f.useCallback)(()=>{j(e=>(e&&(F(null),N(null)),!e))},[]),Q=i?.supportedShapes??[];o((0,f.useMemo)(()=>A&&!S&&i&&w?{id:g,order:h,node:(0,p.jsx)(te,{transparent:!0,items:W,supportedShapes:Q,polygonVertices:i.polygonVertices,selectedId:M,onSelect:U,onShapeChange:G,onDrawComplete:K,drawingKind:P})}:null,[A,S,i,w,W,Q,M,U,G,K,P]));let re=i?.supportedShapes.includes(`rect`)??!1,ie=i?.supportedShapes.includes(`polygon`)??!1,$=i!==null&&(i.maxRegions<=0||i.supportedShapes.length===0),ae=!S&&!$&&i!==null&&w!==null;return r?(0,p.jsx)(e,{title:`Privacy Mask`,icon:(0,p.jsx)(d,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,p.jsx)(`div`,{className:`flex flex-col gap-3`,children:S||$?(0,p.jsx)(`p`,{className:`${l} leading-relaxed`,children:`This camera doesn't support an on-board privacy mask.`}):ae?(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(`p`,{className:`${l} leading-relaxed`,children:[`Toggle `,(0,p.jsx)(`strong`,{className:`text-foreground`,children:`Edit mask`}),` to draw blanked-out zones on the live frame, then `,(0,p.jsx)(`strong`,{className:`text-foreground`,children:`Save`}),` to push them to the camera. Drag a rectangle to move, its corner to resize; drag polygon vertices, click an edge midpoint to add one, or right-click a vertex to remove it.`]}),(0,p.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,p.jsx)(`button`,{type:`button`,onClick:ne,disabled:O,"aria-pressed":A,className:A?v:_,children:A?`Done editing`:`Edit mask`}),(0,p.jsx)(`button`,{type:`button`,onClick:H,disabled:O,"aria-pressed":w.enabled,className:w.enabled?v:_,children:w.enabled?`Mask on`:`Mask off`}),re&&(0,p.jsx)(`button`,{type:`button`,onClick:()=>q(`rect`),disabled:O||V,"aria-pressed":P===`rect`,className:P===`rect`?v:_,title:V?`Maximum zones reached`:`Add a rectangle zone`,children:`+ Rect`}),ie&&(0,p.jsx)(`button`,{type:`button`,onClick:()=>q(`polygon`),disabled:O||V,"aria-pressed":P===`polygon`,className:P===`polygon`?v:_,title:V?`Maximum zones reached`:`Add a polygon zone`,children:`+ Polygon`}),(0,p.jsxs)(`span`,{className:`${l} ml-1 tabular-nums`,children:[R,` / `,z,` zones`]}),(0,p.jsx)(`span`,{className:`flex-1`}),(0,p.jsx)(`button`,{type:`button`,onClick:X,disabled:O||!L,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:`Revert`}),(0,p.jsx)(`button`,{type:`button`,onClick:()=>void Z(),disabled:O||!L,className:v,children:O?`Saving…`:`Save`})]}),R>0?(0,p.jsx)(`div`,{className:`flex flex-col gap-1`,children:w.regions.map(e=>{let t=M===e.id,n=e.shape.kind===`polygon`?m:s;return(0,p.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border px-2 py-1 transition-colors ${t?`border-primary/50 bg-primary/10`:`border-border bg-surface`}`,children:[(0,p.jsxs)(`button`,{type:`button`,onClick:()=>J(e.id),disabled:O,className:`flex flex-1 items-center gap-2 text-left text-[11px] font-medium text-foreground-subtle hover:text-foreground disabled:opacity-40 transition-colors`,children:[(0,p.jsx)(n,{className:`h-3.5 w-3.5 shrink-0`}),(0,p.jsxs)(`span`,{children:[`Zone `,e.id]}),(0,p.jsx)(`span`,{className:`text-foreground-faint capitalize`,children:e.shape.kind})]}),(0,p.jsx)(`button`,{type:`button`,onClick:()=>Y(e.id),disabled:O,"aria-label":`Delete zone ${String(e.id)}`,title:`Delete zone`,className:`inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-surface text-foreground-subtle hover:border-red-400/40 hover:bg-red-500/10 hover:text-red-400 disabled:opacity-40 transition-colors`,children:(0,p.jsx)(a,{className:`h-3.5 w-3.5`})})]},e.id)})}):null]}):(0,p.jsx)(`p`,{className:`${l} leading-relaxed`,children:`Loading the camera's privacy mask…`})})}):null}export{S as PrivacyMaskSettings};
1
+ import{a as e,c as t,d as n,f as r,g as i,i as a,l as o,n as s,o as c,r as l,s as u,t as d,u as ee}from"./index-9Ob2YrIf.js";import{MaskShapeCanvas as te}from"./MaskShapeCanvas-DI4BY7W2-Dx-Vrpyt.js";var f=i(r(),1),p=i(n(),1),m=c(`hexagon`,[[`path`,{d:`M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z`,key:`yt0hxn`}]]),h=120,g=`privacy-mask`,_=`rounded-md border border-border bg-surface px-2 py-1 text-[11px] font-medium text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,v=`rounded-md border border-primary/50 bg-primary/15 px-2.5 py-1 text-[11px] font-medium text-primary hover:bg-primary/25 disabled:opacity-40 transition-colors`;function y(e){return e.kind===`rect`||e.kind===`polygon`?e:null}function b(e){let t=new Set(e.map(e=>e.id)),n=0;for(;t.has(n);)n+=1;return n}function x(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(JSON.stringify(e[n])!==JSON.stringify(t[n]))return!1;return!0}function S({deviceId:n}){let r=t(ee().trpcClient,n),[i,c]=(0,f.useState)(null),[S,C]=(0,f.useState)(!1),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(null),[O,k]=(0,f.useState)(!1),[A,j]=(0,f.useState)(!1),[M,N]=(0,f.useState)(null),[P,F]=(0,f.useState)(null),I=(0,f.useRef)(!1);(0,f.useEffect)(()=>{if(!r)return;let e=!1;return I.current=!1,c(null),C(!1),T(null),D(null),j(!1),N(null),F(null),(async()=>{try{let t=await r.privacyMask?.getOptions({});if(e)return;if(!t)throw Error(`device proxy not ready`);if(c(t),I.current)return;let n=await r.privacyMask?.getStatus({});if(e)return;if(!n)throw Error(`device proxy not ready`);I.current=!0;let i={enabled:n.enabled,regions:n.regions};D(i),T(i)}catch(t){if(e)return;u(t)?C(!0):console.error(`Privacy Mask load failed`,t)}})(),()=>{e=!0}},[r]);let L=(0,f.useMemo)(()=>w!==null&&E!==null&&(w.enabled!==E.enabled||!x(w.regions,E.regions)),[w,E]),R=w?w.regions.length:0,z=i?i.maxRegions:0,B=(0,f.useRef)(0);(0,f.useEffect)(()=>{B.current=z},[z]);let V=z>0&&R>=z,H=(0,f.useCallback)(()=>{T(e=>e&&{...e,enabled:!e.enabled})},[]),U=(0,f.useCallback)(e=>{N(typeof e==`number`?e:null)},[]),W=(0,f.useMemo)(()=>w?w.regions.map(e=>({id:e.id,shape:e.shape,enabled:e.enabled,label:`Zone ${String(e.id)}`})):[],[w]),G=(0,f.useCallback)((e,t)=>{let n=y(t);n&&T(t=>t&&{...t,regions:t.regions.map(t=>t.id===e?{...t,shape:n}:t)})},[]),K=(0,f.useCallback)(e=>{let t=y(e);t&&(F(null),T(e=>{if(!e)return e;let n=B.current;if(n>0&&e.regions.length>=n)return e;let r=b(e.regions),i={id:r,enabled:!0,shape:t};return N(r),{...e,regions:[...e.regions,i]}}))},[]),q=(0,f.useCallback)(e=>{j(!0),N(null),F(e)},[]),J=(0,f.useCallback)(e=>{j(!0),F(null),N(e)},[]),Y=(0,f.useCallback)(e=>{N(t=>t===e?null:t),T(t=>t&&{...t,regions:t.regions.filter(t=>t.id!==e)})},[]),X=(0,f.useCallback)(()=>{F(null),N(null),E&&T({enabled:E.enabled,regions:E.regions})},[E]),Z=(0,f.useCallback)(async()=>{if(!(!r||!w)){k(!0);try{await r.privacyMask?.setMask({patch:{enabled:w.enabled,regions:[...w.regions]}});let e=await r.privacyMask?.getStatus({});if(e){let t={enabled:e.enabled,regions:e.regions};D(t),T(t)}}catch(e){console.error(`Privacy Mask save failed`,e)}finally{k(!1)}}},[r,w]),ne=(0,f.useCallback)(()=>{j(e=>(e&&(F(null),N(null)),!e))},[]),Q=i?.supportedShapes??[];o((0,f.useMemo)(()=>A&&!S&&i&&w?{id:g,order:h,node:(0,p.jsx)(te,{transparent:!0,items:W,supportedShapes:Q,polygonVertices:i.polygonVertices,selectedId:M,onSelect:U,onShapeChange:G,onDrawComplete:K,drawingKind:P})}:null,[A,S,i,w,W,Q,M,U,G,K,P]));let re=i?.supportedShapes.includes(`rect`)??!1,ie=i?.supportedShapes.includes(`polygon`)??!1,$=i!==null&&(i.maxRegions<=0||i.supportedShapes.length===0),ae=!S&&!$&&i!==null&&w!==null;return r?(0,p.jsx)(e,{title:`Privacy Mask`,icon:(0,p.jsx)(d,{className:`h-3.5 w-3.5 text-foreground-subtle`}),children:(0,p.jsx)(`div`,{className:`flex flex-col gap-3`,children:S||$?(0,p.jsx)(`p`,{className:`${l} leading-relaxed`,children:`This camera doesn't support an on-board privacy mask.`}):ae?(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(`p`,{className:`${l} leading-relaxed`,children:[`Toggle `,(0,p.jsx)(`strong`,{className:`text-foreground`,children:`Edit mask`}),` to draw blanked-out zones on the live frame, then `,(0,p.jsx)(`strong`,{className:`text-foreground`,children:`Save`}),` to push them to the camera. Drag a rectangle to move, its corner to resize; drag polygon vertices, click an edge midpoint to add one, or right-click a vertex to remove it.`]}),(0,p.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,p.jsx)(`button`,{type:`button`,onClick:ne,disabled:O,"aria-pressed":A,className:A?v:_,children:A?`Done editing`:`Edit mask`}),(0,p.jsx)(`button`,{type:`button`,onClick:H,disabled:O,"aria-pressed":w.enabled,className:w.enabled?v:_,children:w.enabled?`Mask on`:`Mask off`}),re&&(0,p.jsx)(`button`,{type:`button`,onClick:()=>q(`rect`),disabled:O||V,"aria-pressed":P===`rect`,className:P===`rect`?v:_,title:V?`Maximum zones reached`:`Add a rectangle zone`,children:`+ Rect`}),ie&&(0,p.jsx)(`button`,{type:`button`,onClick:()=>q(`polygon`),disabled:O||V,"aria-pressed":P===`polygon`,className:P===`polygon`?v:_,title:V?`Maximum zones reached`:`Add a polygon zone`,children:`+ Polygon`}),(0,p.jsxs)(`span`,{className:`${l} ml-1 tabular-nums`,children:[R,` / `,z,` zones`]}),(0,p.jsx)(`span`,{className:`flex-1`}),(0,p.jsx)(`button`,{type:`button`,onClick:X,disabled:O||!L,className:`rounded-md border border-border bg-surface px-2 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover disabled:opacity-40 transition-colors`,children:`Revert`}),(0,p.jsx)(`button`,{type:`button`,onClick:()=>void Z(),disabled:O||!L,className:v,children:O?`Saving…`:`Save`})]}),R>0?(0,p.jsx)(`div`,{className:`flex flex-col gap-1`,children:w.regions.map(e=>{let t=M===e.id,n=e.shape.kind===`polygon`?m:s;return(0,p.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border px-2 py-1 transition-colors ${t?`border-primary/50 bg-primary/10`:`border-border bg-surface`}`,children:[(0,p.jsxs)(`button`,{type:`button`,onClick:()=>J(e.id),disabled:O,className:`flex flex-1 items-center gap-2 text-left text-[11px] font-medium text-foreground-subtle hover:text-foreground disabled:opacity-40 transition-colors`,children:[(0,p.jsx)(n,{className:`h-3.5 w-3.5 shrink-0`}),(0,p.jsxs)(`span`,{children:[`Zone `,e.id]}),(0,p.jsx)(`span`,{className:`text-foreground-faint capitalize`,children:e.shape.kind})]}),(0,p.jsx)(`button`,{type:`button`,onClick:()=>Y(e.id),disabled:O,"aria-label":`Delete zone ${String(e.id)}`,title:`Delete zone`,className:`inline-flex h-6 w-6 items-center justify-center rounded border border-border bg-surface text-foreground-subtle hover:border-red-400/40 hover:bg-red-500/10 hover:text-red-400 disabled:opacity-40 transition-colors`,children:(0,p.jsx)(a,{className:`h-3.5 w-3.5`})})]},e.id)})}):null]}):(0,p.jsx)(`p`,{className:`${l} leading-relaxed`,children:`Loading the camera's privacy mask…`})})}):null}export{S as PrivacyMaskSettings};