@camstack/ui-library 0.1.50 → 0.1.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,29 +1,30 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region \0rolldown/runtime.js
3
3
  var __create = Object.create;
4
- var __defProp = Object.defineProperty;
4
+ var __defProp$1 = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
9
9
  var __copyProps = (to, from, except, desc) => {
10
10
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
11
  key = keys[i];
12
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$1(to, key, {
13
13
  get: ((k) => from[k]).bind(null, key),
14
14
  enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
15
  });
16
16
  }
17
17
  return to;
18
18
  };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", {
20
20
  value: mod,
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
24
  const require_theme_index = require("./theme/index.cjs");
25
25
  let react = require("react");
26
- react = __toESM(react, 1);
26
+ let react$1 = __toESM(react, 1);
27
+ react = __toESM(react);
27
28
  let react_jsx_runtime = require("react/jsx-runtime");
28
29
  react_jsx_runtime = __toESM(react_jsx_runtime, 1);
29
30
  let react_dom = require("react-dom");
@@ -38,6 +39,7 @@ let _trpc_react_query = require("@trpc/react-query");
38
39
  _trpc_react_query = __toESM(_trpc_react_query, 1);
39
40
  let _camstack_types = require("@camstack/types");
40
41
  let _camstack_sdk = require("@camstack/sdk");
42
+ let zod = require("zod");
41
43
  //#region ../../node_modules/clsx/dist/clsx.mjs
42
44
  function r(e) {
43
45
  var t, f, n = "";
@@ -3590,13 +3592,13 @@ function getPhaseVisual(phase) {
3590
3592
  * the Map is typed as `Context<unknown>`).
3591
3593
  */
3592
3594
  function createSharedContext(name, defaultValue) {
3593
- if (typeof globalThis === "undefined") return (0, react.createContext)(defaultValue);
3595
+ if (typeof globalThis === "undefined") return (0, react$1.createContext)(defaultValue);
3594
3596
  const existingMap = globalThis.__camstackSharedContexts;
3595
3597
  const map = existingMap ?? /* @__PURE__ */ new Map();
3596
3598
  if (!existingMap) globalThis.__camstackSharedContexts = map;
3597
3599
  const existing = map.get(name);
3598
3600
  if (existing) return existing;
3599
- const ctx = (0, react.createContext)(defaultValue);
3601
+ const ctx = (0, react$1.createContext)(defaultValue);
3600
3602
  map.set(name, ctx);
3601
3603
  return ctx;
3602
3604
  }
@@ -6866,7 +6868,7 @@ function getModuleCache() {
6866
6868
  }
6867
6869
  function populateShareCache() {
6868
6870
  const cache = getModuleCache();
6869
- cache.share["react"] ??= react;
6871
+ cache.share["react"] ??= react$1;
6870
6872
  cache.share["react-dom"] ??= react_dom;
6871
6873
  cache.share["react-dom/client"] ??= react_dom_client;
6872
6874
  cache.share["react/jsx-runtime"] ??= react_jsx_runtime;
@@ -6884,7 +6886,7 @@ function ensureMfHostInit() {
6884
6886
  name: "admin_ui_host",
6885
6887
  remotes: [],
6886
6888
  shared: {
6887
- "react": npmShared(() => react),
6889
+ "react": npmShared(() => react$1),
6888
6890
  "react-dom": npmShared(() => react_dom),
6889
6891
  "react-dom/client": npmShared(() => react_dom_client),
6890
6892
  "react/jsx-runtime": npmShared(() => react_jsx_runtime),
@@ -7991,6 +7993,68 @@ var PowerOff = createLucideIcon("power-off", [
7991
7993
  key: "1ooewy"
7992
7994
  }]
7993
7995
  ]);
7996
+ var QrCode$1 = createLucideIcon("qr-code", [
7997
+ ["rect", {
7998
+ width: "5",
7999
+ height: "5",
8000
+ x: "3",
8001
+ y: "3",
8002
+ rx: "1",
8003
+ key: "1tu5fj"
8004
+ }],
8005
+ ["rect", {
8006
+ width: "5",
8007
+ height: "5",
8008
+ x: "16",
8009
+ y: "3",
8010
+ rx: "1",
8011
+ key: "1v8r4q"
8012
+ }],
8013
+ ["rect", {
8014
+ width: "5",
8015
+ height: "5",
8016
+ x: "3",
8017
+ y: "16",
8018
+ rx: "1",
8019
+ key: "1x03jg"
8020
+ }],
8021
+ ["path", {
8022
+ d: "M21 16h-3a2 2 0 0 0-2 2v3",
8023
+ key: "177gqh"
8024
+ }],
8025
+ ["path", {
8026
+ d: "M21 21v.01",
8027
+ key: "ents32"
8028
+ }],
8029
+ ["path", {
8030
+ d: "M12 7v3a2 2 0 0 1-2 2H7",
8031
+ key: "8crl2c"
8032
+ }],
8033
+ ["path", {
8034
+ d: "M3 12h.01",
8035
+ key: "nlz23k"
8036
+ }],
8037
+ ["path", {
8038
+ d: "M12 3h.01",
8039
+ key: "n36tog"
8040
+ }],
8041
+ ["path", {
8042
+ d: "M12 16v.01",
8043
+ key: "133mhm"
8044
+ }],
8045
+ ["path", {
8046
+ d: "M16 12h1",
8047
+ key: "1slzba"
8048
+ }],
8049
+ ["path", {
8050
+ d: "M21 12v.01",
8051
+ key: "1lwtk9"
8052
+ }],
8053
+ ["path", {
8054
+ d: "M12 21v-1",
8055
+ key: "1880an"
8056
+ }]
8057
+ ]);
7994
8058
  var Radar = createLucideIcon("radar", [
7995
8059
  ["path", {
7996
8060
  d: "M19.07 4.93A10 10 0 0 0 6.99 3.34",
@@ -8176,6 +8240,40 @@ var Server = createLucideIcon("server", [
8176
8240
  key: "nzw8ys"
8177
8241
  }]
8178
8242
  ]);
8243
+ var Share2 = createLucideIcon("share-2", [
8244
+ ["circle", {
8245
+ cx: "18",
8246
+ cy: "5",
8247
+ r: "3",
8248
+ key: "gq8acd"
8249
+ }],
8250
+ ["circle", {
8251
+ cx: "6",
8252
+ cy: "12",
8253
+ r: "3",
8254
+ key: "w7nqdw"
8255
+ }],
8256
+ ["circle", {
8257
+ cx: "18",
8258
+ cy: "19",
8259
+ r: "3",
8260
+ key: "1xt0gg"
8261
+ }],
8262
+ ["line", {
8263
+ x1: "8.59",
8264
+ x2: "15.42",
8265
+ y1: "13.51",
8266
+ y2: "17.49",
8267
+ key: "47mynk"
8268
+ }],
8269
+ ["line", {
8270
+ x1: "15.41",
8271
+ x2: "8.59",
8272
+ y1: "6.51",
8273
+ y2: "10.49",
8274
+ key: "1n3mei"
8275
+ }]
8276
+ ]);
8179
8277
  var Shield = createLucideIcon("shield", [["path", {
8180
8278
  d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",
8181
8279
  key: "oel41y"
@@ -8383,6 +8481,10 @@ var TriangleAlert = createLucideIcon("triangle-alert", [
8383
8481
  key: "p32p05"
8384
8482
  }]
8385
8483
  ]);
8484
+ var Unlink2 = createLucideIcon("unlink-2", [["path", {
8485
+ d: "M15 7h2a5 5 0 0 1 0 10h-2m-6 0H7A5 5 0 0 1 7 7h2",
8486
+ key: "1re2ne"
8487
+ }]]);
8386
8488
  var Upload = createLucideIcon("upload", [
8387
8489
  ["path", {
8388
8490
  d: "M12 3v12",
@@ -8603,7 +8705,7 @@ var buttonVariants = cva("inline-flex items-center justify-center rounded-md fon
8603
8705
  size: "sm"
8604
8706
  }
8605
8707
  });
8606
- var Button = (0, react.forwardRef)(({ className, variant, size, ...props }, ref) => {
8708
+ var Button = (0, react$1.forwardRef)(({ className, variant, size, ...props }, ref) => {
8607
8709
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8608
8710
  ref,
8609
8711
  className: cn(buttonVariants({
@@ -8636,7 +8738,7 @@ var iconButtonVariants = cva("inline-flex items-center justify-center rounded-md
8636
8738
  size: "sm"
8637
8739
  }
8638
8740
  });
8639
- var IconButton = (0, react.forwardRef)(({ className, variant, size, icon: Icon, ...props }, ref) => {
8741
+ var IconButton = (0, react$1.forwardRef)(({ className, variant, size, icon: Icon, ...props }, ref) => {
8640
8742
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8641
8743
  ref,
8642
8744
  className: cn(iconButtonVariants({
@@ -8669,7 +8771,7 @@ var badgeVariants = cva("inline-flex items-center rounded-full text-xs font-medi
8669
8771
  styleVariant: "solid"
8670
8772
  }
8671
8773
  });
8672
- var Badge = (0, react.forwardRef)(({ className, variant, style, ...props }, ref) => {
8774
+ var Badge = (0, react$1.forwardRef)(({ className, variant, style, ...props }, ref) => {
8673
8775
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8674
8776
  ref,
8675
8777
  className: cn(badgeVariants({
@@ -8689,7 +8791,7 @@ var cardVariants = cva("rounded-lg p-3", {
8689
8791
  } },
8690
8792
  defaultVariants: { variant: "bordered" }
8691
8793
  });
8692
- var Card = (0, react.forwardRef)(({ className, variant, ...props }, ref) => {
8794
+ var Card = (0, react$1.forwardRef)(({ className, variant, ...props }, ref) => {
8693
8795
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8694
8796
  ref,
8695
8797
  className: cn(cardVariants({ variant }), className),
@@ -8725,7 +8827,7 @@ function CollapsibleCard({ expanded, onExpandedChange, header, children, dimmed
8725
8827
  }
8726
8828
  //#endregion
8727
8829
  //#region src/primitives/label.tsx
8728
- var Label = (0, react.forwardRef)(({ className, ...props }, ref) => {
8830
+ var Label = (0, react$1.forwardRef)(({ className, ...props }, ref) => {
8729
8831
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8730
8832
  ref,
8731
8833
  className: cn("text-[10px] uppercase tracking-wider text-foreground-muted font-medium", className),
@@ -8742,7 +8844,7 @@ var separatorVariants = cva("", {
8742
8844
  } },
8743
8845
  defaultVariants: { orientation: "horizontal" }
8744
8846
  });
8745
- var Separator = (0, react.forwardRef)(({ className, orientation, ...props }, ref) => {
8847
+ var Separator = (0, react$1.forwardRef)(({ className, orientation, ...props }, ref) => {
8746
8848
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8747
8849
  ref,
8748
8850
  role: "separator",
@@ -8753,7 +8855,7 @@ var Separator = (0, react.forwardRef)(({ className, orientation, ...props }, ref
8753
8855
  Separator.displayName = "Separator";
8754
8856
  //#endregion
8755
8857
  //#region src/primitives/skeleton.tsx
8756
- var Skeleton = (0, react.forwardRef)(({ className, ...props }, ref) => {
8858
+ var Skeleton = (0, react$1.forwardRef)(({ className, ...props }, ref) => {
8757
8859
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8758
8860
  ref,
8759
8861
  className: cn("animate-pulse bg-surface-hover rounded-md h-4 w-full", className),
@@ -8770,7 +8872,7 @@ var inputVariants = cva("h-7 w-full px-2.5 text-xs bg-surface border rounded-md
8770
8872
  } },
8771
8873
  defaultVariants: { state: "default" }
8772
8874
  });
8773
- var Input = (0, react.forwardRef)(({ className, state, leftSlot, rightSlot, ...props }, ref) => {
8875
+ var Input = (0, react$1.forwardRef)(({ className, state, leftSlot, rightSlot, ...props }, ref) => {
8774
8876
  if (leftSlot || rightSlot) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8775
8877
  className: "relative flex items-center w-full",
8776
8878
  children: [
@@ -8798,7 +8900,7 @@ var Input = (0, react.forwardRef)(({ className, state, leftSlot, rightSlot, ...p
8798
8900
  Input.displayName = "Input";
8799
8901
  //#endregion
8800
8902
  //#region src/primitives/select.tsx
8801
- var Select = (0, react.forwardRef)(({ className, options, ...props }, ref) => {
8903
+ var Select = (0, react$1.forwardRef)(({ className, options, ...props }, ref) => {
8802
8904
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8803
8905
  className: "relative w-full",
8804
8906
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
@@ -8818,7 +8920,7 @@ var Select = (0, react.forwardRef)(({ className, options, ...props }, ref) => {
8818
8920
  Select.displayName = "Select";
8819
8921
  //#endregion
8820
8922
  //#region src/primitives/checkbox.tsx
8821
- var Checkbox = (0, react.forwardRef)(({ className, ...props }, ref) => {
8923
+ var Checkbox = (0, react$1.forwardRef)(({ className, ...props }, ref) => {
8822
8924
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8823
8925
  ref,
8824
8926
  type: "checkbox",
@@ -8829,7 +8931,7 @@ var Checkbox = (0, react.forwardRef)(({ className, ...props }, ref) => {
8829
8931
  Checkbox.displayName = "Checkbox";
8830
8932
  //#endregion
8831
8933
  //#region src/primitives/switch.tsx
8832
- var Switch = (0, react.forwardRef)(({ className, checked, onCheckedChange, label, ...props }, ref) => {
8934
+ var Switch = (0, react$1.forwardRef)(({ className, checked, onCheckedChange, label, ...props }, ref) => {
8833
8935
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8834
8936
  ref,
8835
8937
  role: "switch",
@@ -8850,17 +8952,17 @@ var Switch = (0, react.forwardRef)(({ className, checked, onCheckedChange, label
8850
8952
  Switch.displayName = "Switch";
8851
8953
  //#endregion
8852
8954
  //#region src/primitives/dialog.tsx
8853
- var DialogContext = (0, react.createContext)(null);
8955
+ var DialogContext = (0, react$1.createContext)(null);
8854
8956
  function useDialogContext() {
8855
- const ctx = (0, react.useContext)(DialogContext);
8957
+ const ctx = (0, react$1.useContext)(DialogContext);
8856
8958
  if (!ctx) throw new Error("Dialog compound components must be used within <Dialog>");
8857
8959
  return ctx;
8858
8960
  }
8859
8961
  function Dialog({ children, open: controlledOpen, onOpenChange }) {
8860
- const [uncontrolledOpen, setUncontrolledOpen] = (0, react.useState)(false);
8962
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, react$1.useState)(false);
8861
8963
  const open = controlledOpen ?? uncontrolledOpen;
8862
- const contentId = (0, react.useId)();
8863
- const setOpen = (0, react.useCallback)((next) => {
8964
+ const contentId = (0, react$1.useId)();
8965
+ const setOpen = (0, react$1.useCallback)((next) => {
8864
8966
  onOpenChange?.(next);
8865
8967
  if (controlledOpen === void 0) setUncontrolledOpen(next);
8866
8968
  }, [controlledOpen, onOpenChange]);
@@ -8890,11 +8992,11 @@ var contentVariants = cva("bg-background-elevated border border-border rounded-l
8890
8992
  } },
8891
8993
  defaultVariants: { width: "md" }
8892
8994
  });
8893
- var DialogContent = (0, react.forwardRef)(({ className, width, children, ...props }, ref) => {
8995
+ var DialogContent = (0, react$1.forwardRef)(({ className, width, children, ...props }, ref) => {
8894
8996
  const { open, setOpen, contentId } = useDialogContext();
8895
- const innerRef = (0, react.useRef)(null);
8997
+ const innerRef = (0, react$1.useRef)(null);
8896
8998
  const dialogRef = ref ?? innerRef;
8897
- (0, react.useEffect)(() => {
8999
+ (0, react$1.useEffect)(() => {
8898
9000
  const el = dialogRef.current;
8899
9001
  if (!el) return;
8900
9002
  if (open && !el.open) el.showModal();
@@ -8940,17 +9042,17 @@ function DialogDescription({ className, ...props }) {
8940
9042
  }
8941
9043
  //#endregion
8942
9044
  //#region src/primitives/dropdown.tsx
8943
- var DropdownContext = (0, react.createContext)(null);
9045
+ var DropdownContext = (0, react$1.createContext)(null);
8944
9046
  function useDropdownContext() {
8945
- const ctx = (0, react.useContext)(DropdownContext);
9047
+ const ctx = (0, react$1.useContext)(DropdownContext);
8946
9048
  if (!ctx) throw new Error("Dropdown compound components must be used within <Dropdown>");
8947
9049
  return ctx;
8948
9050
  }
8949
9051
  function Dropdown({ children }) {
8950
- const [open, setOpen] = (0, react.useState)(false);
8951
- const triggerId = (0, react.useId)();
8952
- const contentId = (0, react.useId)();
8953
- const triggerRef = (0, react.useRef)(null);
9052
+ const [open, setOpen] = (0, react$1.useState)(false);
9053
+ const triggerId = (0, react$1.useId)();
9054
+ const contentId = (0, react$1.useId)();
9055
+ const triggerRef = (0, react$1.useRef)(null);
8954
9056
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropdownContext.Provider, {
8955
9057
  value: {
8956
9058
  open,
@@ -8981,9 +9083,9 @@ function DropdownTrigger({ children, ...props }) {
8981
9083
  }
8982
9084
  function DropdownContent({ className, children, align = "start", offset = 4, ...props }) {
8983
9085
  const { open, setOpen, contentId, triggerId, triggerRef } = useDropdownContext();
8984
- const ref = (0, react.useRef)(null);
8985
- const [coords, setCoords] = (0, react.useState)(null);
8986
- (0, react.useLayoutEffect)(() => {
9086
+ const ref = (0, react$1.useRef)(null);
9087
+ const [coords, setCoords] = (0, react$1.useState)(null);
9088
+ (0, react$1.useLayoutEffect)(() => {
8987
9089
  if (!open) {
8988
9090
  setCoords(null);
8989
9091
  return;
@@ -9012,7 +9114,7 @@ function DropdownContent({ className, children, align = "start", offset = 4, ...
9012
9114
  offset,
9013
9115
  triggerRef
9014
9116
  ]);
9015
- (0, react.useEffect)(() => {
9117
+ (0, react$1.useEffect)(() => {
9016
9118
  if (!open) return;
9017
9119
  const handler = (e) => {
9018
9120
  const el = ref.current;
@@ -9052,7 +9154,7 @@ function DropdownContent({ className, children, align = "start", offset = 4, ...
9052
9154
  }
9053
9155
  function DropdownItem({ className, icon: Icon, variant = "default", children, onClick, ...props }) {
9054
9156
  const { setOpen } = useDropdownContext();
9055
- const handleClick = (0, react.useCallback)((e) => {
9157
+ const handleClick = (0, react$1.useCallback)((e) => {
9056
9158
  onClick?.(e);
9057
9159
  setOpen(false);
9058
9160
  }, [onClick, setOpen]);
@@ -9067,16 +9169,16 @@ function DropdownItem({ className, icon: Icon, variant = "default", children, on
9067
9169
  }
9068
9170
  //#endregion
9069
9171
  //#region src/primitives/tooltip.tsx
9070
- var TooltipContext = (0, react.createContext)(null);
9172
+ var TooltipContext = (0, react$1.createContext)(null);
9071
9173
  function useTooltipContext() {
9072
- const ctx = (0, react.useContext)(TooltipContext);
9174
+ const ctx = (0, react$1.useContext)(TooltipContext);
9073
9175
  if (!ctx) throw new Error("Tooltip compound components must be used within <Tooltip>");
9074
9176
  return ctx;
9075
9177
  }
9076
9178
  function Tooltip({ children }) {
9077
- const [open, setOpen] = (0, react.useState)(false);
9078
- const timerRef = (0, react.useRef)(null);
9079
- const tooltipId = (0, react.useId)();
9179
+ const [open, setOpen] = (0, react$1.useState)(false);
9180
+ const timerRef = (0, react$1.useRef)(null);
9181
+ const tooltipId = (0, react$1.useId)();
9080
9182
  const show = () => {
9081
9183
  timerRef.current = setTimeout(() => setOpen(true), 300);
9082
9184
  };
@@ -9143,7 +9245,7 @@ function getServerSnapshot() {
9143
9245
  return false;
9144
9246
  }
9145
9247
  function useIsMobile() {
9146
- return (0, react.useSyncExternalStore)(subscribeQuery(MOBILE_QUERY), getSnapshot(MOBILE_QUERY), getServerSnapshot);
9248
+ return (0, react$1.useSyncExternalStore)(subscribeQuery(MOBILE_QUERY), getSnapshot(MOBILE_QUERY), getServerSnapshot);
9147
9249
  }
9148
9250
  /**
9149
9251
  * True when the viewport is in the medium (`md`) Tailwind range —
@@ -9152,12 +9254,12 @@ function useIsMobile() {
9152
9254
  * sidebar rail, narrower stat tiles).
9153
9255
  */
9154
9256
  function useIsMidWidth() {
9155
- return (0, react.useSyncExternalStore)(subscribeQuery(MID_QUERY), getSnapshot(MID_QUERY), getServerSnapshot);
9257
+ return (0, react$1.useSyncExternalStore)(subscribeQuery(MID_QUERY), getSnapshot(MID_QUERY), getServerSnapshot);
9156
9258
  }
9157
9259
  //#endregion
9158
9260
  //#region src/primitives/bottom-sheet.tsx
9159
9261
  function BottomSheet({ open, onClose, title, children, className }) {
9160
- (0, react.useEffect)(() => {
9262
+ (0, react$1.useEffect)(() => {
9161
9263
  if (!open) return;
9162
9264
  const handleKeyDown = (e) => {
9163
9265
  if (e.key === "Escape") onClose();
@@ -9202,18 +9304,18 @@ function BottomSheet({ open, onClose, title, children, className }) {
9202
9304
  }
9203
9305
  //#endregion
9204
9306
  //#region src/primitives/popover.tsx
9205
- var PopoverContext = (0, react.createContext)(null);
9307
+ var PopoverContext = (0, react$1.createContext)(null);
9206
9308
  function usePopoverContext() {
9207
- const ctx = (0, react.useContext)(PopoverContext);
9309
+ const ctx = (0, react$1.useContext)(PopoverContext);
9208
9310
  if (!ctx) throw new Error("Popover compound components must be used within <Popover>");
9209
9311
  return ctx;
9210
9312
  }
9211
9313
  function Popover({ children, open: controlledOpen, onOpenChange }) {
9212
- const [uncontrolledOpen, setUncontrolledOpen] = (0, react.useState)(false);
9314
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, react$1.useState)(false);
9213
9315
  const open = controlledOpen ?? uncontrolledOpen;
9214
- const triggerId = (0, react.useId)();
9215
- const contentId = (0, react.useId)();
9216
- const setOpen = (0, react.useCallback)((next) => {
9316
+ const triggerId = (0, react$1.useId)();
9317
+ const contentId = (0, react$1.useId)();
9318
+ const setOpen = (0, react$1.useCallback)((next) => {
9217
9319
  onOpenChange?.(next);
9218
9320
  if (controlledOpen === void 0) setUncontrolledOpen(next);
9219
9321
  }, [controlledOpen, onOpenChange]);
@@ -9246,8 +9348,8 @@ function PopoverTrigger({ children, ...props }) {
9246
9348
  function PopoverContent({ className, children, ...props }) {
9247
9349
  const { open, setOpen, contentId, triggerId } = usePopoverContext();
9248
9350
  const isMobile = useIsMobile();
9249
- const ref = (0, react.useRef)(null);
9250
- (0, react.useEffect)(() => {
9351
+ const ref = (0, react$1.useRef)(null);
9352
+ (0, react$1.useEffect)(() => {
9251
9353
  if (!open || isMobile) return;
9252
9354
  const handler = (e) => {
9253
9355
  const el = ref.current;
@@ -9287,16 +9389,16 @@ function PopoverContent({ className, children, ...props }) {
9287
9389
  }
9288
9390
  //#endregion
9289
9391
  //#region src/primitives/tabs.tsx
9290
- var TabsContext = (0, react.createContext)(null);
9392
+ var TabsContext = (0, react$1.createContext)(null);
9291
9393
  function useTabsContext() {
9292
- const ctx = (0, react.useContext)(TabsContext);
9394
+ const ctx = (0, react$1.useContext)(TabsContext);
9293
9395
  if (!ctx) throw new Error("Tabs compound components must be used within <Tabs>");
9294
9396
  return ctx;
9295
9397
  }
9296
9398
  function Tabs({ value: controlledValue, onValueChange, defaultValue = "", className, ...props }) {
9297
- const [uncontrolledValue, setUncontrolledValue] = (0, react.useState)(defaultValue);
9399
+ const [uncontrolledValue, setUncontrolledValue] = (0, react$1.useState)(defaultValue);
9298
9400
  const value = controlledValue ?? uncontrolledValue;
9299
- const setValue = (0, react.useCallback)((next) => {
9401
+ const setValue = (0, react$1.useCallback)((next) => {
9300
9402
  onValueChange?.(next);
9301
9403
  if (controlledValue === void 0) setUncontrolledValue(next);
9302
9404
  }, [controlledValue, onValueChange]);
@@ -9344,7 +9446,7 @@ function TabsContent({ value, className, ...props }) {
9344
9446
  }
9345
9447
  //#endregion
9346
9448
  //#region src/primitives/scroll-area.tsx
9347
- var ScrollArea = (0, react.forwardRef)(({ className, ...props }, ref) => {
9449
+ var ScrollArea = (0, react$1.forwardRef)(({ className, ...props }, ref) => {
9348
9450
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9349
9451
  ref,
9350
9452
  className: cn("overflow-auto [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-surface-hover [&::-webkit-scrollbar-thumb]:rounded-full", className),
@@ -9355,23 +9457,23 @@ ScrollArea.displayName = "ScrollArea";
9355
9457
  //#endregion
9356
9458
  //#region src/primitives/floating-panel.tsx
9357
9459
  function FloatingPanel({ title, onClose, children, defaultWidth = 360, defaultHeight = 280, minWidth = 280, minHeight = 160, offsetIndex = 0, className }) {
9358
- const [pos, setPos] = (0, react.useState)({
9460
+ const [pos, setPos] = (0, react$1.useState)({
9359
9461
  x: 80 + offsetIndex * 30,
9360
9462
  y: 80 + offsetIndex * 30
9361
9463
  });
9362
- const [size, setSize] = (0, react.useState)({
9464
+ const [size, setSize] = (0, react$1.useState)({
9363
9465
  w: defaultWidth,
9364
9466
  h: defaultHeight
9365
9467
  });
9366
- const [minimized, setMinimized] = (0, react.useState)(false);
9367
- const dragging = (0, react.useRef)(false);
9368
- const resizing = (0, react.useRef)(false);
9369
- const offset = (0, react.useRef)({
9468
+ const [minimized, setMinimized] = (0, react$1.useState)(false);
9469
+ const dragging = (0, react$1.useRef)(false);
9470
+ const resizing = (0, react$1.useRef)(false);
9471
+ const offset = (0, react$1.useRef)({
9370
9472
  x: 0,
9371
9473
  y: 0
9372
9474
  });
9373
9475
  const isMobile = useIsMobile();
9374
- const onDragStart = (0, react.useCallback)((e) => {
9476
+ const onDragStart = (0, react$1.useCallback)((e) => {
9375
9477
  e.preventDefault();
9376
9478
  dragging.current = true;
9377
9479
  offset.current = {
@@ -9379,7 +9481,7 @@ function FloatingPanel({ title, onClose, children, defaultWidth = 360, defaultHe
9379
9481
  y: e.clientY - pos.y
9380
9482
  };
9381
9483
  }, [pos]);
9382
- const onResizeStart = (0, react.useCallback)((e) => {
9484
+ const onResizeStart = (0, react$1.useCallback)((e) => {
9383
9485
  e.preventDefault();
9384
9486
  e.stopPropagation();
9385
9487
  resizing.current = true;
@@ -9388,7 +9490,7 @@ function FloatingPanel({ title, onClose, children, defaultWidth = 360, defaultHe
9388
9490
  y: e.clientY
9389
9491
  };
9390
9492
  }, []);
9391
- (0, react.useEffect)(() => {
9493
+ (0, react$1.useEffect)(() => {
9392
9494
  const onMouseMove = (e) => {
9393
9495
  if (dragging.current) setPos({
9394
9496
  x: e.clientX - offset.current.x,
@@ -9493,8 +9595,8 @@ function FloatingPanel({ title, onClose, children, defaultWidth = 360, defaultHe
9493
9595
  //#endregion
9494
9596
  //#region src/primitives/mobile-drawer.tsx
9495
9597
  function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
9496
- const drawerRef = (0, react.useRef)(null);
9497
- (0, react.useEffect)(() => {
9598
+ const drawerRef = (0, react$1.useRef)(null);
9599
+ (0, react$1.useEffect)(() => {
9498
9600
  if (!open) return;
9499
9601
  const handleKeyDown = (e) => {
9500
9602
  if (e.key === "Escape") onClose();
@@ -9538,7 +9640,7 @@ function Breadcrumb({ items, className }) {
9538
9640
  children: items.map((item, i) => {
9539
9641
  const isLast = i === items.length - 1;
9540
9642
  const isClickable = !isLast && (item.onClick || item.href);
9541
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.default.Fragment, { children: [i > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRight, { className: "h-3 w-3 flex-shrink-0" }), isClickable ? item.onClick ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9643
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react$1.default.Fragment, { children: [i > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRight, { className: "h-3 w-3 flex-shrink-0" }), isClickable ? item.onClick ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9542
9644
  type: "button",
9543
9645
  onClick: item.onClick,
9544
9646
  className: "hover:text-foreground transition-colors",
@@ -9614,7 +9716,7 @@ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyM
9614
9716
  //#endregion
9615
9717
  //#region src/composites/slide-over-panel.tsx
9616
9718
  function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widthClass = "w-[360px]" }) {
9617
- (0, react.useEffect)(() => {
9719
+ (0, react$1.useEffect)(() => {
9618
9720
  if (!open) return;
9619
9721
  const onEsc = (e) => {
9620
9722
  if (e.key === "Escape") onClose();
@@ -9757,7 +9859,7 @@ function modelsForStep(schema) {
9757
9859
  }));
9758
9860
  }
9759
9861
  function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0, onChange, onDelete: _onDelete, readOnly = false, toggleMode = "simple", overrideState = null, onOverrideChange, inheritedEnabled, hideModelAndSettings = false }) {
9760
- const [expanded, setExpanded] = (0, react.useState)(false);
9862
+ const [expanded, setExpanded] = (0, react$1.useState)(false);
9761
9863
  const models = modelsForStep(schema);
9762
9864
  if (models.length > 0 && !models.some((m) => m.id === step.modelId) && !readOnly) {
9763
9865
  const fallback = (schema?.defaultModelId ? models.find((m) => m.id === schema.defaultModelId) : null) ?? models[0];
@@ -10308,7 +10410,7 @@ function DeviceModeEditor({ addon, agentDefault, agentNodeId, currentPatch, mode
10308
10410
  }
10309
10411
  function AgentStepEditor(props) {
10310
10412
  const { mode, addon, agentDefault, agentNodeId, currentPatch, onChangeAgentConfig, onChangePatch, engineFormat } = props;
10311
- const modelsForFormat = (0, react.useMemo)(() => addon.models.filter((m) => Boolean(m.formats[engineFormat])), [addon.models, engineFormat]);
10413
+ const modelsForFormat = (0, react$1.useMemo)(() => addon.models.filter((m) => Boolean(m.formats[engineFormat])), [addon.models, engineFormat]);
10312
10414
  if (mode === "agent") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentModeEditor, {
10313
10415
  addon,
10314
10416
  agentDefault,
@@ -10458,7 +10560,7 @@ function Row({ node, depth, agents, getCellState, onCellClick, selectedCell, tog
10458
10560
  })] });
10459
10561
  }
10460
10562
  function PipelineTreeMatrix({ tree, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
10461
- const rows = (0, react.useMemo)(() => flattenTree(tree), [tree]);
10563
+ const rows = (0, react$1.useMemo)(() => flattenTree(tree), [tree]);
10462
10564
  const gridTemplate = `minmax(320px, 1fr) repeat(${agents.length}, minmax(160px, 220px))`;
10463
10565
  const showToggle = onToggleEnabled !== void 0 && agents.length === 1;
10464
10566
  const onlyAgent = agents[0]?.agentNodeId;
@@ -10564,7 +10666,7 @@ function SystemProvider({ system, children }) {
10564
10666
  * relies on the system, so a clear error beats a silent null.
10565
10667
  */
10566
10668
  function useSystem() {
10567
- const sys = (0, react.useContext)(SystemContext);
10669
+ const sys = (0, react$1.useContext)(SystemContext);
10568
10670
  if (!sys) throw new Error("useSystem(): no <SystemProvider> in tree");
10569
10671
  return sys;
10570
10672
  }
@@ -10574,7 +10676,7 @@ function useSystem() {
10574
10676
  * (boot-time splash screens etc.).
10575
10677
  */
10576
10678
  function useOptionalSystem() {
10577
- return (0, react.useContext)(SystemContext);
10679
+ return (0, react$1.useContext)(SystemContext);
10578
10680
  }
10579
10681
  //#endregion
10580
10682
  //#region src/hooks/use-live-event.ts
@@ -10590,15 +10692,15 @@ function useOptionalSystem() {
10590
10692
  */
10591
10693
  function useLiveEvent(category, cb) {
10592
10694
  const system = useSystem();
10593
- const cbRef = (0, react.useRef)(cb);
10695
+ const cbRef = (0, react$1.useRef)(cb);
10594
10696
  cbRef.current = cb;
10595
- const [tick, setTick] = (0, react.useState)(system.connectionVersion);
10596
- (0, react.useEffect)(() => {
10697
+ const [tick, setTick] = (0, react$1.useState)(system.connectionVersion);
10698
+ (0, react$1.useEffect)(() => {
10597
10699
  return system.subscribeConnectionEvents((state, version) => {
10598
10700
  if (state === "connected") setTick(version);
10599
10701
  });
10600
10702
  }, [system]);
10601
- (0, react.useEffect)(() => {
10703
+ (0, react$1.useEffect)(() => {
10602
10704
  return system.subscribeEvent(category, (evt) => {
10603
10705
  cbRef.current(evt);
10604
10706
  });
@@ -10617,12 +10719,12 @@ function useLiveEvent(category, cb) {
10617
10719
  * useEventStreamMap — same but accumulates per-key payloads into a map.
10618
10720
  */
10619
10721
  function useFreshRef(value) {
10620
- const ref = (0, react.useRef)(value);
10722
+ const ref = (0, react$1.useRef)(value);
10621
10723
  ref.current = value;
10622
10724
  return ref;
10623
10725
  }
10624
10726
  function useEventStreamLatest(category, filter) {
10625
- const [data, setData] = (0, react.useState)(null);
10727
+ const [data, setData] = (0, react$1.useState)(null);
10626
10728
  const filterRef = useFreshRef(filter);
10627
10729
  useLiveEvent(category, (evt) => {
10628
10730
  const payload = evt.data;
@@ -10633,7 +10735,7 @@ function useEventStreamLatest(category, filter) {
10633
10735
  return data;
10634
10736
  }
10635
10737
  function useEventStreamMap(category, keyOf, filter) {
10636
- const [map, setMap] = (0, react.useState)(() => /* @__PURE__ */ new Map());
10738
+ const [map, setMap] = (0, react$1.useState)(() => /* @__PURE__ */ new Map());
10637
10739
  const keyOfRef = useFreshRef(keyOf);
10638
10740
  const filterRef = useFreshRef(filter);
10639
10741
  useLiveEvent(category, (evt) => {
@@ -10649,7 +10751,7 @@ function useEventStreamMap(category, keyOf, filter) {
10649
10751
  });
10650
10752
  return {
10651
10753
  map,
10652
- values: (0, react.useMemo)(() => Array.from(map.values()), [map])
10754
+ values: (0, react$1.useMemo)(() => Array.from(map.values()), [map])
10653
10755
  };
10654
10756
  }
10655
10757
  //#endregion
@@ -10669,7 +10771,7 @@ function useClusterNodes() {
10669
10771
  const { data: bootstrapTopology, isLoading } = trpc.nodes.topology.useQuery(void 0, { staleTime: 6e4 });
10670
10772
  const sourceNodes = useEventStreamLatest("cluster.topology-snapshot")?.nodes ?? bootstrapTopology;
10671
10773
  return {
10672
- nodes: (0, react.useMemo)(() => {
10774
+ nodes: (0, react$1.useMemo)(() => {
10673
10775
  const list = [];
10674
10776
  for (const n of sourceNodes ?? []) list.push({
10675
10777
  id: String(n.id ?? ""),
@@ -10803,7 +10905,7 @@ function ProviderBadge({ provider, showLabel = true, className }) {
10803
10905
  }
10804
10906
  //#endregion
10805
10907
  //#region src/composites/version-badge.tsx
10806
- var VARIANT_STYLES = {
10908
+ var VARIANT_STYLES$1 = {
10807
10909
  success: "bg-emerald-400 text-emerald-950",
10808
10910
  warning: "bg-amber-400 text-amber-950",
10809
10911
  danger: "bg-red-400 text-red-950",
@@ -10816,7 +10918,7 @@ var VARIANT_STYLES = {
10816
10918
  */
10817
10919
  function SemanticBadge({ children, variant = "neutral", mono, className }) {
10818
10920
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10819
- className: cn("inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-bold leading-tight", mono && "font-mono", VARIANT_STYLES[variant], className),
10921
+ className: cn("inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-bold leading-tight", mono && "font-mono", VARIANT_STYLES$1[variant], className),
10820
10922
  children
10821
10923
  });
10822
10924
  }
@@ -10905,16 +11007,65 @@ function EmptyState({ icon: Icon, title, description, action, className }) {
10905
11007
  });
10906
11008
  }
10907
11009
  //#endregion
11010
+ //#region src/composites/error-box.tsx
11011
+ var VARIANT_STYLES = {
11012
+ danger: {
11013
+ box: "border-danger/40 bg-danger/10",
11014
+ icon: "text-danger",
11015
+ title: "text-danger",
11016
+ message: "text-danger"
11017
+ },
11018
+ warning: {
11019
+ box: "border-amber-500/40 bg-amber-500/10",
11020
+ icon: "text-amber-600 dark:text-amber-400",
11021
+ title: "text-amber-700 dark:text-amber-300",
11022
+ message: "text-amber-700 dark:text-amber-300"
11023
+ }
11024
+ };
11025
+ function ErrorBox({ message, title, onRetry, action, variant = "danger", className }) {
11026
+ const styles = VARIANT_STYLES[variant];
11027
+ const Icon = variant === "warning" ? TriangleAlert : CircleAlert;
11028
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11029
+ role: "alert",
11030
+ className: cn("flex items-start gap-2.5 rounded border px-3 py-2.5", styles.box, className),
11031
+ children: [
11032
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
11033
+ className: cn("h-4 w-4 mt-0.5 shrink-0", styles.icon),
11034
+ "aria-hidden": "true"
11035
+ }),
11036
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11037
+ className: "flex-1 min-w-0",
11038
+ children: [title && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11039
+ className: cn("text-xs font-semibold", styles.title),
11040
+ children: title
11041
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11042
+ className: cn("text-xs break-words", styles.message, title ? "mt-0.5" : ""),
11043
+ children: message
11044
+ })]
11045
+ }),
11046
+ action ?? (onRetry && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
11047
+ type: "button",
11048
+ onClick: onRetry,
11049
+ className: cn("shrink-0 inline-flex items-center gap-1 rounded px-2 py-1 text-[11px] font-medium", "border border-current/30 hover:bg-current/10 transition-colors", styles.message),
11050
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RefreshCw, {
11051
+ className: "h-3 w-3",
11052
+ "aria-hidden": "true"
11053
+ }), "Retry"]
11054
+ }))
11055
+ ]
11056
+ });
11057
+ }
11058
+ //#endregion
10908
11059
  //#region src/composites/confirm-dialog.tsx
10909
11060
  var ConfirmContext = createSharedContext("camstack:confirm-dialog", null);
10910
11061
  function useConfirm() {
10911
- const ctx = (0, react.useContext)(ConfirmContext);
11062
+ const ctx = (0, react$1.useContext)(ConfirmContext);
10912
11063
  if (!ctx) throw new Error("useConfirm must be used within ConfirmDialogProvider");
10913
11064
  return ctx.confirm;
10914
11065
  }
10915
11066
  function ConfirmDialogProvider({ children }) {
10916
- const [dialog, setDialog] = (0, react.useState)(null);
10917
- const confirm = (0, react.useCallback)((options) => {
11067
+ const [dialog, setDialog] = (0, react$1.useState)(null);
11068
+ const confirm = (0, react$1.useCallback)((options) => {
10918
11069
  return new Promise((resolve) => {
10919
11070
  setDialog({
10920
11071
  ...options,
@@ -11026,8 +11177,8 @@ function KeyValueList({ items, className }) {
11026
11177
  //#endregion
11027
11178
  //#region src/composites/code-block.tsx
11028
11179
  function CodeBlock({ children, maxHeight = 300, className }) {
11029
- const [copied, setCopied] = (0, react.useState)(false);
11030
- const handleCopy = (0, react.useCallback)(() => {
11180
+ const [copied, setCopied] = (0, react$1.useState)(false);
11181
+ const handleCopy = (0, react$1.useCallback)(() => {
11031
11182
  navigator.clipboard.writeText(children).then(() => {
11032
11183
  setCopied(true);
11033
11184
  setTimeout(() => setCopied(false), 2e3);
@@ -11057,7 +11208,7 @@ function CodeBlock({ children, maxHeight = 300, className }) {
11057
11208
  //#region src/composites/filter-bar.tsx
11058
11209
  function FilterBar({ filters, values, onChange, className }) {
11059
11210
  const isMobile = useIsMobile();
11060
- const [sheetOpen, setSheetOpen] = (0, react.useState)(false);
11211
+ const [sheetOpen, setSheetOpen] = (0, react$1.useState)(false);
11061
11212
  const handleChange = (key, value) => {
11062
11213
  onChange({
11063
11214
  ...values,
@@ -11222,7 +11373,7 @@ function Sidebar({ logo, sections, footer, onNavigate, className }) {
11222
11373
  //#region src/composites/app-shell/app-shell.tsx
11223
11374
  function AppShell({ sidebar, header, mobileLogo, mobileActions, children, className }) {
11224
11375
  const isMobile = useIsMobile();
11225
- const [drawerOpen, setDrawerOpen] = (0, react.useState)(false);
11376
+ const [drawerOpen, setDrawerOpen] = (0, react$1.useState)(false);
11226
11377
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11227
11378
  className: cn("flex h-screen", className),
11228
11379
  children: [
@@ -11408,8 +11559,8 @@ var BINDING_CHANGED_CATEGORY = "capability.binding-changed";
11408
11559
  * when `deviceId` is null. Re-rendered when bindings change.
11409
11560
  */
11410
11561
  function useDeviceProxy(trpc, deviceId) {
11411
- const [binding, setBinding] = (0, react.useState)(null);
11412
- (0, react.useEffect)(() => {
11562
+ const [binding, setBinding] = (0, react$1.useState)(null);
11563
+ (0, react$1.useEffect)(() => {
11413
11564
  if (deviceId === null) {
11414
11565
  setBinding(null);
11415
11566
  return;
@@ -11437,7 +11588,7 @@ function useDeviceProxy(trpc, deviceId) {
11437
11588
  sub?.unsubscribe();
11438
11589
  };
11439
11590
  }, [trpc, deviceId]);
11440
- return (0, react.useMemo)(() => {
11591
+ return (0, react$1.useMemo)(() => {
11441
11592
  if (!binding) return null;
11442
11593
  return (0, _camstack_types.createDeviceProxy)(trpc, binding);
11443
11594
  }, [trpc, binding]);
@@ -11461,12 +11612,12 @@ function useDeviceProxy(trpc, deviceId) {
11461
11612
  * de-dups identical pushes).
11462
11613
  */
11463
11614
  function useDeviceStateSlice(handle) {
11464
- const subscribe = (0, react.useCallback)((notify) => {
11615
+ const subscribe = (0, react$1.useCallback)((notify) => {
11465
11616
  if (!handle) return () => void 0;
11466
11617
  return handle.subscribe(() => notify());
11467
11618
  }, [handle]);
11468
- const getSnapshot = (0, react.useCallback)(() => handle?.value, [handle]);
11469
- return (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
11619
+ const getSnapshot = (0, react$1.useCallback)(() => handle?.value, [handle]);
11620
+ return (0, react$1.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
11470
11621
  }
11471
11622
  /**
11472
11623
  * One-line combinator — collapse the common
@@ -11751,7 +11902,7 @@ function ChildSwitchToggle({ trpc, deviceId }) {
11751
11902
  cap: (d) => d.switch,
11752
11903
  slice: (d) => d.state.switch
11753
11904
  });
11754
- const [pending, setPending] = (0, react.useState)(false);
11905
+ const [pending, setPending] = (0, react$1.useState)(false);
11755
11906
  if (dev !== null && !cap) return null;
11756
11907
  const on = slice?.on === true;
11757
11908
  const knobStyle = { transform: on ? "translateX(14px)" : "translateX(2px)" };
@@ -11789,7 +11940,7 @@ function ChildMotionTriggerToggle({ trpc, deviceId, features }) {
11789
11940
  requireFeature: "motion-trigger",
11790
11941
  deviceFeatures: features
11791
11942
  });
11792
- const [pending, setPending] = (0, react.useState)(false);
11943
+ const [pending, setPending] = (0, react$1.useState)(false);
11793
11944
  if (dev !== null && !cap) return null;
11794
11945
  const on = slice?.enabled === true;
11795
11946
  const handleClick = async (e) => {
@@ -11867,7 +12018,7 @@ function SwitchToggle({ trpc, deviceId }) {
11867
12018
  cap: (d) => d.switch,
11868
12019
  slice: (d) => d.state.switch
11869
12020
  });
11870
- const [pending, setPending] = (0, react.useState)(false);
12021
+ const [pending, setPending] = (0, react$1.useState)(false);
11871
12022
  if (dev !== null && !cap) return null;
11872
12023
  const on = slice?.on === true;
11873
12024
  const knobStyle = { transform: on ? "translateX(14px)" : "translateX(2px)" };
@@ -11905,7 +12056,7 @@ function OnMotionToggle({ trpc, deviceId, features }) {
11905
12056
  requireFeature: "motion-trigger",
11906
12057
  deviceFeatures: features
11907
12058
  });
11908
- const [pending, setPending] = (0, react.useState)(false);
12059
+ const [pending, setPending] = (0, react$1.useState)(false);
11909
12060
  if (dev !== null && !cap) return null;
11910
12061
  const on = slice?.enabled === true;
11911
12062
  const handleClick = async (e) => {
@@ -11939,10 +12090,10 @@ function MoreActionsMenu({ trpc, deviceId }) {
11939
12090
  cap: (d) => d.reboot,
11940
12091
  slice: () => void 0
11941
12092
  });
11942
- const triggerRef = (0, react.useRef)(null);
11943
- const menuRef = (0, react.useRef)(null);
11944
- const [position, setPosition] = (0, react.useState)(null);
11945
- const [pending, setPending] = (0, react.useState)(false);
12093
+ const triggerRef = (0, react$1.useRef)(null);
12094
+ const menuRef = (0, react$1.useRef)(null);
12095
+ const [position, setPosition] = (0, react$1.useState)(null);
12096
+ const [pending, setPending] = (0, react$1.useState)(false);
11946
12097
  const ready = dev !== null && cap !== void 0 && cap !== null;
11947
12098
  const isOpen = position !== null;
11948
12099
  const close = () => setPosition(null);
@@ -11957,7 +12108,7 @@ function MoreActionsMenu({ trpc, deviceId }) {
11957
12108
  left
11958
12109
  });
11959
12110
  };
11960
- (0, react.useEffect)(() => {
12111
+ (0, react$1.useEffect)(() => {
11961
12112
  if (!isOpen) return;
11962
12113
  const onMouseDown = (e) => {
11963
12114
  const trg = triggerRef.current;
@@ -12095,10 +12246,10 @@ function buildResolved(rawFeatures, binding) {
12095
12246
  return out;
12096
12247
  }
12097
12248
  function useDeviceFeatures(trpc, deviceId, rawFeatures) {
12098
- const [binding, setBinding] = (0, react.useState)(null);
12099
- const [errored, setErrored] = (0, react.useState)(false);
12100
- const [loading, setLoading] = (0, react.useState)(true);
12101
- (0, react.useEffect)(() => {
12249
+ const [binding, setBinding] = (0, react$1.useState)(null);
12250
+ const [errored, setErrored] = (0, react$1.useState)(false);
12251
+ const [loading, setLoading] = (0, react$1.useState)(true);
12252
+ (0, react$1.useEffect)(() => {
12102
12253
  if (deviceId === null) {
12103
12254
  setBinding(null);
12104
12255
  setErrored(false);
@@ -12196,8 +12347,8 @@ function ChildrenCountBadge({ accessoryCount, adoptedCount }) {
12196
12347
  var POPOVER_WIDTH$1 = 240;
12197
12348
  var POPOVER_MIN_HEIGHT = 200;
12198
12349
  function FeatureRow({ resolved }) {
12199
- const triggerRef = (0, react.useRef)(null);
12200
- const [position, setPosition] = (0, react.useState)(null);
12350
+ const triggerRef = (0, react$1.useRef)(null);
12351
+ const [position, setPosition] = (0, react$1.useState)(null);
12201
12352
  const open = () => {
12202
12353
  const el = triggerRef.current;
12203
12354
  if (!el) return;
@@ -12390,7 +12541,7 @@ function useDeviceBattery(trpc, deviceId) {
12390
12541
  */
12391
12542
  function useDeviceSnapshotImage(trpc, deviceId) {
12392
12543
  const dev = useDeviceProxy(trpc, deviceId);
12393
- const forceRef = (0, react.useRef)(false);
12544
+ const forceRef = (0, react$1.useRef)(false);
12394
12545
  const { data, isLoading, isFetching, refetch } = (0, _tanstack_react_query.useQuery)({
12395
12546
  queryKey: [
12396
12547
  "device",
@@ -12507,8 +12658,8 @@ var POPOVER_WIDTH = 288;
12507
12658
  var POPOVER_HEIGHT = 196;
12508
12659
  var TRIGGER_GAP = 8;
12509
12660
  function SnapshotPopoverInline({ deviceName, snapshotUrl, status }) {
12510
- const triggerRef = (0, react.useRef)(null);
12511
- const [position, setPosition] = (0, react.useState)(null);
12661
+ const triggerRef = (0, react$1.useRef)(null);
12662
+ const [position, setPosition] = (0, react$1.useState)(null);
12512
12663
  const offline = status === "offline" || status === "disabled";
12513
12664
  const open = () => {
12514
12665
  const el = triggerRef.current;
@@ -12598,7 +12749,7 @@ function DeviceItem(props) {
12598
12749
  const accessoryChildren = childrenList.filter(isAccessoryChild);
12599
12750
  const adoptedChildren = childrenList.filter((c) => !isAccessoryChild(c));
12600
12751
  const hasChildren = childrenList.length > 0;
12601
- const [localExpanded, setLocalExpanded] = (0, react.useState)(false);
12752
+ const [localExpanded, setLocalExpanded] = (0, react$1.useState)(false);
12602
12753
  const expanded = props.expanded ?? localExpanded;
12603
12754
  const onToggleExpand = props.onToggleExpand ?? (() => setLocalExpanded((v) => !v));
12604
12755
  const navigate = (id) => {
@@ -12748,8 +12899,8 @@ function DeviceItemTableRow(props) {
12748
12899
  * (caller's `useState`); this hook produces a debounced derivation.
12749
12900
  */
12750
12901
  function useDebouncedString(value, delayMs) {
12751
- const [debounced, setDebounced] = (0, react.useState)(value);
12752
- (0, react.useEffect)(() => {
12902
+ const [debounced, setDebounced] = (0, react$1.useState)(value);
12903
+ (0, react$1.useEffect)(() => {
12753
12904
  const t = setTimeout(() => setDebounced(value), delayMs);
12754
12905
  return () => clearTimeout(t);
12755
12906
  }, [value, delayMs]);
@@ -13050,12 +13201,12 @@ function writeUrlState(scope, next, defaultView) {
13050
13201
  }
13051
13202
  function useDeviceListUrlState(options) {
13052
13203
  const { scope, defaultView, lsKey } = options;
13053
- const [state, setState] = (0, react.useState)(() => {
13204
+ const [state, setState] = (0, react$1.useState)(() => {
13054
13205
  return readUrlState(scope, defaultView, readFromLS(lsKey));
13055
13206
  });
13056
- const stateRef = (0, react.useRef)(state);
13207
+ const stateRef = (0, react$1.useRef)(state);
13057
13208
  stateRef.current = state;
13058
- (0, react.useEffect)(() => {
13209
+ (0, react$1.useEffect)(() => {
13059
13210
  const handler = () => {
13060
13211
  const next = readUrlState(scope, defaultView, readFromLS(lsKey));
13061
13212
  stateRef.current = next;
@@ -13068,7 +13219,7 @@ function useDeviceListUrlState(options) {
13068
13219
  defaultView,
13069
13220
  lsKey
13070
13221
  ]);
13071
- const apply = (0, react.useCallback)((mutate) => {
13222
+ const apply = (0, react$1.useCallback)((mutate) => {
13072
13223
  const next = mutate(stateRef.current);
13073
13224
  stateRef.current = next;
13074
13225
  setState(next);
@@ -13086,30 +13237,30 @@ function useDeviceListUrlState(options) {
13086
13237
  ]);
13087
13238
  return {
13088
13239
  state,
13089
- setView: (0, react.useCallback)((view) => apply((s) => ({
13240
+ setView: (0, react$1.useCallback)((view) => apply((s) => ({
13090
13241
  ...s,
13091
13242
  view
13092
13243
  })), [apply]),
13093
- setPage: (0, react.useCallback)((page) => apply((s) => ({
13244
+ setPage: (0, react$1.useCallback)((page) => apply((s) => ({
13094
13245
  ...s,
13095
13246
  page
13096
13247
  })), [apply]),
13097
- setAddon: (0, react.useCallback)((addon) => apply((s) => ({
13248
+ setAddon: (0, react$1.useCallback)((addon) => apply((s) => ({
13098
13249
  ...s,
13099
13250
  addon,
13100
13251
  page: 1
13101
13252
  })), [apply]),
13102
- setType: (0, react.useCallback)((type) => apply((s) => ({
13253
+ setType: (0, react$1.useCallback)((type) => apply((s) => ({
13103
13254
  ...s,
13104
13255
  type,
13105
13256
  page: 1
13106
13257
  })), [apply]),
13107
- setQ: (0, react.useCallback)((q) => apply((s) => ({
13258
+ setQ: (0, react$1.useCallback)((q) => apply((s) => ({
13108
13259
  ...s,
13109
13260
  q,
13110
13261
  page: 1
13111
13262
  })), [apply]),
13112
- clearFilters: (0, react.useCallback)(() => apply((s) => ({
13263
+ clearFilters: (0, react$1.useCallback)(() => apply((s) => ({
13113
13264
  ...s,
13114
13265
  addon: null,
13115
13266
  type: null,
@@ -13149,13 +13300,13 @@ function DeviceList(props) {
13149
13300
  });
13150
13301
  const view = url.state.view;
13151
13302
  const currentPageSize = view === "cards" ? pageSize.cards : pageSize.table;
13152
- const [searchInput, setSearchInput] = (0, react.useState)(url.state.q);
13303
+ const [searchInput, setSearchInput] = (0, react$1.useState)(url.state.q);
13153
13304
  const debouncedSearch = useDebouncedString(searchInput, 300);
13154
- (0, react.useEffect)(() => {
13305
+ (0, react$1.useEffect)(() => {
13155
13306
  if (debouncedSearch !== url.state.q) url.setQ(debouncedSearch);
13156
13307
  }, [debouncedSearch]);
13157
13308
  const effectiveAddon = forceAddon ?? url.state.addon;
13158
- const filtered = (0, react.useMemo)(() => {
13309
+ const filtered = (0, react$1.useMemo)(() => {
13159
13310
  const q = url.state.q.toLowerCase().trim();
13160
13311
  return devices.filter((d) => {
13161
13312
  if (effectiveAddon && d.addonId !== effectiveAddon) return false;
@@ -13169,8 +13320,8 @@ function DeviceList(props) {
13169
13320
  url.state.type,
13170
13321
  url.state.q
13171
13322
  ]);
13172
- const grouped = (0, react.useMemo)(() => groupTopLevelAndAccessories(filtered), [filtered]);
13173
- const autoExpandedParents = (0, react.useMemo)(() => {
13323
+ const grouped = (0, react$1.useMemo)(() => groupTopLevelAndAccessories(filtered), [filtered]);
13324
+ const autoExpandedParents = (0, react$1.useMemo)(() => {
13174
13325
  if (url.state.q.trim() === "") return /* @__PURE__ */ new Set();
13175
13326
  const q = url.state.q.toLowerCase().trim();
13176
13327
  const matching = /* @__PURE__ */ new Set();
@@ -13182,7 +13333,7 @@ function DeviceList(props) {
13182
13333
  const safePage = Math.min(url.state.page, totalPages);
13183
13334
  const startIdx = (safePage - 1) * currentPageSize;
13184
13335
  const pageRows = grouped.topLevel.slice(startIdx, startIdx + currentPageSize);
13185
- (0, react.useEffect)(() => {
13336
+ (0, react$1.useEffect)(() => {
13186
13337
  if (safePage !== url.state.page) url.setPage(safePage);
13187
13338
  }, [safePage]);
13188
13339
  useDeviceListRealtimeSync();
@@ -13287,7 +13438,7 @@ function topLevelIndentLevel(device, parentType) {
13287
13438
  return 0;
13288
13439
  }
13289
13440
  function TableLayout({ rows, accessoriesByParent, autoExpandedParents, devices, trpc, resolveIntegrationIcon, resolveParent, onNavigate }) {
13290
- const parentTypeById = (0, react.useMemo)(() => {
13441
+ const parentTypeById = (0, react$1.useMemo)(() => {
13291
13442
  const m = /* @__PURE__ */ new Map();
13292
13443
  for (const d of devices) m.set(d.id, d.type);
13293
13444
  return m;
@@ -13342,9 +13493,9 @@ function TableLayout({ rows, accessoriesByParent, autoExpandedParents, devices,
13342
13493
  });
13343
13494
  }
13344
13495
  function TableRowGroup({ parent, accessories, hasAccessories, forceExpanded, trpc, integrationIcon, parentRowParent, indentLevel, onNavigate }) {
13345
- const [expanded, setExpanded] = (0, react.useState)(forceExpanded);
13346
- const prevForce = (0, react.useRef)(forceExpanded);
13347
- (0, react.useEffect)(() => {
13496
+ const [expanded, setExpanded] = (0, react$1.useState)(forceExpanded);
13497
+ const prevForce = (0, react$1.useRef)(forceExpanded);
13498
+ (0, react$1.useEffect)(() => {
13348
13499
  if (prevForce.current !== forceExpanded) {
13349
13500
  setExpanded(forceExpanded);
13350
13501
  prevForce.current = forceExpanded;
@@ -13508,9 +13659,9 @@ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateI
13508
13659
  inheritedEnabled: inheritedEnabledByAddon[addonId]
13509
13660
  } : {}
13510
13661
  });
13511
- const excluded = (0, react.useMemo)(() => new Set(excludeAddons), [excludeAddons]);
13512
- const schemaMap = (0, react.useMemo)(() => buildSchemaMap(schema), [schema]);
13513
- const [warnings, setWarnings] = (0, react.useState)([]);
13662
+ const excluded = (0, react$1.useMemo)(() => new Set(excludeAddons), [excludeAddons]);
13663
+ const schemaMap = (0, react$1.useMemo)(() => buildSchemaMap(schema), [schema]);
13664
+ const [warnings, setWarnings] = (0, react$1.useState)([]);
13514
13665
  const dirty = selectedTemplateId ? JSON.stringify(steps) !== JSON.stringify(templates.find((t) => t.id === selectedTemplateId)?.steps) : false;
13515
13666
  function handleSelectTemplate(e) {
13516
13667
  const id = e.target.value || null;
@@ -13965,8 +14116,8 @@ function BoundingBox({ detection, imageWidth, imageHeight, color, showConfidence
13965
14116
  }
13966
14117
  /** Renders a segmentation mask as a semi-transparent colored canvas overlay */
13967
14118
  function MaskOverlay({ mask, maskWidth, maskHeight, bbox, imageWidth, imageHeight, color }) {
13968
- const canvasRef = (0, react.useRef)(null);
13969
- (0, react.useEffect)(() => {
14119
+ const canvasRef = (0, react$1.useRef)(null);
14120
+ (0, react$1.useEffect)(() => {
13970
14121
  const canvas = canvasRef.current;
13971
14122
  if (!canvas) return;
13972
14123
  const ctx = canvas.getContext("2d");
@@ -14278,7 +14429,7 @@ function ChildrenTree({ items, colors, hiddenKeys, onToggleVisibility }) {
14278
14429
  });
14279
14430
  }
14280
14431
  function AlternateLabelsSection({ alternateLabels, colors }) {
14281
- const [expanded, setExpanded] = (0, react.useState)(false);
14432
+ const [expanded, setExpanded] = (0, react$1.useState)(false);
14282
14433
  const sources = Object.keys(alternateLabels);
14283
14434
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14284
14435
  className: "mt-1",
@@ -15184,11 +15335,11 @@ function SpinnerIcon({ className }) {
15184
15335
  });
15185
15336
  }
15186
15337
  function LoginForm({ onLogin, serverUrl, logoSrc, error: externalError, className }) {
15187
- const [username, setUsername] = (0, react.useState)("");
15188
- const [password, setPassword] = (0, react.useState)("");
15189
- const [showPassword, setShowPassword] = (0, react.useState)(false);
15190
- const [submitting, setSubmitting] = (0, react.useState)(false);
15191
- const [internalError, setInternalError] = (0, react.useState)(null);
15338
+ const [username, setUsername] = (0, react$1.useState)("");
15339
+ const [password, setPassword] = (0, react$1.useState)("");
15340
+ const [showPassword, setShowPassword] = (0, react$1.useState)(false);
15341
+ const [submitting, setSubmitting] = (0, react$1.useState)(false);
15342
+ const [internalError, setInternalError] = (0, react$1.useState)(null);
15192
15343
  const error = externalError ?? internalError;
15193
15344
  const handleSubmit = async (e) => {
15194
15345
  e.preventDefault();
@@ -15280,9 +15431,9 @@ function LoginForm({ onLogin, serverUrl, logoSrc, error: externalError, classNam
15280
15431
  //#endregion
15281
15432
  //#region src/composites/dev-shell.tsx
15282
15433
  var STORAGE_KEY = "camstack_dev_token";
15283
- var DevShellContext = (0, react.createContext)(null);
15434
+ var DevShellContext = (0, react$1.createContext)(null);
15284
15435
  function useDevShell() {
15285
- const ctx = (0, react.useContext)(DevShellContext);
15436
+ const ctx = (0, react$1.useContext)(DevShellContext);
15286
15437
  if (!ctx) throw new Error("useDevShell must be used within a DevShell");
15287
15438
  return ctx;
15288
15439
  }
@@ -15332,7 +15483,7 @@ function MoonIcon({ className }) {
15332
15483
  }
15333
15484
  function DevShellInner({ children, serverUrl, title, token, onLogout }) {
15334
15485
  const theme = require_theme_index.useThemeMode$1();
15335
- const links = (0, react.useMemo)(() => {
15486
+ const links = (0, react$1.useMemo)(() => {
15336
15487
  return [(0, _trpc_client.splitLink)({
15337
15488
  condition: (op) => op.type === "subscription",
15338
15489
  true: (0, _trpc_client.wsLink)({
@@ -15349,20 +15500,20 @@ function DevShellInner({ children, serverUrl, title, token, onLogout }) {
15349
15500
  })
15350
15501
  })];
15351
15502
  }, [serverUrl, token]);
15352
- const trpc$1 = (0, react.useMemo)(() => (0, _trpc_client.createTRPCClient)({ links }), [links]);
15353
- const trpcReactClient = (0, react.useMemo)(() => trpc.createClient({ links }), [links]);
15354
- const system = (0, react.useMemo)(() => (0, _camstack_sdk.createSystem)({
15503
+ const trpc$1 = (0, react$1.useMemo)(() => (0, _trpc_client.createTRPCClient)({ links }), [links]);
15504
+ const trpcReactClient = (0, react$1.useMemo)(() => trpc.createClient({ links }), [links]);
15505
+ const system = (0, react$1.useMemo)(() => (0, _camstack_sdk.createSystem)({
15355
15506
  serverUrl,
15356
15507
  token
15357
15508
  }), [serverUrl, token]);
15358
- (0, react.useEffect)(() => {
15509
+ (0, react$1.useEffect)(() => {
15359
15510
  system.init().catch(() => void 0);
15360
15511
  return () => {
15361
15512
  system.close();
15362
15513
  };
15363
15514
  }, [system]);
15364
- const queryClient = (0, react.useMemo)(() => new _tanstack_react_query.QueryClient(), []);
15365
- const contextValue = (0, react.useMemo)(() => ({
15515
+ const queryClient = (0, react$1.useMemo)(() => new _tanstack_react_query.QueryClient(), []);
15516
+ const contextValue = (0, react$1.useMemo)(() => ({
15366
15517
  trpc: trpc$1,
15367
15518
  token,
15368
15519
  logout: onLogout
@@ -15429,8 +15580,8 @@ function DevShellInner({ children, serverUrl, title, token, onLogout }) {
15429
15580
  });
15430
15581
  }
15431
15582
  function DevShell({ children, serverUrl = "https://localhost:4443", title }) {
15432
- const [token, setToken] = (0, react.useState)(getStoredToken);
15433
- const handleLogin = (0, react.useCallback)(async (username, password) => {
15583
+ const [token, setToken] = (0, react$1.useState)(getStoredToken);
15584
+ const handleLogin = (0, react$1.useCallback)(async (username, password) => {
15434
15585
  const loginResult = await (0, _trpc_client.createTRPCClient)({ links: [(0, _trpc_client.httpLink)({
15435
15586
  url: `${serverUrl}/trpc`,
15436
15587
  transformer: SuperJSON
@@ -15442,7 +15593,7 @@ function DevShell({ children, serverUrl = "https://localhost:4443", title }) {
15442
15593
  localStorage.setItem(STORAGE_KEY, loginResult.token);
15443
15594
  setToken(loginResult.token);
15444
15595
  }, [serverUrl]);
15445
- const handleLogout = (0, react.useCallback)(() => {
15596
+ const handleLogout = (0, react$1.useCallback)(() => {
15446
15597
  localStorage.removeItem(STORAGE_KEY);
15447
15598
  setToken(null);
15448
15599
  }, []);
@@ -15491,10 +15642,10 @@ function mountAddonPage(PageComponent, options = {}) {
15491
15642
  console.error(`[mountAddonPage] Element #${rootId} not found`);
15492
15643
  return;
15493
15644
  }
15494
- (0, react_dom_client.createRoot)(root).render((0, react.createElement)(DevShell, {
15645
+ (0, react_dom_client.createRoot)(root).render((0, react$1.createElement)(DevShell, {
15495
15646
  serverUrl,
15496
15647
  title,
15497
- children: ({ trpc, theme }) => (0, react.createElement)(PageComponent, {
15648
+ children: ({ trpc, theme }) => (0, react$1.createElement)(PageComponent, {
15498
15649
  trpc,
15499
15650
  theme: { isDark: theme.resolvedMode === "dark" },
15500
15651
  navigate: (path) => {
@@ -15554,7 +15705,7 @@ function CustomFieldRenderersProvider({ renderers, children }) {
15554
15705
  * (or renders nothing).
15555
15706
  */
15556
15707
  function useCustomFieldRenderer(type) {
15557
- return (0, react.useContext)(CustomFieldRenderersContext)[type] ?? null;
15708
+ return (0, react$1.useContext)(CustomFieldRenderersContext)[type] ?? null;
15558
15709
  }
15559
15710
  //#endregion
15560
15711
  //#region src/contexts/device-context.tsx
@@ -15591,11 +15742,11 @@ function DeviceContextProvider({ deviceId, device, children }) {
15591
15742
  }
15592
15743
  /** @returns the device id of the current page subtree, or null if outside any provider. */
15593
15744
  function useDeviceId() {
15594
- return (0, react.useContext)(DeviceContext)?.deviceId ?? null;
15745
+ return (0, react$1.useContext)(DeviceContext)?.deviceId ?? null;
15595
15746
  }
15596
15747
  /** @returns the cached device snapshot, or null when no snapshot is provided. */
15597
15748
  function useDeviceSnapshot() {
15598
- return (0, react.useContext)(DeviceContext)?.device ?? null;
15749
+ return (0, react$1.useContext)(DeviceContext)?.device ?? null;
15599
15750
  }
15600
15751
  //#endregion
15601
15752
  //#region src/generated/system-hooks.ts
@@ -15649,6 +15800,14 @@ var useAddonsRollbackPackage = trpc.addons.rollbackPackage.useMutation;
15649
15800
  var useAddonsForceRefresh = trpc.addons.forceRefresh.useMutation;
15650
15801
  /** Generated alias around `trpc.addons.restartServer.useMutation`. */
15651
15802
  var useAddonsRestartServer = trpc.addons.restartServer.useMutation;
15803
+ /** Generated alias around `trpc.addons.getLastRestart.useQuery`. */
15804
+ var useAddonsGetLastRestart = trpc.addons.getLastRestart.useQuery;
15805
+ /** Generated alias around `trpc.addons.listFrameworkPackages.useQuery`. */
15806
+ var useAddonsListFrameworkPackages = trpc.addons.listFrameworkPackages.useQuery;
15807
+ /** Generated alias around `trpc.addons.listCapabilityProviders.useQuery`. */
15808
+ var useAddonsListCapabilityProviders = trpc.addons.listCapabilityProviders.useQuery;
15809
+ /** Generated alias around `trpc.addons.updateFrameworkPackage.useMutation`. */
15810
+ var useAddonsUpdateFrameworkPackage = trpc.addons.updateFrameworkPackage.useMutation;
15652
15811
  /** Generated alias around `trpc.addons.getVersions.useQuery`. */
15653
15812
  var useAddonsGetVersions = trpc.addons.getVersions.useQuery;
15654
15813
  /** Generated alias around `trpc.addons.restartAddon.useMutation`. */
@@ -16748,7 +16907,7 @@ var BOOT_WINDOW_MS = 3e4;
16748
16907
  var POLL_INTERVAL_MS = 2e3;
16749
16908
  function WidgetRegistryProvider({ children }) {
16750
16909
  const queryClient = (0, _tanstack_react_query.useQueryClient)();
16751
- const mountedAtRef = (0, react.useRef)(Date.now());
16910
+ const mountedAtRef = (0, react$1.useRef)(Date.now());
16752
16911
  const { data: rawWidgets } = useAddonWidgetsListWidgets(void 0, {
16753
16912
  staleTime: 0,
16754
16913
  refetchOnMount: "always",
@@ -16762,8 +16921,8 @@ function WidgetRegistryProvider({ children }) {
16762
16921
  useLiveEvent("addon.widget-ready", () => {
16763
16922
  queryClient.invalidateQueries({ queryKey: [["addonWidgets", "listWidgets"]] });
16764
16923
  });
16765
- const [resolvedTick, setResolvedTick] = (0, react.useState)(0);
16766
- (0, react.useEffect)(() => {
16924
+ const [resolvedTick, setResolvedTick] = (0, react$1.useState)(0);
16925
+ (0, react$1.useEffect)(() => {
16767
16926
  if (!rawWidgets) return;
16768
16927
  let cancelled = false;
16769
16928
  const seenRemotes = /* @__PURE__ */ new Set();
@@ -16787,7 +16946,7 @@ function WidgetRegistryProvider({ children }) {
16787
16946
  cancelled = true;
16788
16947
  };
16789
16948
  }, [rawWidgets]);
16790
- const registry = (0, react.useMemo)(() => {
16949
+ const registry = (0, react$1.useMemo)(() => {
16791
16950
  const widgets = rawWidgets ?? [];
16792
16951
  const byId = /* @__PURE__ */ new Map();
16793
16952
  for (const w of widgets) byId.set(`${w.addonId}/${w.stableId}`, w);
@@ -16859,7 +17018,7 @@ function useOptionalWidgetRegistry() {
16859
17018
  return useContextSafe(WidgetRegistryContext);
16860
17019
  }
16861
17020
  function useContextSafe(ctx) {
16862
- return (0, react.useContext)(ctx);
17021
+ return (0, react$1.useContext)(ctx);
16863
17022
  }
16864
17023
  //#endregion
16865
17024
  //#region src/composites/widget-slot.tsx
@@ -16883,7 +17042,7 @@ function WidgetSlot(props) {
16883
17042
  const { widgetId, host = "device-tab", config, deviceId, integrationId, instanceId, size, columns, rows } = props;
16884
17043
  const Component = useWidget(widgetId);
16885
17044
  const metadata = useWidgetMetadata(widgetId);
16886
- const resolvedInstanceId = (0, react.useMemo)(() => instanceId ?? widgetId, [instanceId, widgetId]);
17045
+ const resolvedInstanceId = (0, react$1.useMemo)(() => instanceId ?? widgetId, [instanceId, widgetId]);
16887
17046
  if (Component === void 0 && metadata === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetMissingError, {
16888
17047
  widgetId,
16889
17048
  reason: "unknown"
@@ -16977,9 +17136,9 @@ function TextField({ field, value, onChange, disabled, translationFn }) {
16977
17136
  });
16978
17137
  }
16979
17138
  function NumberField({ field, value, onChange, disabled, translationFn }) {
16980
- const [local, setLocal] = (0, react.useState)(value === void 0 || value === null ? "" : String(value));
16981
- const focusedRef = (0, react.useRef)(false);
16982
- (0, react.useEffect)(() => {
17139
+ const [local, setLocal] = (0, react$1.useState)(value === void 0 || value === null ? "" : String(value));
17140
+ const focusedRef = (0, react$1.useRef)(false);
17141
+ (0, react$1.useEffect)(() => {
16983
17142
  if (focusedRef.current) return;
16984
17143
  setLocal(value === void 0 || value === null ? "" : String(value));
16985
17144
  }, [value]);
@@ -17145,7 +17304,7 @@ function MultiSelectField({ field, value, onChange, disabled, translationFn }) {
17145
17304
  });
17146
17305
  }
17147
17306
  function PasswordField({ field, value, onChange, disabled, translationFn }) {
17148
- const [show, setShow] = (0, react.useState)(false);
17307
+ const [show, setShow] = (0, react$1.useState)(false);
17149
17308
  const showToggle = field.showToggle !== false;
17150
17309
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldWrapper, {
17151
17310
  label: field.label,
@@ -17312,9 +17471,9 @@ function SliderField({ field, value, onChange, disabled, translationFn }) {
17312
17471
  }
17313
17472
  function TagsField({ field, value, onChange, disabled, translationFn }) {
17314
17473
  const tags = Array.isArray(value) ? value : [];
17315
- const [input, setInput] = (0, react.useState)("");
17316
- const inputRef = (0, react.useRef)(null);
17317
- const addTag = (0, react.useCallback)((tag) => {
17474
+ const [input, setInput] = (0, react$1.useState)("");
17475
+ const inputRef = (0, react$1.useRef)(null);
17476
+ const addTag = (0, react$1.useCallback)((tag) => {
17318
17477
  const trimmed = tag.trim();
17319
17478
  if (!trimmed || tags.includes(trimmed)) return;
17320
17479
  if (field.maxTags !== void 0 && tags.length >= field.maxTags) return;
@@ -17473,12 +17632,12 @@ function ColorField({ field, value, onChange, disabled, translationFn }) {
17473
17632
  });
17474
17633
  }
17475
17634
  function ProbeField({ field, value, onChange, disabled, translationFn, onTestField, onAction, externalProbe }) {
17476
- const [localStatus, setLocalStatus] = (0, react.useState)("idle");
17477
- const [localResult, setLocalResult] = (0, react.useState)(null);
17635
+ const [localStatus, setLocalStatus] = (0, react$1.useState)("idle");
17636
+ const [localResult, setLocalResult] = (0, react$1.useState)(null);
17478
17637
  const probeStatus = externalProbe?.status ?? localStatus;
17479
17638
  const probeResult = externalProbe?.result ?? localResult;
17480
17639
  const hasTestHandler = !!onTestField || !!onAction;
17481
- const handleTest = (0, react.useCallback)(async () => {
17640
+ const handleTest = (0, react$1.useCallback)(async () => {
17482
17641
  if (!hasTestHandler) return;
17483
17642
  setLocalStatus("probing");
17484
17643
  setLocalResult(null);
@@ -17557,7 +17716,7 @@ function ProbeField({ field, value, onChange, disabled, translationFn, onTestFie
17557
17716
  });
17558
17717
  }
17559
17718
  function GroupField({ field, values, onChange, disabled, translationFn, onTestField }) {
17560
- const [collapsed, setCollapsed] = (0, react.useState)(field.defaultCollapsed ?? false);
17719
+ const [collapsed, setCollapsed] = (0, react$1.useState)(field.defaultCollapsed ?? false);
17561
17720
  const isAccordion = field.style === "accordion";
17562
17721
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
17563
17722
  className: field.span === 2 ? "col-span-2" : field.span === 3 ? "col-span-3" : field.span === 4 ? "col-span-4" : "col-span-1",
@@ -17588,7 +17747,7 @@ function GroupField({ field, values, onChange, disabled, translationFn, onTestFi
17588
17747
  });
17589
17748
  }
17590
17749
  function SubTabsField({ field, values, onChange, disabled, translationFn, onTestField, onAction }) {
17591
- const [active, setActive] = (0, react.useState)(field.tabs[0]?.id ?? "");
17750
+ const [active, setActive] = (0, react$1.useState)(field.tabs[0]?.id ?? "");
17592
17751
  const colSpanClass = field.span === 2 ? "col-span-2" : field.span === 3 ? "col-span-3" : field.span === 4 ? "col-span-4" : "col-span-1";
17593
17752
  if (field.tabs.length === 0) return null;
17594
17753
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -17929,7 +18088,7 @@ function EditableArrayField({ field, value, onChange, disabled, translationFn, o
17929
18088
  });
17930
18089
  }
17931
18090
  function ButtonField({ field, disabled, onAction }) {
17932
- const [loading, setLoading] = (0, react.useState)(false);
18091
+ const [loading, setLoading] = (0, react$1.useState)(false);
17933
18092
  const confirm = useConfirm();
17934
18093
  const handleClick = async () => {
17935
18094
  if (field.confirmMessage) {
@@ -17975,12 +18134,12 @@ function resolveActionParams(field, values) {
17975
18134
  return params;
17976
18135
  }
17977
18136
  function AddonActionSelectField({ field, value, values, onChange, disabled, onAction }) {
17978
- const [loading, setLoading] = (0, react.useState)(false);
17979
- const [error, setError] = (0, react.useState)(null);
17980
- const [options, setOptions] = (0, react.useState)(null);
18137
+ const [loading, setLoading] = (0, react$1.useState)(false);
18138
+ const [error, setError] = (0, react$1.useState)(null);
18139
+ const [options, setOptions] = (0, react$1.useState)(null);
17981
18140
  const params = resolveActionParams(field, values);
17982
18141
  const missingParam = Object.keys(field.paramsFromForm ?? {}).some((k) => params[k] === void 0);
17983
- (0, react.useEffect)(() => {
18142
+ (0, react$1.useEffect)(() => {
17984
18143
  if (!onAction || missingParam) {
17985
18144
  setOptions(null);
17986
18145
  setError(null);
@@ -18066,8 +18225,8 @@ function AddonActionSelectField({ field, value, values, onChange, disabled, onAc
18066
18225
  });
18067
18226
  }
18068
18227
  function AddonActionButtonField({ field, values, disabled, onAction }) {
18069
- const [loading, setLoading] = (0, react.useState)(false);
18070
- const [status, setStatus] = (0, react.useState)(null);
18228
+ const [loading, setLoading] = (0, react$1.useState)(false);
18229
+ const [status, setStatus] = (0, react$1.useState)(null);
18071
18230
  const confirm = useConfirm();
18072
18231
  const handleClick = async () => {
18073
18232
  if (field.confirmMessage) {
@@ -18212,7 +18371,7 @@ function InlineIconGlyph({ name }) {
18212
18371
  */
18213
18372
  function InlineActionIcon({ action, fieldKey, value, onAction }) {
18214
18373
  const confirm = useConfirm();
18215
- const [loading, setLoading] = (0, react.useState)(false);
18374
+ const [loading, setLoading] = (0, react$1.useState)(false);
18216
18375
  const variantClass = action.variant === "danger" ? "text-danger hover:bg-danger/10 border-danger/30" : action.variant === "primary" ? "text-primary hover:bg-primary/10 border-primary/30" : "text-foreground-subtle hover:text-foreground hover:bg-surface-hover border-border";
18217
18376
  const handleClick = async () => {
18218
18377
  if (action.confirmMessage) {
@@ -18560,7 +18719,7 @@ function resolveLabel(value, t) {
18560
18719
  return value;
18561
18720
  }
18562
18721
  function SectionCard({ section, values, onChange, disabled, translationFn, onTestField, probeResults }) {
18563
- const [collapsed, setCollapsed] = (0, react.useState)(section.defaultCollapsed ?? false);
18722
+ const [collapsed, setCollapsed] = (0, react$1.useState)(section.defaultCollapsed ?? false);
18564
18723
  const isAccordion = section.style === "accordion";
18565
18724
  const columns = section.columns ?? 2;
18566
18725
  const gridClass = columns === 1 ? "grid-cols-1" : columns === 3 ? "grid-cols-1 @[480px]:grid-cols-2 @[880px]:grid-cols-3" : columns === 4 ? "grid-cols-1 @[480px]:grid-cols-2 @[1140px]:grid-cols-4" : "grid-cols-1 @[640px]:grid-cols-2";
@@ -18665,14 +18824,14 @@ function stripValues(schema) {
18665
18824
  }
18666
18825
  function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAfterChange, refreshToken, collapsible, defaultOpen, mode, onOverrideChange }) {
18667
18826
  const effectiveMode = mode ?? "persist";
18668
- const [hydrated, setHydrated] = (0, react.useState)(null);
18669
- const [loading, setLoading] = (0, react.useState)(true);
18670
- const [error, setError] = (0, react.useState)(null);
18671
- const [saving, setSaving] = (0, react.useState)(false);
18672
- const [open, setOpen] = (0, react.useState)(defaultOpen ?? false);
18673
- const [overrideValues, setOverrideValues] = (0, react.useState)({});
18674
- const [baseValues, setBaseValues] = (0, react.useState)(null);
18675
- (0, react.useEffect)(() => {
18827
+ const [hydrated, setHydrated] = (0, react$1.useState)(null);
18828
+ const [loading, setLoading] = (0, react$1.useState)(true);
18829
+ const [error, setError] = (0, react$1.useState)(null);
18830
+ const [saving, setSaving] = (0, react$1.useState)(false);
18831
+ const [open, setOpen] = (0, react$1.useState)(defaultOpen ?? false);
18832
+ const [overrideValues, setOverrideValues] = (0, react$1.useState)({});
18833
+ const [baseValues, setBaseValues] = (0, react$1.useState)(null);
18834
+ (0, react$1.useEffect)(() => {
18676
18835
  setBaseValues(null);
18677
18836
  setOverrideValues({});
18678
18837
  }, [
@@ -18682,7 +18841,7 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
18682
18841
  refreshToken,
18683
18842
  effectiveMode
18684
18843
  ]);
18685
- (0, react.useEffect)(() => {
18844
+ (0, react$1.useEffect)(() => {
18686
18845
  let cancelled = false;
18687
18846
  setLoading(true);
18688
18847
  setError(null);
@@ -18712,8 +18871,8 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
18712
18871
  effectiveMode,
18713
18872
  JSON.stringify(overrideValues)
18714
18873
  ]);
18715
- const values = (0, react.useMemo)(() => extractValues(hydrated), [hydrated]);
18716
- const schemaNoValues = (0, react.useMemo)(() => hydrated ? stripValues(hydrated) : null, [hydrated]);
18874
+ const values = (0, react$1.useMemo)(() => extractValues(hydrated), [hydrated]);
18875
+ const schemaNoValues = (0, react$1.useMemo)(() => hydrated ? stripValues(hydrated) : null, [hydrated]);
18717
18876
  const handleChange = async (nextValues) => {
18718
18877
  if (effectiveMode === "override") {
18719
18878
  const ref = baseValues ?? values;
@@ -18960,30 +19119,30 @@ function computeClientHints(container) {
18960
19119
  var RECONNECT_DELAY_MS = 3e3;
18961
19120
  var MAX_RECONNECT_ATTEMPTS = 5;
18962
19121
  function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, muted: initialMuted = true, showControls = true, className = "", onStateChange, onError, overlay, createSession, sendAnswer, closeSession, hintsOverride }) {
18963
- const videoRef = (0, react.useRef)(null);
18964
- const containerRef = (0, react.useRef)(null);
18965
- const pcRef = (0, react.useRef)(null);
19122
+ const videoRef = (0, react$1.useRef)(null);
19123
+ const containerRef = (0, react$1.useRef)(null);
19124
+ const pcRef = (0, react$1.useRef)(null);
18966
19125
  /** All session IDs created during this player's lifetime — closed on cleanup */
18967
- const sessionIdsRef = (0, react.useRef)(/* @__PURE__ */ new Set());
19126
+ const sessionIdsRef = (0, react$1.useRef)(/* @__PURE__ */ new Set());
18968
19127
  /** Abort controller to cancel in-flight connection attempts on cleanup */
18969
- const connectAbortRef = (0, react.useRef)(null);
18970
- const reconnectTimerRef = (0, react.useRef)(null);
18971
- const reconnectAttemptsRef = (0, react.useRef)(0);
18972
- const mountedRef = (0, react.useRef)(true);
18973
- const [state, setState] = (0, react.useState)("idle");
18974
- const [errorMessage, setErrorMessage] = (0, react.useState)("");
18975
- const [isMuted, setIsMuted] = (0, react.useState)(initialMuted);
18976
- const [isFullscreen, setIsFullscreen] = (0, react.useState)(false);
18977
- const [showToolbar, setShowToolbar] = (0, react.useState)(false);
18978
- const hideTimerRef = (0, react.useRef)(null);
18979
- const serverOfferModeRef = (0, react.useRef)(false);
19128
+ const connectAbortRef = (0, react$1.useRef)(null);
19129
+ const reconnectTimerRef = (0, react$1.useRef)(null);
19130
+ const reconnectAttemptsRef = (0, react$1.useRef)(0);
19131
+ const mountedRef = (0, react$1.useRef)(true);
19132
+ const [state, setState] = (0, react$1.useState)("idle");
19133
+ const [errorMessage, setErrorMessage] = (0, react$1.useState)("");
19134
+ const [isMuted, setIsMuted] = (0, react$1.useState)(initialMuted);
19135
+ const [isFullscreen, setIsFullscreen] = (0, react$1.useState)(false);
19136
+ const [showToolbar, setShowToolbar] = (0, react$1.useState)(false);
19137
+ const hideTimerRef = (0, react$1.useRef)(null);
19138
+ const serverOfferModeRef = (0, react$1.useRef)(false);
18980
19139
  if (sendAnswer || createSession) serverOfferModeRef.current = true;
18981
19140
  const useServerOffer = serverOfferModeRef.current;
18982
- const updateState = (0, react.useCallback)((s) => {
19141
+ const updateState = (0, react$1.useCallback)((s) => {
18983
19142
  setState(s);
18984
19143
  onStateChange?.(s);
18985
19144
  }, [onStateChange]);
18986
- const cleanup = (0, react.useCallback)(() => {
19145
+ const cleanup = (0, react$1.useCallback)(() => {
18987
19146
  connectAbortRef.current?.abort();
18988
19147
  connectAbortRef.current = null;
18989
19148
  if (reconnectTimerRef.current) {
@@ -19000,7 +19159,7 @@ function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, mute
19000
19159
  }
19001
19160
  if (videoRef.current) videoRef.current.srcObject = null;
19002
19161
  }, [closeSession]);
19003
- const connectServerOffer = (0, react.useCallback)(async () => {
19162
+ const connectServerOffer = (0, react$1.useCallback)(async () => {
19004
19163
  if (!mountedRef.current || !createSession || !sendAnswer) return;
19005
19164
  cleanup();
19006
19165
  updateState("connecting");
@@ -19091,7 +19250,7 @@ function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, mute
19091
19250
  onError,
19092
19251
  hintsOverride
19093
19252
  ]);
19094
- const connectWhep = (0, react.useCallback)(async () => {
19253
+ const connectWhep = (0, react$1.useCallback)(async () => {
19095
19254
  if (!mountedRef.current) return;
19096
19255
  cleanup();
19097
19256
  updateState("connecting");
@@ -19152,9 +19311,9 @@ function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, mute
19152
19311
  onError
19153
19312
  ]);
19154
19313
  const connect = useServerOffer ? connectServerOffer : connectWhep;
19155
- const connectRef = (0, react.useRef)(() => {});
19314
+ const connectRef = (0, react$1.useRef)(() => {});
19156
19315
  connectRef.current = connect;
19157
- const scheduleReconnect = (0, react.useCallback)(() => {
19316
+ const scheduleReconnect = (0, react$1.useCallback)(() => {
19158
19317
  if (!mountedRef.current) return;
19159
19318
  if (reconnectAttemptsRef.current >= MAX_RECONNECT_ATTEMPTS) return;
19160
19319
  reconnectAttemptsRef.current += 1;
@@ -19162,7 +19321,7 @@ function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, mute
19162
19321
  if (mountedRef.current) connectRef.current();
19163
19322
  }, RECONNECT_DELAY_MS);
19164
19323
  }, []);
19165
- (0, react.useEffect)(() => {
19324
+ (0, react$1.useEffect)(() => {
19166
19325
  mountedRef.current = true;
19167
19326
  reconnectAttemptsRef.current = 0;
19168
19327
  if (autoPlay) connect();
@@ -19171,8 +19330,8 @@ function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, mute
19171
19330
  cleanup();
19172
19331
  };
19173
19332
  }, [serverUrl, streamKey]);
19174
- const hasSignaledRef = (0, react.useRef)(false);
19175
- (0, react.useEffect)(() => {
19333
+ const hasSignaledRef = (0, react$1.useRef)(false);
19334
+ (0, react$1.useEffect)(() => {
19176
19335
  if (!autoPlay || !useServerOffer) return;
19177
19336
  if (!createSession || !sendAnswer) return;
19178
19337
  if (hasSignaledRef.current) return;
@@ -19218,7 +19377,7 @@ function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, mute
19218
19377
  link.href = canvas.toDataURL("image/jpeg", .92);
19219
19378
  link.click();
19220
19379
  };
19221
- (0, react.useEffect)(() => {
19380
+ (0, react$1.useEffect)(() => {
19222
19381
  const handler = () => setIsFullscreen(!!document.fullscreenElement);
19223
19382
  document.addEventListener("fullscreenchange", handler);
19224
19383
  return () => document.removeEventListener("fullscreenchange", handler);
@@ -19442,16 +19601,16 @@ async function waitForIceGathering(pc) {
19442
19601
  var PlayerOverlaysStateContext = createSharedContext("camstack:player-overlays-state", null);
19443
19602
  var PlayerOverlaysActionsContext = createSharedContext("camstack:player-overlays-actions", null);
19444
19603
  function PlayerOverlaysProvider({ children }) {
19445
- const [layers, setLayers] = (0, react.useState)(() => /* @__PURE__ */ new Map());
19446
- const [buttons, setButtons] = (0, react.useState)(() => /* @__PURE__ */ new Map());
19447
- const setLayer = (0, react.useCallback)((layer) => {
19604
+ const [layers, setLayers] = (0, react$1.useState)(() => /* @__PURE__ */ new Map());
19605
+ const [buttons, setButtons] = (0, react$1.useState)(() => /* @__PURE__ */ new Map());
19606
+ const setLayer = (0, react$1.useCallback)((layer) => {
19448
19607
  setLayers((prev) => {
19449
19608
  const next = new Map(prev);
19450
19609
  next.set(layer.id, layer);
19451
19610
  return next;
19452
19611
  });
19453
19612
  }, []);
19454
- const removeLayer = (0, react.useCallback)((id) => {
19613
+ const removeLayer = (0, react$1.useCallback)((id) => {
19455
19614
  setLayers((prev) => {
19456
19615
  if (!prev.has(id)) return prev;
19457
19616
  const next = new Map(prev);
@@ -19459,14 +19618,14 @@ function PlayerOverlaysProvider({ children }) {
19459
19618
  return next;
19460
19619
  });
19461
19620
  }, []);
19462
- const setButton = (0, react.useCallback)((button) => {
19621
+ const setButton = (0, react$1.useCallback)((button) => {
19463
19622
  setButtons((prev) => {
19464
19623
  const next = new Map(prev);
19465
19624
  next.set(button.id, button);
19466
19625
  return next;
19467
19626
  });
19468
19627
  }, []);
19469
- const removeButton = (0, react.useCallback)((id) => {
19628
+ const removeButton = (0, react$1.useCallback)((id) => {
19470
19629
  setButtons((prev) => {
19471
19630
  if (!prev.has(id)) return prev;
19472
19631
  const next = new Map(prev);
@@ -19474,11 +19633,11 @@ function PlayerOverlaysProvider({ children }) {
19474
19633
  return next;
19475
19634
  });
19476
19635
  }, []);
19477
- const stateValue = (0, react.useMemo)(() => ({
19636
+ const stateValue = (0, react$1.useMemo)(() => ({
19478
19637
  layers,
19479
19638
  buttons
19480
19639
  }), [layers, buttons]);
19481
- const actionsValue = (0, react.useMemo)(() => ({
19640
+ const actionsValue = (0, react$1.useMemo)(() => ({
19482
19641
  setLayer,
19483
19642
  removeLayer,
19484
19643
  setButton,
@@ -19501,16 +19660,16 @@ function PlayerOverlaysProvider({ children }) {
19501
19660
  * by insertion order of the underlying Map). Returns `[]` outside a
19502
19661
  * provider. */
19503
19662
  function usePlayerOverlayLayers() {
19504
- const state = (0, react.useContext)(PlayerOverlaysStateContext);
19505
- return (0, react.useMemo)(() => {
19663
+ const state = (0, react$1.useContext)(PlayerOverlaysStateContext);
19664
+ return (0, react$1.useMemo)(() => {
19506
19665
  if (!state) return [];
19507
19666
  return [...state.layers.values()].sort((a, b) => a.order - b.order);
19508
19667
  }, [state]);
19509
19668
  }
19510
19669
  /** Snapshot of registered toolbar buttons, ordered by `order` (asc). */
19511
19670
  function usePlayerToolbarButtons() {
19512
- const state = (0, react.useContext)(PlayerOverlaysStateContext);
19513
- return (0, react.useMemo)(() => {
19671
+ const state = (0, react$1.useContext)(PlayerOverlaysStateContext);
19672
+ return (0, react$1.useMemo)(() => {
19514
19673
  if (!state) return [];
19515
19674
  return [...state.buttons.values()].sort((a, b) => a.order - b.order);
19516
19675
  }, [state]);
@@ -19527,8 +19686,8 @@ function usePlayerToolbarButtons() {
19527
19686
  * effects depend on referential equality of the spec object.
19528
19687
  */
19529
19688
  function usePlayerOverlayLayer(spec) {
19530
- const actions = (0, react.useContext)(PlayerOverlaysActionsContext);
19531
- (0, react.useEffect)(() => {
19689
+ const actions = (0, react$1.useContext)(PlayerOverlaysActionsContext);
19690
+ (0, react$1.useEffect)(() => {
19532
19691
  if (!actions || !spec) return void 0;
19533
19692
  actions.setLayer(spec);
19534
19693
  return () => actions.removeLayer(spec.id);
@@ -19536,8 +19695,8 @@ function usePlayerOverlayLayer(spec) {
19536
19695
  }
19537
19696
  /** Same shape as `usePlayerOverlayLayer`, scoped to toolbar buttons. */
19538
19697
  function usePlayerToolbarButton(spec) {
19539
- const actions = (0, react.useContext)(PlayerOverlaysActionsContext);
19540
- (0, react.useEffect)(() => {
19698
+ const actions = (0, react$1.useContext)(PlayerOverlaysActionsContext);
19699
+ (0, react$1.useEffect)(() => {
19541
19700
  if (!actions || !spec) return void 0;
19542
19701
  actions.setButton(spec);
19543
19702
  return () => actions.removeButton(spec.id);
@@ -19706,13 +19865,13 @@ function ImageOffIcon({ className }) {
19706
19865
  }
19707
19866
  function StreamPanel({ serverUrl, createSession, sendAnswer, closeSession, streams, activeStreamId: controlledStreamId, onStreamChange, deviceName, phase, pipelineMetrics, detections, defaultShowDetections = true, defaultShowMotion = false, streamStats, autoPlay = false, showPlayStop = false, snapshotSrc, snapshotLoading = false, onRefreshSnapshot, showStreamStats = false, children, extraOverlay, ptzAvailable = false, ptzShown = false, ptzOverlay, onPtzToggle, intercomAvailable = false, intercomShown = false, onIntercomToggle, chromeless = false, className }) {
19708
19867
  const registeredButtons = usePlayerToolbarButtons();
19709
- const [isPlaying, setIsPlaying] = (0, react.useState)(autoPlay);
19710
- const [showDetections, setShowDetections] = (0, react.useState)(defaultShowDetections);
19711
- const [showMotion, setShowMotion] = (0, react.useState)(defaultShowMotion);
19712
- const [internalStreamId, setInternalStreamId] = (0, react.useState)(null);
19713
- const [menuOpen, setMenuOpen] = (0, react.useState)(false);
19714
- const menuRef = (0, react.useRef)(null);
19715
- (0, react.useEffect)(() => {
19868
+ const [isPlaying, setIsPlaying] = (0, react$1.useState)(autoPlay);
19869
+ const [showDetections, setShowDetections] = (0, react$1.useState)(defaultShowDetections);
19870
+ const [showMotion, setShowMotion] = (0, react$1.useState)(defaultShowMotion);
19871
+ const [internalStreamId, setInternalStreamId] = (0, react$1.useState)(null);
19872
+ const [menuOpen, setMenuOpen] = (0, react$1.useState)(false);
19873
+ const menuRef = (0, react$1.useRef)(null);
19874
+ (0, react$1.useEffect)(() => {
19716
19875
  if (!menuOpen) return;
19717
19876
  function onClick(e) {
19718
19877
  if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false);
@@ -19735,7 +19894,7 @@ function StreamPanel({ serverUrl, createSession, sendAnswer, closeSession, strea
19735
19894
  setTimeout(() => setIsPlaying(true), 50);
19736
19895
  }
19737
19896
  };
19738
- const playerCreateSession = (0, react.useMemo)(() => {
19897
+ const playerCreateSession = (0, react$1.useMemo)(() => {
19739
19898
  const target = selectedChoice?.target;
19740
19899
  if (!target) return void 0;
19741
19900
  return (hints) => createSession(target, hints);
@@ -20058,10 +20217,10 @@ function profileLabel(streamId) {
20058
20217
  return streamId.charAt(0).toUpperCase() + streamId.slice(1);
20059
20218
  }
20060
20219
  function StreamBrokerSelector({ deviceId, value, onChange, disabled, label, className }) {
20061
- const labelId = (0, react.useId)();
20220
+ const labelId = (0, react$1.useId)();
20062
20221
  const query = useCameraStreamsGetRtspEntries({ deviceId }, { refetchOnWindowFocus: false });
20063
- const [options, setOptions] = (0, react.useState)([AUTO_OPTION]);
20064
- (0, react.useEffect)(() => {
20222
+ const [options, setOptions] = (0, react$1.useState)([AUTO_OPTION]);
20223
+ (0, react$1.useEffect)(() => {
20065
20224
  if (!query.data) return;
20066
20225
  const prefix = `${deviceId}/`;
20067
20226
  const next = [AUTO_OPTION];
@@ -20100,6 +20259,1479 @@ function StreamBrokerSelector({ deviceId, value, onChange, disabled, label, clas
20100
20259
  });
20101
20260
  }
20102
20261
  //#endregion
20262
+ //#region ../../node_modules/qrcode.react/lib/esm/index.js
20263
+ var __defProp = Object.defineProperty;
20264
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
20265
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
20266
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
20267
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
20268
+ enumerable: true,
20269
+ configurable: true,
20270
+ writable: true,
20271
+ value
20272
+ }) : obj[key] = value;
20273
+ var __spreadValues = (a, b) => {
20274
+ for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]);
20275
+ if (__getOwnPropSymbols) {
20276
+ for (var prop of __getOwnPropSymbols(b)) if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]);
20277
+ }
20278
+ return a;
20279
+ };
20280
+ var __objRest = (source, exclude) => {
20281
+ var target = {};
20282
+ for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop];
20283
+ if (source != null && __getOwnPropSymbols) {
20284
+ for (var prop of __getOwnPropSymbols(source)) if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop];
20285
+ }
20286
+ return target;
20287
+ };
20288
+ /**
20289
+ * @license QR Code generator library (TypeScript)
20290
+ * Copyright (c) Project Nayuki.
20291
+ * SPDX-License-Identifier: MIT
20292
+ */
20293
+ var qrcodegen;
20294
+ ((qrcodegen2) => {
20295
+ const _QrCode = class _QrCode {
20296
+ constructor(version, errorCorrectionLevel, dataCodewords, msk) {
20297
+ this.version = version;
20298
+ this.errorCorrectionLevel = errorCorrectionLevel;
20299
+ this.modules = [];
20300
+ this.isFunction = [];
20301
+ if (version < _QrCode.MIN_VERSION || version > _QrCode.MAX_VERSION) throw new RangeError("Version value out of range");
20302
+ if (msk < -1 || msk > 7) throw new RangeError("Mask value out of range");
20303
+ this.size = version * 4 + 17;
20304
+ let row = [];
20305
+ for (let i = 0; i < this.size; i++) row.push(false);
20306
+ for (let i = 0; i < this.size; i++) {
20307
+ this.modules.push(row.slice());
20308
+ this.isFunction.push(row.slice());
20309
+ }
20310
+ this.drawFunctionPatterns();
20311
+ const allCodewords = this.addEccAndInterleave(dataCodewords);
20312
+ this.drawCodewords(allCodewords);
20313
+ if (msk == -1) {
20314
+ let minPenalty = 1e9;
20315
+ for (let i = 0; i < 8; i++) {
20316
+ this.applyMask(i);
20317
+ this.drawFormatBits(i);
20318
+ const penalty = this.getPenaltyScore();
20319
+ if (penalty < minPenalty) {
20320
+ msk = i;
20321
+ minPenalty = penalty;
20322
+ }
20323
+ this.applyMask(i);
20324
+ }
20325
+ }
20326
+ assert(0 <= msk && msk <= 7);
20327
+ this.mask = msk;
20328
+ this.applyMask(msk);
20329
+ this.drawFormatBits(msk);
20330
+ this.isFunction = [];
20331
+ }
20332
+ static encodeText(text, ecl) {
20333
+ const segs = qrcodegen2.QrSegment.makeSegments(text);
20334
+ return _QrCode.encodeSegments(segs, ecl);
20335
+ }
20336
+ static encodeBinary(data, ecl) {
20337
+ const seg = qrcodegen2.QrSegment.makeBytes(data);
20338
+ return _QrCode.encodeSegments([seg], ecl);
20339
+ }
20340
+ static encodeSegments(segs, ecl, minVersion = 1, maxVersion = 40, mask = -1, boostEcl = true) {
20341
+ if (!(_QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= _QrCode.MAX_VERSION) || mask < -1 || mask > 7) throw new RangeError("Invalid value");
20342
+ let version;
20343
+ let dataUsedBits;
20344
+ for (version = minVersion;; version++) {
20345
+ const dataCapacityBits2 = _QrCode.getNumDataCodewords(version, ecl) * 8;
20346
+ const usedBits = QrSegment.getTotalBits(segs, version);
20347
+ if (usedBits <= dataCapacityBits2) {
20348
+ dataUsedBits = usedBits;
20349
+ break;
20350
+ }
20351
+ if (version >= maxVersion) throw new RangeError("Data too long");
20352
+ }
20353
+ for (const newEcl of [
20354
+ _QrCode.Ecc.MEDIUM,
20355
+ _QrCode.Ecc.QUARTILE,
20356
+ _QrCode.Ecc.HIGH
20357
+ ]) if (boostEcl && dataUsedBits <= _QrCode.getNumDataCodewords(version, newEcl) * 8) ecl = newEcl;
20358
+ let bb = [];
20359
+ for (const seg of segs) {
20360
+ appendBits(seg.mode.modeBits, 4, bb);
20361
+ appendBits(seg.numChars, seg.mode.numCharCountBits(version), bb);
20362
+ for (const b of seg.getData()) bb.push(b);
20363
+ }
20364
+ assert(bb.length == dataUsedBits);
20365
+ const dataCapacityBits = _QrCode.getNumDataCodewords(version, ecl) * 8;
20366
+ assert(bb.length <= dataCapacityBits);
20367
+ appendBits(0, Math.min(4, dataCapacityBits - bb.length), bb);
20368
+ appendBits(0, (8 - bb.length % 8) % 8, bb);
20369
+ assert(bb.length % 8 == 0);
20370
+ for (let padByte = 236; bb.length < dataCapacityBits; padByte ^= 253) appendBits(padByte, 8, bb);
20371
+ let dataCodewords = [];
20372
+ while (dataCodewords.length * 8 < bb.length) dataCodewords.push(0);
20373
+ bb.forEach((b, i) => dataCodewords[i >>> 3] |= b << 7 - (i & 7));
20374
+ return new _QrCode(version, ecl, dataCodewords, mask);
20375
+ }
20376
+ getModule(x, y) {
20377
+ return 0 <= x && x < this.size && 0 <= y && y < this.size && this.modules[y][x];
20378
+ }
20379
+ getModules() {
20380
+ return this.modules;
20381
+ }
20382
+ drawFunctionPatterns() {
20383
+ for (let i = 0; i < this.size; i++) {
20384
+ this.setFunctionModule(6, i, i % 2 == 0);
20385
+ this.setFunctionModule(i, 6, i % 2 == 0);
20386
+ }
20387
+ this.drawFinderPattern(3, 3);
20388
+ this.drawFinderPattern(this.size - 4, 3);
20389
+ this.drawFinderPattern(3, this.size - 4);
20390
+ const alignPatPos = this.getAlignmentPatternPositions();
20391
+ const numAlign = alignPatPos.length;
20392
+ for (let i = 0; i < numAlign; i++) for (let j = 0; j < numAlign; j++) if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0)) this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
20393
+ this.drawFormatBits(0);
20394
+ this.drawVersion();
20395
+ }
20396
+ drawFormatBits(mask) {
20397
+ const data = this.errorCorrectionLevel.formatBits << 3 | mask;
20398
+ let rem = data;
20399
+ for (let i = 0; i < 10; i++) rem = rem << 1 ^ (rem >>> 9) * 1335;
20400
+ const bits = (data << 10 | rem) ^ 21522;
20401
+ assert(bits >>> 15 == 0);
20402
+ for (let i = 0; i <= 5; i++) this.setFunctionModule(8, i, getBit(bits, i));
20403
+ this.setFunctionModule(8, 7, getBit(bits, 6));
20404
+ this.setFunctionModule(8, 8, getBit(bits, 7));
20405
+ this.setFunctionModule(7, 8, getBit(bits, 8));
20406
+ for (let i = 9; i < 15; i++) this.setFunctionModule(14 - i, 8, getBit(bits, i));
20407
+ for (let i = 0; i < 8; i++) this.setFunctionModule(this.size - 1 - i, 8, getBit(bits, i));
20408
+ for (let i = 8; i < 15; i++) this.setFunctionModule(8, this.size - 15 + i, getBit(bits, i));
20409
+ this.setFunctionModule(8, this.size - 8, true);
20410
+ }
20411
+ drawVersion() {
20412
+ if (this.version < 7) return;
20413
+ let rem = this.version;
20414
+ for (let i = 0; i < 12; i++) rem = rem << 1 ^ (rem >>> 11) * 7973;
20415
+ const bits = this.version << 12 | rem;
20416
+ assert(bits >>> 18 == 0);
20417
+ for (let i = 0; i < 18; i++) {
20418
+ const color = getBit(bits, i);
20419
+ const a = this.size - 11 + i % 3;
20420
+ const b = Math.floor(i / 3);
20421
+ this.setFunctionModule(a, b, color);
20422
+ this.setFunctionModule(b, a, color);
20423
+ }
20424
+ }
20425
+ drawFinderPattern(x, y) {
20426
+ for (let dy = -4; dy <= 4; dy++) for (let dx = -4; dx <= 4; dx++) {
20427
+ const dist = Math.max(Math.abs(dx), Math.abs(dy));
20428
+ const xx = x + dx;
20429
+ const yy = y + dy;
20430
+ if (0 <= xx && xx < this.size && 0 <= yy && yy < this.size) this.setFunctionModule(xx, yy, dist != 2 && dist != 4);
20431
+ }
20432
+ }
20433
+ drawAlignmentPattern(x, y) {
20434
+ for (let dy = -2; dy <= 2; dy++) for (let dx = -2; dx <= 2; dx++) this.setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) != 1);
20435
+ }
20436
+ setFunctionModule(x, y, isDark) {
20437
+ this.modules[y][x] = isDark;
20438
+ this.isFunction[y][x] = true;
20439
+ }
20440
+ addEccAndInterleave(data) {
20441
+ const ver = this.version;
20442
+ const ecl = this.errorCorrectionLevel;
20443
+ if (data.length != _QrCode.getNumDataCodewords(ver, ecl)) throw new RangeError("Invalid argument");
20444
+ const numBlocks = _QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
20445
+ const blockEccLen = _QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver];
20446
+ const rawCodewords = Math.floor(_QrCode.getNumRawDataModules(ver) / 8);
20447
+ const numShortBlocks = numBlocks - rawCodewords % numBlocks;
20448
+ const shortBlockLen = Math.floor(rawCodewords / numBlocks);
20449
+ let blocks = [];
20450
+ const rsDiv = _QrCode.reedSolomonComputeDivisor(blockEccLen);
20451
+ for (let i = 0, k = 0; i < numBlocks; i++) {
20452
+ let dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
20453
+ k += dat.length;
20454
+ const ecc = _QrCode.reedSolomonComputeRemainder(dat, rsDiv);
20455
+ if (i < numShortBlocks) dat.push(0);
20456
+ blocks.push(dat.concat(ecc));
20457
+ }
20458
+ let result = [];
20459
+ for (let i = 0; i < blocks[0].length; i++) blocks.forEach((block, j) => {
20460
+ if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) result.push(block[i]);
20461
+ });
20462
+ assert(result.length == rawCodewords);
20463
+ return result;
20464
+ }
20465
+ drawCodewords(data) {
20466
+ if (data.length != Math.floor(_QrCode.getNumRawDataModules(this.version) / 8)) throw new RangeError("Invalid argument");
20467
+ let i = 0;
20468
+ for (let right = this.size - 1; right >= 1; right -= 2) {
20469
+ if (right == 6) right = 5;
20470
+ for (let vert = 0; vert < this.size; vert++) for (let j = 0; j < 2; j++) {
20471
+ const x = right - j;
20472
+ const y = (right + 1 & 2) == 0 ? this.size - 1 - vert : vert;
20473
+ if (!this.isFunction[y][x] && i < data.length * 8) {
20474
+ this.modules[y][x] = getBit(data[i >>> 3], 7 - (i & 7));
20475
+ i++;
20476
+ }
20477
+ }
20478
+ }
20479
+ assert(i == data.length * 8);
20480
+ }
20481
+ applyMask(mask) {
20482
+ if (mask < 0 || mask > 7) throw new RangeError("Mask value out of range");
20483
+ for (let y = 0; y < this.size; y++) for (let x = 0; x < this.size; x++) {
20484
+ let invert;
20485
+ switch (mask) {
20486
+ case 0:
20487
+ invert = (x + y) % 2 == 0;
20488
+ break;
20489
+ case 1:
20490
+ invert = y % 2 == 0;
20491
+ break;
20492
+ case 2:
20493
+ invert = x % 3 == 0;
20494
+ break;
20495
+ case 3:
20496
+ invert = (x + y) % 3 == 0;
20497
+ break;
20498
+ case 4:
20499
+ invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 == 0;
20500
+ break;
20501
+ case 5:
20502
+ invert = x * y % 2 + x * y % 3 == 0;
20503
+ break;
20504
+ case 6:
20505
+ invert = (x * y % 2 + x * y % 3) % 2 == 0;
20506
+ break;
20507
+ case 7:
20508
+ invert = ((x + y) % 2 + x * y % 3) % 2 == 0;
20509
+ break;
20510
+ default: throw new Error("Unreachable");
20511
+ }
20512
+ if (!this.isFunction[y][x] && invert) this.modules[y][x] = !this.modules[y][x];
20513
+ }
20514
+ }
20515
+ getPenaltyScore() {
20516
+ let result = 0;
20517
+ for (let y = 0; y < this.size; y++) {
20518
+ let runColor = false;
20519
+ let runX = 0;
20520
+ let runHistory = [
20521
+ 0,
20522
+ 0,
20523
+ 0,
20524
+ 0,
20525
+ 0,
20526
+ 0,
20527
+ 0
20528
+ ];
20529
+ for (let x = 0; x < this.size; x++) if (this.modules[y][x] == runColor) {
20530
+ runX++;
20531
+ if (runX == 5) result += _QrCode.PENALTY_N1;
20532
+ else if (runX > 5) result++;
20533
+ } else {
20534
+ this.finderPenaltyAddHistory(runX, runHistory);
20535
+ if (!runColor) result += this.finderPenaltyCountPatterns(runHistory) * _QrCode.PENALTY_N3;
20536
+ runColor = this.modules[y][x];
20537
+ runX = 1;
20538
+ }
20539
+ result += this.finderPenaltyTerminateAndCount(runColor, runX, runHistory) * _QrCode.PENALTY_N3;
20540
+ }
20541
+ for (let x = 0; x < this.size; x++) {
20542
+ let runColor = false;
20543
+ let runY = 0;
20544
+ let runHistory = [
20545
+ 0,
20546
+ 0,
20547
+ 0,
20548
+ 0,
20549
+ 0,
20550
+ 0,
20551
+ 0
20552
+ ];
20553
+ for (let y = 0; y < this.size; y++) if (this.modules[y][x] == runColor) {
20554
+ runY++;
20555
+ if (runY == 5) result += _QrCode.PENALTY_N1;
20556
+ else if (runY > 5) result++;
20557
+ } else {
20558
+ this.finderPenaltyAddHistory(runY, runHistory);
20559
+ if (!runColor) result += this.finderPenaltyCountPatterns(runHistory) * _QrCode.PENALTY_N3;
20560
+ runColor = this.modules[y][x];
20561
+ runY = 1;
20562
+ }
20563
+ result += this.finderPenaltyTerminateAndCount(runColor, runY, runHistory) * _QrCode.PENALTY_N3;
20564
+ }
20565
+ for (let y = 0; y < this.size - 1; y++) for (let x = 0; x < this.size - 1; x++) {
20566
+ const color = this.modules[y][x];
20567
+ if (color == this.modules[y][x + 1] && color == this.modules[y + 1][x] && color == this.modules[y + 1][x + 1]) result += _QrCode.PENALTY_N2;
20568
+ }
20569
+ let dark = 0;
20570
+ for (const row of this.modules) dark = row.reduce((sum, color) => sum + (color ? 1 : 0), dark);
20571
+ const total = this.size * this.size;
20572
+ const k = Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1;
20573
+ assert(0 <= k && k <= 9);
20574
+ result += k * _QrCode.PENALTY_N4;
20575
+ assert(0 <= result && result <= 2568888);
20576
+ return result;
20577
+ }
20578
+ getAlignmentPatternPositions() {
20579
+ if (this.version == 1) return [];
20580
+ else {
20581
+ const numAlign = Math.floor(this.version / 7) + 2;
20582
+ const step = this.version == 32 ? 26 : Math.ceil((this.version * 4 + 4) / (numAlign * 2 - 2)) * 2;
20583
+ let result = [6];
20584
+ for (let pos = this.size - 7; result.length < numAlign; pos -= step) result.splice(1, 0, pos);
20585
+ return result;
20586
+ }
20587
+ }
20588
+ static getNumRawDataModules(ver) {
20589
+ if (ver < _QrCode.MIN_VERSION || ver > _QrCode.MAX_VERSION) throw new RangeError("Version number out of range");
20590
+ let result = (16 * ver + 128) * ver + 64;
20591
+ if (ver >= 2) {
20592
+ const numAlign = Math.floor(ver / 7) + 2;
20593
+ result -= (25 * numAlign - 10) * numAlign - 55;
20594
+ if (ver >= 7) result -= 36;
20595
+ }
20596
+ assert(208 <= result && result <= 29648);
20597
+ return result;
20598
+ }
20599
+ static getNumDataCodewords(ver, ecl) {
20600
+ return Math.floor(_QrCode.getNumRawDataModules(ver) / 8) - _QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] * _QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
20601
+ }
20602
+ static reedSolomonComputeDivisor(degree) {
20603
+ if (degree < 1 || degree > 255) throw new RangeError("Degree out of range");
20604
+ let result = [];
20605
+ for (let i = 0; i < degree - 1; i++) result.push(0);
20606
+ result.push(1);
20607
+ let root = 1;
20608
+ for (let i = 0; i < degree; i++) {
20609
+ for (let j = 0; j < result.length; j++) {
20610
+ result[j] = _QrCode.reedSolomonMultiply(result[j], root);
20611
+ if (j + 1 < result.length) result[j] ^= result[j + 1];
20612
+ }
20613
+ root = _QrCode.reedSolomonMultiply(root, 2);
20614
+ }
20615
+ return result;
20616
+ }
20617
+ static reedSolomonComputeRemainder(data, divisor) {
20618
+ let result = divisor.map((_) => 0);
20619
+ for (const b of data) {
20620
+ const factor = b ^ result.shift();
20621
+ result.push(0);
20622
+ divisor.forEach((coef, i) => result[i] ^= _QrCode.reedSolomonMultiply(coef, factor));
20623
+ }
20624
+ return result;
20625
+ }
20626
+ static reedSolomonMultiply(x, y) {
20627
+ if (x >>> 8 != 0 || y >>> 8 != 0) throw new RangeError("Byte out of range");
20628
+ let z = 0;
20629
+ for (let i = 7; i >= 0; i--) {
20630
+ z = z << 1 ^ (z >>> 7) * 285;
20631
+ z ^= (y >>> i & 1) * x;
20632
+ }
20633
+ assert(z >>> 8 == 0);
20634
+ return z;
20635
+ }
20636
+ finderPenaltyCountPatterns(runHistory) {
20637
+ const n = runHistory[1];
20638
+ assert(n <= this.size * 3);
20639
+ const core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;
20640
+ return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
20641
+ }
20642
+ finderPenaltyTerminateAndCount(currentRunColor, currentRunLength, runHistory) {
20643
+ if (currentRunColor) {
20644
+ this.finderPenaltyAddHistory(currentRunLength, runHistory);
20645
+ currentRunLength = 0;
20646
+ }
20647
+ currentRunLength += this.size;
20648
+ this.finderPenaltyAddHistory(currentRunLength, runHistory);
20649
+ return this.finderPenaltyCountPatterns(runHistory);
20650
+ }
20651
+ finderPenaltyAddHistory(currentRunLength, runHistory) {
20652
+ if (runHistory[0] == 0) currentRunLength += this.size;
20653
+ runHistory.pop();
20654
+ runHistory.unshift(currentRunLength);
20655
+ }
20656
+ };
20657
+ _QrCode.MIN_VERSION = 1;
20658
+ _QrCode.MAX_VERSION = 40;
20659
+ _QrCode.PENALTY_N1 = 3;
20660
+ _QrCode.PENALTY_N2 = 3;
20661
+ _QrCode.PENALTY_N3 = 40;
20662
+ _QrCode.PENALTY_N4 = 10;
20663
+ _QrCode.ECC_CODEWORDS_PER_BLOCK = [
20664
+ [
20665
+ -1,
20666
+ 7,
20667
+ 10,
20668
+ 15,
20669
+ 20,
20670
+ 26,
20671
+ 18,
20672
+ 20,
20673
+ 24,
20674
+ 30,
20675
+ 18,
20676
+ 20,
20677
+ 24,
20678
+ 26,
20679
+ 30,
20680
+ 22,
20681
+ 24,
20682
+ 28,
20683
+ 30,
20684
+ 28,
20685
+ 28,
20686
+ 28,
20687
+ 28,
20688
+ 30,
20689
+ 30,
20690
+ 26,
20691
+ 28,
20692
+ 30,
20693
+ 30,
20694
+ 30,
20695
+ 30,
20696
+ 30,
20697
+ 30,
20698
+ 30,
20699
+ 30,
20700
+ 30,
20701
+ 30,
20702
+ 30,
20703
+ 30,
20704
+ 30,
20705
+ 30
20706
+ ],
20707
+ [
20708
+ -1,
20709
+ 10,
20710
+ 16,
20711
+ 26,
20712
+ 18,
20713
+ 24,
20714
+ 16,
20715
+ 18,
20716
+ 22,
20717
+ 22,
20718
+ 26,
20719
+ 30,
20720
+ 22,
20721
+ 22,
20722
+ 24,
20723
+ 24,
20724
+ 28,
20725
+ 28,
20726
+ 26,
20727
+ 26,
20728
+ 26,
20729
+ 26,
20730
+ 28,
20731
+ 28,
20732
+ 28,
20733
+ 28,
20734
+ 28,
20735
+ 28,
20736
+ 28,
20737
+ 28,
20738
+ 28,
20739
+ 28,
20740
+ 28,
20741
+ 28,
20742
+ 28,
20743
+ 28,
20744
+ 28,
20745
+ 28,
20746
+ 28,
20747
+ 28,
20748
+ 28
20749
+ ],
20750
+ [
20751
+ -1,
20752
+ 13,
20753
+ 22,
20754
+ 18,
20755
+ 26,
20756
+ 18,
20757
+ 24,
20758
+ 18,
20759
+ 22,
20760
+ 20,
20761
+ 24,
20762
+ 28,
20763
+ 26,
20764
+ 24,
20765
+ 20,
20766
+ 30,
20767
+ 24,
20768
+ 28,
20769
+ 28,
20770
+ 26,
20771
+ 30,
20772
+ 28,
20773
+ 30,
20774
+ 30,
20775
+ 30,
20776
+ 30,
20777
+ 28,
20778
+ 30,
20779
+ 30,
20780
+ 30,
20781
+ 30,
20782
+ 30,
20783
+ 30,
20784
+ 30,
20785
+ 30,
20786
+ 30,
20787
+ 30,
20788
+ 30,
20789
+ 30,
20790
+ 30,
20791
+ 30
20792
+ ],
20793
+ [
20794
+ -1,
20795
+ 17,
20796
+ 28,
20797
+ 22,
20798
+ 16,
20799
+ 22,
20800
+ 28,
20801
+ 26,
20802
+ 26,
20803
+ 24,
20804
+ 28,
20805
+ 24,
20806
+ 28,
20807
+ 22,
20808
+ 24,
20809
+ 24,
20810
+ 30,
20811
+ 28,
20812
+ 28,
20813
+ 26,
20814
+ 28,
20815
+ 30,
20816
+ 24,
20817
+ 30,
20818
+ 30,
20819
+ 30,
20820
+ 30,
20821
+ 30,
20822
+ 30,
20823
+ 30,
20824
+ 30,
20825
+ 30,
20826
+ 30,
20827
+ 30,
20828
+ 30,
20829
+ 30,
20830
+ 30,
20831
+ 30,
20832
+ 30,
20833
+ 30,
20834
+ 30
20835
+ ]
20836
+ ];
20837
+ _QrCode.NUM_ERROR_CORRECTION_BLOCKS = [
20838
+ [
20839
+ -1,
20840
+ 1,
20841
+ 1,
20842
+ 1,
20843
+ 1,
20844
+ 1,
20845
+ 2,
20846
+ 2,
20847
+ 2,
20848
+ 2,
20849
+ 4,
20850
+ 4,
20851
+ 4,
20852
+ 4,
20853
+ 4,
20854
+ 6,
20855
+ 6,
20856
+ 6,
20857
+ 6,
20858
+ 7,
20859
+ 8,
20860
+ 8,
20861
+ 9,
20862
+ 9,
20863
+ 10,
20864
+ 12,
20865
+ 12,
20866
+ 12,
20867
+ 13,
20868
+ 14,
20869
+ 15,
20870
+ 16,
20871
+ 17,
20872
+ 18,
20873
+ 19,
20874
+ 19,
20875
+ 20,
20876
+ 21,
20877
+ 22,
20878
+ 24,
20879
+ 25
20880
+ ],
20881
+ [
20882
+ -1,
20883
+ 1,
20884
+ 1,
20885
+ 1,
20886
+ 2,
20887
+ 2,
20888
+ 4,
20889
+ 4,
20890
+ 4,
20891
+ 5,
20892
+ 5,
20893
+ 5,
20894
+ 8,
20895
+ 9,
20896
+ 9,
20897
+ 10,
20898
+ 10,
20899
+ 11,
20900
+ 13,
20901
+ 14,
20902
+ 16,
20903
+ 17,
20904
+ 17,
20905
+ 18,
20906
+ 20,
20907
+ 21,
20908
+ 23,
20909
+ 25,
20910
+ 26,
20911
+ 28,
20912
+ 29,
20913
+ 31,
20914
+ 33,
20915
+ 35,
20916
+ 37,
20917
+ 38,
20918
+ 40,
20919
+ 43,
20920
+ 45,
20921
+ 47,
20922
+ 49
20923
+ ],
20924
+ [
20925
+ -1,
20926
+ 1,
20927
+ 1,
20928
+ 2,
20929
+ 2,
20930
+ 4,
20931
+ 4,
20932
+ 6,
20933
+ 6,
20934
+ 8,
20935
+ 8,
20936
+ 8,
20937
+ 10,
20938
+ 12,
20939
+ 16,
20940
+ 12,
20941
+ 17,
20942
+ 16,
20943
+ 18,
20944
+ 21,
20945
+ 20,
20946
+ 23,
20947
+ 23,
20948
+ 25,
20949
+ 27,
20950
+ 29,
20951
+ 34,
20952
+ 34,
20953
+ 35,
20954
+ 38,
20955
+ 40,
20956
+ 43,
20957
+ 45,
20958
+ 48,
20959
+ 51,
20960
+ 53,
20961
+ 56,
20962
+ 59,
20963
+ 62,
20964
+ 65,
20965
+ 68
20966
+ ],
20967
+ [
20968
+ -1,
20969
+ 1,
20970
+ 1,
20971
+ 2,
20972
+ 4,
20973
+ 4,
20974
+ 4,
20975
+ 5,
20976
+ 6,
20977
+ 8,
20978
+ 8,
20979
+ 11,
20980
+ 11,
20981
+ 16,
20982
+ 16,
20983
+ 18,
20984
+ 16,
20985
+ 19,
20986
+ 21,
20987
+ 25,
20988
+ 25,
20989
+ 25,
20990
+ 34,
20991
+ 30,
20992
+ 32,
20993
+ 35,
20994
+ 37,
20995
+ 40,
20996
+ 42,
20997
+ 45,
20998
+ 48,
20999
+ 51,
21000
+ 54,
21001
+ 57,
21002
+ 60,
21003
+ 63,
21004
+ 66,
21005
+ 70,
21006
+ 74,
21007
+ 77,
21008
+ 81
21009
+ ]
21010
+ ];
21011
+ qrcodegen2.QrCode = _QrCode;
21012
+ function appendBits(val, len, bb) {
21013
+ if (len < 0 || len > 31 || val >>> len != 0) throw new RangeError("Value out of range");
21014
+ for (let i = len - 1; i >= 0; i--) bb.push(val >>> i & 1);
21015
+ }
21016
+ function getBit(x, i) {
21017
+ return (x >>> i & 1) != 0;
21018
+ }
21019
+ function assert(cond) {
21020
+ if (!cond) throw new Error("Assertion error");
21021
+ }
21022
+ const _QrSegment = class _QrSegment {
21023
+ constructor(mode, numChars, bitData) {
21024
+ this.mode = mode;
21025
+ this.numChars = numChars;
21026
+ this.bitData = bitData;
21027
+ if (numChars < 0) throw new RangeError("Invalid argument");
21028
+ this.bitData = bitData.slice();
21029
+ }
21030
+ static makeBytes(data) {
21031
+ let bb = [];
21032
+ for (const b of data) appendBits(b, 8, bb);
21033
+ return new _QrSegment(_QrSegment.Mode.BYTE, data.length, bb);
21034
+ }
21035
+ static makeNumeric(digits) {
21036
+ if (!_QrSegment.isNumeric(digits)) throw new RangeError("String contains non-numeric characters");
21037
+ let bb = [];
21038
+ for (let i = 0; i < digits.length;) {
21039
+ const n = Math.min(digits.length - i, 3);
21040
+ appendBits(parseInt(digits.substring(i, i + n), 10), n * 3 + 1, bb);
21041
+ i += n;
21042
+ }
21043
+ return new _QrSegment(_QrSegment.Mode.NUMERIC, digits.length, bb);
21044
+ }
21045
+ static makeAlphanumeric(text) {
21046
+ if (!_QrSegment.isAlphanumeric(text)) throw new RangeError("String contains unencodable characters in alphanumeric mode");
21047
+ let bb = [];
21048
+ let i;
21049
+ for (i = 0; i + 2 <= text.length; i += 2) {
21050
+ let temp = _QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
21051
+ temp += _QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
21052
+ appendBits(temp, 11, bb);
21053
+ }
21054
+ if (i < text.length) appendBits(_QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6, bb);
21055
+ return new _QrSegment(_QrSegment.Mode.ALPHANUMERIC, text.length, bb);
21056
+ }
21057
+ static makeSegments(text) {
21058
+ if (text == "") return [];
21059
+ else if (_QrSegment.isNumeric(text)) return [_QrSegment.makeNumeric(text)];
21060
+ else if (_QrSegment.isAlphanumeric(text)) return [_QrSegment.makeAlphanumeric(text)];
21061
+ else return [_QrSegment.makeBytes(_QrSegment.toUtf8ByteArray(text))];
21062
+ }
21063
+ static makeEci(assignVal) {
21064
+ let bb = [];
21065
+ if (assignVal < 0) throw new RangeError("ECI assignment value out of range");
21066
+ else if (assignVal < 128) appendBits(assignVal, 8, bb);
21067
+ else if (assignVal < 16384) {
21068
+ appendBits(2, 2, bb);
21069
+ appendBits(assignVal, 14, bb);
21070
+ } else if (assignVal < 1e6) {
21071
+ appendBits(6, 3, bb);
21072
+ appendBits(assignVal, 21, bb);
21073
+ } else throw new RangeError("ECI assignment value out of range");
21074
+ return new _QrSegment(_QrSegment.Mode.ECI, 0, bb);
21075
+ }
21076
+ static isNumeric(text) {
21077
+ return _QrSegment.NUMERIC_REGEX.test(text);
21078
+ }
21079
+ static isAlphanumeric(text) {
21080
+ return _QrSegment.ALPHANUMERIC_REGEX.test(text);
21081
+ }
21082
+ getData() {
21083
+ return this.bitData.slice();
21084
+ }
21085
+ static getTotalBits(segs, version) {
21086
+ let result = 0;
21087
+ for (const seg of segs) {
21088
+ const ccbits = seg.mode.numCharCountBits(version);
21089
+ if (seg.numChars >= 1 << ccbits) return Infinity;
21090
+ result += 4 + ccbits + seg.bitData.length;
21091
+ }
21092
+ return result;
21093
+ }
21094
+ static toUtf8ByteArray(str) {
21095
+ str = encodeURI(str);
21096
+ let result = [];
21097
+ for (let i = 0; i < str.length; i++) if (str.charAt(i) != "%") result.push(str.charCodeAt(i));
21098
+ else {
21099
+ result.push(parseInt(str.substring(i + 1, i + 3), 16));
21100
+ i += 2;
21101
+ }
21102
+ return result;
21103
+ }
21104
+ };
21105
+ _QrSegment.NUMERIC_REGEX = /^[0-9]*$/;
21106
+ _QrSegment.ALPHANUMERIC_REGEX = /^[A-Z0-9 $%*+.\/:-]*$/;
21107
+ _QrSegment.ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
21108
+ let QrSegment = _QrSegment;
21109
+ qrcodegen2.QrSegment = _QrSegment;
21110
+ })(qrcodegen || (qrcodegen = {}));
21111
+ ((qrcodegen2) => {
21112
+ ((QrCode2) => {
21113
+ const _Ecc = class _Ecc {
21114
+ constructor(ordinal, formatBits) {
21115
+ this.ordinal = ordinal;
21116
+ this.formatBits = formatBits;
21117
+ }
21118
+ };
21119
+ _Ecc.LOW = new _Ecc(0, 1);
21120
+ _Ecc.MEDIUM = new _Ecc(1, 0);
21121
+ _Ecc.QUARTILE = new _Ecc(2, 3);
21122
+ _Ecc.HIGH = new _Ecc(3, 2);
21123
+ QrCode2.Ecc = _Ecc;
21124
+ })(qrcodegen2.QrCode || (qrcodegen2.QrCode = {}));
21125
+ })(qrcodegen || (qrcodegen = {}));
21126
+ ((qrcodegen2) => {
21127
+ ((QrSegment2) => {
21128
+ const _Mode = class _Mode {
21129
+ constructor(modeBits, numBitsCharCount) {
21130
+ this.modeBits = modeBits;
21131
+ this.numBitsCharCount = numBitsCharCount;
21132
+ }
21133
+ numCharCountBits(ver) {
21134
+ return this.numBitsCharCount[Math.floor((ver + 7) / 17)];
21135
+ }
21136
+ };
21137
+ _Mode.NUMERIC = new _Mode(1, [
21138
+ 10,
21139
+ 12,
21140
+ 14
21141
+ ]);
21142
+ _Mode.ALPHANUMERIC = new _Mode(2, [
21143
+ 9,
21144
+ 11,
21145
+ 13
21146
+ ]);
21147
+ _Mode.BYTE = new _Mode(4, [
21148
+ 8,
21149
+ 16,
21150
+ 16
21151
+ ]);
21152
+ _Mode.KANJI = new _Mode(8, [
21153
+ 8,
21154
+ 10,
21155
+ 12
21156
+ ]);
21157
+ _Mode.ECI = new _Mode(7, [
21158
+ 0,
21159
+ 0,
21160
+ 0
21161
+ ]);
21162
+ QrSegment2.Mode = _Mode;
21163
+ })(qrcodegen2.QrSegment || (qrcodegen2.QrSegment = {}));
21164
+ })(qrcodegen || (qrcodegen = {}));
21165
+ var qrcodegen_default = qrcodegen;
21166
+ /**
21167
+ * @license qrcode.react
21168
+ * Copyright (c) Paul O'Shannessy
21169
+ * SPDX-License-Identifier: ISC
21170
+ */
21171
+ var ERROR_LEVEL_MAP = {
21172
+ L: qrcodegen_default.QrCode.Ecc.LOW,
21173
+ M: qrcodegen_default.QrCode.Ecc.MEDIUM,
21174
+ Q: qrcodegen_default.QrCode.Ecc.QUARTILE,
21175
+ H: qrcodegen_default.QrCode.Ecc.HIGH
21176
+ };
21177
+ var DEFAULT_SIZE$1 = 128;
21178
+ var DEFAULT_LEVEL = "L";
21179
+ var DEFAULT_BGCOLOR = "#FFFFFF";
21180
+ var DEFAULT_FGCOLOR = "#000000";
21181
+ var DEFAULT_INCLUDEMARGIN = false;
21182
+ var DEFAULT_MINVERSION = 1;
21183
+ var SPEC_MARGIN_SIZE = 4;
21184
+ var DEFAULT_MARGIN_SIZE = 0;
21185
+ var DEFAULT_IMG_SCALE = .1;
21186
+ function generatePath(modules, margin = 0) {
21187
+ const ops = [];
21188
+ modules.forEach(function(row, y) {
21189
+ let start = null;
21190
+ row.forEach(function(cell, x) {
21191
+ if (!cell && start !== null) {
21192
+ ops.push(`M${start + margin} ${y + margin}h${x - start}v1H${start + margin}z`);
21193
+ start = null;
21194
+ return;
21195
+ }
21196
+ if (x === row.length - 1) {
21197
+ if (!cell) return;
21198
+ if (start === null) ops.push(`M${x + margin},${y + margin} h1v1H${x + margin}z`);
21199
+ else ops.push(`M${start + margin},${y + margin} h${x + 1 - start}v1H${start + margin}z`);
21200
+ return;
21201
+ }
21202
+ if (cell && start === null) start = x;
21203
+ });
21204
+ });
21205
+ return ops.join("");
21206
+ }
21207
+ function excavateModules(modules, excavation) {
21208
+ return modules.slice().map((row, y) => {
21209
+ if (y < excavation.y || y >= excavation.y + excavation.h) return row;
21210
+ return row.map((cell, x) => {
21211
+ if (x < excavation.x || x >= excavation.x + excavation.w) return cell;
21212
+ return false;
21213
+ });
21214
+ });
21215
+ }
21216
+ function getImageSettings(cells, size, margin, imageSettings) {
21217
+ if (imageSettings == null) return null;
21218
+ const numCells = cells.length + margin * 2;
21219
+ const defaultSize = Math.floor(size * DEFAULT_IMG_SCALE);
21220
+ const scale = numCells / size;
21221
+ const w = (imageSettings.width || defaultSize) * scale;
21222
+ const h = (imageSettings.height || defaultSize) * scale;
21223
+ const x = imageSettings.x == null ? cells.length / 2 - w / 2 : imageSettings.x * scale;
21224
+ const y = imageSettings.y == null ? cells.length / 2 - h / 2 : imageSettings.y * scale;
21225
+ const opacity = imageSettings.opacity == null ? 1 : imageSettings.opacity;
21226
+ let excavation = null;
21227
+ if (imageSettings.excavate) {
21228
+ let floorX = Math.floor(x);
21229
+ let floorY = Math.floor(y);
21230
+ excavation = {
21231
+ x: floorX,
21232
+ y: floorY,
21233
+ w: Math.ceil(w + x - floorX),
21234
+ h: Math.ceil(h + y - floorY)
21235
+ };
21236
+ }
21237
+ const crossOrigin = imageSettings.crossOrigin;
21238
+ return {
21239
+ x,
21240
+ y,
21241
+ h,
21242
+ w,
21243
+ excavation,
21244
+ opacity,
21245
+ crossOrigin
21246
+ };
21247
+ }
21248
+ function getMarginSize(includeMargin, marginSize) {
21249
+ if (marginSize != null) return Math.max(Math.floor(marginSize), 0);
21250
+ return includeMargin ? SPEC_MARGIN_SIZE : DEFAULT_MARGIN_SIZE;
21251
+ }
21252
+ function useQRCode({ value, level, minVersion, includeMargin, marginSize, imageSettings, size, boostLevel }) {
21253
+ let qrcode = react.default.useMemo(() => {
21254
+ const segments = (Array.isArray(value) ? value : [value]).reduce((accum, v) => {
21255
+ accum.push(...qrcodegen_default.QrSegment.makeSegments(v));
21256
+ return accum;
21257
+ }, []);
21258
+ return qrcodegen_default.QrCode.encodeSegments(segments, ERROR_LEVEL_MAP[level], minVersion, void 0, void 0, boostLevel);
21259
+ }, [
21260
+ value,
21261
+ level,
21262
+ minVersion,
21263
+ boostLevel
21264
+ ]);
21265
+ const { cells, margin, numCells, calculatedImageSettings } = react.default.useMemo(() => {
21266
+ let cells2 = qrcode.getModules();
21267
+ const margin2 = getMarginSize(includeMargin, marginSize);
21268
+ return {
21269
+ cells: cells2,
21270
+ margin: margin2,
21271
+ numCells: cells2.length + margin2 * 2,
21272
+ calculatedImageSettings: getImageSettings(cells2, size, margin2, imageSettings)
21273
+ };
21274
+ }, [
21275
+ qrcode,
21276
+ size,
21277
+ imageSettings,
21278
+ includeMargin,
21279
+ marginSize
21280
+ ]);
21281
+ return {
21282
+ qrcode,
21283
+ margin,
21284
+ cells,
21285
+ numCells,
21286
+ calculatedImageSettings
21287
+ };
21288
+ }
21289
+ var SUPPORTS_PATH2D = function() {
21290
+ try {
21291
+ new Path2D().addPath(new Path2D());
21292
+ } catch (e) {
21293
+ return false;
21294
+ }
21295
+ return true;
21296
+ }();
21297
+ var QRCodeCanvas = react.default.forwardRef(function QRCodeCanvas2(props, forwardedRef) {
21298
+ const _a = props, { value, size = DEFAULT_SIZE$1, level = DEFAULT_LEVEL, bgColor = DEFAULT_BGCOLOR, fgColor = DEFAULT_FGCOLOR, includeMargin = DEFAULT_INCLUDEMARGIN, minVersion = DEFAULT_MINVERSION, boostLevel, marginSize, imageSettings } = _a;
21299
+ const _b = __objRest(_a, [
21300
+ "value",
21301
+ "size",
21302
+ "level",
21303
+ "bgColor",
21304
+ "fgColor",
21305
+ "includeMargin",
21306
+ "minVersion",
21307
+ "boostLevel",
21308
+ "marginSize",
21309
+ "imageSettings"
21310
+ ]), { style } = _b, otherProps = __objRest(_b, ["style"]);
21311
+ const imgSrc = imageSettings == null ? void 0 : imageSettings.src;
21312
+ const _canvas = react.default.useRef(null);
21313
+ const _image = react.default.useRef(null);
21314
+ const setCanvasRef = react.default.useCallback((node) => {
21315
+ _canvas.current = node;
21316
+ if (typeof forwardedRef === "function") forwardedRef(node);
21317
+ else if (forwardedRef) forwardedRef.current = node;
21318
+ }, [forwardedRef]);
21319
+ const [isImgLoaded, setIsImageLoaded] = react.default.useState(false);
21320
+ const { margin, cells, numCells, calculatedImageSettings } = useQRCode({
21321
+ value,
21322
+ level,
21323
+ minVersion,
21324
+ boostLevel,
21325
+ includeMargin,
21326
+ marginSize,
21327
+ imageSettings,
21328
+ size
21329
+ });
21330
+ react.default.useEffect(() => {
21331
+ if (_canvas.current != null) {
21332
+ const canvas = _canvas.current;
21333
+ const ctx = canvas.getContext("2d");
21334
+ if (!ctx) return;
21335
+ let cellsToDraw = cells;
21336
+ const image = _image.current;
21337
+ const haveImageToRender = calculatedImageSettings != null && image !== null && image.complete && image.naturalHeight !== 0 && image.naturalWidth !== 0;
21338
+ if (haveImageToRender) {
21339
+ if (calculatedImageSettings.excavation != null) cellsToDraw = excavateModules(cells, calculatedImageSettings.excavation);
21340
+ }
21341
+ const pixelRatio = window.devicePixelRatio || 1;
21342
+ canvas.height = canvas.width = size * pixelRatio;
21343
+ const scale = size / numCells * pixelRatio;
21344
+ ctx.scale(scale, scale);
21345
+ ctx.fillStyle = bgColor;
21346
+ ctx.fillRect(0, 0, numCells, numCells);
21347
+ ctx.fillStyle = fgColor;
21348
+ if (SUPPORTS_PATH2D) ctx.fill(new Path2D(generatePath(cellsToDraw, margin)));
21349
+ else cells.forEach(function(row, rdx) {
21350
+ row.forEach(function(cell, cdx) {
21351
+ if (cell) ctx.fillRect(cdx + margin, rdx + margin, 1, 1);
21352
+ });
21353
+ });
21354
+ if (calculatedImageSettings) ctx.globalAlpha = calculatedImageSettings.opacity;
21355
+ if (haveImageToRender) ctx.drawImage(image, calculatedImageSettings.x + margin, calculatedImageSettings.y + margin, calculatedImageSettings.w, calculatedImageSettings.h);
21356
+ }
21357
+ });
21358
+ react.default.useEffect(() => {
21359
+ setIsImageLoaded(false);
21360
+ }, [imgSrc]);
21361
+ const canvasStyle = __spreadValues({
21362
+ height: size,
21363
+ width: size
21364
+ }, style);
21365
+ let img = null;
21366
+ if (imgSrc != null) img = /* @__PURE__ */ react.default.createElement("img", {
21367
+ src: imgSrc,
21368
+ key: imgSrc,
21369
+ style: { display: "none" },
21370
+ onLoad: () => {
21371
+ setIsImageLoaded(true);
21372
+ },
21373
+ ref: _image,
21374
+ crossOrigin: calculatedImageSettings == null ? void 0 : calculatedImageSettings.crossOrigin
21375
+ });
21376
+ return /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement("canvas", __spreadValues({
21377
+ style: canvasStyle,
21378
+ height: size,
21379
+ width: size,
21380
+ ref: setCanvasRef,
21381
+ role: "img"
21382
+ }, otherProps)), img);
21383
+ });
21384
+ QRCodeCanvas.displayName = "QRCodeCanvas";
21385
+ var QRCodeSVG = react.default.forwardRef(function QRCodeSVG2(props, forwardedRef) {
21386
+ const _a = props, { value, size = DEFAULT_SIZE$1, level = DEFAULT_LEVEL, bgColor = DEFAULT_BGCOLOR, fgColor = DEFAULT_FGCOLOR, includeMargin = DEFAULT_INCLUDEMARGIN, minVersion = DEFAULT_MINVERSION, boostLevel, title, marginSize, imageSettings } = _a, otherProps = __objRest(_a, [
21387
+ "value",
21388
+ "size",
21389
+ "level",
21390
+ "bgColor",
21391
+ "fgColor",
21392
+ "includeMargin",
21393
+ "minVersion",
21394
+ "boostLevel",
21395
+ "title",
21396
+ "marginSize",
21397
+ "imageSettings"
21398
+ ]);
21399
+ const { margin, cells, numCells, calculatedImageSettings } = useQRCode({
21400
+ value,
21401
+ level,
21402
+ minVersion,
21403
+ boostLevel,
21404
+ includeMargin,
21405
+ marginSize,
21406
+ imageSettings,
21407
+ size
21408
+ });
21409
+ let cellsToDraw = cells;
21410
+ let image = null;
21411
+ if (imageSettings != null && calculatedImageSettings != null) {
21412
+ if (calculatedImageSettings.excavation != null) cellsToDraw = excavateModules(cells, calculatedImageSettings.excavation);
21413
+ image = /* @__PURE__ */ react.default.createElement("image", {
21414
+ href: imageSettings.src,
21415
+ height: calculatedImageSettings.h,
21416
+ width: calculatedImageSettings.w,
21417
+ x: calculatedImageSettings.x + margin,
21418
+ y: calculatedImageSettings.y + margin,
21419
+ preserveAspectRatio: "none",
21420
+ opacity: calculatedImageSettings.opacity,
21421
+ crossOrigin: calculatedImageSettings.crossOrigin
21422
+ });
21423
+ }
21424
+ const fgPath = generatePath(cellsToDraw, margin);
21425
+ return /* @__PURE__ */ react.default.createElement("svg", __spreadValues({
21426
+ height: size,
21427
+ width: size,
21428
+ viewBox: `0 0 ${numCells} ${numCells}`,
21429
+ ref: forwardedRef,
21430
+ role: "img"
21431
+ }, otherProps), !!title && /* @__PURE__ */ react.default.createElement("title", null, title), /* @__PURE__ */ react.default.createElement("path", {
21432
+ fill: bgColor,
21433
+ d: `M0,0 h${numCells}v${numCells}H0z`,
21434
+ shapeRendering: "crispEdges"
21435
+ }), /* @__PURE__ */ react.default.createElement("path", {
21436
+ fill: fgColor,
21437
+ d: fgPath,
21438
+ shapeRendering: "crispEdges"
21439
+ }), image);
21440
+ });
21441
+ QRCodeSVG.displayName = "QRCodeSVG";
21442
+ //#endregion
21443
+ //#region src/composites/qr-code.tsx
21444
+ var DEFAULT_SIZE = 192;
21445
+ function QrCode({ value, size = DEFAULT_SIZE, className, alt }) {
21446
+ const trimmed = value.trim();
21447
+ if (trimmed.length === 0) return null;
21448
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21449
+ className: cn("inline-flex rounded-md bg-white p-2", className),
21450
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QRCodeSVG, {
21451
+ value: trimmed,
21452
+ size,
21453
+ marginSize: 1,
21454
+ title: alt ?? "QR code"
21455
+ })
21456
+ });
21457
+ }
21458
+ //#endregion
21459
+ //#region src/composites/copy-button.tsx
21460
+ /**
21461
+ * `CopyButton` — a compact button that copies a string `value` to the
21462
+ * clipboard via `navigator.clipboard.writeText`, showing a brief
21463
+ * "copied" check state. Addon-agnostic; used wherever a secret / URL
21464
+ * needs a one-click copy affordance (export setup panels, etc.).
21465
+ */
21466
+ var COPIED_RESET_MS = 2e3;
21467
+ function CopyButton({ value, label, className, disabled }) {
21468
+ const [copied, setCopied] = (0, react$1.useState)(false);
21469
+ const handleCopy = (0, react$1.useCallback)(() => {
21470
+ if (!value) return;
21471
+ navigator.clipboard.writeText(value).then(() => {
21472
+ setCopied(true);
21473
+ setTimeout(() => setCopied(false), COPIED_RESET_MS);
21474
+ });
21475
+ }, [value]);
21476
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
21477
+ size: "sm",
21478
+ variant: "ghost",
21479
+ type: "button",
21480
+ disabled: disabled || value.length === 0,
21481
+ onClick: handleCopy,
21482
+ className: cn(className),
21483
+ "aria-label": copied ? "Copied" : `Copy ${label ?? "value"}`,
21484
+ children: [copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Check, { className: "h-3.5 w-3.5 text-success" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Copy, { className: "h-3.5 w-3.5" }), label ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
21485
+ className: "ml-1",
21486
+ children: copied ? "Copied" : label
21487
+ }) : null]
21488
+ });
21489
+ }
21490
+ //#endregion
21491
+ //#region src/composites/device-export-panel.tsx
21492
+ /**
21493
+ * DeviceExportPanel — generic, addon-agnostic surface for the
21494
+ * `device-export` capability.
21495
+ *
21496
+ * Renders the COMMON device-export surface for a single export addon
21497
+ * (HomeAssistant via MQTT, HomeKit/HAP, Alexa Smart Home, …):
21498
+ *
21499
+ * - a link-state status badge + exposed-device count from `getStatus`,
21500
+ * - the exposed-devices table from `listExposedDevices` (device name,
21501
+ * status, stream preference) with a per-row unexpose action
21502
+ * (`unexposeDevice`),
21503
+ * - an empty state directing the operator to the device-details page.
21504
+ *
21505
+ * This composite is the reusable replacement for the per-addon
21506
+ * Module-Federation overview tables that each export addon used to
21507
+ * ship. It is driven entirely by the `device-export` cap — there are no
21508
+ * Alexa / HAP / MQTT specifics here. Mount it next to an export addon's
21509
+ * standard settings form (e.g. in the addon-settings modal).
21510
+ *
21511
+ * Routing note: `device-export` is a collection cap; the codegen'd
21512
+ * router resolves `{ nodeId }` to the first registered provider. Export
21513
+ * addons are all `hub-only`, so the panel queries `nodeId: 'hub'`. When
21514
+ * multiple device-export addons are co-installed the cap-router today
21515
+ * resolves to the first provider only (per-provider routing is a
21516
+ * separate follow-up) — identical behaviour to the pages it replaces.
21517
+ */
21518
+ var ExposedDeviceArraySchema = zod.z.array(_camstack_types.ExposedDeviceSchema);
21519
+ var STATUS_POLL_INTERVAL_MS = 1e4;
21520
+ function statusVariant(state) {
21521
+ if (state === "linked") return "success";
21522
+ if (state === "error") return "danger";
21523
+ return "warning";
21524
+ }
21525
+ function capitaliseLinkState(state) {
21526
+ if (state === "linked") return "Linked";
21527
+ if (state === "unlinked") return "Unlinked";
21528
+ if (state === "error") return "Error";
21529
+ return state;
21530
+ }
21531
+ /**
21532
+ * A single label/value row in the Setup section. `secret` rows mask the
21533
+ * value behind a reveal toggle; every row gets a copy button.
21534
+ */
21535
+ function SetupFieldRow({ field }) {
21536
+ const [revealed, setRevealed] = (0, react$1.useState)(false);
21537
+ const isSecret = field.secret === true;
21538
+ const displayValue = isSecret && !revealed ? "•".repeat(Math.min(field.value.length, 24)) : field.value;
21539
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21540
+ className: "flex items-center gap-2 py-1.5",
21541
+ children: [
21542
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
21543
+ className: "text-[11px] text-foreground-subtle w-32 shrink-0",
21544
+ children: field.label
21545
+ }),
21546
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
21547
+ className: "flex-1 min-w-0 truncate font-mono text-xs text-foreground",
21548
+ children: displayValue || "—"
21549
+ }),
21550
+ isSecret && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
21551
+ size: "sm",
21552
+ variant: "ghost",
21553
+ type: "button",
21554
+ "aria-label": revealed ? "Hide value" : "Reveal value",
21555
+ onClick: () => setRevealed((v) => !v),
21556
+ children: revealed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EyeOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Eye, { className: "h-3.5 w-3.5" })
21557
+ }),
21558
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyButton, {
21559
+ value: field.value,
21560
+ label: field.label
21561
+ })
21562
+ ]
21563
+ });
21564
+ }
21565
+ /**
21566
+ * Generic "Setup" section — pairing QR + copyable label/value rows +
21567
+ * operator note. Driven entirely by the cap's `setup` block; renders
21568
+ * nothing addon-specific.
21569
+ */
21570
+ function SetupSection({ setup }) {
21571
+ const fields = setup.fields ?? [];
21572
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21573
+ className: "border-b border-border bg-surface-hover/10",
21574
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21575
+ className: "flex items-center gap-2 px-4 py-2 border-b border-border",
21576
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(QrCode$1, { className: "h-3.5 w-3.5 text-foreground-subtle shrink-0" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
21577
+ className: "text-[11px] font-semibold text-foreground-subtle uppercase tracking-wide",
21578
+ children: "Setup"
21579
+ })]
21580
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21581
+ className: "flex flex-col gap-3 p-4 sm:flex-row sm:items-start",
21582
+ children: [setup.qr && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21583
+ className: "shrink-0",
21584
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QrCode, {
21585
+ value: setup.qr,
21586
+ alt: "Pairing QR code"
21587
+ })
21588
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21589
+ className: "flex-1 min-w-0",
21590
+ children: [setup.note && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
21591
+ className: "text-xs text-foreground-muted whitespace-pre-line mb-2",
21592
+ children: setup.note
21593
+ }), fields.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21594
+ className: "divide-y divide-border-subtle",
21595
+ children: fields.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SetupFieldRow, { field }, field.label))
21596
+ })]
21597
+ })]
21598
+ })]
21599
+ });
21600
+ }
21601
+ /**
21602
+ * Generic device-export panel. Addon-agnostic — only the `device-export`
21603
+ * cap drives it.
21604
+ */
21605
+ function DeviceExportPanel({ addonId, onOpenDevice }) {
21606
+ const queryClient = (0, _tanstack_react_query.useQueryClient)();
21607
+ const statusQuery = useDeviceExportGetStatus({ nodeId: "hub" }, {
21608
+ refetchInterval: STATUS_POLL_INTERVAL_MS,
21609
+ retry: false
21610
+ });
21611
+ const exposedQuery = useDeviceExportListExposedDevices({ nodeId: "hub" }, {
21612
+ refetchInterval: STATUS_POLL_INTERVAL_MS,
21613
+ retry: false
21614
+ });
21615
+ const unexposeMutation = useDeviceExportUnexposeDevice({ onSuccess: () => {
21616
+ queryClient.invalidateQueries({ queryKey: [["deviceExport"]] });
21617
+ } });
21618
+ const status = (0, react$1.useMemo)(() => {
21619
+ const parsed = _camstack_types.DeviceExportStatusSchema.safeParse(statusQuery.data);
21620
+ return parsed.success ? parsed.data : null;
21621
+ }, [statusQuery.data]);
21622
+ const exposed = (0, react$1.useMemo)(() => {
21623
+ const parsed = ExposedDeviceArraySchema.safeParse(exposedQuery.data);
21624
+ return parsed.success ? parsed.data : [];
21625
+ }, [exposedQuery.data]);
21626
+ const linkState = status?.linkState ?? "unlinked";
21627
+ const rows = (0, react$1.useMemo)(() => exposed.map((entry) => ({
21628
+ deviceId: entry.deviceId,
21629
+ displayName: entry.exposedAs ?? `Device ${entry.deviceId}`,
21630
+ streamPreference: "auto",
21631
+ linkState
21632
+ })), [exposed, linkState]);
21633
+ const loading = statusQuery.isLoading || exposedQuery.isLoading;
21634
+ const exposedCount = status?.exposedDeviceCount ?? rows.length;
21635
+ const columns = (0, react$1.useMemo)(() => [
21636
+ {
21637
+ key: "device",
21638
+ header: "Device",
21639
+ render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21640
+ className: "flex flex-col",
21641
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
21642
+ className: "text-foreground font-medium",
21643
+ children: row.displayName
21644
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
21645
+ className: "text-foreground-subtle text-xs font-mono",
21646
+ children: ["#", row.deviceId]
21647
+ })]
21648
+ })
21649
+ },
21650
+ {
21651
+ key: "status",
21652
+ header: "Status",
21653
+ render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
21654
+ variant: statusVariant(row.linkState),
21655
+ children: capitaliseLinkState(row.linkState)
21656
+ })
21657
+ },
21658
+ {
21659
+ key: "stream",
21660
+ header: "Stream",
21661
+ render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
21662
+ className: "text-xs text-foreground-subtle font-mono",
21663
+ children: row.streamPreference === "auto" ? "Auto" : row.streamPreference
21664
+ })
21665
+ },
21666
+ {
21667
+ key: "actions",
21668
+ header: "",
21669
+ align: "right",
21670
+ render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21671
+ className: "flex items-center justify-end gap-2",
21672
+ children: [onOpenDevice && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
21673
+ size: "sm",
21674
+ variant: "ghost",
21675
+ onClick: () => onOpenDevice(row.deviceId),
21676
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExternalLink, { className: "h-3.5 w-3.5 mr-1" }), "Open"]
21677
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
21678
+ size: "sm",
21679
+ variant: "ghost",
21680
+ disabled: unexposeMutation.isPending,
21681
+ onClick: () => unexposeMutation.mutate({
21682
+ deviceId: row.deviceId,
21683
+ nodeId: "hub"
21684
+ }),
21685
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Unlink2, { className: "h-3.5 w-3.5 mr-1" }), "Unexpose"]
21686
+ })]
21687
+ })
21688
+ }
21689
+ ], [onOpenDevice, unexposeMutation]);
21690
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21691
+ className: "rounded-lg border border-border bg-surface overflow-hidden",
21692
+ children: [
21693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21694
+ className: "flex items-center justify-between gap-3 px-4 py-2.5 border-b border-border bg-surface-hover/20",
21695
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
21696
+ className: "flex items-center gap-2 min-w-0",
21697
+ children: [
21698
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Share2, { className: "h-3.5 w-3.5 text-foreground-subtle shrink-0" }),
21699
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
21700
+ className: "text-[11px] font-semibold text-foreground-subtle uppercase tracking-wide",
21701
+ children: "Exported devices"
21702
+ }),
21703
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
21704
+ variant: statusVariant(linkState),
21705
+ children: capitaliseLinkState(linkState)
21706
+ }),
21707
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
21708
+ className: "text-[11px] text-foreground-subtle",
21709
+ children: [exposedCount, " exposed"]
21710
+ })
21711
+ ]
21712
+ }), loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin text-foreground-subtle" })]
21713
+ }),
21714
+ status?.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21715
+ className: "px-4 py-3 border-b border-border",
21716
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: status.error })
21717
+ }),
21718
+ status?.setup && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SetupSection, { setup: status.setup }),
21719
+ rows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, {
21720
+ icon: Share2,
21721
+ title: "No devices exposed",
21722
+ description: `Expose a camera to "${addonId}" from its device-details page to surface it in the connected ecosystem.`
21723
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21724
+ className: "p-3",
21725
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
21726
+ columns,
21727
+ rows,
21728
+ rowKey: (row) => row.deviceId
21729
+ })
21730
+ })
21731
+ ]
21732
+ });
21733
+ }
21734
+ //#endregion
20103
21735
  //#region src/composites/audio-waveform.tsx
20104
21736
  /**
20105
21737
  * Canvas-based audio waveform visualization.
@@ -20107,9 +21739,9 @@ function StreamBrokerSelector({ deviceId, value, onChange, disabled, label, clas
20107
21739
  * Downsamples to pixel resolution for performance.
20108
21740
  */
20109
21741
  function AudioWaveform({ samples, sampleRate = 16e3, height = 96, className = "", color = "#3b82f6", bgColor = "transparent" }) {
20110
- const canvasRef = (0, react.useRef)(null);
20111
- const containerRef = (0, react.useRef)(null);
20112
- const draw = (0, react.useCallback)(() => {
21742
+ const canvasRef = (0, react$1.useRef)(null);
21743
+ const containerRef = (0, react$1.useRef)(null);
21744
+ const draw = (0, react$1.useCallback)(() => {
20113
21745
  const canvas = canvasRef.current;
20114
21746
  const container = containerRef.current;
20115
21747
  if (!canvas || !container || !samples || samples.length === 0) return;
@@ -20161,10 +21793,10 @@ function AudioWaveform({ samples, sampleRate = 16e3, height = 96, className = ""
20161
21793
  color,
20162
21794
  bgColor
20163
21795
  ]);
20164
- (0, react.useEffect)(() => {
21796
+ (0, react$1.useEffect)(() => {
20165
21797
  draw();
20166
21798
  }, [draw]);
20167
- (0, react.useEffect)(() => {
21799
+ (0, react$1.useEffect)(() => {
20168
21800
  const observer = new ResizeObserver(() => draw());
20169
21801
  const el = containerRef.current;
20170
21802
  if (el) observer.observe(el);
@@ -20203,10 +21835,10 @@ function AudioWaveform({ samples, sampleRate = 16e3, height = 96, className = ""
20203
21835
  * (each chunk, ~0.5s, produces one sample via `frame.level.dbfs`).
20204
21836
  */
20205
21837
  function AudioLevelWaveform({ currentDbfs, durationSec = 30, maxSamples = 120, height = 64, className = "", color = "#10b981", clipColor = "#ef4444", clipThreshold = -6, minDbfs = -96 }) {
20206
- const canvasRef = (0, react.useRef)(null);
20207
- const containerRef = (0, react.useRef)(null);
20208
- const [samples, setSamples] = (0, react.useState)([]);
20209
- (0, react.useEffect)(() => {
21838
+ const canvasRef = (0, react$1.useRef)(null);
21839
+ const containerRef = (0, react$1.useRef)(null);
21840
+ const [samples, setSamples] = (0, react$1.useState)([]);
21841
+ (0, react$1.useEffect)(() => {
20210
21842
  if (currentDbfs === null) return;
20211
21843
  setSamples((prev) => {
20212
21844
  const next = [...prev, {
@@ -20216,7 +21848,7 @@ function AudioLevelWaveform({ currentDbfs, durationSec = 30, maxSamples = 120, h
20216
21848
  return next.length > maxSamples ? next.slice(-maxSamples) : next;
20217
21849
  });
20218
21850
  }, [currentDbfs, maxSamples]);
20219
- const draw = (0, react.useCallback)(() => {
21851
+ const draw = (0, react$1.useCallback)(() => {
20220
21852
  const canvas = canvasRef.current;
20221
21853
  const container = containerRef.current;
20222
21854
  if (!canvas || !container) return;
@@ -20269,10 +21901,10 @@ function AudioLevelWaveform({ currentDbfs, durationSec = 30, maxSamples = 120, h
20269
21901
  clipThreshold,
20270
21902
  minDbfs
20271
21903
  ]);
20272
- (0, react.useEffect)(() => {
21904
+ (0, react$1.useEffect)(() => {
20273
21905
  draw();
20274
21906
  }, [draw]);
20275
- (0, react.useEffect)(() => {
21907
+ (0, react$1.useEffect)(() => {
20276
21908
  const observer = new ResizeObserver(() => draw());
20277
21909
  const el = containerRef.current;
20278
21910
  if (el) observer.observe(el);
@@ -20394,7 +22026,7 @@ function AudioClassificationList({ classifications, processing = false, inferenc
20394
22026
  * Expandable log box showing the raw JSON response from a pipeline run.
20395
22027
  */
20396
22028
  function ResponseLog({ data, label = "Response", className = "" }) {
20397
- const [expanded, setExpanded] = (0, react.useState)(false);
22029
+ const [expanded, setExpanded] = (0, react$1.useState)(false);
20398
22030
  if (!data) return null;
20399
22031
  const json = JSON.stringify(data, null, 2);
20400
22032
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -20466,17 +22098,17 @@ function PhaseIcon({ phase, ...props }) {
20466
22098
  * keeping idle subscriptions alive.
20467
22099
  */
20468
22100
  function useLiveBuffer(max) {
20469
- const [entries, setEntries] = (0, react.useState)([]);
20470
- const append = (0, react.useCallback)((entry) => {
22101
+ const [entries, setEntries] = (0, react$1.useState)([]);
22102
+ const append = (0, react$1.useCallback)((entry) => {
20471
22103
  setEntries((prev) => {
20472
22104
  const next = [...prev, entry];
20473
22105
  return next.length > max ? next.slice(-max) : next;
20474
22106
  });
20475
22107
  }, [max]);
20476
- const reset = (0, react.useCallback)(() => {
22108
+ const reset = (0, react$1.useCallback)(() => {
20477
22109
  setEntries([]);
20478
22110
  }, []);
20479
- return (0, react.useMemo)(() => ({
22111
+ return (0, react$1.useMemo)(() => ({
20480
22112
  entries,
20481
22113
  append,
20482
22114
  reset
@@ -20550,15 +22182,15 @@ function passesLevel(logLevel, filterLevel) {
20550
22182
  return (LEVEL_SEVERITY[logLevel] ?? 0) >= (LEVEL_SEVERITY[filterLevel] ?? 0);
20551
22183
  }
20552
22184
  function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: propsDeviceId, integrationId: propsIntegrationId, requestId: propsRequestId, level: initialLevel, maxHeight = "max-h-96", showScope = false, showFilters = true, limit = 100, liveBuffer: externalBuffer, onClose, className }) {
20553
- const [localAddonId, setLocalAddonId] = (0, react.useState)("");
20554
- const [localDeviceId, setLocalDeviceId] = (0, react.useState)("");
20555
- const [levelFilter, setLevelFilter] = (0, react.useState)(initialLevel);
22185
+ const [localAddonId, setLocalAddonId] = (0, react$1.useState)("");
22186
+ const [localDeviceId, setLocalDeviceId] = (0, react$1.useState)("");
22187
+ const [levelFilter, setLevelFilter] = (0, react$1.useState)(initialLevel);
20556
22188
  const agentId = propsAgentId;
20557
22189
  const addonId = propsAddonId ?? (localAddonId || void 0);
20558
22190
  const deviceId = propsDeviceId ?? (localDeviceId ? Number(localDeviceId) : void 0);
20559
22191
  const integrationId = propsIntegrationId;
20560
22192
  const requestId = propsRequestId;
20561
- const tags = (0, react.useMemo)(() => {
22193
+ const tags = (0, react$1.useMemo)(() => {
20562
22194
  const t = {};
20563
22195
  if (agentId) t.agentId = agentId;
20564
22196
  if (addonId) t.addonId = addonId;
@@ -20576,15 +22208,15 @@ function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: pro
20576
22208
  const fallbackBuffer = useLiveBuffer(MAX_LIVE_ENTRIES$2);
20577
22209
  const buffer = externalBuffer ?? fallbackBuffer;
20578
22210
  const liveLogs = buffer.entries;
20579
- const [clearedAt, setClearedAt] = (0, react.useState)(0);
20580
- const [autoScroll, setAutoScroll] = (0, react.useState)(false);
20581
- const [copied, setCopied] = (0, react.useState)(false);
20582
- const [expandedRows, setExpandedRows] = (0, react.useState)(/* @__PURE__ */ new Set());
20583
- const [searchText, setSearchText] = (0, react.useState)("");
20584
- const scrollRef = (0, react.useRef)(null);
22211
+ const [clearedAt, setClearedAt] = (0, react$1.useState)(0);
22212
+ const [autoScroll, setAutoScroll] = (0, react$1.useState)(false);
22213
+ const [copied, setCopied] = (0, react$1.useState)(false);
22214
+ const [expandedRows, setExpandedRows] = (0, react$1.useState)(/* @__PURE__ */ new Set());
22215
+ const [searchText, setSearchText] = (0, react$1.useState)("");
22216
+ const scrollRef = (0, react$1.useRef)(null);
20585
22217
  const scopeKey = `${agentId ?? ""}:${addonId ?? ""}:${String(deviceId ?? "")}:${integrationId ?? ""}:${requestId ?? ""}`;
20586
- const prevScopeRef = (0, react.useRef)(scopeKey);
20587
- (0, react.useEffect)(() => {
22218
+ const prevScopeRef = (0, react$1.useRef)(scopeKey);
22219
+ (0, react$1.useEffect)(() => {
20588
22220
  if (prevScopeRef.current !== scopeKey) {
20589
22221
  prevScopeRef.current = scopeKey;
20590
22222
  buffer.reset();
@@ -20599,8 +22231,8 @@ function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: pro
20599
22231
  trpc.logs.subscribe.useSubscription({ ...tags ? { tags } : {} }, { onData: (entry) => {
20600
22232
  buffer.append(entry);
20601
22233
  } });
20602
- const prevLiveCountRef = (0, react.useRef)(liveLogs.length);
20603
- (0, react.useEffect)(() => {
22234
+ const prevLiveCountRef = (0, react$1.useRef)(liveLogs.length);
22235
+ (0, react$1.useEffect)(() => {
20604
22236
  const el = scrollRef.current;
20605
22237
  if (!el) {
20606
22238
  prevLiveCountRef.current = liveLogs.length;
@@ -20616,7 +22248,7 @@ function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: pro
20616
22248
  el.scrollTop += rowHeight * (liveLogs.length - prevCount);
20617
22249
  }
20618
22250
  }, [liveLogs.length, autoScroll]);
20619
- const allLogs = (0, react.useMemo)(() => {
22251
+ const allLogs = (0, react$1.useMemo)(() => {
20620
22252
  const initial = (initialLogs ?? []).map((log) => ({
20621
22253
  timestamp: log.timestamp,
20622
22254
  level: log.level,
@@ -20661,7 +22293,7 @@ function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: pro
20661
22293
  clearedAt,
20662
22294
  searchText
20663
22295
  ]);
20664
- const handleCopyAll = (0, react.useCallback)(() => {
22296
+ const handleCopyAll = (0, react$1.useCallback)(() => {
20665
22297
  const lines = allLogs.map((log) => {
20666
22298
  const time = new Date(log.timestamp).toLocaleTimeString();
20667
22299
  const tagsStr = log.tags ? " " + Object.entries(log.tags).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join(" ") : "";
@@ -20673,7 +22305,7 @@ function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: pro
20673
22305
  });
20674
22306
  }, [allLogs]);
20675
22307
  const clearMutation = trpc.logs.clear.useMutation();
20676
- const handleClear = (0, react.useCallback)(() => {
22308
+ const handleClear = (0, react$1.useCallback)(() => {
20677
22309
  setClearedAt(Date.now());
20678
22310
  buffer.reset();
20679
22311
  clearMutation.mutate({ ...tags ? { tags } : {} });
@@ -20682,7 +22314,7 @@ function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: pro
20682
22314
  clearMutation,
20683
22315
  tags
20684
22316
  ]);
20685
- const toggleRow = (0, react.useCallback)((rowKey) => {
22317
+ const toggleRow = (0, react$1.useCallback)((rowKey) => {
20686
22318
  setExpandedRows((prev) => {
20687
22319
  const next = new Set(prev);
20688
22320
  if (next.has(rowKey)) next.delete(rowKey);
@@ -20690,8 +22322,8 @@ function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: pro
20690
22322
  return next;
20691
22323
  });
20692
22324
  }, []);
20693
- const [copiedRowKey, setCopiedRowKey] = (0, react.useState)(null);
20694
- const copyOne = (0, react.useCallback)((log, key) => {
22325
+ const [copiedRowKey, setCopiedRowKey] = (0, react$1.useState)(null);
22326
+ const copyOne = (0, react$1.useCallback)((log, key) => {
20695
22327
  const time = new Date(log.timestamp).toISOString();
20696
22328
  const tagsStr = log.tags ? " " + Object.entries(log.tags).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join(" ") : "";
20697
22329
  const metaStr = log.meta && Object.keys(log.meta).length > 0 ? ` meta=${JSON.stringify(log.meta)}` : "";
@@ -20701,7 +22333,7 @@ function LogStream({ agentId: propsAgentId, addonId: propsAddonId, deviceId: pro
20701
22333
  setTimeout(() => setCopiedRowKey((prev) => prev === key ? null : prev), 1200);
20702
22334
  });
20703
22335
  }, []);
20704
- const rowKey = (0, react.useCallback)((log) => `${log.timestamp}|${log.level}|${log.scope ?? ""}|${log.message}`, []);
22336
+ const rowKey = (0, react$1.useCallback)((log) => `${log.timestamp}|${log.level}|${log.scope ?? ""}|${log.message}`, []);
20705
22337
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
20706
22338
  className: cn("h-full min-h-0 flex flex-col", className),
20707
22339
  onClick: (e) => e.stopPropagation(),
@@ -21266,11 +22898,11 @@ function hasContent(entry) {
21266
22898
  }
21267
22899
  var MAX_LIVE_ENTRIES$1 = 300;
21268
22900
  function EventStream({ agentId, addonId, deviceId, defaultCategories, categories: legacyCategories, category: propsCategory, maxHeight = "max-h-96", limit = 50, showCategoryFilter = true, showFilters: _showFilters = false, liveBuffer: externalBuffer, onClose, className }) {
21269
- const defaultsArray = (0, react.useMemo)(() => defaultCategories ?? legacyCategories ?? DEFAULT_EVENT_CATEGORIES, [defaultCategories, legacyCategories]);
21270
- const defaultsKey = (0, react.useMemo)(() => [...defaultsArray].sort().join(","), [defaultsArray]);
21271
- const [activeCategories, setActiveCategories] = (0, react.useState)(() => new Set(defaultsArray));
21272
- const prevDefaultsKey = (0, react.useRef)(defaultsKey);
21273
- (0, react.useEffect)(() => {
22901
+ const defaultsArray = (0, react$1.useMemo)(() => defaultCategories ?? legacyCategories ?? DEFAULT_EVENT_CATEGORIES, [defaultCategories, legacyCategories]);
22902
+ const defaultsKey = (0, react$1.useMemo)(() => [...defaultsArray].sort().join(","), [defaultsArray]);
22903
+ const [activeCategories, setActiveCategories] = (0, react$1.useState)(() => new Set(defaultsArray));
22904
+ const prevDefaultsKey = (0, react$1.useRef)(defaultsKey);
22905
+ (0, react$1.useEffect)(() => {
21274
22906
  if (prevDefaultsKey.current !== defaultsKey) {
21275
22907
  prevDefaultsKey.current = defaultsKey;
21276
22908
  setActiveCategories(new Set(defaultsArray));
@@ -21279,17 +22911,17 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21279
22911
  const fallbackBuffer = useLiveBuffer(MAX_LIVE_ENTRIES$1);
21280
22912
  const buffer = externalBuffer ?? fallbackBuffer;
21281
22913
  const liveEvents = buffer.entries;
21282
- const [autoScroll, setAutoScroll] = (0, react.useState)(true);
21283
- const [expandedRows, setExpandedRows] = (0, react.useState)(/* @__PURE__ */ new Set());
21284
- const [searchText, setSearchText] = (0, react.useState)("");
21285
- const [filterOpen, setFilterOpen] = (0, react.useState)(false);
21286
- const [categorySearch, setCategorySearch] = (0, react.useState)("");
21287
- const [clearedAt, setClearedAt] = (0, react.useState)(0);
21288
- const scrollRef = (0, react.useRef)(null);
21289
- const filterRootRef = (0, react.useRef)(null);
22914
+ const [autoScroll, setAutoScroll] = (0, react$1.useState)(true);
22915
+ const [expandedRows, setExpandedRows] = (0, react$1.useState)(/* @__PURE__ */ new Set());
22916
+ const [searchText, setSearchText] = (0, react$1.useState)("");
22917
+ const [filterOpen, setFilterOpen] = (0, react$1.useState)(false);
22918
+ const [categorySearch, setCategorySearch] = (0, react$1.useState)("");
22919
+ const [clearedAt, setClearedAt] = (0, react$1.useState)(0);
22920
+ const scrollRef = (0, react$1.useRef)(null);
22921
+ const filterRootRef = (0, react$1.useRef)(null);
21290
22922
  const scopeKey = `${agentId ?? ""}:${addonId ?? ""}:${String(deviceId ?? "")}:${propsCategory ?? ""}`;
21291
- const prevScopeRef = (0, react.useRef)(scopeKey);
21292
- (0, react.useEffect)(() => {
22923
+ const prevScopeRef = (0, react$1.useRef)(scopeKey);
22924
+ (0, react$1.useEffect)(() => {
21293
22925
  if (prevScopeRef.current !== scopeKey) {
21294
22926
  prevScopeRef.current = scopeKey;
21295
22927
  buffer.reset();
@@ -21297,7 +22929,7 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21297
22929
  setClearedAt(0);
21298
22930
  }
21299
22931
  }, [scopeKey, buffer]);
21300
- (0, react.useEffect)(() => {
22932
+ (0, react$1.useEffect)(() => {
21301
22933
  if (!filterOpen) return;
21302
22934
  const onDocClick = (e) => {
21303
22935
  const root = filterRootRef.current;
@@ -21308,7 +22940,7 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21308
22940
  document.removeEventListener("mousedown", onDocClick);
21309
22941
  };
21310
22942
  }, [filterOpen]);
21311
- const scopeInput = (0, react.useMemo)(() => {
22943
+ const scopeInput = (0, react$1.useMemo)(() => {
21312
22944
  const s = {};
21313
22945
  if (agentId) s.agentId = agentId;
21314
22946
  if (addonId) s.addonId = addonId;
@@ -21321,8 +22953,8 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21321
22953
  deviceId,
21322
22954
  propsCategory
21323
22955
  ]);
21324
- const activeArray = (0, react.useMemo)(() => [...activeCategories].sort(), [activeCategories]);
21325
- const getRecentInput = (0, react.useMemo)(() => {
22956
+ const activeArray = (0, react$1.useMemo)(() => [...activeCategories].sort(), [activeCategories]);
22957
+ const getRecentInput = (0, react$1.useMemo)(() => {
21326
22958
  const s = {
21327
22959
  ...scopeInput,
21328
22960
  limit
@@ -21332,12 +22964,12 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21332
22964
  }, [
21333
22965
  scopeInput,
21334
22966
  limit,
21335
- (0, react.useMemo)(() => activeArray.join(","), [activeArray]),
22967
+ (0, react$1.useMemo)(() => activeArray.join(","), [activeArray]),
21336
22968
  activeArray
21337
22969
  ]);
21338
22970
  const { data: initialEvents, isLoading } = trpc.systemEvents.getRecent.useQuery(getRecentInput, { staleTime: 3e4 });
21339
- const activeCategoriesRef = (0, react.useRef)(activeCategories);
21340
- (0, react.useEffect)(() => {
22971
+ const activeCategoriesRef = (0, react$1.useRef)(activeCategories);
22972
+ (0, react$1.useEffect)(() => {
21341
22973
  activeCategoriesRef.current = activeCategories;
21342
22974
  }, [activeCategories]);
21343
22975
  const subInput = scopeInput;
@@ -21348,8 +22980,8 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21348
22980
  if (!activeCategoriesRef.current.has(entry.category)) return;
21349
22981
  buffer.append(entry);
21350
22982
  } });
21351
- const prevLiveCountRef = (0, react.useRef)(liveEvents.length);
21352
- (0, react.useEffect)(() => {
22983
+ const prevLiveCountRef = (0, react$1.useRef)(liveEvents.length);
22984
+ (0, react$1.useEffect)(() => {
21353
22985
  const el = scrollRef.current;
21354
22986
  if (!el) {
21355
22987
  prevLiveCountRef.current = liveEvents.length;
@@ -21365,7 +22997,7 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21365
22997
  el.scrollTop += rowHeight * (liveEvents.length - prevCount);
21366
22998
  }
21367
22999
  }, [liveEvents.length, autoScroll]);
21368
- const allEvents = (0, react.useMemo)(() => {
23000
+ const allEvents = (0, react$1.useMemo)(() => {
21369
23001
  const byId = /* @__PURE__ */ new Map();
21370
23002
  for (const e of initialEvents ?? []) byId.set(e.id, e);
21371
23003
  for (const e of liveEvents) byId.set(e.id, e);
@@ -21394,7 +23026,7 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21394
23026
  searchText,
21395
23027
  clearedAt
21396
23028
  ]);
21397
- const toggleRow = (0, react.useCallback)((id) => {
23029
+ const toggleRow = (0, react$1.useCallback)((id) => {
21398
23030
  setExpandedRows((prev) => {
21399
23031
  const next = new Set(prev);
21400
23032
  if (next.has(id)) next.delete(id);
@@ -21402,7 +23034,7 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21402
23034
  return next;
21403
23035
  });
21404
23036
  }, []);
21405
- const toggleCategory = (0, react.useCallback)((cat) => {
23037
+ const toggleCategory = (0, react$1.useCallback)((cat) => {
21406
23038
  setActiveCategories((prev) => {
21407
23039
  const next = new Set(prev);
21408
23040
  if (next.has(cat)) next.delete(cat);
@@ -21410,43 +23042,43 @@ function EventStream({ agentId, addonId, deviceId, defaultCategories, categories
21410
23042
  return next;
21411
23043
  });
21412
23044
  }, []);
21413
- const handleReset = (0, react.useCallback)(() => {
23045
+ const handleReset = (0, react$1.useCallback)(() => {
21414
23046
  setActiveCategories(new Set(defaultsArray));
21415
23047
  setSearchText("");
21416
23048
  setClearedAt(0);
21417
23049
  }, [defaultsArray]);
21418
- const handleClear = (0, react.useCallback)(() => {
23050
+ const handleClear = (0, react$1.useCallback)(() => {
21419
23051
  setClearedAt(Date.now());
21420
23052
  buffer.reset();
21421
23053
  }, [buffer]);
21422
- const [copiedAll, setCopiedAll] = (0, react.useState)(false);
21423
- const [copiedRowId, setCopiedRowId] = (0, react.useState)(null);
21424
- const formatEventForCopy = (0, react.useCallback)((event) => {
23054
+ const [copiedAll, setCopiedAll] = (0, react$1.useState)(false);
23055
+ const [copiedRowId, setCopiedRowId] = (0, react$1.useState)(null);
23056
+ const formatEventForCopy = (0, react$1.useCallback)((event) => {
21425
23057
  const time = new Date(event.timestamp).toISOString();
21426
23058
  const summary = summarizeEvent(event.category, event.data) ?? "";
21427
23059
  const summaryStr = summary ? ` ${summary}` : "";
21428
23060
  return `${time} [${event.category}]${summaryStr} data=${JSON.stringify(event.data)}`;
21429
23061
  }, []);
21430
- const handleCopyAll = (0, react.useCallback)(() => {
23062
+ const handleCopyAll = (0, react$1.useCallback)(() => {
21431
23063
  const lines = allEvents.map(formatEventForCopy);
21432
23064
  navigator.clipboard.writeText(lines.join("\n")).then(() => {
21433
23065
  setCopiedAll(true);
21434
23066
  setTimeout(() => setCopiedAll(false), 1500);
21435
23067
  });
21436
23068
  }, [allEvents, formatEventForCopy]);
21437
- const copyOne = (0, react.useCallback)((event) => {
23069
+ const copyOne = (0, react$1.useCallback)((event) => {
21438
23070
  navigator.clipboard.writeText(formatEventForCopy(event)).then(() => {
21439
23071
  setCopiedRowId(event.id);
21440
23072
  setTimeout(() => setCopiedRowId((prev) => prev === event.id ? null : prev), 1200);
21441
23073
  });
21442
23074
  }, [formatEventForCopy]);
21443
- const handleSelectAll = (0, react.useCallback)(() => {
23075
+ const handleSelectAll = (0, react$1.useCallback)(() => {
21444
23076
  setActiveCategories(new Set(ALL_EVENT_CATEGORIES));
21445
23077
  }, []);
21446
- const handleSelectNone = (0, react.useCallback)(() => {
23078
+ const handleSelectNone = (0, react$1.useCallback)(() => {
21447
23079
  setActiveCategories(/* @__PURE__ */ new Set());
21448
23080
  }, []);
21449
- const filteredPopoverCategories = (0, react.useMemo)(() => {
23081
+ const filteredPopoverCategories = (0, react$1.useMemo)(() => {
21450
23082
  const needle = categorySearch.trim().toLowerCase();
21451
23083
  if (!needle) return ALL_EVENT_CATEGORIES;
21452
23084
  return ALL_EVENT_CATEGORIES.filter((c) => c.toLowerCase().includes(needle));
@@ -21824,8 +23456,8 @@ function DiscoveryPanel({ deviceId, className = "", onOpenChild }) {
21824
23456
  const releaseMutation = trpc.deviceDiscovery.releaseDevice.useMutation({ onSuccess: () => {
21825
23457
  utils.deviceDiscovery.listDiscovered.invalidate({ deviceId });
21826
23458
  } });
21827
- const [busyChildId, setBusyChildId] = (0, react.useState)(null);
21828
- const { available, adopted } = (0, react.useMemo)(() => {
23459
+ const [busyChildId, setBusyChildId] = (0, react$1.useState)(null);
23460
+ const { available, adopted } = (0, react$1.useMemo)(() => {
21829
23461
  const list = listQuery.data ?? [];
21830
23462
  const sortKey = (c) => typeof c.metadata.rtspChannel === "number" ? c.metadata.rtspChannel : Number.POSITIVE_INFINITY;
21831
23463
  const byChannel = (a, b) => {
@@ -22104,20 +23736,20 @@ var MAX_LIVE_ENTRIES = 300;
22104
23736
  */
22105
23737
  var ALL_DEVICE_CAP_NAMES = Object.freeze([...new Set(_camstack_types.ALL_CAPABILITY_DEFINITIONS.filter((c) => c.scope === "device").map((c) => c.name))].sort());
22106
23738
  function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limit = 50, liveBuffer: externalBuffer, onClose, className }) {
22107
- const [activeCaps, setActiveCaps] = (0, react.useState)((0, react.useMemo)(() => new Set(defaultCaps ?? []), [defaultCaps]));
22108
- const [searchText, setSearchText] = (0, react.useState)("");
22109
- const [autoScroll, setAutoScroll] = (0, react.useState)(true);
22110
- const [expandedRows, setExpandedRows] = (0, react.useState)(/* @__PURE__ */ new Set());
22111
- const [clearedAt, setClearedAt] = (0, react.useState)(0);
22112
- const [filterOpen, setFilterOpen] = (0, react.useState)(false);
22113
- const [filterSearch, setFilterSearch] = (0, react.useState)("");
22114
- const filterRootRef = (0, react.useRef)(null);
23739
+ const [activeCaps, setActiveCaps] = (0, react$1.useState)((0, react$1.useMemo)(() => new Set(defaultCaps ?? []), [defaultCaps]));
23740
+ const [searchText, setSearchText] = (0, react$1.useState)("");
23741
+ const [autoScroll, setAutoScroll] = (0, react$1.useState)(true);
23742
+ const [expandedRows, setExpandedRows] = (0, react$1.useState)(/* @__PURE__ */ new Set());
23743
+ const [clearedAt, setClearedAt] = (0, react$1.useState)(0);
23744
+ const [filterOpen, setFilterOpen] = (0, react$1.useState)(false);
23745
+ const [filterSearch, setFilterSearch] = (0, react$1.useState)("");
23746
+ const filterRootRef = (0, react$1.useRef)(null);
22115
23747
  const fallbackBuffer = useLiveBuffer(MAX_LIVE_ENTRIES);
22116
23748
  const buffer = externalBuffer ?? fallbackBuffer;
22117
23749
  const liveEvents = buffer.entries;
22118
- const scrollRef = (0, react.useRef)(null);
22119
- const prevDeviceRef = (0, react.useRef)(deviceId);
22120
- (0, react.useEffect)(() => {
23750
+ const scrollRef = (0, react$1.useRef)(null);
23751
+ const prevDeviceRef = (0, react$1.useRef)(deviceId);
23752
+ (0, react$1.useEffect)(() => {
22121
23753
  if (prevDeviceRef.current !== deviceId) {
22122
23754
  prevDeviceRef.current = deviceId;
22123
23755
  buffer.reset();
@@ -22125,14 +23757,14 @@ function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limi
22125
23757
  setClearedAt(0);
22126
23758
  }
22127
23759
  }, [deviceId, buffer]);
22128
- const recentInput = (0, react.useMemo)(() => ({
23760
+ const recentInput = (0, react$1.useMemo)(() => ({
22129
23761
  deviceId,
22130
23762
  category: _camstack_types.EventCategory.DeviceStateChanged,
22131
23763
  limit
22132
23764
  }), [deviceId, limit]);
22133
23765
  const { data: initialEvents, isLoading } = trpc.systemEvents.getRecent.useQuery(recentInput, { staleTime: 3e4 });
22134
- const activeCapsRef = (0, react.useRef)(activeCaps);
22135
- (0, react.useEffect)(() => {
23766
+ const activeCapsRef = (0, react$1.useRef)(activeCaps);
23767
+ (0, react$1.useEffect)(() => {
22136
23768
  activeCapsRef.current = activeCaps;
22137
23769
  }, [activeCaps]);
22138
23770
  trpc.systemEvents.subscribe.useSubscription({
@@ -22146,8 +23778,8 @@ function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limi
22146
23778
  if (active.size > 0 && !active.has(entry.capName)) return;
22147
23779
  buffer.append(entry);
22148
23780
  } });
22149
- const prevLiveCountRef = (0, react.useRef)(liveEvents.length);
22150
- (0, react.useEffect)(() => {
23781
+ const prevLiveCountRef = (0, react$1.useRef)(liveEvents.length);
23782
+ (0, react$1.useEffect)(() => {
22151
23783
  const el = scrollRef.current;
22152
23784
  if (!el) {
22153
23785
  prevLiveCountRef.current = liveEvents.length;
@@ -22164,7 +23796,7 @@ function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limi
22164
23796
  el.scrollTop += rowHeight * newCount;
22165
23797
  }
22166
23798
  }, [liveEvents.length, autoScroll]);
22167
- const allEntries = (0, react.useMemo)(() => {
23799
+ const allEntries = (0, react$1.useMemo)(() => {
22168
23800
  const byId = /* @__PURE__ */ new Map();
22169
23801
  for (const e of initialEvents ?? []) {
22170
23802
  const entry = toEntry(e);
@@ -22196,7 +23828,7 @@ function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limi
22196
23828
  searchText,
22197
23829
  clearedAt
22198
23830
  ]);
22199
- const visibleCaps = (0, react.useMemo)(() => {
23831
+ const visibleCaps = (0, react$1.useMemo)(() => {
22200
23832
  const caps = new Set(ALL_DEVICE_CAP_NAMES);
22201
23833
  for (const e of initialEvents ?? []) {
22202
23834
  const entry = toEntry(e);
@@ -22205,7 +23837,7 @@ function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limi
22205
23837
  for (const e of liveEvents) caps.add(e.capName);
22206
23838
  return [...caps].sort();
22207
23839
  }, [initialEvents, liveEvents]);
22208
- const toggleRow = (0, react.useCallback)((id) => {
23840
+ const toggleRow = (0, react$1.useCallback)((id) => {
22209
23841
  setExpandedRows((prev) => {
22210
23842
  const next = new Set(prev);
22211
23843
  if (next.has(id)) next.delete(id);
@@ -22213,7 +23845,7 @@ function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limi
22213
23845
  return next;
22214
23846
  });
22215
23847
  }, []);
22216
- const toggleCap = (0, react.useCallback)((cap) => {
23848
+ const toggleCap = (0, react$1.useCallback)((cap) => {
22217
23849
  setActiveCaps((prev) => {
22218
23850
  const next = new Set(prev);
22219
23851
  if (next.has(cap)) next.delete(cap);
@@ -22221,39 +23853,39 @@ function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limi
22221
23853
  return next;
22222
23854
  });
22223
23855
  }, []);
22224
- const handleReset = (0, react.useCallback)(() => {
23856
+ const handleReset = (0, react$1.useCallback)(() => {
22225
23857
  setActiveCaps(new Set(defaultCaps ?? []));
22226
23858
  setSearchText("");
22227
23859
  }, [defaultCaps]);
22228
- const handleClear = (0, react.useCallback)(() => {
23860
+ const handleClear = (0, react$1.useCallback)(() => {
22229
23861
  setClearedAt(Date.now());
22230
23862
  buffer.reset();
22231
23863
  }, [buffer]);
22232
- const [copiedAll, setCopiedAll] = (0, react.useState)(false);
22233
- const [copiedRowId, setCopiedRowId] = (0, react.useState)(null);
22234
- const formatEntryForCopy = (0, react.useCallback)((entry) => {
23864
+ const [copiedAll, setCopiedAll] = (0, react$1.useState)(false);
23865
+ const [copiedRowId, setCopiedRowId] = (0, react$1.useState)(null);
23866
+ const formatEntryForCopy = (0, react$1.useCallback)((entry) => {
22235
23867
  return `${new Date(entry.timestamp).toISOString()} [${entry.capName}] slice=${JSON.stringify(entry.slice)}`;
22236
23868
  }, []);
22237
- const handleCopyAll = (0, react.useCallback)(() => {
23869
+ const handleCopyAll = (0, react$1.useCallback)(() => {
22238
23870
  const lines = allEntries.map(formatEntryForCopy);
22239
23871
  navigator.clipboard.writeText(lines.join("\n")).then(() => {
22240
23872
  setCopiedAll(true);
22241
23873
  setTimeout(() => setCopiedAll(false), 1500);
22242
23874
  });
22243
23875
  }, [allEntries, formatEntryForCopy]);
22244
- const copyOne = (0, react.useCallback)((entry) => {
23876
+ const copyOne = (0, react$1.useCallback)((entry) => {
22245
23877
  navigator.clipboard.writeText(formatEntryForCopy(entry)).then(() => {
22246
23878
  setCopiedRowId(entry.id);
22247
23879
  setTimeout(() => setCopiedRowId((prev) => prev === entry.id ? null : prev), 1200);
22248
23880
  });
22249
23881
  }, [formatEntryForCopy]);
22250
- const handleSelectAllCaps = (0, react.useCallback)(() => {
23882
+ const handleSelectAllCaps = (0, react$1.useCallback)(() => {
22251
23883
  setActiveCaps(new Set(visibleCaps));
22252
23884
  }, [visibleCaps]);
22253
- const handleSelectNoCaps = (0, react.useCallback)(() => {
23885
+ const handleSelectNoCaps = (0, react$1.useCallback)(() => {
22254
23886
  setActiveCaps(/* @__PURE__ */ new Set());
22255
23887
  }, []);
22256
- const filteredPopoverCaps = (0, react.useMemo)(() => {
23888
+ const filteredPopoverCaps = (0, react$1.useMemo)(() => {
22257
23889
  const needle = filterSearch.trim().toLowerCase();
22258
23890
  if (!needle) return visibleCaps;
22259
23891
  return visibleCaps.filter((c) => c.toLowerCase().includes(needle));
@@ -22262,7 +23894,7 @@ function StateValuesStream({ deviceId, defaultCaps, maxHeight = "max-h-96", limi
22262
23894
  const totalActive = activeCaps.size;
22263
23895
  const allSelected = totalActive === 0 || totalActive === totalAvailable;
22264
23896
  const filterLabel = allSelected ? "All" : `${totalActive}/${totalAvailable}`;
22265
- (0, react.useEffect)(() => {
23897
+ (0, react$1.useEffect)(() => {
22266
23898
  if (!filterOpen) return;
22267
23899
  const onDocClick = (e) => {
22268
23900
  const root = filterRootRef.current;
@@ -22622,14 +24254,14 @@ var TABS = [
22622
24254
  }
22623
24255
  ];
22624
24256
  function DeviceActivityPanel({ deviceId, defaultEventCategories, defaultStateCaps, initialTab = "events", className, maxHeight = "max-h-96" }) {
22625
- const [tab, setTab] = (0, react.useState)(initialTab);
24257
+ const [tab, setTab] = (0, react$1.useState)(initialTab);
22626
24258
  const logsBuffer = useLiveBuffer(PANEL_BUFFER_SIZE);
22627
24259
  const eventsBuffer = useLiveBuffer(PANEL_BUFFER_SIZE);
22628
24260
  const stateBuffer = useLiveBuffer(PANEL_BUFFER_SIZE);
22629
24261
  const logsReset = logsBuffer.reset;
22630
24262
  const eventsReset = eventsBuffer.reset;
22631
24263
  const stateReset = stateBuffer.reset;
22632
- (0, react.useEffect)(() => {
24264
+ (0, react$1.useEffect)(() => {
22633
24265
  logsReset();
22634
24266
  eventsReset();
22635
24267
  stateReset();
@@ -22693,9 +24325,9 @@ function DeviceActivityPanel({ deviceId, defaultEventCategories, defaultStateCap
22693
24325
  * for reboot, RefreshCw for restart).
22694
24326
  */
22695
24327
  function ConfirmActionButton({ label, icon: Icon, title = "Confirm action", description, confirmLabel, triggerVariant = "outline", confirmVariant = "danger", size = "sm", disabled, className, action, onSuccess }) {
22696
- const [open, setOpen] = (0, react.useState)(false);
22697
- const [running, setRunning] = (0, react.useState)(false);
22698
- const [error, setError] = (0, react.useState)(null);
24328
+ const [open, setOpen] = (0, react$1.useState)(false);
24329
+ const [running, setRunning] = (0, react$1.useState)(false);
24330
+ const [error, setError] = (0, react$1.useState)(null);
22699
24331
  const handleConfirm = async () => {
22700
24332
  setError(null);
22701
24333
  setRunning(true);
@@ -22774,9 +24406,9 @@ function ConfirmActionButton({ label, icon: Icon, title = "Confirm action", desc
22774
24406
  * release (`startContinuous` + `stopContinuous` on pointer up).
22775
24407
  */
22776
24408
  function DPadButton({ direction, icon: Icon, disabled, className, variant, onMove, onStart, onStop }) {
22777
- const [pressedAt, setPressedAt] = (0, react.useState)(null);
22778
- const [continuous, setContinuous] = (0, react.useState)(false);
22779
- const handlePointerDown = (0, react.useCallback)((e) => {
24409
+ const [pressedAt, setPressedAt] = (0, react$1.useState)(null);
24410
+ const [continuous, setContinuous] = (0, react$1.useState)(false);
24411
+ const handlePointerDown = (0, react$1.useCallback)((e) => {
22780
24412
  if (disabled) return;
22781
24413
  e.currentTarget.setPointerCapture(e.pointerId);
22782
24414
  setPressedAt(Date.now());
@@ -22791,7 +24423,7 @@ function DPadButton({ direction, icon: Icon, disabled, className, variant, onMov
22791
24423
  disabled,
22792
24424
  onStart
22793
24425
  ]);
22794
- const handlePointerUp = (0, react.useCallback)((e) => {
24426
+ const handlePointerUp = (0, react$1.useCallback)((e) => {
22795
24427
  const timerId = Number(e.currentTarget.dataset.timer);
22796
24428
  if (timerId) clearTimeout(timerId);
22797
24429
  e.currentTarget.dataset.timer = "";
@@ -22806,7 +24438,7 @@ function DPadButton({ direction, icon: Icon, disabled, className, variant, onMov
22806
24438
  onStop,
22807
24439
  pressedAt
22808
24440
  ]);
22809
- const handlePointerCancel = (0, react.useCallback)((e) => {
24441
+ const handlePointerCancel = (0, react$1.useCallback)((e) => {
22810
24442
  const timerId = Number(e.currentTarget.dataset.timer);
22811
24443
  if (timerId) clearTimeout(timerId);
22812
24444
  e.currentTarget.dataset.timer = "";
@@ -22829,7 +24461,7 @@ function DPadButton({ direction, icon: Icon, disabled, className, variant, onMov
22829
24461
  }
22830
24462
  function PTZOverlay({ controls, mode = "overlay", showPresets, showZoom = true, showHome = true, className }) {
22831
24463
  const { move, startContinuous, stopContinuous, zoom, goHome, goToPreset, presets, busy, error } = controls;
22832
- const [presetsOpen, setPresetsOpen] = (0, react.useState)(false);
24464
+ const [presetsOpen, setPresetsOpen] = (0, react$1.useState)(false);
22833
24465
  const presetsVisible = (showPresets ?? presets.length > 0) && presets.length > 0;
22834
24466
  const isPanel = mode === "panel";
22835
24467
  const containerClass = isPanel ? "flex flex-col items-stretch gap-2 w-full h-full p-3" : "pointer-events-auto absolute top-3 right-3 z-10 flex flex-col items-end gap-2";
@@ -22982,11 +24614,11 @@ function downloadDataUrl(filename, dataUrl) {
22982
24614
  document.body.removeChild(link);
22983
24615
  }
22984
24616
  function SnapshotButton({ trpc, deviceId, deviceName, size = "sm", className }) {
22985
- const [busy, setBusy] = (0, react.useState)(false);
22986
- const [done, setDone] = (0, react.useState)(false);
22987
- const [error, setError] = (0, react.useState)(null);
24617
+ const [busy, setBusy] = (0, react$1.useState)(false);
24618
+ const [done, setDone] = (0, react$1.useState)(false);
24619
+ const [error, setError] = (0, react$1.useState)(null);
22988
24620
  const safeName = deviceName.replace(/[^a-zA-Z0-9_.-]+/g, "_");
22989
- const fetchSnapshot = (0, react.useCallback)(async (action) => {
24621
+ const fetchSnapshot = (0, react$1.useCallback)(async (action) => {
22990
24622
  setBusy(true);
22991
24623
  setError(null);
22992
24624
  setDone(false);
@@ -23019,8 +24651,8 @@ function SnapshotButton({ trpc, deviceId, deviceName, size = "sm", className })
23019
24651
  safeName
23020
24652
  ]);
23021
24653
  const sizeClasses = size === "md" ? "h-9 px-3 text-sm gap-2" : "h-7 px-2.5 text-[11px] gap-1.5";
23022
- const [pressTimer, setPressTimer] = (0, react.useState)(null);
23023
- const [longPressed, setLongPressed] = (0, react.useState)(false);
24654
+ const [pressTimer, setPressTimer] = (0, react$1.useState)(null);
24655
+ const [longPressed, setLongPressed] = (0, react$1.useState)(false);
23024
24656
  const handlePointerDown = () => {
23025
24657
  setLongPressed(false);
23026
24658
  setPressTimer(setTimeout(() => {
@@ -23127,7 +24759,7 @@ function DoorbellRecentPanel({ history, limit = 5, latestIsFresh, className }) {
23127
24759
  * touch devices, no extra wiring needed.
23128
24760
  */
23129
24761
  function KebabMenu({ items, header, triggerClassName, title = "More actions" }) {
23130
- const [open, setOpen] = (0, react.useState)(false);
24762
+ const [open, setOpen] = (0, react$1.useState)(false);
23131
24763
  const visible = items.filter((i) => !i.hidden);
23132
24764
  if (visible.length === 0) return null;
23133
24765
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Popover, {
@@ -23269,19 +24901,19 @@ function clampedAccessForRow(row, parent) {
23269
24901
  function ScopePicker({ value, onChange, clampToParent, emptyHint }) {
23270
24902
  const { data: addons } = useAddonsList();
23271
24903
  const { data: devices } = useDeviceManagerListAll({});
23272
- const addonChoices = (0, react.useMemo)(() => (addons ?? []).map((a) => ({
24904
+ const addonChoices = (0, react$1.useMemo)(() => (addons ?? []).map((a) => ({
23273
24905
  value: a.manifest.id,
23274
24906
  label: a.manifest.id
23275
24907
  })).sort((a, b) => a.label.localeCompare(b.label)), [addons]);
23276
- const capChoices = (0, react.useMemo)(() => [..._camstack_types.KNOWN_CAP_NAMES].sort().map((c) => ({
24908
+ const capChoices = (0, react$1.useMemo)(() => [..._camstack_types.KNOWN_CAP_NAMES].sort().map((c) => ({
23277
24909
  value: c,
23278
24910
  label: c
23279
24911
  })), []);
23280
- const deviceChoices = (0, react.useMemo)(() => (devices ?? []).map((d) => ({
24912
+ const deviceChoices = (0, react$1.useMemo)(() => (devices ?? []).map((d) => ({
23281
24913
  value: String(d.id),
23282
24914
  label: `${d.name} (#${d.id} · ${d.addonId})`
23283
24915
  })).sort((a, b) => a.label.localeCompare(b.label)), [devices]);
23284
- const parentDeviceClamp = (0, react.useMemo)(() => clampToParent == null ? null : parentDeviceTargets(clampToParent), [clampToParent]);
24916
+ const parentDeviceClamp = (0, react$1.useMemo)(() => clampToParent == null ? null : parentDeviceTargets(clampToParent), [clampToParent]);
23285
24917
  /**
23286
24918
  * Build a fresh scope row when `type` changes. The discriminated union
23287
24919
  * forces us to re-construct the object per variant so the resulting
@@ -23448,8 +25080,8 @@ function ScopePicker({ value, onChange, clampToParent, emptyHint }) {
23448
25080
  });
23449
25081
  }
23450
25082
  function DeviceTargetPicker({ value, choices, clampToParent, onChange }) {
23451
- const [pendingAdd, setPendingAdd] = (0, react.useState)("");
23452
- const visibleChoices = (0, react.useMemo)(() => {
25083
+ const [pendingAdd, setPendingAdd] = (0, react$1.useState)("");
25084
+ const visibleChoices = (0, react$1.useMemo)(() => {
23453
25085
  const filtered = clampToParent == null ? choices : choices.filter((c) => clampToParent.includes(c.value));
23454
25086
  const taken = new Set(value);
23455
25087
  return filtered.filter((c) => !taken.has(c.value));
@@ -23545,11 +25177,11 @@ function validateScopes(scopes) {
23545
25177
  */
23546
25178
  var ZoneEditingContext = createSharedContext("camstack:zone-editing", null);
23547
25179
  function ZoneEditingProvider({ children }) {
23548
- const [editing, setEditingRaw] = (0, react.useState)(false);
23549
- const [drawingKind, setDrawingKindRaw] = (0, react.useState)(null);
23550
- const [selectedZoneId, setSelectedZoneIdRaw] = (0, react.useState)(null);
23551
- const [editingDraft, setEditingDraftRaw] = (0, react.useState)(null);
23552
- const setEditing = (0, react.useCallback)((next) => {
25180
+ const [editing, setEditingRaw] = (0, react$1.useState)(false);
25181
+ const [drawingKind, setDrawingKindRaw] = (0, react$1.useState)(null);
25182
+ const [selectedZoneId, setSelectedZoneIdRaw] = (0, react$1.useState)(null);
25183
+ const [editingDraft, setEditingDraftRaw] = (0, react$1.useState)(null);
25184
+ const setEditing = (0, react$1.useCallback)((next) => {
23553
25185
  setEditingRaw(next);
23554
25186
  if (!next) {
23555
25187
  setDrawingKindRaw(null);
@@ -23557,38 +25189,38 @@ function ZoneEditingProvider({ children }) {
23557
25189
  setEditingDraftRaw(null);
23558
25190
  }
23559
25191
  }, []);
23560
- const setDrawingKind = (0, react.useCallback)((kind) => {
25192
+ const setDrawingKind = (0, react$1.useCallback)((kind) => {
23561
25193
  setDrawingKindRaw(kind);
23562
25194
  }, []);
23563
- const setSelectedZoneId = (0, react.useCallback)((id) => {
25195
+ const setSelectedZoneId = (0, react$1.useCallback)((id) => {
23564
25196
  setSelectedZoneIdRaw(id);
23565
25197
  }, []);
23566
- const startDrawing = (0, react.useCallback)((kind) => {
25198
+ const startDrawing = (0, react$1.useCallback)((kind) => {
23567
25199
  setEditingRaw(true);
23568
25200
  setSelectedZoneIdRaw(null);
23569
25201
  setDrawingKindRaw(kind);
23570
25202
  setEditingDraftRaw(null);
23571
25203
  }, []);
23572
- const exitEditing = (0, react.useCallback)(() => {
25204
+ const exitEditing = (0, react$1.useCallback)(() => {
23573
25205
  setEditingRaw(false);
23574
25206
  setDrawingKindRaw(null);
23575
25207
  setSelectedZoneIdRaw(null);
23576
25208
  setEditingDraftRaw(null);
23577
25209
  }, []);
23578
- const enterDraft = (0, react.useCallback)((draft) => {
25210
+ const enterDraft = (0, react$1.useCallback)((draft) => {
23579
25211
  setSelectedZoneIdRaw(draft.id);
23580
25212
  setEditingDraftRaw(draft);
23581
25213
  }, []);
23582
- const updateDraft = (0, react.useCallback)((patch) => {
25214
+ const updateDraft = (0, react$1.useCallback)((patch) => {
23583
25215
  setEditingDraftRaw((prev) => prev === null ? prev : {
23584
25216
  ...prev,
23585
25217
  ...patch
23586
25218
  });
23587
25219
  }, []);
23588
- const discardDraft = (0, react.useCallback)(() => {
25220
+ const discardDraft = (0, react$1.useCallback)(() => {
23589
25221
  setEditingDraftRaw(null);
23590
25222
  }, []);
23591
- const value = (0, react.useMemo)(() => ({
25223
+ const value = (0, react$1.useMemo)(() => ({
23592
25224
  editing,
23593
25225
  drawingKind,
23594
25226
  selectedZoneId,
@@ -23624,7 +25256,7 @@ function ZoneEditingProvider({ children }) {
23624
25256
  * provider so callers that mount in pages without zones (e.g. a
23625
25257
  * shared hero on a non-camera device) can no-op gracefully. */
23626
25258
  function useZoneEditing() {
23627
- return (0, react.useContext)(ZoneEditingContext);
25259
+ return (0, react$1.useContext)(ZoneEditingContext);
23628
25260
  }
23629
25261
  //#endregion
23630
25262
  //#region src/hooks/use-device-detections.ts
@@ -23652,14 +25284,14 @@ function matchesDevice(source, deviceId) {
23652
25284
  return source?.id === deviceId;
23653
25285
  }
23654
25286
  function useDeviceDetections(trpc, deviceId) {
23655
- const [motion, setMotion] = (0, react.useState)(null);
23656
- const [motionRaw, setMotionRaw] = (0, react.useState)(null);
23657
- const [detection, setDetection] = (0, react.useState)(null);
23658
- const [phase, setPhase] = (0, react.useState)("watching");
23659
- const motionTimer = (0, react.useRef)(void 0);
23660
- const motionRawTimer = (0, react.useRef)(void 0);
23661
- const detectionTimer = (0, react.useRef)(void 0);
23662
- (0, react.useEffect)(() => {
25287
+ const [motion, setMotion] = (0, react$1.useState)(null);
25288
+ const [motionRaw, setMotionRaw] = (0, react$1.useState)(null);
25289
+ const [detection, setDetection] = (0, react$1.useState)(null);
25290
+ const [phase, setPhase] = (0, react$1.useState)("watching");
25291
+ const motionTimer = (0, react$1.useRef)(void 0);
25292
+ const motionRawTimer = (0, react$1.useRef)(void 0);
25293
+ const detectionTimer = (0, react$1.useRef)(void 0);
25294
+ (0, react$1.useEffect)(() => {
23663
25295
  if (deviceId === null) return;
23664
25296
  const sub = safeSubscribe(trpc, "detection.motion-analysis", (event) => {
23665
25297
  const e = event;
@@ -23682,7 +25314,7 @@ function useDeviceDetections(trpc, deviceId) {
23682
25314
  if (motionTimer.current) clearTimeout(motionTimer.current);
23683
25315
  };
23684
25316
  }, [trpc, deviceId]);
23685
- (0, react.useEffect)(() => {
25317
+ (0, react$1.useEffect)(() => {
23686
25318
  if (deviceId === null) return;
23687
25319
  const sub = safeSubscribe(trpc, "detection.motion-zones-raw", (event) => {
23688
25320
  const e = event;
@@ -23706,7 +25338,7 @@ function useDeviceDetections(trpc, deviceId) {
23706
25338
  if (motionRawTimer.current) clearTimeout(motionRawTimer.current);
23707
25339
  };
23708
25340
  }, [trpc, deviceId]);
23709
- (0, react.useEffect)(() => {
25341
+ (0, react$1.useEffect)(() => {
23710
25342
  if (deviceId === null) return;
23711
25343
  const sub = safeSubscribe(trpc, "detection.result", (event) => {
23712
25344
  const e = event;
@@ -23726,7 +25358,7 @@ function useDeviceDetections(trpc, deviceId) {
23726
25358
  if (detectionTimer.current) clearTimeout(detectionTimer.current);
23727
25359
  };
23728
25360
  }, [trpc, deviceId]);
23729
- (0, react.useEffect)(() => {
25361
+ (0, react$1.useEffect)(() => {
23730
25362
  if (deviceId === null) return;
23731
25363
  const sub = safeSubscribe(trpc, "detection.phase-transition", (event) => {
23732
25364
  const e = event;
@@ -23763,8 +25395,8 @@ function useDeviceDetections(trpc, deviceId) {
23763
25395
  * @param pollIntervalMs - how often to refresh profile slots (default: 5000)
23764
25396
  */
23765
25397
  function useDeviceWebrtc(trpc, deviceId, pollIntervalMs = 5e3) {
23766
- const [remoteStreams, setRemoteStreams] = (0, react.useState)([]);
23767
- (0, react.useEffect)(() => {
25398
+ const [remoteStreams, setRemoteStreams] = (0, react$1.useState)([]);
25399
+ (0, react$1.useEffect)(() => {
23768
25400
  if (deviceId === null) return;
23769
25401
  let cancelled = false;
23770
25402
  const fetch = () => {
@@ -23783,8 +25415,8 @@ function useDeviceWebrtc(trpc, deviceId, pollIntervalMs = 5e3) {
23783
25415
  deviceId,
23784
25416
  pollIntervalMs
23785
25417
  ]);
23786
- const [pipelineMetrics, setPipelineMetrics] = (0, react.useState)(null);
23787
- (0, react.useEffect)(() => {
25418
+ const [pipelineMetrics, setPipelineMetrics] = (0, react$1.useState)(null);
25419
+ (0, react$1.useEffect)(() => {
23788
25420
  if (deviceId === null) return;
23789
25421
  let cancelled = false;
23790
25422
  if (trpc.pipelineOrchestrator) trpc.pipelineOrchestrator.getCameraMetrics.query({ deviceId }).then((m) => {
@@ -23811,7 +25443,7 @@ function useDeviceWebrtc(trpc, deviceId, pollIntervalMs = 5e3) {
23811
25443
  droppedFrames: payload.metrics.droppedFrames
23812
25444
  });
23813
25445
  });
23814
- const { streams, hasWebrtc } = (0, react.useMemo)(() => {
25446
+ const { streams, hasWebrtc } = (0, react$1.useMemo)(() => {
23815
25447
  if (deviceId === null || remoteStreams.length === 0) return {
23816
25448
  streams: [],
23817
25449
  hasWebrtc: false
@@ -23833,7 +25465,7 @@ function useDeviceWebrtc(trpc, deviceId, pollIntervalMs = 5e3) {
23833
25465
  streams,
23834
25466
  hasWebrtc,
23835
25467
  pipelineMetrics,
23836
- createSession: (0, react.useCallback)(async (target, hints) => {
25468
+ createSession: (0, react$1.useCallback)(async (target, hints) => {
23837
25469
  if (deviceId === null) throw new Error("No device selected");
23838
25470
  const res = await trpc.webrtcSession.createSession.mutate({
23839
25471
  deviceId,
@@ -23845,7 +25477,7 @@ function useDeviceWebrtc(trpc, deviceId, pollIntervalMs = 5e3) {
23845
25477
  sdpOffer: res.sdpOffer
23846
25478
  };
23847
25479
  }, [trpc, deviceId]),
23848
- sendAnswer: (0, react.useCallback)(async (sessionId, sdpAnswer) => {
25480
+ sendAnswer: (0, react$1.useCallback)(async (sessionId, sdpAnswer) => {
23849
25481
  if (deviceId === null) throw new Error("No device selected");
23850
25482
  await trpc.webrtcSession.handleAnswer.mutate({
23851
25483
  deviceId,
@@ -23853,7 +25485,7 @@ function useDeviceWebrtc(trpc, deviceId, pollIntervalMs = 5e3) {
23853
25485
  sdpAnswer
23854
25486
  });
23855
25487
  }, [trpc, deviceId]),
23856
- closeSession: (0, react.useCallback)(async (sessionId) => {
25488
+ closeSession: (0, react$1.useCallback)(async (sessionId) => {
23857
25489
  if (deviceId === null) return;
23858
25490
  await trpc.webrtcSession.closeSession.mutate({
23859
25491
  deviceId,
@@ -23926,10 +25558,10 @@ function usePTZ(trpc, deviceId, options) {
23926
25558
  const pulseMs = options?.pulseMs ?? 250;
23927
25559
  const enabled = options?.enabled ?? true;
23928
25560
  const ptz = useDeviceProxy(trpc, enabled ? deviceId : null)?.ptz;
23929
- const [presets, setPresets] = (0, react.useState)([]);
23930
- const [busy, setBusy] = (0, react.useState)(false);
23931
- const [error, setError] = (0, react.useState)(null);
23932
- const refreshPresets = (0, react.useCallback)(async () => {
25561
+ const [presets, setPresets] = (0, react$1.useState)([]);
25562
+ const [busy, setBusy] = (0, react$1.useState)(false);
25563
+ const [error, setError] = (0, react$1.useState)(null);
25564
+ const refreshPresets = (0, react$1.useCallback)(async () => {
23933
25565
  if (!enabled || !ptz) return;
23934
25566
  try {
23935
25567
  setPresets(await ptz.getPresets({}));
@@ -23939,10 +25571,10 @@ function usePTZ(trpc, deviceId, options) {
23939
25571
  setError(msg);
23940
25572
  }
23941
25573
  }, [ptz, enabled]);
23942
- (0, react.useEffect)(() => {
25574
+ (0, react$1.useEffect)(() => {
23943
25575
  refreshPresets();
23944
25576
  }, [refreshPresets]);
23945
- const wrap = (0, react.useCallback)(async (fn) => {
25577
+ const wrap = (0, react$1.useCallback)(async (fn) => {
23946
25578
  if (!enabled || !ptz) return void 0;
23947
25579
  setError(null);
23948
25580
  setBusy(true);
@@ -23956,7 +25588,7 @@ function usePTZ(trpc, deviceId, options) {
23956
25588
  }
23957
25589
  }, [enabled, ptz]);
23958
25590
  return {
23959
- move: (0, react.useCallback)(async (direction, speed) => {
25591
+ move: (0, react$1.useCallback)(async (direction, speed) => {
23960
25592
  if (!ptz) return;
23961
25593
  const v = DIRECTION_VECTORS[direction];
23962
25594
  const s = speed ?? defaultSpeed;
@@ -23975,7 +25607,7 @@ function usePTZ(trpc, deviceId, options) {
23975
25607
  pulseMs,
23976
25608
  wrap
23977
25609
  ]),
23978
- startContinuous: (0, react.useCallback)(async (direction, speed) => {
25610
+ startContinuous: (0, react$1.useCallback)(async (direction, speed) => {
23979
25611
  if (!ptz) return;
23980
25612
  const v = DIRECTION_VECTORS[direction];
23981
25613
  const s = speed ?? defaultSpeed;
@@ -23989,11 +25621,11 @@ function usePTZ(trpc, deviceId, options) {
23989
25621
  defaultSpeed,
23990
25622
  wrap
23991
25623
  ]),
23992
- stopContinuous: (0, react.useCallback)(async () => {
25624
+ stopContinuous: (0, react$1.useCallback)(async () => {
23993
25625
  if (!ptz) return;
23994
25626
  await wrap(() => ptz.stop({}));
23995
25627
  }, [ptz, wrap]),
23996
- zoom: (0, react.useCallback)(async (direction, speed) => {
25628
+ zoom: (0, react$1.useCallback)(async (direction, speed) => {
23997
25629
  if (!ptz) return;
23998
25630
  const z = direction === "in" ? 1 : -1;
23999
25631
  const s = speed ?? defaultSpeed;
@@ -24011,11 +25643,11 @@ function usePTZ(trpc, deviceId, options) {
24011
25643
  pulseMs,
24012
25644
  wrap
24013
25645
  ]),
24014
- goHome: (0, react.useCallback)(async () => {
25646
+ goHome: (0, react$1.useCallback)(async () => {
24015
25647
  if (!ptz) return;
24016
25648
  await wrap(() => ptz.goHome({}));
24017
25649
  }, [ptz, wrap]),
24018
- goToPreset: (0, react.useCallback)(async (presetId) => {
25650
+ goToPreset: (0, react$1.useCallback)(async (presetId) => {
24019
25651
  if (!ptz) return;
24020
25652
  await wrap(() => ptz.goToPreset({ presetId }));
24021
25653
  }, [ptz, wrap]),
@@ -24042,8 +25674,8 @@ function useDoorbellEvents(options) {
24042
25674
  const deviceId = options?.deviceId ?? null;
24043
25675
  const historyLimit = options?.historyLimit ?? 20;
24044
25676
  const event = useEventStreamLatest("doorbell.onPressed", deviceId !== null ? (data) => data.deviceId === deviceId : void 0);
24045
- const [history, setHistory] = (0, react.useState)([]);
24046
- (0, react.useEffect)(() => {
25677
+ const [history, setHistory] = (0, react$1.useState)([]);
25678
+ (0, react$1.useEffect)(() => {
24047
25679
  if (!event) return;
24048
25680
  setHistory((prev) => {
24049
25681
  if (prev.length > 0 && prev[0].deviceId === event.deviceId && prev[0].timestamp === event.timestamp) return prev;
@@ -24079,9 +25711,9 @@ function useDoorbellEvents(options) {
24079
25711
  */
24080
25712
  function useDevices(filters) {
24081
25713
  const system = useSystem();
24082
- const filtersKey = (0, react.useMemo)(() => filters ? JSON.stringify(filters) : "", [filters]);
24083
- const [devices, setDevices] = (0, react.useState)(() => system.listDevices(filters));
24084
- (0, react.useEffect)(() => {
25714
+ const filtersKey = (0, react$1.useMemo)(() => filters ? JSON.stringify(filters) : "", [filters]);
25715
+ const [devices, setDevices] = (0, react$1.useState)(() => system.listDevices(filters));
25716
+ (0, react$1.useEffect)(() => {
24085
25717
  const refresh = () => {
24086
25718
  setDevices(system.listDevices(filters));
24087
25719
  };
@@ -24114,8 +25746,8 @@ function useDevices(filters) {
24114
25746
  */
24115
25747
  function useDevice(deviceId) {
24116
25748
  const system = useSystem();
24117
- const [device, setDevice] = (0, react.useState)(() => deviceId === null ? null : system.getDevice(deviceId));
24118
- (0, react.useEffect)(() => {
25749
+ const [device, setDevice] = (0, react$1.useState)(() => deviceId === null ? null : system.getDevice(deviceId));
25750
+ (0, react$1.useEffect)(() => {
24119
25751
  if (deviceId === null) {
24120
25752
  setDevice(null);
24121
25753
  return;
@@ -24213,15 +25845,15 @@ function useSystemMutation(select, opts) {
24213
25845
  function useEventInvalidation(queryKey, categories) {
24214
25846
  const system = useSystem();
24215
25847
  const queryClient = (0, _tanstack_react_query.useQueryClient)();
24216
- const [tick, setTick] = (0, react.useState)(system.connectionVersion);
24217
- (0, react.useEffect)(() => {
25848
+ const [tick, setTick] = (0, react$1.useState)(system.connectionVersion);
25849
+ (0, react$1.useEffect)(() => {
24218
25850
  return system.subscribeConnectionEvents((state, version) => {
24219
25851
  if (state === "connected") setTick(version);
24220
25852
  });
24221
25853
  }, [system]);
24222
25854
  const key = categories.join("|");
24223
25855
  const keyJson = JSON.stringify(queryKey);
24224
- (0, react.useEffect)(() => {
25856
+ (0, react$1.useEffect)(() => {
24225
25857
  const subs = [];
24226
25858
  const refresh = () => {
24227
25859
  const raw = JSON.parse(keyJson);
@@ -24276,6 +25908,7 @@ exports.ConfigFormField = FormField;
24276
25908
  exports.ConfigSchemaField = ConfigSchemaField;
24277
25909
  exports.ConfirmActionButton = ConfirmActionButton;
24278
25910
  exports.ConfirmDialogProvider = ConfirmDialogProvider;
25911
+ exports.CopyButton = CopyButton;
24279
25912
  exports.CustomFieldRenderersProvider = CustomFieldRenderersProvider;
24280
25913
  exports.DEFAULT_COLOR = DEFAULT_COLOR;
24281
25914
  exports.DataTable = DataTable;
@@ -24286,6 +25919,7 @@ exports.DevShell = DevShell;
24286
25919
  exports.DeviceActivityPanel = DeviceActivityPanel;
24287
25920
  exports.DeviceCard = DeviceCard;
24288
25921
  exports.DeviceContextProvider = DeviceContextProvider;
25922
+ exports.DeviceExportPanel = DeviceExportPanel;
24289
25923
  exports.DeviceGrid = DeviceGrid;
24290
25924
  exports.DeviceItem = DeviceItem;
24291
25925
  exports.DeviceList = DeviceList;
@@ -24303,6 +25937,7 @@ exports.DropdownContent = DropdownContent;
24303
25937
  exports.DropdownItem = DropdownItem;
24304
25938
  exports.DropdownTrigger = DropdownTrigger;
24305
25939
  exports.EmptyState = EmptyState;
25940
+ exports.ErrorBox = ErrorBox;
24306
25941
  exports.EventStream = EventStream;
24307
25942
  exports.FilterBar = FilterBar;
24308
25943
  exports.FloatingEventStream = FloatingEventStream;
@@ -24340,6 +25975,7 @@ exports.Popover = Popover;
24340
25975
  exports.PopoverContent = PopoverContent;
24341
25976
  exports.PopoverTrigger = PopoverTrigger;
24342
25977
  exports.ProviderBadge = ProviderBadge;
25978
+ exports.QrCode = QrCode;
24343
25979
  exports.ResponseLog = ResponseLog;
24344
25980
  exports.SECTION_BODY = SECTION_BODY;
24345
25981
  exports.SECTION_CARD = SECTION_CARD;
@@ -24414,12 +26050,15 @@ exports.useAddonsCustom = useAddonsCustom;
24414
26050
  exports.useAddonsForceRefresh = useAddonsForceRefresh;
24415
26051
  exports.useAddonsGetAddonAutoUpdate = useAddonsGetAddonAutoUpdate;
24416
26052
  exports.useAddonsGetAutoUpdateSettings = useAddonsGetAutoUpdateSettings;
26053
+ exports.useAddonsGetLastRestart = useAddonsGetLastRestart;
24417
26054
  exports.useAddonsGetLogs = useAddonsGetLogs;
24418
26055
  exports.useAddonsGetVersions = useAddonsGetVersions;
24419
26056
  exports.useAddonsInstallFromWorkspace = useAddonsInstallFromWorkspace;
24420
26057
  exports.useAddonsInstallPackage = useAddonsInstallPackage;
24421
26058
  exports.useAddonsIsWorkspaceAvailable = useAddonsIsWorkspaceAvailable;
24422
26059
  exports.useAddonsList = useAddonsList;
26060
+ exports.useAddonsListCapabilityProviders = useAddonsListCapabilityProviders;
26061
+ exports.useAddonsListFrameworkPackages = useAddonsListFrameworkPackages;
24423
26062
  exports.useAddonsListPackages = useAddonsListPackages;
24424
26063
  exports.useAddonsListUpdates = useAddonsListUpdates;
24425
26064
  exports.useAddonsListWorkspacePackages = useAddonsListWorkspacePackages;
@@ -24433,6 +26072,7 @@ exports.useAddonsSearchAvailable = useAddonsSearchAvailable;
24433
26072
  exports.useAddonsSetAddonAutoUpdate = useAddonsSetAddonAutoUpdate;
24434
26073
  exports.useAddonsSetAutoUpdateSettings = useAddonsSetAutoUpdateSettings;
24435
26074
  exports.useAddonsUninstallPackage = useAddonsUninstallPackage;
26075
+ exports.useAddonsUpdateFrameworkPackage = useAddonsUpdateFrameworkPackage;
24436
26076
  exports.useAddonsUpdatePackage = useAddonsUpdatePackage;
24437
26077
  exports.useAlertsDismiss = useAlertsDismiss;
24438
26078
  exports.useAlertsEmit = useAlertsEmit;