@camstack/ui-library 1.2.194 → 1.2.196

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.js CHANGED
@@ -13,7 +13,7 @@ import * as __mfHostReactDOMClient from "react-dom/client";
13
13
  import { createRoot } from "react-dom/client";
14
14
  import * as __mfHostTrpcClient from "@trpc/client";
15
15
  import { createTRPCClient, createWSClient, httpLink, splitLink, wsLink } from "@trpc/client";
16
- import { ALL_CAPABILITY_DEFINITIONS, CAM_PROFILE_ORDER, CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, CONTAINER_CHILD_PRIORITY, DEFAULT_EVENTS_BAND_BUFFER_SEC, DEFAULT_EVENT_COLOR, DEVICE_TYPE_CONTROL_KIND, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EVENT_TAXONOMY, EventCategory, ExposedDeviceSchema, FIRST_LEVEL_MACRO_CLASSES, KNOWN_CAP_NAMES, MAX_SENSOR_TRIGGER_DEVICES, MODEL_PROVIDER_IDS, NAVIGATION_LIGHT_LEVEL_MAX, NAVIGATION_LIGHT_LEVEL_MIN, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, RECORDING_AUDIO_TRIGGER_OFFERED_DBFS, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, buildModelVariantGroups, canConvertUnit, clusterStepSettingFieldsFor, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, findTimezone, formatParkedFor, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveRecordingProfiles, resolveVariantModelId, resolveViewableDeviceIds, selectAssignedProfileSlots, tryConvertUnit } from "@camstack/types";
16
+ import { ALL_CAPABILITY_DEFINITIONS, CAM_PROFILE_ORDER, CLIP_STILL_DISPOSITION_HEADER, CLIP_STILL_REASON_CODE_HEADER, CLIP_STILL_REASON_HEADER, CONTAINER_CHILD_PRIORITY, DEFAULT_EVENTS_BAND_BUFFER_SEC, DEFAULT_EVENT_COLOR, DEVICE_TYPE_CONTROL_KIND, DISPLAY_ICON_GROUPS, DeviceExportStatusSchema, DeviceFeature, DeviceRole, DeviceType, EVENT_TAXONOMY, EventCategory, ExposedDeviceSchema, FIRST_LEVEL_MACRO_CLASSES, KNOWN_CAP_NAMES, MAX_SENSOR_TRIGGER_DEVICES, MODEL_PROVIDER_IDS, NAVIGATION_LIGHT_LEVEL_MAX, NAVIGATION_LIGHT_LEVEL_MIN, PET_FEEDER_MANUAL_FEED_MAX, PET_FEEDER_MANUAL_FEED_MIN, RECORDING_AUDIO_TRIGGER_OFFERED_DBFS, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, buildModelVariantGroups, canConvertUnit, clusterStepSettingFieldsFor, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, findTimezone, formatParkedFor, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveRecordingProfiles, resolveVariantModelId, resolveViewableDeviceIds, searchDisplayIcons, selectAssignedProfileSlots, tryConvertUnit } from "@camstack/types";
17
17
  import { createSystem } from "@camstack/sdk";
18
18
  import { z } from "zod";
19
19
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
@@ -351,6 +351,30 @@ var Bath = createLucideIcon("bath", [
351
351
  * This source code is licensed under the ISC license.
352
352
  * See the LICENSE file in the root directory of this source tree.
353
353
  */
354
+ var BatteryCharging = createLucideIcon("battery-charging", [
355
+ ["path", {
356
+ d: "m11 7-3 5h4l-3 5",
357
+ key: "b4a64w"
358
+ }],
359
+ ["path", {
360
+ d: "M14.856 6H16a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.935",
361
+ key: "lre1cr"
362
+ }],
363
+ ["path", {
364
+ d: "M22 14v-4",
365
+ key: "14q9d5"
366
+ }],
367
+ ["path", {
368
+ d: "M5.14 18H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2.936",
369
+ key: "13q5k0"
370
+ }]
371
+ ]);
372
+ /**
373
+ * @license lucide-react v0.576.0 - ISC
374
+ *
375
+ * This source code is licensed under the ISC license.
376
+ * See the LICENSE file in the root directory of this source tree.
377
+ */
354
378
  var BatteryFull = createLucideIcon("battery-full", [
355
379
  ["path", {
356
380
  d: "M10 10v4",
@@ -480,6 +504,78 @@ var Battery = createLucideIcon("battery", [["path", {
480
504
  * This source code is licensed under the ISC license.
481
505
  * See the LICENSE file in the root directory of this source tree.
482
506
  */
507
+ var BedDouble = createLucideIcon("bed-double", [
508
+ ["path", {
509
+ d: "M2 20v-8a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v8",
510
+ key: "1k78r4"
511
+ }],
512
+ ["path", {
513
+ d: "M4 10V6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v4",
514
+ key: "fb3tl2"
515
+ }],
516
+ ["path", {
517
+ d: "M12 4v6",
518
+ key: "1dcgq2"
519
+ }],
520
+ ["path", {
521
+ d: "M2 18h20",
522
+ key: "ajqnye"
523
+ }]
524
+ ]);
525
+ /**
526
+ * @license lucide-react v0.576.0 - ISC
527
+ *
528
+ * This source code is licensed under the ISC license.
529
+ * See the LICENSE file in the root directory of this source tree.
530
+ */
531
+ var Bed = createLucideIcon("bed", [
532
+ ["path", {
533
+ d: "M2 4v16",
534
+ key: "vw9hq8"
535
+ }],
536
+ ["path", {
537
+ d: "M2 8h18a2 2 0 0 1 2 2v10",
538
+ key: "1dgv2r"
539
+ }],
540
+ ["path", {
541
+ d: "M2 17h20",
542
+ key: "18nfp3"
543
+ }],
544
+ ["path", {
545
+ d: "M6 8v9",
546
+ key: "1yriud"
547
+ }]
548
+ ]);
549
+ /**
550
+ * @license lucide-react v0.576.0 - ISC
551
+ *
552
+ * This source code is licensed under the ISC license.
553
+ * See the LICENSE file in the root directory of this source tree.
554
+ */
555
+ var BellOff = createLucideIcon("bell-off", [
556
+ ["path", {
557
+ d: "M10.268 21a2 2 0 0 0 3.464 0",
558
+ key: "vwvbt9"
559
+ }],
560
+ ["path", {
561
+ d: "M17 17H4a1 1 0 0 1-.74-1.673C4.59 13.956 6 12.499 6 8a6 6 0 0 1 .258-1.742",
562
+ key: "178tsu"
563
+ }],
564
+ ["path", {
565
+ d: "m2 2 20 20",
566
+ key: "1ooewy"
567
+ }],
568
+ ["path", {
569
+ d: "M8.668 3.01A6 6 0 0 1 18 8c0 2.687.77 4.653 1.707 6.05",
570
+ key: "1hqiys"
571
+ }]
572
+ ]);
573
+ /**
574
+ * @license lucide-react v0.576.0 - ISC
575
+ *
576
+ * This source code is licensed under the ISC license.
577
+ * See the LICENSE file in the root directory of this source tree.
578
+ */
483
579
  var BellRing = createLucideIcon("bell-ring", [
484
580
  ["path", {
485
581
  d: "M10.268 21a2 2 0 0 0 3.464 0",
@@ -617,6 +713,16 @@ var Blinds = createLucideIcon("blinds", [
617
713
  * This source code is licensed under the ISC license.
618
714
  * See the LICENSE file in the root directory of this source tree.
619
715
  */
716
+ var Bluetooth = createLucideIcon("bluetooth", [["path", {
717
+ d: "m7 7 10 10-5 5V2l5 5L7 17",
718
+ key: "1q5490"
719
+ }]]);
720
+ /**
721
+ * @license lucide-react v0.576.0 - ISC
722
+ *
723
+ * This source code is licensed under the ISC license.
724
+ * See the LICENSE file in the root directory of this source tree.
725
+ */
620
726
  var Bone = createLucideIcon("bone", [["path", {
621
727
  d: "M17 10c.7-.7 1.69 0 2.5 0a2.5 2.5 0 1 0 0-5 .5.5 0 0 1-.5-.5 2.5 2.5 0 1 0-5 0c0 .81.7 1.8 0 2.5l-7 7c-.7.7-1.69 0-2.5 0a2.5 2.5 0 0 0 0 5c.28 0 .5.22.5.5a2.5 2.5 0 1 0 5 0c0-.81-.7-1.8 0-2.5Z",
622
728
  key: "w610uw"
@@ -683,6 +789,23 @@ var Box = createLucideIcon("box", [
683
789
  * This source code is licensed under the ISC license.
684
790
  * See the LICENSE file in the root directory of this source tree.
685
791
  */
792
+ var Briefcase = createLucideIcon("briefcase", [["path", {
793
+ d: "M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16",
794
+ key: "jecpp"
795
+ }], ["rect", {
796
+ width: "20",
797
+ height: "14",
798
+ x: "2",
799
+ y: "6",
800
+ rx: "2",
801
+ key: "i6l2r4"
802
+ }]]);
803
+ /**
804
+ * @license lucide-react v0.576.0 - ISC
805
+ *
806
+ * This source code is licensed under the ISC license.
807
+ * See the LICENSE file in the root directory of this source tree.
808
+ */
686
809
  var Bug = createLucideIcon("bug", [
687
810
  ["path", {
688
811
  d: "M12 20v-9",
@@ -735,6 +858,90 @@ var Bug = createLucideIcon("bug", [
735
858
  * This source code is licensed under the ISC license.
736
859
  * See the LICENSE file in the root directory of this source tree.
737
860
  */
861
+ var Building2 = createLucideIcon("building-2", [
862
+ ["path", {
863
+ d: "M10 12h4",
864
+ key: "a56b0p"
865
+ }],
866
+ ["path", {
867
+ d: "M10 8h4",
868
+ key: "1sr2af"
869
+ }],
870
+ ["path", {
871
+ d: "M14 21v-3a2 2 0 0 0-4 0v3",
872
+ key: "1rgiei"
873
+ }],
874
+ ["path", {
875
+ d: "M6 10H4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-2",
876
+ key: "secmi2"
877
+ }],
878
+ ["path", {
879
+ d: "M6 21V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v16",
880
+ key: "16ra0t"
881
+ }]
882
+ ]);
883
+ /**
884
+ * @license lucide-react v0.576.0 - ISC
885
+ *
886
+ * This source code is licensed under the ISC license.
887
+ * See the LICENSE file in the root directory of this source tree.
888
+ */
889
+ var Building = createLucideIcon("building", [
890
+ ["path", {
891
+ d: "M12 10h.01",
892
+ key: "1nrarc"
893
+ }],
894
+ ["path", {
895
+ d: "M12 14h.01",
896
+ key: "1etili"
897
+ }],
898
+ ["path", {
899
+ d: "M12 6h.01",
900
+ key: "1vi96p"
901
+ }],
902
+ ["path", {
903
+ d: "M16 10h.01",
904
+ key: "1m94wz"
905
+ }],
906
+ ["path", {
907
+ d: "M16 14h.01",
908
+ key: "1gbofw"
909
+ }],
910
+ ["path", {
911
+ d: "M16 6h.01",
912
+ key: "1x0f13"
913
+ }],
914
+ ["path", {
915
+ d: "M8 10h.01",
916
+ key: "19clt8"
917
+ }],
918
+ ["path", {
919
+ d: "M8 14h.01",
920
+ key: "6423bh"
921
+ }],
922
+ ["path", {
923
+ d: "M8 6h.01",
924
+ key: "1dz90k"
925
+ }],
926
+ ["path", {
927
+ d: "M9 22v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3",
928
+ key: "cabbwy"
929
+ }],
930
+ ["rect", {
931
+ x: "4",
932
+ y: "2",
933
+ width: "16",
934
+ height: "20",
935
+ rx: "2",
936
+ key: "1uxh74"
937
+ }]
938
+ ]);
939
+ /**
940
+ * @license lucide-react v0.576.0 - ISC
941
+ *
942
+ * This source code is licensed under the ISC license.
943
+ * See the LICENSE file in the root directory of this source tree.
944
+ */
738
945
  var Bus = createLucideIcon("bus", [
739
946
  ["path", {
740
947
  d: "M8 6v6",
@@ -811,6 +1018,34 @@ var Cable = createLucideIcon("cable", [
811
1018
  * This source code is licensed under the ISC license.
812
1019
  * See the LICENSE file in the root directory of this source tree.
813
1020
  */
1021
+ var Calendar = createLucideIcon("calendar", [
1022
+ ["path", {
1023
+ d: "M8 2v4",
1024
+ key: "1cmpym"
1025
+ }],
1026
+ ["path", {
1027
+ d: "M16 2v4",
1028
+ key: "4m81vk"
1029
+ }],
1030
+ ["rect", {
1031
+ width: "18",
1032
+ height: "18",
1033
+ x: "3",
1034
+ y: "4",
1035
+ rx: "2",
1036
+ key: "1hopcy"
1037
+ }],
1038
+ ["path", {
1039
+ d: "M3 10h18",
1040
+ key: "8toen8"
1041
+ }]
1042
+ ]);
1043
+ /**
1044
+ * @license lucide-react v0.576.0 - ISC
1045
+ *
1046
+ * This source code is licensed under the ISC license.
1047
+ * See the LICENSE file in the root directory of this source tree.
1048
+ */
814
1049
  var Camera = createLucideIcon("camera", [["path", {
815
1050
  d: "M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z",
816
1051
  key: "18u6gg"
@@ -1054,6 +1289,21 @@ var CircleDot = createLucideIcon("circle-dot", [["circle", {
1054
1289
  * This source code is licensed under the ISC license.
1055
1290
  * See the LICENSE file in the root directory of this source tree.
1056
1291
  */
1292
+ var CircleParking = createLucideIcon("circle-parking", [["circle", {
1293
+ cx: "12",
1294
+ cy: "12",
1295
+ r: "10",
1296
+ key: "1mglay"
1297
+ }], ["path", {
1298
+ d: "M9 17V7h4a3 3 0 0 1 0 6H9",
1299
+ key: "1dfk2c"
1300
+ }]]);
1301
+ /**
1302
+ * @license lucide-react v0.576.0 - ISC
1303
+ *
1304
+ * This source code is licensed under the ISC license.
1305
+ * See the LICENSE file in the root directory of this source tree.
1306
+ */
1057
1307
  var CirclePause = createLucideIcon("circle-pause", [
1058
1308
  ["circle", {
1059
1309
  cx: "12",
@@ -1409,6 +1659,30 @@ var Cog = createLucideIcon("cog", [
1409
1659
  * This source code is licensed under the ISC license.
1410
1660
  * See the LICENSE file in the root directory of this source tree.
1411
1661
  */
1662
+ var CookingPot = createLucideIcon("cooking-pot", [
1663
+ ["path", {
1664
+ d: "M2 12h20",
1665
+ key: "9i4pu4"
1666
+ }],
1667
+ ["path", {
1668
+ d: "M20 12v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8",
1669
+ key: "u0tga0"
1670
+ }],
1671
+ ["path", {
1672
+ d: "m4 8 16-4",
1673
+ key: "16g0ng"
1674
+ }],
1675
+ ["path", {
1676
+ d: "m8.86 6.78-.45-1.81a2 2 0 0 1 1.45-2.43l1.94-.48a2 2 0 0 1 2.43 1.46l.45 1.8",
1677
+ key: "12cejc"
1678
+ }]
1679
+ ]);
1680
+ /**
1681
+ * @license lucide-react v0.576.0 - ISC
1682
+ *
1683
+ * This source code is licensed under the ISC license.
1684
+ * See the LICENSE file in the root directory of this source tree.
1685
+ */
1412
1686
  var CopyPlus = createLucideIcon("copy-plus", [
1413
1687
  ["line", {
1414
1688
  x1: "15",
@@ -1695,6 +1969,38 @@ var Download = createLucideIcon("download", [
1695
1969
  * This source code is licensed under the ISC license.
1696
1970
  * See the LICENSE file in the root directory of this source tree.
1697
1971
  */
1972
+ var Drill = createLucideIcon("drill", [
1973
+ ["path", {
1974
+ d: "M10 18a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H5a3 3 0 0 1-3-3 1 1 0 0 1 1-1z",
1975
+ key: "ioqxb1"
1976
+ }],
1977
+ ["path", {
1978
+ d: "M13 10H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1l-.81 3.242a1 1 0 0 1-.97.758H8",
1979
+ key: "1rs59n"
1980
+ }],
1981
+ ["path", {
1982
+ d: "M14 4h3a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-3",
1983
+ key: "105ega"
1984
+ }],
1985
+ ["path", {
1986
+ d: "M18 6h4",
1987
+ key: "66u95g"
1988
+ }],
1989
+ ["path", {
1990
+ d: "m5 10-2 8",
1991
+ key: "xt2lic"
1992
+ }],
1993
+ ["path", {
1994
+ d: "m7 18 2-8",
1995
+ key: "1bzku2"
1996
+ }]
1997
+ ]);
1998
+ /**
1999
+ * @license lucide-react v0.576.0 - ISC
2000
+ *
2001
+ * This source code is licensed under the ISC license.
2002
+ * See the LICENSE file in the root directory of this source tree.
2003
+ */
1698
2004
  var Droplet = createLucideIcon("droplet", [["path", {
1699
2005
  d: "M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z",
1700
2006
  key: "c7niix"
@@ -1718,6 +2024,34 @@ var Droplets = createLucideIcon("droplets", [["path", {
1718
2024
  * This source code is licensed under the ISC license.
1719
2025
  * See the LICENSE file in the root directory of this source tree.
1720
2026
  */
2027
+ var Dumbbell = createLucideIcon("dumbbell", [
2028
+ ["path", {
2029
+ d: "M17.596 12.768a2 2 0 1 0 2.829-2.829l-1.768-1.767a2 2 0 0 0 2.828-2.829l-2.828-2.828a2 2 0 0 0-2.829 2.828l-1.767-1.768a2 2 0 1 0-2.829 2.829z",
2030
+ key: "9m4mmf"
2031
+ }],
2032
+ ["path", {
2033
+ d: "m2.5 21.5 1.4-1.4",
2034
+ key: "17g3f0"
2035
+ }],
2036
+ ["path", {
2037
+ d: "m20.1 3.9 1.4-1.4",
2038
+ key: "1qn309"
2039
+ }],
2040
+ ["path", {
2041
+ d: "M5.343 21.485a2 2 0 1 0 2.829-2.828l1.767 1.768a2 2 0 1 0 2.829-2.829l-6.364-6.364a2 2 0 1 0-2.829 2.829l1.768 1.767a2 2 0 0 0-2.828 2.829z",
2042
+ key: "1t2c92"
2043
+ }],
2044
+ ["path", {
2045
+ d: "m9.6 14.4 4.8-4.8",
2046
+ key: "6umqxw"
2047
+ }]
2048
+ ]);
2049
+ /**
2050
+ * @license lucide-react v0.576.0 - ISC
2051
+ *
2052
+ * This source code is licensed under the ISC license.
2053
+ * See the LICENSE file in the root directory of this source tree.
2054
+ */
1721
2055
  var EllipsisVertical = createLucideIcon("ellipsis-vertical", [
1722
2056
  ["circle", {
1723
2057
  cx: "12",
@@ -1836,6 +2170,42 @@ var Feather = createLucideIcon("feather", [
1836
2170
  * This source code is licensed under the ISC license.
1837
2171
  * See the LICENSE file in the root directory of this source tree.
1838
2172
  */
2173
+ var Fence = createLucideIcon("fence", [
2174
+ ["path", {
2175
+ d: "M4 3 2 5v15c0 .6.4 1 1 1h2c.6 0 1-.4 1-1V5Z",
2176
+ key: "1n2rgs"
2177
+ }],
2178
+ ["path", {
2179
+ d: "M6 8h4",
2180
+ key: "utf9t1"
2181
+ }],
2182
+ ["path", {
2183
+ d: "M6 18h4",
2184
+ key: "12yh4b"
2185
+ }],
2186
+ ["path", {
2187
+ d: "m12 3-2 2v15c0 .6.4 1 1 1h2c.6 0 1-.4 1-1V5Z",
2188
+ key: "3ha7mj"
2189
+ }],
2190
+ ["path", {
2191
+ d: "M14 8h4",
2192
+ key: "1r8wg2"
2193
+ }],
2194
+ ["path", {
2195
+ d: "M14 18h4",
2196
+ key: "1t3kbu"
2197
+ }],
2198
+ ["path", {
2199
+ d: "m20 3-2 2v15c0 .6.4 1 1 1h2c.6 0 1-.4 1-1V5Z",
2200
+ key: "dfd4e2"
2201
+ }]
2202
+ ]);
2203
+ /**
2204
+ * @license lucide-react v0.576.0 - ISC
2205
+ *
2206
+ * This source code is licensed under the ISC license.
2207
+ * See the LICENSE file in the root directory of this source tree.
2208
+ */
1839
2209
  var Film = createLucideIcon("film", [
1840
2210
  ["rect", {
1841
2211
  width: "18",
@@ -1958,6 +2328,56 @@ var FlaskConical = createLucideIcon("flask-conical", [
1958
2328
  * This source code is licensed under the ISC license.
1959
2329
  * See the LICENSE file in the root directory of this source tree.
1960
2330
  */
2331
+ var Flower = createLucideIcon("flower", [
2332
+ ["circle", {
2333
+ cx: "12",
2334
+ cy: "12",
2335
+ r: "3",
2336
+ key: "1v7zrd"
2337
+ }],
2338
+ ["path", {
2339
+ d: "M12 16.5A4.5 4.5 0 1 1 7.5 12 4.5 4.5 0 1 1 12 7.5a4.5 4.5 0 1 1 4.5 4.5 4.5 4.5 0 1 1-4.5 4.5",
2340
+ key: "14wa3c"
2341
+ }],
2342
+ ["path", {
2343
+ d: "M12 7.5V9",
2344
+ key: "1oy5b0"
2345
+ }],
2346
+ ["path", {
2347
+ d: "M7.5 12H9",
2348
+ key: "eltsq1"
2349
+ }],
2350
+ ["path", {
2351
+ d: "M16.5 12H15",
2352
+ key: "vk5kw4"
2353
+ }],
2354
+ ["path", {
2355
+ d: "M12 16.5V15",
2356
+ key: "k7eayi"
2357
+ }],
2358
+ ["path", {
2359
+ d: "m8 8 1.88 1.88",
2360
+ key: "nxy4qf"
2361
+ }],
2362
+ ["path", {
2363
+ d: "M14.12 9.88 16 8",
2364
+ key: "1lst6k"
2365
+ }],
2366
+ ["path", {
2367
+ d: "m8 16 1.88-1.88",
2368
+ key: "h2eex1"
2369
+ }],
2370
+ ["path", {
2371
+ d: "M14.12 14.12 16 16",
2372
+ key: "uqkrx3"
2373
+ }]
2374
+ ]);
2375
+ /**
2376
+ * @license lucide-react v0.576.0 - ISC
2377
+ *
2378
+ * This source code is licensed under the ISC license.
2379
+ * See the LICENSE file in the root directory of this source tree.
2380
+ */
1961
2381
  var Footprints = createLucideIcon("footprints", [
1962
2382
  ["path", {
1963
2383
  d: "M4 16v-2.38C4 11.5 2.97 10.5 3 8c.03-2.72 1.49-6 4.5-6C9.37 2 10 3.8 10 5.5c0 3.11-2 5.66-2 8.68V16a2 2 0 1 1-4 0Z",
@@ -2217,6 +2637,77 @@ var Hash = createLucideIcon("hash", [
2217
2637
  * This source code is licensed under the ISC license.
2218
2638
  * See the LICENSE file in the root directory of this source tree.
2219
2639
  */
2640
+ var HeartPulse = createLucideIcon("heart-pulse", [["path", {
2641
+ d: "M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5",
2642
+ key: "mvr1a0"
2643
+ }], ["path", {
2644
+ d: "M3.22 13H9.5l.5-1 2 4.5 2-7 1.5 3.5h5.27",
2645
+ key: "auskq0"
2646
+ }]]);
2647
+ /**
2648
+ * @license lucide-react v0.576.0 - ISC
2649
+ *
2650
+ * This source code is licensed under the ISC license.
2651
+ * See the LICENSE file in the root directory of this source tree.
2652
+ */
2653
+ var Heart = createLucideIcon("heart", [["path", {
2654
+ d: "M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5",
2655
+ key: "mvr1a0"
2656
+ }]]);
2657
+ /**
2658
+ * @license lucide-react v0.576.0 - ISC
2659
+ *
2660
+ * This source code is licensed under the ISC license.
2661
+ * See the LICENSE file in the root directory of this source tree.
2662
+ */
2663
+ var Heater = createLucideIcon("heater", [
2664
+ ["path", {
2665
+ d: "M11 8c2-3-2-3 0-6",
2666
+ key: "1ldv5m"
2667
+ }],
2668
+ ["path", {
2669
+ d: "M15.5 8c2-3-2-3 0-6",
2670
+ key: "1otqoz"
2671
+ }],
2672
+ ["path", {
2673
+ d: "M6 10h.01",
2674
+ key: "1lbq93"
2675
+ }],
2676
+ ["path", {
2677
+ d: "M6 14h.01",
2678
+ key: "zudwn7"
2679
+ }],
2680
+ ["path", {
2681
+ d: "M10 16v-4",
2682
+ key: "1c25yv"
2683
+ }],
2684
+ ["path", {
2685
+ d: "M14 16v-4",
2686
+ key: "1dkbt8"
2687
+ }],
2688
+ ["path", {
2689
+ d: "M18 16v-4",
2690
+ key: "1yg9me"
2691
+ }],
2692
+ ["path", {
2693
+ d: "M20 6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h3",
2694
+ key: "1ubg90"
2695
+ }],
2696
+ ["path", {
2697
+ d: "M5 20v2",
2698
+ key: "1abpe8"
2699
+ }],
2700
+ ["path", {
2701
+ d: "M19 20v2",
2702
+ key: "kqn6ft"
2703
+ }]
2704
+ ]);
2705
+ /**
2706
+ * @license lucide-react v0.576.0 - ISC
2707
+ *
2708
+ * This source code is licensed under the ISC license.
2709
+ * See the LICENSE file in the root directory of this source tree.
2710
+ */
2220
2711
  var House = createLucideIcon("house", [["path", {
2221
2712
  d: "M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",
2222
2713
  key: "5wwlr5"
@@ -2333,6 +2824,141 @@ var Info = createLucideIcon("info", [
2333
2824
  * This source code is licensed under the ISC license.
2334
2825
  * See the LICENSE file in the root directory of this source tree.
2335
2826
  */
2827
+ var KeyRound = createLucideIcon("key-round", [["path", {
2828
+ d: "M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",
2829
+ key: "1s6t7t"
2830
+ }], ["circle", {
2831
+ cx: "16.5",
2832
+ cy: "7.5",
2833
+ r: ".5",
2834
+ fill: "currentColor",
2835
+ key: "w0ekpg"
2836
+ }]]);
2837
+ /**
2838
+ * @license lucide-react v0.576.0 - ISC
2839
+ *
2840
+ * This source code is licensed under the ISC license.
2841
+ * See the LICENSE file in the root directory of this source tree.
2842
+ */
2843
+ var Key = createLucideIcon("key", [
2844
+ ["path", {
2845
+ d: "m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4",
2846
+ key: "g0fldk"
2847
+ }],
2848
+ ["path", {
2849
+ d: "m21 2-9.6 9.6",
2850
+ key: "1j0ho8"
2851
+ }],
2852
+ ["circle", {
2853
+ cx: "7.5",
2854
+ cy: "15.5",
2855
+ r: "5.5",
2856
+ key: "yqb3hr"
2857
+ }]
2858
+ ]);
2859
+ /**
2860
+ * @license lucide-react v0.576.0 - ISC
2861
+ *
2862
+ * This source code is licensed under the ISC license.
2863
+ * See the LICENSE file in the root directory of this source tree.
2864
+ */
2865
+ var LampCeiling = createLucideIcon("lamp-ceiling", [
2866
+ ["path", {
2867
+ d: "M12 2v5",
2868
+ key: "nd4vlx"
2869
+ }],
2870
+ ["path", {
2871
+ d: "M14.829 15.998a3 3 0 1 1-5.658 0",
2872
+ key: "1pybiy"
2873
+ }],
2874
+ ["path", {
2875
+ d: "M20.92 14.606A1 1 0 0 1 20 16H4a1 1 0 0 1-.92-1.394l3-7A1 1 0 0 1 7 7h10a1 1 0 0 1 .92.606z",
2876
+ key: "ma1wor"
2877
+ }]
2878
+ ]);
2879
+ /**
2880
+ * @license lucide-react v0.576.0 - ISC
2881
+ *
2882
+ * This source code is licensed under the ISC license.
2883
+ * See the LICENSE file in the root directory of this source tree.
2884
+ */
2885
+ var LampDesk = createLucideIcon("lamp-desk", [
2886
+ ["path", {
2887
+ d: "M10.293 2.293a1 1 0 0 1 1.414 0l2.5 2.5 5.994 1.227a1 1 0 0 1 .506 1.687l-7 7a1 1 0 0 1-1.687-.506l-1.227-5.994-2.5-2.5a1 1 0 0 1 0-1.414z",
2888
+ key: "sb8slu"
2889
+ }],
2890
+ ["path", {
2891
+ d: "m14.207 4.793-3.414 3.414",
2892
+ key: "m2x3oj"
2893
+ }],
2894
+ ["path", {
2895
+ d: "M3 20a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z",
2896
+ key: "8b3myj"
2897
+ }],
2898
+ ["path", {
2899
+ d: "m9.086 6.5-4.793 4.793a1 1 0 0 0-.18 1.17L7 18",
2900
+ key: "43s6cu"
2901
+ }]
2902
+ ]);
2903
+ /**
2904
+ * @license lucide-react v0.576.0 - ISC
2905
+ *
2906
+ * This source code is licensed under the ISC license.
2907
+ * See the LICENSE file in the root directory of this source tree.
2908
+ */
2909
+ var LampFloor = createLucideIcon("lamp-floor", [
2910
+ ["path", {
2911
+ d: "M12 10v12",
2912
+ key: "6ubwww"
2913
+ }],
2914
+ ["path", {
2915
+ d: "M17.929 7.629A1 1 0 0 1 17 9H7a1 1 0 0 1-.928-1.371l2-5A1 1 0 0 1 9 2h6a1 1 0 0 1 .928.629z",
2916
+ key: "1o95gh"
2917
+ }],
2918
+ ["path", {
2919
+ d: "M9 22h6",
2920
+ key: "1rlq3v"
2921
+ }]
2922
+ ]);
2923
+ /**
2924
+ * @license lucide-react v0.576.0 - ISC
2925
+ *
2926
+ * This source code is licensed under the ISC license.
2927
+ * See the LICENSE file in the root directory of this source tree.
2928
+ */
2929
+ var Lamp = createLucideIcon("lamp", [
2930
+ ["path", {
2931
+ d: "M12 12v6",
2932
+ key: "3ahymv"
2933
+ }],
2934
+ ["path", {
2935
+ d: "M4.077 10.615A1 1 0 0 0 5 12h14a1 1 0 0 0 .923-1.385l-3.077-7.384A2 2 0 0 0 15 2H9a2 2 0 0 0-1.846 1.23Z",
2936
+ key: "1l7kg2"
2937
+ }],
2938
+ ["path", {
2939
+ d: "M8 20a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1z",
2940
+ key: "1mmzpi"
2941
+ }]
2942
+ ]);
2943
+ /**
2944
+ * @license lucide-react v0.576.0 - ISC
2945
+ *
2946
+ * This source code is licensed under the ISC license.
2947
+ * See the LICENSE file in the root directory of this source tree.
2948
+ */
2949
+ var Laptop = createLucideIcon("laptop", [["path", {
2950
+ d: "M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z",
2951
+ key: "1pdavp"
2952
+ }], ["path", {
2953
+ d: "M20.054 15.987H3.946",
2954
+ key: "14rxg9"
2955
+ }]]);
2956
+ /**
2957
+ * @license lucide-react v0.576.0 - ISC
2958
+ *
2959
+ * This source code is licensed under the ISC license.
2960
+ * See the LICENSE file in the root directory of this source tree.
2961
+ */
2336
2962
  var Laugh = createLucideIcon("laugh", [
2337
2963
  ["circle", {
2338
2964
  cx: "12",
@@ -2632,6 +3258,33 @@ var Mail = createLucideIcon("mail", [["path", {
2632
3258
  * This source code is licensed under the ISC license.
2633
3259
  * See the LICENSE file in the root directory of this source tree.
2634
3260
  */
3261
+ var Mailbox = createLucideIcon("mailbox", [
3262
+ ["path", {
3263
+ d: "M22 17a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9.5C2 7 4 5 6.5 5H18c2.2 0 4 1.8 4 4v8Z",
3264
+ key: "1lbycx"
3265
+ }],
3266
+ ["polyline", {
3267
+ points: "15,9 18,9 18,11",
3268
+ key: "1pm9c0"
3269
+ }],
3270
+ ["path", {
3271
+ d: "M6.5 5C9 5 11 7 11 9.5V17a2 2 0 0 1-2 2",
3272
+ key: "15i455"
3273
+ }],
3274
+ ["line", {
3275
+ x1: "6",
3276
+ x2: "7",
3277
+ y1: "10",
3278
+ y2: "10",
3279
+ key: "1e2scm"
3280
+ }]
3281
+ ]);
3282
+ /**
3283
+ * @license lucide-react v0.576.0 - ISC
3284
+ *
3285
+ * This source code is licensed under the ISC license.
3286
+ * See the LICENSE file in the root directory of this source tree.
3287
+ */
2635
3288
  var MapPin = createLucideIcon("map-pin", [["path", {
2636
3289
  d: "M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0",
2637
3290
  key: "1r0f0z"
@@ -2721,6 +3374,38 @@ var MessageSquare = createLucideIcon("message-square", [["path", {
2721
3374
  * This source code is licensed under the ISC license.
2722
3375
  * See the LICENSE file in the root directory of this source tree.
2723
3376
  */
3377
+ var MicOff = createLucideIcon("mic-off", [
3378
+ ["path", {
3379
+ d: "M12 19v3",
3380
+ key: "npa21l"
3381
+ }],
3382
+ ["path", {
3383
+ d: "M15 9.34V5a3 3 0 0 0-5.68-1.33",
3384
+ key: "1gzdoj"
3385
+ }],
3386
+ ["path", {
3387
+ d: "M16.95 16.95A7 7 0 0 1 5 12v-2",
3388
+ key: "cqa7eg"
3389
+ }],
3390
+ ["path", {
3391
+ d: "M18.89 13.23A7 7 0 0 0 19 12v-2",
3392
+ key: "16hl24"
3393
+ }],
3394
+ ["path", {
3395
+ d: "m2 2 20 20",
3396
+ key: "1ooewy"
3397
+ }],
3398
+ ["path", {
3399
+ d: "M9 9v3a3 3 0 0 0 5.12 2.12",
3400
+ key: "r2i35w"
3401
+ }]
3402
+ ]);
3403
+ /**
3404
+ * @license lucide-react v0.576.0 - ISC
3405
+ *
3406
+ * This source code is licensed under the ISC license.
3407
+ * See the LICENSE file in the root directory of this source tree.
3408
+ */
2724
3409
  var Mic = createLucideIcon("mic", [
2725
3410
  ["path", {
2726
3411
  d: "M12 19v3",
@@ -2745,6 +3430,42 @@ var Mic = createLucideIcon("mic", [
2745
3430
  * This source code is licensed under the ISC license.
2746
3431
  * See the LICENSE file in the root directory of this source tree.
2747
3432
  */
3433
+ var Microwave = createLucideIcon("microwave", [
3434
+ ["rect", {
3435
+ width: "20",
3436
+ height: "15",
3437
+ x: "2",
3438
+ y: "4",
3439
+ rx: "2",
3440
+ key: "2no95f"
3441
+ }],
3442
+ ["rect", {
3443
+ width: "8",
3444
+ height: "7",
3445
+ x: "6",
3446
+ y: "8",
3447
+ rx: "1",
3448
+ key: "zh9wx"
3449
+ }],
3450
+ ["path", {
3451
+ d: "M18 8v7",
3452
+ key: "o5zi4n"
3453
+ }],
3454
+ ["path", {
3455
+ d: "M6 19v2",
3456
+ key: "1loha6"
3457
+ }],
3458
+ ["path", {
3459
+ d: "M18 19v2",
3460
+ key: "1dawf0"
3461
+ }]
3462
+ ]);
3463
+ /**
3464
+ * @license lucide-react v0.576.0 - ISC
3465
+ *
3466
+ * This source code is licensed under the ISC license.
3467
+ * See the LICENSE file in the root directory of this source tree.
3468
+ */
2748
3469
  var Minimize2 = createLucideIcon("minimize-2", [
2749
3470
  ["path", {
2750
3471
  d: "m14 10 7-7",
@@ -2807,6 +3528,36 @@ var MonitorPlay = createLucideIcon("monitor-play", [
2807
3528
  * This source code is licensed under the ISC license.
2808
3529
  * See the LICENSE file in the root directory of this source tree.
2809
3530
  */
3531
+ var Monitor = createLucideIcon("monitor", [
3532
+ ["rect", {
3533
+ width: "20",
3534
+ height: "14",
3535
+ x: "2",
3536
+ y: "3",
3537
+ rx: "2",
3538
+ key: "48i651"
3539
+ }],
3540
+ ["line", {
3541
+ x1: "8",
3542
+ x2: "16",
3543
+ y1: "21",
3544
+ y2: "21",
3545
+ key: "1svkeh"
3546
+ }],
3547
+ ["line", {
3548
+ x1: "12",
3549
+ x2: "12",
3550
+ y1: "17",
3551
+ y2: "21",
3552
+ key: "vw1qmm"
3553
+ }]
3554
+ ]);
3555
+ /**
3556
+ * @license lucide-react v0.576.0 - ISC
3557
+ *
3558
+ * This source code is licensed under the ISC license.
3559
+ * See the LICENSE file in the root directory of this source tree.
3560
+ */
2810
3561
  var Moon = createLucideIcon("moon", [["path", {
2811
3562
  d: "M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",
2812
3563
  key: "kfwtm"
@@ -2817,6 +3568,16 @@ var Moon = createLucideIcon("moon", [["path", {
2817
3568
  * This source code is licensed under the ISC license.
2818
3569
  * See the LICENSE file in the root directory of this source tree.
2819
3570
  */
3571
+ var Mountain = createLucideIcon("mountain", [["path", {
3572
+ d: "m8 3 4 8 5-5 5 15H2L8 3z",
3573
+ key: "otkl63"
3574
+ }]]);
3575
+ /**
3576
+ * @license lucide-react v0.576.0 - ISC
3577
+ *
3578
+ * This source code is licensed under the ISC license.
3579
+ * See the LICENSE file in the root directory of this source tree.
3580
+ */
2820
3581
  var MousePointerClick = createLucideIcon("mouse-pointer-click", [
2821
3582
  ["path", {
2822
3583
  d: "M14 4.1 12 6",
@@ -3079,6 +3840,32 @@ var Pencil = createLucideIcon("pencil", [["path", {
3079
3840
  * This source code is licensed under the ISC license.
3080
3841
  * See the LICENSE file in the root directory of this source tree.
3081
3842
  */
3843
+ var PersonStanding = createLucideIcon("person-standing", [
3844
+ ["circle", {
3845
+ cx: "12",
3846
+ cy: "5",
3847
+ r: "1",
3848
+ key: "gxeob9"
3849
+ }],
3850
+ ["path", {
3851
+ d: "m9 20 3-6 3 6",
3852
+ key: "se2kox"
3853
+ }],
3854
+ ["path", {
3855
+ d: "m6 8 6 2 6-2",
3856
+ key: "4o3us4"
3857
+ }],
3858
+ ["path", {
3859
+ d: "M12 10v4",
3860
+ key: "1kjpxc"
3861
+ }]
3862
+ ]);
3863
+ /**
3864
+ * @license lucide-react v0.576.0 - ISC
3865
+ *
3866
+ * This source code is licensed under the ISC license.
3867
+ * See the LICENSE file in the root directory of this source tree.
3868
+ */
3082
3869
  var Phone = createLucideIcon("phone", [["path", {
3083
3870
  d: "M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384",
3084
3871
  key: "9njp5v"
@@ -3129,6 +3916,34 @@ var Play = createLucideIcon("play", [["path", {
3129
3916
  * This source code is licensed under the ISC license.
3130
3917
  * See the LICENSE file in the root directory of this source tree.
3131
3918
  */
3919
+ var PlugZap = createLucideIcon("plug-zap", [
3920
+ ["path", {
3921
+ d: "M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z",
3922
+ key: "goz73y"
3923
+ }],
3924
+ ["path", {
3925
+ d: "m2 22 3-3",
3926
+ key: "19mgm9"
3927
+ }],
3928
+ ["path", {
3929
+ d: "M7.5 13.5 10 11",
3930
+ key: "7xgeeb"
3931
+ }],
3932
+ ["path", {
3933
+ d: "M10.5 16.5 13 14",
3934
+ key: "10btkg"
3935
+ }],
3936
+ ["path", {
3937
+ d: "m18 3-4 4h6l-4 4",
3938
+ key: "16psg9"
3939
+ }]
3940
+ ]);
3941
+ /**
3942
+ * @license lucide-react v0.576.0 - ISC
3943
+ *
3944
+ * This source code is licensed under the ISC license.
3945
+ * See the LICENSE file in the root directory of this source tree.
3946
+ */
3132
3947
  var Plus = createLucideIcon("plus", [["path", {
3133
3948
  d: "M5 12h14",
3134
3949
  key: "1ays0h"
@@ -3203,6 +4018,64 @@ var Power = createLucideIcon("power", [["path", {
3203
4018
  * This source code is licensed under the ISC license.
3204
4019
  * See the LICENSE file in the root directory of this source tree.
3205
4020
  */
4021
+ var Printer = createLucideIcon("printer", [
4022
+ ["path", {
4023
+ d: "M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2",
4024
+ key: "143wyd"
4025
+ }],
4026
+ ["path", {
4027
+ d: "M6 9V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6",
4028
+ key: "1itne7"
4029
+ }],
4030
+ ["rect", {
4031
+ x: "6",
4032
+ y: "14",
4033
+ width: "12",
4034
+ height: "8",
4035
+ rx: "1",
4036
+ key: "1ue0tg"
4037
+ }]
4038
+ ]);
4039
+ /**
4040
+ * @license lucide-react v0.576.0 - ISC
4041
+ *
4042
+ * This source code is licensed under the ISC license.
4043
+ * See the LICENSE file in the root directory of this source tree.
4044
+ */
4045
+ var Projector = createLucideIcon("projector", [
4046
+ ["path", {
4047
+ d: "M5 7 3 5",
4048
+ key: "1yys58"
4049
+ }],
4050
+ ["path", {
4051
+ d: "M9 6V3",
4052
+ key: "1ptz9u"
4053
+ }],
4054
+ ["path", {
4055
+ d: "m13 7 2-2",
4056
+ key: "1w3vmq"
4057
+ }],
4058
+ ["circle", {
4059
+ cx: "9",
4060
+ cy: "13",
4061
+ r: "3",
4062
+ key: "1mma13"
4063
+ }],
4064
+ ["path", {
4065
+ d: "M11.83 12H20a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h2.17",
4066
+ key: "2frwzc"
4067
+ }],
4068
+ ["path", {
4069
+ d: "M16 16h2",
4070
+ key: "dnq2od"
4071
+ }]
4072
+ ]);
4073
+ /**
4074
+ * @license lucide-react v0.576.0 - ISC
4075
+ *
4076
+ * This source code is licensed under the ISC license.
4077
+ * See the LICENSE file in the root directory of this source tree.
4078
+ */
3206
4079
  var QrCode$1 = createLucideIcon("qr-code", [
3207
4080
  ["rect", {
3208
4081
  width: "5",
@@ -3405,6 +4278,26 @@ var RefreshCw = createLucideIcon("refresh-cw", [
3405
4278
  * This source code is licensed under the ISC license.
3406
4279
  * See the LICENSE file in the root directory of this source tree.
3407
4280
  */
4281
+ var Refrigerator = createLucideIcon("refrigerator", [
4282
+ ["path", {
4283
+ d: "M5 6a4 4 0 0 1 4-4h6a4 4 0 0 1 4 4v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6Z",
4284
+ key: "fpq118"
4285
+ }],
4286
+ ["path", {
4287
+ d: "M5 10h14",
4288
+ key: "elsbfy"
4289
+ }],
4290
+ ["path", {
4291
+ d: "M15 7v6",
4292
+ key: "1nx30x"
4293
+ }]
4294
+ ]);
4295
+ /**
4296
+ * @license lucide-react v0.576.0 - ISC
4297
+ *
4298
+ * This source code is licensed under the ISC license.
4299
+ * See the LICENSE file in the root directory of this source tree.
4300
+ */
3408
4301
  var RotateCcw = createLucideIcon("rotate-ccw", [["path", {
3409
4302
  d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
3410
4303
  key: "1357e3"
@@ -3431,6 +4324,66 @@ var RotateCw = createLucideIcon("rotate-cw", [["path", {
3431
4324
  * This source code is licensed under the ISC license.
3432
4325
  * See the LICENSE file in the root directory of this source tree.
3433
4326
  */
4327
+ var Route = createLucideIcon("route", [
4328
+ ["circle", {
4329
+ cx: "6",
4330
+ cy: "19",
4331
+ r: "3",
4332
+ key: "1kj8tv"
4333
+ }],
4334
+ ["path", {
4335
+ d: "M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15",
4336
+ key: "1d8sl"
4337
+ }],
4338
+ ["circle", {
4339
+ cx: "18",
4340
+ cy: "5",
4341
+ r: "3",
4342
+ key: "gq8acd"
4343
+ }]
4344
+ ]);
4345
+ /**
4346
+ * @license lucide-react v0.576.0 - ISC
4347
+ *
4348
+ * This source code is licensed under the ISC license.
4349
+ * See the LICENSE file in the root directory of this source tree.
4350
+ */
4351
+ var Router = createLucideIcon("router", [
4352
+ ["rect", {
4353
+ width: "20",
4354
+ height: "8",
4355
+ x: "2",
4356
+ y: "14",
4357
+ rx: "2",
4358
+ key: "w68u3i"
4359
+ }],
4360
+ ["path", {
4361
+ d: "M6.01 18H6",
4362
+ key: "19vcac"
4363
+ }],
4364
+ ["path", {
4365
+ d: "M10.01 18H10",
4366
+ key: "uamcmx"
4367
+ }],
4368
+ ["path", {
4369
+ d: "M15 10v4",
4370
+ key: "qjz1xs"
4371
+ }],
4372
+ ["path", {
4373
+ d: "M17.84 7.17a4 4 0 0 0-5.66 0",
4374
+ key: "1rif40"
4375
+ }],
4376
+ ["path", {
4377
+ d: "M20.66 4.34a8 8 0 0 0-11.31 0",
4378
+ key: "6a5xfq"
4379
+ }]
4380
+ ]);
4381
+ /**
4382
+ * @license lucide-react v0.576.0 - ISC
4383
+ *
4384
+ * This source code is licensed under the ISC license.
4385
+ * See the LICENSE file in the root directory of this source tree.
4386
+ */
3434
4387
  var Sailboat = createLucideIcon("sailboat", [
3435
4388
  ["path", {
3436
4389
  d: "M10 2v15",
@@ -3904,6 +4857,64 @@ var Snowflake = createLucideIcon("snowflake", [
3904
4857
  * This source code is licensed under the ISC license.
3905
4858
  * See the LICENSE file in the root directory of this source tree.
3906
4859
  */
4860
+ var Sofa = createLucideIcon("sofa", [
4861
+ ["path", {
4862
+ d: "M20 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v3",
4863
+ key: "1dgpiv"
4864
+ }],
4865
+ ["path", {
4866
+ d: "M2 16a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5a2 2 0 0 0-4 0v1.5a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5V11a2 2 0 0 0-4 0z",
4867
+ key: "xacw8m"
4868
+ }],
4869
+ ["path", {
4870
+ d: "M4 18v2",
4871
+ key: "jwo5n2"
4872
+ }],
4873
+ ["path", {
4874
+ d: "M20 18v2",
4875
+ key: "1ar1qi"
4876
+ }],
4877
+ ["path", {
4878
+ d: "M12 4v9",
4879
+ key: "oqhhn3"
4880
+ }]
4881
+ ]);
4882
+ /**
4883
+ * @license lucide-react v0.576.0 - ISC
4884
+ *
4885
+ * This source code is licensed under the ISC license.
4886
+ * See the LICENSE file in the root directory of this source tree.
4887
+ */
4888
+ var Speaker = createLucideIcon("speaker", [
4889
+ ["rect", {
4890
+ width: "16",
4891
+ height: "20",
4892
+ x: "4",
4893
+ y: "2",
4894
+ rx: "2",
4895
+ key: "1nb95v"
4896
+ }],
4897
+ ["path", {
4898
+ d: "M12 6h.01",
4899
+ key: "1vi96p"
4900
+ }],
4901
+ ["circle", {
4902
+ cx: "12",
4903
+ cy: "14",
4904
+ r: "4",
4905
+ key: "1jruaj"
4906
+ }],
4907
+ ["path", {
4908
+ d: "M12 14h.01",
4909
+ key: "1etili"
4910
+ }]
4911
+ ]);
4912
+ /**
4913
+ * @license lucide-react v0.576.0 - ISC
4914
+ *
4915
+ * This source code is licensed under the ISC license.
4916
+ * See the LICENSE file in the root directory of this source tree.
4917
+ */
3907
4918
  var Sparkles = createLucideIcon("sparkles", [
3908
4919
  ["path", {
3909
4920
  d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
@@ -3974,6 +4985,26 @@ var Star = createLucideIcon("star", [["path", {
3974
4985
  * This source code is licensed under the ISC license.
3975
4986
  * See the LICENSE file in the root directory of this source tree.
3976
4987
  */
4988
+ var Store = createLucideIcon("store", [
4989
+ ["path", {
4990
+ d: "M15 21v-5a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v5",
4991
+ key: "slp6dd"
4992
+ }],
4993
+ ["path", {
4994
+ d: "M17.774 10.31a1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.451 0 1.12 1.12 0 0 0-1.548 0 2.5 2.5 0 0 1-3.452 0 1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.77-3.248l2.889-4.184A2 2 0 0 1 7 2h10a2 2 0 0 1 1.653.873l2.895 4.192a2.5 2.5 0 0 1-3.774 3.244",
4995
+ key: "o0xfot"
4996
+ }],
4997
+ ["path", {
4998
+ d: "M4 10.95V19a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8.05",
4999
+ key: "wn3emo"
5000
+ }]
5001
+ ]);
5002
+ /**
5003
+ * @license lucide-react v0.576.0 - ISC
5004
+ *
5005
+ * This source code is licensed under the ISC license.
5006
+ * See the LICENSE file in the root directory of this source tree.
5007
+ */
3977
5008
  var SunMedium = createLucideIcon("sun-medium", [
3978
5009
  ["circle", {
3979
5010
  cx: "12",
@@ -4106,6 +5137,27 @@ var Sunrise = createLucideIcon("sunrise", [
4106
5137
  * This source code is licensed under the ISC license.
4107
5138
  * See the LICENSE file in the root directory of this source tree.
4108
5139
  */
5140
+ var Tablet = createLucideIcon("tablet", [["rect", {
5141
+ width: "16",
5142
+ height: "20",
5143
+ x: "4",
5144
+ y: "2",
5145
+ rx: "2",
5146
+ ry: "2",
5147
+ key: "76otgf"
5148
+ }], ["line", {
5149
+ x1: "12",
5150
+ x2: "12.01",
5151
+ y1: "18",
5152
+ y2: "18",
5153
+ key: "1dp563"
5154
+ }]]);
5155
+ /**
5156
+ * @license lucide-react v0.576.0 - ISC
5157
+ *
5158
+ * This source code is licensed under the ISC license.
5159
+ * See the LICENSE file in the root directory of this source tree.
5160
+ */
4109
5161
  var Tag = createLucideIcon("tag", [["path", {
4110
5162
  d: "M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z",
4111
5163
  key: "vktsd0"
@@ -4148,6 +5200,46 @@ var Target = createLucideIcon("target", [
4148
5200
  * This source code is licensed under the ISC license.
4149
5201
  * See the LICENSE file in the root directory of this source tree.
4150
5202
  */
5203
+ var ThermometerSnowflake = createLucideIcon("thermometer-snowflake", [
5204
+ ["path", {
5205
+ d: "m10 20-1.25-2.5L6 18",
5206
+ key: "18frcb"
5207
+ }],
5208
+ ["path", {
5209
+ d: "M10 4 8.75 6.5 6 6",
5210
+ key: "7mghy3"
5211
+ }],
5212
+ ["path", {
5213
+ d: "M10.585 15H10",
5214
+ key: "4nqulp"
5215
+ }],
5216
+ ["path", {
5217
+ d: "M2 12h6.5L10 9",
5218
+ key: "kv9z4n"
5219
+ }],
5220
+ ["path", {
5221
+ d: "M20 14.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0z",
5222
+ key: "yu0u2z"
5223
+ }],
5224
+ ["path", {
5225
+ d: "m4 10 1.5 2L4 14",
5226
+ key: "k9enpj"
5227
+ }],
5228
+ ["path", {
5229
+ d: "m7 21 3-6-1.5-3",
5230
+ key: "j8hb9u"
5231
+ }],
5232
+ ["path", {
5233
+ d: "m7 3 3 6h2",
5234
+ key: "1bbqgq"
5235
+ }]
5236
+ ]);
5237
+ /**
5238
+ * @license lucide-react v0.576.0 - ISC
5239
+ *
5240
+ * This source code is licensed under the ISC license.
5241
+ * See the LICENSE file in the root directory of this source tree.
5242
+ */
4151
5243
  var Thermometer = createLucideIcon("thermometer", [["path", {
4152
5244
  d: "M14 4v10.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0Z",
4153
5245
  key: "17jzev"
@@ -4158,6 +5250,66 @@ var Thermometer = createLucideIcon("thermometer", [["path", {
4158
5250
  * This source code is licensed under the ISC license.
4159
5251
  * See the LICENSE file in the root directory of this source tree.
4160
5252
  */
5253
+ var ThermometerSun = createLucideIcon("thermometer-sun", [
5254
+ ["path", {
5255
+ d: "M12 2v2",
5256
+ key: "tus03m"
5257
+ }],
5258
+ ["path", {
5259
+ d: "M12 8a4 4 0 0 0-1.645 7.647",
5260
+ key: "wz5p04"
5261
+ }],
5262
+ ["path", {
5263
+ d: "M2 12h2",
5264
+ key: "1t8f8n"
5265
+ }],
5266
+ ["path", {
5267
+ d: "M20 14.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0z",
5268
+ key: "yu0u2z"
5269
+ }],
5270
+ ["path", {
5271
+ d: "m4.93 4.93 1.41 1.41",
5272
+ key: "149t6j"
5273
+ }],
5274
+ ["path", {
5275
+ d: "m6.34 17.66-1.41 1.41",
5276
+ key: "1m8zz5"
5277
+ }]
5278
+ ]);
5279
+ /**
5280
+ * @license lucide-react v0.576.0 - ISC
5281
+ *
5282
+ * This source code is licensed under the ISC license.
5283
+ * See the LICENSE file in the root directory of this source tree.
5284
+ */
5285
+ var Timer = createLucideIcon("timer", [
5286
+ ["line", {
5287
+ x1: "10",
5288
+ x2: "14",
5289
+ y1: "2",
5290
+ y2: "2",
5291
+ key: "14vaq8"
5292
+ }],
5293
+ ["line", {
5294
+ x1: "12",
5295
+ x2: "15",
5296
+ y1: "14",
5297
+ y2: "11",
5298
+ key: "17fdiu"
5299
+ }],
5300
+ ["circle", {
5301
+ cx: "12",
5302
+ cy: "14",
5303
+ r: "8",
5304
+ key: "1e1u0o"
5305
+ }]
5306
+ ]);
5307
+ /**
5308
+ * @license lucide-react v0.576.0 - ISC
5309
+ *
5310
+ * This source code is licensed under the ISC license.
5311
+ * See the LICENSE file in the root directory of this source tree.
5312
+ */
4161
5313
  var ToggleLeft = createLucideIcon("toggle-left", [["circle", {
4162
5314
  cx: "9",
4163
5315
  cy: "12",
@@ -4304,6 +5456,43 @@ var Trash2 = createLucideIcon("trash-2", [
4304
5456
  * This source code is licensed under the ISC license.
4305
5457
  * See the LICENSE file in the root directory of this source tree.
4306
5458
  */
5459
+ var TreePine = createLucideIcon("tree-pine", [["path", {
5460
+ d: "m17 14 3 3.3a1 1 0 0 1-.7 1.7H4.7a1 1 0 0 1-.7-1.7L7 14h-.3a1 1 0 0 1-.7-1.7L9 9h-.2A1 1 0 0 1 8 7.3L12 3l4 4.3a1 1 0 0 1-.8 1.7H15l3 3.3a1 1 0 0 1-.7 1.7H17Z",
5461
+ key: "cpyugq"
5462
+ }], ["path", {
5463
+ d: "M12 22v-3",
5464
+ key: "kmzjlo"
5465
+ }]]);
5466
+ /**
5467
+ * @license lucide-react v0.576.0 - ISC
5468
+ *
5469
+ * This source code is licensed under the ISC license.
5470
+ * See the LICENSE file in the root directory of this source tree.
5471
+ */
5472
+ var Trees = createLucideIcon("trees", [
5473
+ ["path", {
5474
+ d: "M10 10v.2A3 3 0 0 1 8.9 16H5a3 3 0 0 1-1-5.8V10a3 3 0 0 1 6 0Z",
5475
+ key: "1l6gj6"
5476
+ }],
5477
+ ["path", {
5478
+ d: "M7 16v6",
5479
+ key: "1a82de"
5480
+ }],
5481
+ ["path", {
5482
+ d: "M13 19v3",
5483
+ key: "13sx9i"
5484
+ }],
5485
+ ["path", {
5486
+ d: "M12 19h8.3a1 1 0 0 0 .7-1.7L18 14h.3a1 1 0 0 0 .7-1.7L16 9h.2a1 1 0 0 0 .8-1.7L13 3l-1.4 1.5",
5487
+ key: "1sj9kv"
5488
+ }]
5489
+ ]);
5490
+ /**
5491
+ * @license lucide-react v0.576.0 - ISC
5492
+ *
5493
+ * This source code is licensed under the ISC license.
5494
+ * See the LICENSE file in the root directory of this source tree.
5495
+ */
4307
5496
  var TrendingUp = createLucideIcon("trending-up", [["path", {
4308
5497
  d: "M16 7h6v6",
4309
5498
  key: "box55l"
@@ -4382,6 +5571,23 @@ var Truck = createLucideIcon("truck", [
4382
5571
  * This source code is licensed under the ISC license.
4383
5572
  * See the LICENSE file in the root directory of this source tree.
4384
5573
  */
5574
+ var Tv = createLucideIcon("tv", [["path", {
5575
+ d: "m17 2-5 5-5-5",
5576
+ key: "16satq"
5577
+ }], ["rect", {
5578
+ width: "20",
5579
+ height: "15",
5580
+ x: "2",
5581
+ y: "7",
5582
+ rx: "2",
5583
+ key: "1e6viu"
5584
+ }]]);
5585
+ /**
5586
+ * @license lucide-react v0.576.0 - ISC
5587
+ *
5588
+ * This source code is licensed under the ISC license.
5589
+ * See the LICENSE file in the root directory of this source tree.
5590
+ */
4385
5591
  var Type = createLucideIcon("type", [
4386
5592
  ["path", {
4387
5593
  d: "M12 4v16",
@@ -4402,6 +5608,26 @@ var Type = createLucideIcon("type", [
4402
5608
  * This source code is licensed under the ISC license.
4403
5609
  * See the LICENSE file in the root directory of this source tree.
4404
5610
  */
5611
+ var Umbrella = createLucideIcon("umbrella", [
5612
+ ["path", {
5613
+ d: "M12 13v7a2 2 0 0 0 4 0",
5614
+ key: "rpgb42"
5615
+ }],
5616
+ ["path", {
5617
+ d: "M12 2v2",
5618
+ key: "tus03m"
5619
+ }],
5620
+ ["path", {
5621
+ d: "M20.992 13a1 1 0 0 0 .97-1.274 10.284 10.284 0 0 0-19.923 0A1 1 0 0 0 3 13z",
5622
+ key: "124nyo"
5623
+ }]
5624
+ ]);
5625
+ /**
5626
+ * @license lucide-react v0.576.0 - ISC
5627
+ *
5628
+ * This source code is licensed under the ISC license.
5629
+ * See the LICENSE file in the root directory of this source tree.
5630
+ */
4405
5631
  var Undo2 = createLucideIcon("undo-2", [["path", {
4406
5632
  d: "M9 14 4 9l5-5",
4407
5633
  key: "102s5s"
@@ -4532,6 +5758,26 @@ var UtensilsCrossed = createLucideIcon("utensils-crossed", [
4532
5758
  * This source code is licensed under the ISC license.
4533
5759
  * See the LICENSE file in the root directory of this source tree.
4534
5760
  */
5761
+ var Utensils = createLucideIcon("utensils", [
5762
+ ["path", {
5763
+ d: "M3 2v7c0 1.1.9 2 2 2h4a2 2 0 0 0 2-2V2",
5764
+ key: "cjf0a3"
5765
+ }],
5766
+ ["path", {
5767
+ d: "M7 2v20",
5768
+ key: "1473qp"
5769
+ }],
5770
+ ["path", {
5771
+ d: "M21 15V2a5 5 0 0 0-5 5v6c0 1.1.9 2 2 2h3Zm0 0v7",
5772
+ key: "j28e5"
5773
+ }]
5774
+ ]);
5775
+ /**
5776
+ * @license lucide-react v0.576.0 - ISC
5777
+ *
5778
+ * This source code is licensed under the ISC license.
5779
+ * See the LICENSE file in the root directory of this source tree.
5780
+ */
4535
5781
  var Vibrate = createLucideIcon("vibrate", [
4536
5782
  ["path", {
4537
5783
  d: "m2 8 2 2-2 2 2 2-2 2",
@@ -4556,6 +5802,43 @@ var Vibrate = createLucideIcon("vibrate", [
4556
5802
  * This source code is licensed under the ISC license.
4557
5803
  * See the LICENSE file in the root directory of this source tree.
4558
5804
  */
5805
+ var VideoOff = createLucideIcon("video-off", [
5806
+ ["path", {
5807
+ d: "M10.66 6H14a2 2 0 0 1 2 2v2.5l5.248-3.062A.5.5 0 0 1 22 7.87v8.196",
5808
+ key: "w8jjjt"
5809
+ }],
5810
+ ["path", {
5811
+ d: "M16 16a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2",
5812
+ key: "1xawa7"
5813
+ }],
5814
+ ["path", {
5815
+ d: "m2 2 20 20",
5816
+ key: "1ooewy"
5817
+ }]
5818
+ ]);
5819
+ /**
5820
+ * @license lucide-react v0.576.0 - ISC
5821
+ *
5822
+ * This source code is licensed under the ISC license.
5823
+ * See the LICENSE file in the root directory of this source tree.
5824
+ */
5825
+ var Video = createLucideIcon("video", [["path", {
5826
+ d: "m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5",
5827
+ key: "ftymec"
5828
+ }], ["rect", {
5829
+ x: "2",
5830
+ y: "6",
5831
+ width: "14",
5832
+ height: "12",
5833
+ rx: "2",
5834
+ key: "158x01"
5835
+ }]]);
5836
+ /**
5837
+ * @license lucide-react v0.576.0 - ISC
5838
+ *
5839
+ * This source code is licensed under the ISC license.
5840
+ * See the LICENSE file in the root directory of this source tree.
5841
+ */
4559
5842
  var Volume2 = createLucideIcon("volume-2", [
4560
5843
  ["path", {
4561
5844
  d: "M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",
@@ -4602,6 +5885,92 @@ var VolumeX = createLucideIcon("volume-x", [
4602
5885
  * This source code is licensed under the ISC license.
4603
5886
  * See the LICENSE file in the root directory of this source tree.
4604
5887
  */
5888
+ var Warehouse = createLucideIcon("warehouse", [
5889
+ ["path", {
5890
+ d: "M18 21V10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1v11",
5891
+ key: "pb2vm6"
5892
+ }],
5893
+ ["path", {
5894
+ d: "M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 1.132-1.803l7.95-3.974a2 2 0 0 1 1.837 0l7.948 3.974A2 2 0 0 1 22 8z",
5895
+ key: "doq5xv"
5896
+ }],
5897
+ ["path", {
5898
+ d: "M6 13h12",
5899
+ key: "yf64js"
5900
+ }],
5901
+ ["path", {
5902
+ d: "M6 17h12",
5903
+ key: "1jwigz"
5904
+ }]
5905
+ ]);
5906
+ /**
5907
+ * @license lucide-react v0.576.0 - ISC
5908
+ *
5909
+ * This source code is licensed under the ISC license.
5910
+ * See the LICENSE file in the root directory of this source tree.
5911
+ */
5912
+ var WashingMachine = createLucideIcon("washing-machine", [
5913
+ ["path", {
5914
+ d: "M3 6h3",
5915
+ key: "155dbl"
5916
+ }],
5917
+ ["path", {
5918
+ d: "M17 6h.01",
5919
+ key: "e2y6kg"
5920
+ }],
5921
+ ["rect", {
5922
+ width: "18",
5923
+ height: "20",
5924
+ x: "3",
5925
+ y: "2",
5926
+ rx: "2",
5927
+ key: "od3kk9"
5928
+ }],
5929
+ ["circle", {
5930
+ cx: "12",
5931
+ cy: "13",
5932
+ r: "5",
5933
+ key: "nlbqau"
5934
+ }],
5935
+ ["path", {
5936
+ d: "M12 18a2.5 2.5 0 0 0 0-5 2.5 2.5 0 0 1 0-5",
5937
+ key: "17lach"
5938
+ }]
5939
+ ]);
5940
+ /**
5941
+ * @license lucide-react v0.576.0 - ISC
5942
+ *
5943
+ * This source code is licensed under the ISC license.
5944
+ * See the LICENSE file in the root directory of this source tree.
5945
+ */
5946
+ var WavesLadder = createLucideIcon("waves-ladder", [
5947
+ ["path", {
5948
+ d: "M19 5a2 2 0 0 0-2 2v11",
5949
+ key: "s41o68"
5950
+ }],
5951
+ ["path", {
5952
+ d: "M2 18c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 2.6 0 2.4 2 5 2 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1",
5953
+ key: "rd2r6e"
5954
+ }],
5955
+ ["path", {
5956
+ d: "M7 13h10",
5957
+ key: "1rwob1"
5958
+ }],
5959
+ ["path", {
5960
+ d: "M7 9h10",
5961
+ key: "12czzb"
5962
+ }],
5963
+ ["path", {
5964
+ d: "M9 5a2 2 0 0 0-2 2v11",
5965
+ key: "x0q4gh"
5966
+ }]
5967
+ ]);
5968
+ /**
5969
+ * @license lucide-react v0.576.0 - ISC
5970
+ *
5971
+ * This source code is licensed under the ISC license.
5972
+ * See the LICENSE file in the root directory of this source tree.
5973
+ */
4605
5974
  var Waves = createLucideIcon("waves", [
4606
5975
  ["path", {
4607
5976
  d: "M2 6c.6.5 1.2 1 2.5 1C7 7 7 5 9.5 5c2.6 0 2.4 2 5 2 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1",
@@ -7191,6 +8560,8 @@ var useVideoclipsListSources = trpc.videoclips.listSources.useQuery;
7191
8560
  var useVideoclipsGetClipPlayback = trpc.videoclips.getClipPlayback.useQuery;
7192
8561
  /** Generated alias around `trpc.videoclips.readClipBytes.useQuery`. */
7193
8562
  var useVideoclipsReadClipBytes = trpc.videoclips.readClipBytes.useQuery;
8563
+ /** Generated alias around `trpc.videoclips.dialClipStream.useQuery`. */
8564
+ var useVideoclipsDialClipStream = trpc.videoclips.dialClipStream.useQuery;
7194
8565
  /** Generated alias around `trpc.waterHeater.setTargetTemp.useMutation`. */
7195
8566
  var useWaterHeaterSetTargetTemp = trpc.waterHeater.setTargetTemp.useMutation;
7196
8567
  /** Generated alias around `trpc.waterHeater.setOperationMode.useMutation`. */
@@ -17662,38 +19033,6 @@ var cva = (base, config) => (props) => {
17662
19033
  }, []), props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
17663
19034
  };
17664
19035
  //#endregion
17665
- //#region src/primitives/badge.tsx
17666
- var badgeVariants = cva("inline-flex items-center rounded-full text-xs font-medium px-2 py-0.5", {
17667
- variants: {
17668
- variant: {
17669
- default: "bg-surface-hover text-foreground",
17670
- success: "bg-success/15 text-success",
17671
- warning: "bg-warning/15 text-warning",
17672
- danger: "bg-danger/15 text-danger",
17673
- info: "bg-info/15 text-info"
17674
- },
17675
- styleVariant: {
17676
- solid: "",
17677
- outline: "border bg-transparent"
17678
- }
17679
- },
17680
- defaultVariants: {
17681
- variant: "default",
17682
- styleVariant: "solid"
17683
- }
17684
- });
17685
- var Badge = forwardRef(({ className, variant, style, ...props }, ref) => {
17686
- return /* @__PURE__ */ jsx("span", {
17687
- ref,
17688
- className: cn(badgeVariants({
17689
- variant,
17690
- styleVariant: style
17691
- }), className),
17692
- ...props
17693
- });
17694
- });
17695
- Badge.displayName = "Badge";
17696
- //#endregion
17697
19036
  //#region src/primitives/button.tsx
17698
19037
  var buttonVariants = cva("inline-flex items-center justify-center rounded-md font-medium transition-colors cursor-pointer disabled:opacity-50 disabled:pointer-events-none", {
17699
19038
  variants: {
@@ -17969,590 +19308,123 @@ function axisTicks(fromMs, toMs, count) {
17969
19308
  return ticks;
17970
19309
  }
17971
19310
  //#endregion
17972
- //#region src/hooks/use-is-mobile.ts
17973
- var MOBILE_QUERY = "(max-width: 767px)";
17974
- /**
17975
- * Mid breakpoint — below this width the sidebar collapses to an
17976
- * icons-only rail to reclaim canvas space. Above it (and outside
17977
- * mobile) the full sidebar renders. Threshold matches Tailwind `lg`
17978
- * so sidebar fans out at the same point grids switch to multi-column.
17979
- */
17980
- var MID_QUERY = "(min-width: 768px) and (max-width: 1023px)";
17981
- /**
17982
- * `matchMedia` is universal in browsers but absent in bare DOM environments.
17983
- * These hooks are called from shared primitives (`DataTable` picks its narrow
17984
- * layout with one), so throwing here takes down the whole page that merely
17985
- * rendered a table. Where the capability is missing, report the desktop
17986
- * layout — a widescreen rendering is wrong-looking; a crashed page is gone.
17987
- */
17988
- function matchQuery(query) {
17989
- if (typeof window.matchMedia !== "function") return null;
17990
- return window.matchMedia(query);
17991
- }
17992
- function subscribeQuery(query) {
17993
- return (callback) => {
17994
- const mql = matchQuery(query);
17995
- if (mql === null) return () => {};
17996
- mql.addEventListener("change", callback);
17997
- return () => mql.removeEventListener("change", callback);
17998
- };
17999
- }
18000
- function getSnapshot(query) {
18001
- return () => matchQuery(query)?.matches ?? false;
18002
- }
18003
- function getServerSnapshot() {
18004
- return false;
18005
- }
18006
- function useIsMobile() {
18007
- return useSyncExternalStore(subscribeQuery(MOBILE_QUERY), getSnapshot(MOBILE_QUERY), getServerSnapshot);
18008
- }
18009
- /**
18010
- * True when the viewport is in the medium (`md`) Tailwind range —
18011
- * 768px ≤ width < 1024px. Use to drive layouts that should pack denser
18012
- * than full-desktop but more legibly than mobile (e.g. icons-only
18013
- * sidebar rail, narrower stat tiles).
18014
- */
18015
- function useIsMidWidth() {
18016
- return useSyncExternalStore(subscribeQuery(MID_QUERY), getSnapshot(MID_QUERY), getServerSnapshot);
18017
- }
18018
- //#endregion
18019
- //#region src/composites/data-table-layout.ts
18020
- /**
18021
- * At this many columns and above, `auto` switches a narrow viewport to cards.
18022
- * Three columns still fit a phone at a readable size; four do not.
18023
- */
18024
- var CARD_MODE_MIN_COLUMNS = 4;
18025
- function resolveTableLayout({ mode, columnCount, isNarrow }) {
18026
- if (!isNarrow) return "table";
18027
- if (mode === "scroll") return "table";
18028
- if (mode === "cards") return "cards";
18029
- if (columnCount === 0) return "table";
18030
- return columnCount >= 4 ? "cards" : "table";
19311
+ //#region src/composites/device-list/pagination.tsx
19312
+ var NEIGHBORS = 2;
19313
+ function computePageButtons(currentPage, totalPages) {
19314
+ if (totalPages <= 1) return [{
19315
+ kind: "page",
19316
+ n: 1
19317
+ }];
19318
+ if (totalPages <= 7) {
19319
+ const all = [];
19320
+ for (let i = 1; i <= totalPages; i++) all.push({
19321
+ kind: "page",
19322
+ n: i
19323
+ });
19324
+ return all;
19325
+ }
19326
+ const result = [];
19327
+ const leftBound = Math.max(2, currentPage - NEIGHBORS);
19328
+ const rightBound = Math.min(totalPages - 1, currentPage + NEIGHBORS);
19329
+ result.push({
19330
+ kind: "page",
19331
+ n: 1
19332
+ });
19333
+ if (leftBound > 2) result.push({
19334
+ kind: "ellipsis",
19335
+ side: "left"
19336
+ });
19337
+ for (let i = leftBound; i <= rightBound; i++) result.push({
19338
+ kind: "page",
19339
+ n: i
19340
+ });
19341
+ if (rightBound < totalPages - 1) result.push({
19342
+ kind: "ellipsis",
19343
+ side: "right"
19344
+ });
19345
+ result.push({
19346
+ kind: "page",
19347
+ n: totalPages
19348
+ });
19349
+ return result;
18031
19350
  }
18032
- //#endregion
18033
- //#region src/lib/responsive.ts
18034
- /**
18035
- * Responsive design tokens — three-tier system.
18036
- *
18037
- * The admin-ui targets three width tiers; every component should pick
18038
- * the right token from this file instead of hand-coding breakpoints.
18039
- * Adopting the tokens uniformly is what makes the app feel consistent
18040
- * across operator devices (mobile / tablet / desktop) and what unlocks
18041
- * targeted tuning (e.g. shrink every label by 1px in one place).
18042
- *
18043
- * Tier definitions (Tailwind breakpoints):
18044
- *
18045
- * • **L1 — Compact** (`< 640px`, default = mobile portrait)
18046
- * Single column, tight padding, smallest text, icon-only buttons
18047
- * where labels can be inferred. The operator can still see every
18048
- * stat / action — no horizontal scroll, no clipped text. The user
18049
- * directive: "molta informazione in poco spazio quando la width è
18050
- * bassa."
18051
- *
18052
- * • **L2 — Standard** (`sm` — `640–1023px`, tablet + small laptop)
18053
- * 2-column grids, side panels become visible, button labels return.
18054
- * Targets ~768px–1024px viewports — the most common operator sizes.
18055
- *
18056
- * • **L3 — Spacious** (`lg+` — `≥ 1024px`, desktop)
18057
- * 4-column grids, generous padding, full-width header text,
18058
- * side-by-side composite layouts. The operator has elbow room.
18059
- *
18060
- * Conventions:
18061
- * - **Always start from L1** — the bare class is always the compact
18062
- * variant, then `sm:` adds room at 640px, `lg:` at 1024px. No
18063
- * desktop-first breakpoints; no max-width queries.
18064
- * - **Token strings are static** — kept as `as const` so callers can
18065
- * compose them via `cn()` / template literals without running a
18066
- * class generator at runtime.
18067
- * - **Pair the token with a comment** — the comment in the file
18068
- * names every breakpoint it crosses, so a reader can predict the
18069
- * layout without going to Tailwind docs.
18070
- */
18071
- /** Container padding for a card-style section (header + body). */
18072
- var SECTION_CARD = "rounded-lg border border-border bg-surface overflow-hidden";
18073
- /** Header strip inside a card (between border-b lines). */
18074
- var SECTION_HEADER = "border-b border-border px-3 sm:px-4 py-1.5 sm:py-2";
18075
- /** Body padding for a card-style section. */
18076
- var SECTION_BODY = "p-2 sm:p-3 lg:p-4";
18077
- /** Gap between cards in a vertical stack. */
18078
- var STACK_GAP = "space-y-3 sm:space-y-4";
18079
- /** Gap between cards in a grid (4 cells / row at lg). */
18080
- var GRID_GAP = "gap-2 sm:gap-3";
18081
- /** Row padding inside a divided list (e.g. InfoRow). */
18082
- var LIST_ROW = "px-3 sm:px-4 py-1.5 sm:py-2";
18083
- /** 1-up at L1, 2-up at L2, 4-up at L3 — quick-stat row. */
18084
- var GRID_QUICK_STATS = "grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4";
18085
- /** 1-up at L1, 2-up at L2+ — paired panels (motion + detection rules). */
18086
- var GRID_PAIRED = "grid grid-cols-1 lg:grid-cols-2";
18087
- /** Side-by-side layout that stacks below md (canvas + side panel). */
18088
- var SPLIT_PANEL_OUTER = "flex flex-col-reverse md:flex-row";
18089
- /** Sidebar narrow lane in a SPLIT_PANEL_OUTER layout. */
18090
- var SPLIT_PANEL_SIDE = "w-full md:w-44 lg:w-52 md:flex-shrink-0 border-b md:border-b-0 md:border-l border-border";
18091
- /**
18092
- * The tier boundary at which a settings label/value row stops stacking.
18093
- *
18094
- * Below it (L1 — compact) the row is ONE column: label on its own line, value
18095
- * on the next at full width. Above it the row is label-left / value-right as
18096
- * before. The two-column form needs `SETTING_ROW_LABEL`'s lane plus a readable
18097
- * value beside it; a phone has neither, and the failure mode is not "cramped"
18098
- * but "the value is the part that gets cut" — the one thing the operator
18099
- * opened the page to read.
18100
- */
18101
- var SETTING_ROW_STACK_BREAKPOINT = "sm";
18102
- /** Outer row: single column at L1, label/value columns from `sm` up. */
18103
- var SETTING_ROW = "flex min-w-0 flex-col gap-0.5 py-1.5 sm:flex-row sm:items-center";
18104
- /** Label lane. Full width (and free to wrap) at L1; a fixed lane from `sm` up. */
18105
- var SETTING_ROW_LABEL = "min-w-0 text-[11px] leading-tight text-foreground-subtle sm:w-32 sm:shrink-0 sm:pr-2";
18106
- /**
18107
- * Value lane — the value text plus its trailing affordances (copy / reveal).
18108
- * `w-full` at L1 so the value owns the whole row once the label is above it;
18109
- * `sm:flex-1` makes it share the row again from `sm` up.
18110
- */
18111
- var SETTING_ROW_VALUE = "flex w-full min-w-0 items-center gap-1 sm:flex-1";
18112
- /**
18113
- * The value text itself. `break-all` lets an opaque token (a key, a URL) wrap
18114
- * at L1 instead of being cut mid-word; `sm:truncate` restores the single-line
18115
- * desktop form, where the row is wide enough for truncation to be a choice
18116
- * rather than data loss.
18117
- */
18118
- var SETTING_ROW_VALUE_TEXT = "min-w-0 break-all text-xs text-foreground sm:truncate";
18119
- /** Section header label (uppercase tracking-wider). */
18120
- var TEXT_SECTION_LABEL = "text-[10px] sm:text-[11px] font-semibold text-foreground uppercase tracking-wider";
18121
- /** Field label inside a row. */
18122
- var TEXT_FIELD_LABEL = "text-[11px] sm:text-xs text-foreground";
18123
- /** Sub-label / hint text. */
18124
- var TEXT_HINT = "text-[10px] text-foreground-subtle";
18125
- /** Primary value (a metric, badge, …). */
18126
- var TEXT_VALUE = "text-[11px] sm:text-xs font-medium text-foreground";
18127
- /** Big metric value (StatCard). */
18128
- var TEXT_METRIC = "text-base sm:text-lg font-semibold leading-tight text-foreground";
18129
- /** Default compact button. */
18130
- var BTN_COMPACT = "inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40";
18131
- /** Primary compact button. */
18132
- var BTN_COMPACT_PRIMARY = "inline-flex items-center justify-center gap-1 rounded border border-primary/40 bg-primary/15 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-primary hover:bg-primary/25 transition-colors disabled:opacity-40";
18133
- /** Danger compact button. */
18134
- var BTN_COMPACT_DANGER = "inline-flex items-center justify-center gap-1 rounded border border-danger/40 bg-danger/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40";
18135
- /** Warning compact button (e.g. cancel-drawing). */
18136
- var BTN_COMPACT_WARNING = "inline-flex items-center justify-center gap-1 rounded border border-warning/40 bg-warning/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-warning hover:bg-warning/20 transition-colors disabled:opacity-40";
18137
- /** Compact text/select/number input. */
18138
- var INPUT_COMPACT = "w-full rounded border border-border bg-background px-1.5 py-0.5 sm:px-2 sm:py-1 text-[11px] sm:text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none";
18139
- /** Chip-style toggle (zone / class selectors in ZoneRulesEditor). */
18140
- var CHIP_BASE = "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors";
18141
- var CHIP_ACTIVE = "border-primary/50 bg-primary/15 text-primary";
18142
- var CHIP_INACTIVE = "border-border bg-surface text-foreground-subtle hover:bg-surface-hover";
18143
- //#endregion
18144
- //#region src/composites/setting-row.tsx
18145
- function SettingRow({ label, children, actions, elements = "plain", className, valueClassName }) {
18146
- const LabelTag = elements === "description" ? "dt" : "span";
18147
- const ValueTag = elements === "description" ? "dd" : "div";
19351
+ function Pagination({ currentPage, totalItems, pageSize, onPageChange, itemNoun = "devices" }) {
19352
+ if (totalItems <= pageSize) return null;
19353
+ const totalPages = Math.ceil(totalItems / pageSize);
19354
+ const startIdx = (currentPage - 1) * pageSize + 1;
19355
+ const endIdx = Math.min(currentPage * pageSize, totalItems);
19356
+ const buttons = computePageButtons(currentPage, totalPages);
18148
19357
  return /* @__PURE__ */ jsxs("div", {
18149
- "data-setting-row": "",
18150
- className: cn(SETTING_ROW, className),
18151
- children: [/* @__PURE__ */ jsx(LabelTag, {
18152
- "data-setting-row-label": "",
18153
- className: SETTING_ROW_LABEL,
18154
- children: label
18155
- }), /* @__PURE__ */ jsxs(ValueTag, {
18156
- "data-setting-row-value": "",
18157
- className: SETTING_ROW_VALUE,
18158
- children: [/* @__PURE__ */ jsx("span", {
18159
- "data-setting-row-value-text": "",
18160
- className: cn(SETTING_ROW_VALUE_TEXT, valueClassName),
18161
- children
18162
- }), actions !== void 0 && /* @__PURE__ */ jsx("span", {
18163
- className: "flex shrink-0 items-center gap-0.5",
18164
- children: actions
18165
- })]
19358
+ className: "flex items-center justify-between gap-4 flex-wrap pt-2 text-[11px] text-foreground-subtle",
19359
+ children: [/* @__PURE__ */ jsxs("span", { children: [
19360
+ "Showing ",
19361
+ startIdx,
19362
+ "–",
19363
+ endIdx,
19364
+ " of ",
19365
+ totalItems,
19366
+ " ",
19367
+ itemNoun
19368
+ ] }), /* @__PURE__ */ jsxs("span", {
19369
+ className: "inline-flex items-center gap-1",
19370
+ children: [
19371
+ /* @__PURE__ */ jsx("button", {
19372
+ type: "button",
19373
+ "aria-label": "Previous page",
19374
+ disabled: currentPage === 1,
19375
+ onClick: () => onPageChange(currentPage - 1),
19376
+ className: cn("inline-flex items-center justify-center h-7 w-7 rounded border border-border bg-surface text-foreground-subtle", "hover:text-foreground hover:bg-surface-hover transition-colors", "disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-surface"),
19377
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-3 w-3" })
19378
+ }),
19379
+ buttons.map((b, i) => {
19380
+ if (b.kind === "ellipsis") return /* @__PURE__ */ jsx("span", {
19381
+ className: "px-1 text-foreground-subtle/60 select-none",
19382
+ children: "…"
19383
+ }, `e-${i}`);
19384
+ return /* @__PURE__ */ jsx("button", {
19385
+ type: "button",
19386
+ onClick: () => onPageChange(b.n),
19387
+ className: cn("inline-flex items-center justify-center h-7 min-w-7 px-1.5 rounded border text-[10.5px] font-medium transition-colors", b.n === currentPage ? "border-primary/40 bg-primary/10 text-primary" : "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface-hover"),
19388
+ children: b.n
19389
+ }, `p-${b.n}`);
19390
+ }),
19391
+ /* @__PURE__ */ jsx("button", {
19392
+ type: "button",
19393
+ "aria-label": "Next page",
19394
+ disabled: currentPage === totalPages,
19395
+ onClick: () => onPageChange(currentPage + 1),
19396
+ className: cn("inline-flex items-center justify-center h-7 w-7 rounded border border-border bg-surface text-foreground-subtle", "hover:text-foreground hover:bg-surface-hover transition-colors", "disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-surface"),
19397
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3" })
19398
+ })
19399
+ ]
18166
19400
  })]
18167
19401
  });
18168
19402
  }
18169
19403
  //#endregion
18170
- //#region src/composites/sort-header-button.tsx
18171
- function SortHeaderButton({ label, active, dir, onSort }) {
18172
- return /* @__PURE__ */ jsxs("button", {
18173
- type: "button",
18174
- onClick: onSort,
18175
- className: "group/sort inline-flex items-center gap-0.5 hover:text-foreground transition-colors",
18176
- children: [/* @__PURE__ */ jsx("span", { children: label }), active ? dir === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3 flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronUp, { className: cn("h-3 w-3 flex-shrink-0 opacity-0 transition-opacity", "group-hover/sort:opacity-30") })]
18177
- });
18178
- }
18179
- //#endregion
18180
- //#region src/composites/table-sort.ts
18181
- /**
18182
- * The toggle rule, and the only copy of it.
18183
- *
18184
- * none → asc → desc → none, and a click on a DIFFERENT column starts that
18185
- * column fresh at `asc`. `sameColumn` says whether the clicked column is the
18186
- * one currently sorted; `currentDir` is its direction (`null` when nothing is
18187
- * sorted). Returns the next direction, or `null` for "unsorted".
18188
- *
18189
- * Split out from {@link nextTableSort} so the device list — whose sort state
18190
- * keys columns by `columnId`, not `columnKey` — can reuse the rule without a
18191
- * cast and without a second copy of it.
18192
- */
18193
- function nextSortDirection(sameColumn, currentDir) {
18194
- if (!sameColumn || currentDir === null) return "asc";
18195
- return currentDir === "asc" ? "desc" : null;
18196
- }
18197
- /**
18198
- * Toggle a column's sort on header click: none → asc → desc → none.
18199
- * Clicking a DIFFERENT column starts it fresh at `asc`.
18200
- */
18201
- function nextTableSort(current, columnKey) {
18202
- const dir = nextSortDirection(current !== null && current.columnKey === columnKey, current === null ? null : current.dir);
18203
- return dir === null ? null : {
18204
- columnKey,
18205
- dir
18206
- };
18207
- }
18208
- /**
18209
- * Ascending comparison of two cell values.
18210
- *
18211
- * Numbers compare numerically and strings compare with `localeCompare` — a
18212
- * numeric column must never be ordered as text ("100" before "9"), and a text
18213
- * column must respect the locale's collation. A mixed column (one row a
18214
- * number, another a string) falls back to string comparison of both, which is
18215
- * the only total order available; it is not a shape any caller should build on
18216
- * purpose.
18217
- *
18218
- * `null` is NOT handled here — {@link sortRowsByColumn} pulls it out first,
18219
- * because its placement is direction-independent and a comparator that is
18220
- * multiplied by the direction factor cannot express that.
18221
- */
18222
- function compareValues(a, b) {
18223
- if (typeof a === "number" && typeof b === "number") return a - b;
18224
- return String(a).localeCompare(String(b));
18225
- }
18226
- /**
18227
- * Return a NEW array of `rows` ordered by `sort`.
18228
- *
18229
- * `valueOf` is the column's `sortValue` — it is called once per row per
18230
- * comparison, so it must be cheap (read a field, do not format a string).
18231
- * `sort === null` ⇒ a fresh shallow copy in the incoming order.
18232
- */
18233
- function sortRowsByColumn(rows, sort, valueOf) {
18234
- if (sort === null) return [...rows];
18235
- const factor = sort.dir === "asc" ? 1 : -1;
18236
- return rows.toSorted((a, b) => {
18237
- const av = valueOf(a);
18238
- const bv = valueOf(b);
18239
- if (av === null || bv === null) {
18240
- if (av === bv) return 0;
18241
- return av === null ? 1 : -1;
18242
- }
18243
- return factor * compareValues(av, bv);
18244
- });
18245
- }
18246
- /** Derive the `<th>` `aria-sort` for `columnKey` from the table's sort state. */
18247
- function ariaSortForColumn(sort, columnKey) {
18248
- if (sort === null || sort.columnKey !== columnKey) return "none";
18249
- return sort.dir === "asc" ? "ascending" : "descending";
18250
- }
18251
- //#endregion
18252
- //#region src/composites/data-table.tsx
18253
- /**
18254
- * DataTable — shared responsive table for admin pages.
18255
- *
18256
- * Recipes baked in:
18257
- * - `overflow-x-auto` wrapper so narrow viewports don't clip the
18258
- * right edge (the rounded border survives the scroll).
18259
- * - `min-w-[Npx]` on the inner table so columns don't squash below
18260
- * readable width before the scroll kicks in.
18261
- * - `whitespace-nowrap` on headers — column titles never wrap to
18262
- * two lines (`AUTO-KILL` was the regression that triggered this).
18263
- * - Themed `bg-surface` + `border-border` so contrast works in both
18264
- * light and dark themes.
18265
- *
18266
- * Column model: caller supplies `columns: DataColumn<T>[]` and
18267
- * `rows: T[]`. Each column declares `header`, optional `align`,
18268
- * optional `nowrap`, and a `render(row) => ReactNode` that produces
18269
- * the cell content.
18270
- *
18271
- * <DataTable
18272
- * columns={[
18273
- * { key: 'username', header: 'Username', render: (u) => u.username },
18274
- * { key: 'role', header: 'Role', render: (u) => <RoleBadge .../> },
18275
- * { key: 'actions', header: '', align: 'right', render: (u) => <Actions .../> },
18276
- * ]}
18277
- * rows={users}
18278
- * minWidthPx={560}
18279
- * />
18280
- *
18281
- * If finer header markup is needed, pass `headerRender` instead of
18282
- * `header` (e.g. for a sortable click affordance).
18283
- *
18284
- * ── Narrow viewports ──────────────────────────────────────────────────────
18285
- * The table stays a table. The wrapper is `overflow-x-auto`, so a phone
18286
- * scrolls the columns sideways INSIDE the table — the page body never moves
18287
- * sideways, and the cells stay one line (`whitespace-nowrap`). That is the
18288
- * default (`mobileMode="scroll"`). Cards are opt-in via `mobileMode="cards"`;
18289
- * `auto` still applies the old column-count rule for a surface that wants it.
18290
- * See `resolveTableLayout`.
18291
- *
18292
- * ── Scrolling the BODY, not the page ──────────────────────────────────────
18293
- * `maxBodyHeight` caps the table and scrolls its rows INSIDE the container
18294
- * with the column header pinned. It is ONE prop, not two, because "this list
18295
- * scrolls internally" and "its header stays visible" are the same decision: a
18296
- * capped table whose header scrolls away is a list of unlabelled cells.
18297
- *
18298
- * Use it wherever the row count is open-ended (rules, targets, delivery
18299
- * history) so the page keeps its own header, filters and actions in view while
18300
- * the operator moves through the rows.
18301
- */
18302
- /**
18303
- * The default cap for an internally-scrolling table.
18304
- *
18305
- * `60vh` leaves the page header, its filters and its actions on screen at
18306
- * every viewport while still showing ~10 rows — and it is a fraction, so it
18307
- * does not need a breakpoint of its own.
18308
- */
18309
- var TABLE_SCROLL_MAX_H = "max-h-[60vh]";
18310
- var ALIGN_CLASS = {
18311
- left: "text-left",
18312
- right: "text-right",
18313
- center: "text-center"
18314
- };
18315
- function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyMessage, className, bordered = true, rowClassName, mobileMode = "scroll", maxBodyHeight, defaultSort }) {
18316
- const isNarrow = useIsMobile();
18317
- const [sort, setSort] = useState(defaultSort ?? null);
18318
- const layout = resolveTableLayout({
18319
- mode: mobileMode,
18320
- columnCount: columns.length,
18321
- isNarrow
18322
- });
18323
- const scrolls = maxBodyHeight !== void 0;
18324
- const sortedColumn = useMemo(() => sort === null ? void 0 : columns.find((col) => col.key === sort.columnKey && col.sortValue !== void 0), [columns, sort]);
18325
- const sortValue = sortedColumn?.sortValue;
18326
- const displayRows = useMemo(() => sortValue === void 0 ? rows : sortRowsByColumn(rows, sort, sortValue), [
18327
- rows,
18328
- sort,
18329
- sortValue
18330
- ]);
18331
- const activeSort = sortedColumn === void 0 ? null : sort;
18332
- if (rows.length === 0 && emptyMessage) return /* @__PURE__ */ jsx("div", {
18333
- className: `rounded-lg ${bordered ? "border border-border" : ""} bg-surface px-3 py-4 text-xs text-foreground-subtle text-center ${className ?? ""}`,
18334
- children: emptyMessage
18335
- });
18336
- if (rows.length === 0) return null;
18337
- if (layout === "cards") return /* @__PURE__ */ jsx("div", {
18338
- className: `space-y-2 ${scrolls ? `${maxBodyHeight} overflow-y-auto` : ""} ${className ?? ""}`,
18339
- children: displayRows.map((row, rowIndex) => /* @__PURE__ */ jsx(DataTableCard, {
18340
- row,
18341
- rowIndex,
18342
- columns,
18343
- bordered,
18344
- onRowClick,
18345
- rowClassName
18346
- }, rowKey ? rowKey(row, rowIndex) : rowIndex))
18347
- });
18348
- return /* @__PURE__ */ jsx("div", {
18349
- className: [
18350
- "rounded-lg",
18351
- bordered ? "border border-border" : "",
18352
- "bg-surface overflow-x-auto",
18353
- scrolls ? `${maxBodyHeight} overflow-y-auto` : "",
18354
- className ?? ""
18355
- ].filter(Boolean).join(" "),
18356
- children: /* @__PURE__ */ jsxs("table", {
18357
- className: `w-full text-xs ${scrolls ? "border-separate border-spacing-0" : ""}`,
18358
- style: { minWidth: `${minWidthPx}px` },
18359
- children: [/* @__PURE__ */ jsx("thead", {
18360
- className: "bg-surface",
18361
- children: /* @__PURE__ */ jsx("tr", { children: columns.map((col) => {
18362
- const align = col.align ?? "left";
18363
- const nowrap = col.nowrap ?? true;
18364
- const sortable = col.sortValue !== void 0;
18365
- const isSorted = activeSort !== null && activeSort.columnKey === col.key;
18366
- return /* @__PURE__ */ jsx("th", {
18367
- "aria-sort": sortable ? ariaSortForColumn(activeSort, col.key) : void 0,
18368
- title: sortable ? void 0 : col.notSortableReason,
18369
- className: [
18370
- "px-3 py-2 text-foreground-subtle font-medium bg-surface border-b border-border",
18371
- scrolls ? "sticky top-0 z-10" : "",
18372
- ALIGN_CLASS[align],
18373
- nowrap ? "whitespace-nowrap" : "",
18374
- col.width ?? ""
18375
- ].filter(Boolean).join(" "),
18376
- children: sortable ? /* @__PURE__ */ jsx(SortHeaderButton, {
18377
- label: col.headerRender ? col.headerRender() : col.header,
18378
- active: isSorted,
18379
- dir: isSorted && activeSort !== null ? activeSort.dir : "asc",
18380
- onSort: () => setSort((prev) => nextTableSort(prev, col.key))
18381
- }) : col.headerRender ? col.headerRender() : col.header
18382
- }, col.key);
18383
- }) })
18384
- }), /* @__PURE__ */ jsx("tbody", { children: displayRows.map((row, rowIndex) => {
18385
- const key = rowKey ? rowKey(row, rowIndex) : rowIndex;
18386
- const extra = rowClassName?.(row, rowIndex) ?? "";
18387
- const interactive = onRowClick !== void 0;
18388
- return /* @__PURE__ */ jsx("tr", {
18389
- onClick: interactive ? () => onRowClick(row, rowIndex) : void 0,
18390
- className: [interactive ? "cursor-pointer hover:bg-primary/5" : "hover:bg-primary/5", extra].filter(Boolean).join(" "),
18391
- children: columns.map((col) => {
18392
- const align = col.align ?? "left";
18393
- const nowrap = col.nowrap ?? true;
18394
- return /* @__PURE__ */ jsx("td", {
18395
- className: [
18396
- "px-3 py-2 text-foreground border-b border-border",
18397
- ALIGN_CLASS[align],
18398
- nowrap ? "whitespace-nowrap" : ""
18399
- ].filter(Boolean).join(" "),
18400
- children: col.render(row, rowIndex)
18401
- }, col.key);
18402
- })
18403
- }, key);
18404
- }) })]
18405
- })
18406
- });
18407
- }
18408
- /**
18409
- * One row as a card. Columns that carry a plain-text `header` become labelled
18410
- * `SettingRow`s — the label is the column title and the value gets the full
18411
- * card width. Columns with no text header (an actions column, a
18412
- * `headerRender`-only column) have no label to show, so they render as a
18413
- * full-width strip at the foot of the card.
18414
- */
18415
- function DataTableCard({ row, rowIndex, columns, bordered, onRowClick, rowClassName }) {
18416
- const labelled = columns.filter((col) => col.header !== void 0 && col.header !== "");
18417
- const unlabelled = columns.filter((col) => col.header === void 0 || col.header === "");
18418
- const interactive = onRowClick !== void 0;
18419
- const extra = rowClassName?.(row, rowIndex) ?? "";
18420
- return /* @__PURE__ */ jsxs("div", {
18421
- "data-data-table-card": "",
18422
- onClick: interactive ? () => onRowClick(row, rowIndex) : void 0,
18423
- className: [
18424
- "rounded-lg bg-surface px-3 py-1.5 divide-y divide-border-subtle",
18425
- bordered ? "border border-border" : "",
18426
- interactive ? "cursor-pointer hover:bg-primary/5" : "",
18427
- extra
18428
- ].filter(Boolean).join(" "),
18429
- children: [labelled.map((col) => /* @__PURE__ */ jsx(SettingRow, {
18430
- label: col.header,
18431
- children: col.render(row, rowIndex)
18432
- }, col.key)), unlabelled.length > 0 && /* @__PURE__ */ jsx("div", {
18433
- className: "flex flex-wrap items-center justify-end gap-2 py-1.5",
18434
- children: unlabelled.map((col) => /* @__PURE__ */ jsx("div", { children: col.render(row, rowIndex) }, col.key))
18435
- })]
18436
- });
18437
- }
18438
- //#endregion
18439
- //#region src/composites/device-list/pagination.tsx
18440
- var NEIGHBORS = 2;
18441
- function computePageButtons(currentPage, totalPages) {
18442
- if (totalPages <= 1) return [{
18443
- kind: "page",
18444
- n: 1
18445
- }];
18446
- if (totalPages <= 7) {
18447
- const all = [];
18448
- for (let i = 1; i <= totalPages; i++) all.push({
18449
- kind: "page",
18450
- n: i
18451
- });
18452
- return all;
18453
- }
18454
- const result = [];
18455
- const leftBound = Math.max(2, currentPage - NEIGHBORS);
18456
- const rightBound = Math.min(totalPages - 1, currentPage + NEIGHBORS);
18457
- result.push({
18458
- kind: "page",
18459
- n: 1
18460
- });
18461
- if (leftBound > 2) result.push({
18462
- kind: "ellipsis",
18463
- side: "left"
18464
- });
18465
- for (let i = leftBound; i <= rightBound; i++) result.push({
18466
- kind: "page",
18467
- n: i
18468
- });
18469
- if (rightBound < totalPages - 1) result.push({
18470
- kind: "ellipsis",
18471
- side: "right"
18472
- });
18473
- result.push({
18474
- kind: "page",
18475
- n: totalPages
18476
- });
18477
- return result;
18478
- }
18479
- function Pagination({ currentPage, totalItems, pageSize, onPageChange, itemNoun = "devices" }) {
18480
- if (totalItems <= pageSize) return null;
18481
- const totalPages = Math.ceil(totalItems / pageSize);
18482
- const startIdx = (currentPage - 1) * pageSize + 1;
18483
- const endIdx = Math.min(currentPage * pageSize, totalItems);
18484
- const buttons = computePageButtons(currentPage, totalPages);
18485
- return /* @__PURE__ */ jsxs("div", {
18486
- className: "flex items-center justify-between gap-4 flex-wrap pt-2 text-[11px] text-foreground-subtle",
18487
- children: [/* @__PURE__ */ jsxs("span", { children: [
18488
- "Showing ",
18489
- startIdx,
18490
- "–",
18491
- endIdx,
18492
- " of ",
18493
- totalItems,
18494
- " ",
18495
- itemNoun
18496
- ] }), /* @__PURE__ */ jsxs("span", {
18497
- className: "inline-flex items-center gap-1",
18498
- children: [
18499
- /* @__PURE__ */ jsx("button", {
18500
- type: "button",
18501
- "aria-label": "Previous page",
18502
- disabled: currentPage === 1,
18503
- onClick: () => onPageChange(currentPage - 1),
18504
- className: cn("inline-flex items-center justify-center h-7 w-7 rounded border border-border bg-surface text-foreground-subtle", "hover:text-foreground hover:bg-surface-hover transition-colors", "disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-surface"),
18505
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-3 w-3" })
18506
- }),
18507
- buttons.map((b, i) => {
18508
- if (b.kind === "ellipsis") return /* @__PURE__ */ jsx("span", {
18509
- className: "px-1 text-foreground-subtle/60 select-none",
18510
- children: "…"
18511
- }, `e-${i}`);
18512
- return /* @__PURE__ */ jsx("button", {
18513
- type: "button",
18514
- onClick: () => onPageChange(b.n),
18515
- className: cn("inline-flex items-center justify-center h-7 min-w-7 px-1.5 rounded border text-[10.5px] font-medium transition-colors", b.n === currentPage ? "border-primary/40 bg-primary/10 text-primary" : "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface-hover"),
18516
- children: b.n
18517
- }, `p-${b.n}`);
18518
- }),
18519
- /* @__PURE__ */ jsx("button", {
18520
- type: "button",
18521
- "aria-label": "Next page",
18522
- disabled: currentPage === totalPages,
18523
- onClick: () => onPageChange(currentPage + 1),
18524
- className: cn("inline-flex items-center justify-center h-7 w-7 rounded border border-border bg-surface text-foreground-subtle", "hover:text-foreground hover:bg-surface-hover transition-colors", "disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-surface"),
18525
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3" })
18526
- })
18527
- ]
18528
- })]
18529
- });
18530
- }
18531
- //#endregion
18532
- //#region src/composites/empty-state.tsx
18533
- function EmptyState({ icon: Icon, title, description, action, className }) {
18534
- return /* @__PURE__ */ jsxs("div", {
18535
- className: cn("flex flex-col items-center justify-center gap-3 py-12", className),
18536
- children: [
18537
- Icon && /* @__PURE__ */ jsx(Icon, {
18538
- className: "h-12 w-12 text-foreground-subtle",
18539
- "aria-hidden": "true"
18540
- }),
18541
- /* @__PURE__ */ jsxs("div", {
18542
- className: "flex flex-col items-center gap-1 text-center",
18543
- children: [/* @__PURE__ */ jsx("p", {
18544
- className: "text-foreground-muted text-sm font-medium",
18545
- children: title
18546
- }), description && /* @__PURE__ */ jsx("p", {
18547
- className: "text-foreground-subtle text-xs max-w-xs",
18548
- children: description
18549
- })]
18550
- }),
18551
- action && /* @__PURE__ */ jsx("div", {
18552
- className: "mt-1",
18553
- children: action
18554
- })
18555
- ]
19404
+ //#region src/composites/empty-state.tsx
19405
+ function EmptyState({ icon: Icon, title, description, action, className }) {
19406
+ return /* @__PURE__ */ jsxs("div", {
19407
+ className: cn("flex flex-col items-center justify-center gap-3 py-12", className),
19408
+ children: [
19409
+ Icon && /* @__PURE__ */ jsx(Icon, {
19410
+ className: "h-12 w-12 text-foreground-subtle",
19411
+ "aria-hidden": "true"
19412
+ }),
19413
+ /* @__PURE__ */ jsxs("div", {
19414
+ className: "flex flex-col items-center gap-1 text-center",
19415
+ children: [/* @__PURE__ */ jsx("p", {
19416
+ className: "text-foreground-muted text-sm font-medium",
19417
+ children: title
19418
+ }), description && /* @__PURE__ */ jsx("p", {
19419
+ className: "text-foreground-subtle text-xs max-w-xs",
19420
+ children: description
19421
+ })]
19422
+ }),
19423
+ action && /* @__PURE__ */ jsx("div", {
19424
+ className: "mt-1",
19425
+ children: action
19426
+ })
19427
+ ]
18556
19428
  });
18557
19429
  }
18558
19430
  //#endregion
@@ -19023,6 +19895,38 @@ function ClipPanel({ deviceId, clip, profile, onProfileChange }) {
19023
19895
  });
19024
19896
  }
19025
19897
  //#endregion
19898
+ //#region src/primitives/badge.tsx
19899
+ var badgeVariants = cva("inline-flex items-center rounded-full text-xs font-medium px-2 py-0.5", {
19900
+ variants: {
19901
+ variant: {
19902
+ default: "bg-surface-hover text-foreground",
19903
+ success: "bg-success/15 text-success",
19904
+ warning: "bg-warning/15 text-warning",
19905
+ danger: "bg-danger/15 text-danger",
19906
+ info: "bg-info/15 text-info"
19907
+ },
19908
+ styleVariant: {
19909
+ solid: "",
19910
+ outline: "border bg-transparent"
19911
+ }
19912
+ },
19913
+ defaultVariants: {
19914
+ variant: "default",
19915
+ styleVariant: "solid"
19916
+ }
19917
+ });
19918
+ var Badge = forwardRef(({ className, variant, style, ...props }, ref) => {
19919
+ return /* @__PURE__ */ jsx("span", {
19920
+ ref,
19921
+ className: cn(badgeVariants({
19922
+ variant,
19923
+ styleVariant: style
19924
+ }), className),
19925
+ ...props
19926
+ });
19927
+ });
19928
+ Badge.displayName = "Badge";
19929
+ //#endregion
19026
19930
  //#region src/lib/format-duration.ts
19027
19931
  /**
19028
19932
  * How long something lasted, the way this product says it.
@@ -19536,24 +20440,6 @@ function describeSource(source) {
19536
20440
  answered: copy.answered
19537
20441
  };
19538
20442
  }
19539
- var MINUTE_MS$1 = 6e4;
19540
- var HOUR_MS$1 = 36e5;
19541
- var DAY_MS$2 = 864e5;
19542
- /**
19543
- * How old a source's catalog is, or null when it did not say.
19544
- *
19545
- * Null is NOT "now". A source that omits `catalogAsOf` was read live and has
19546
- * no age to show; inventing "just now" for a source that never told us would
19547
- * be the same lie as drawing a cached list as current (D549 decision 13).
19548
- */
19549
- function formatCatalogAge(catalogAsOf, now) {
19550
- if (catalogAsOf === void 0) return null;
19551
- const age = Math.max(0, now - catalogAsOf);
19552
- if (age < MINUTE_MS$1) return "under a minute ago";
19553
- if (age < HOUR_MS$1) return `${String(Math.floor(age / MINUTE_MS$1))} min ago`;
19554
- if (age < DAY_MS$2) return `${String(Math.floor(age / HOUR_MS$1))} h ago`;
19555
- return `${String(Math.floor(age / DAY_MS$2))} d ago`;
19556
- }
19557
20443
  //#endregion
19558
20444
  //#region src/composites/clips/clip-view-state.ts
19559
20445
  function resolveClipsView(input) {
@@ -19707,56 +20593,6 @@ function resolveClipsView(input) {
19707
20593
  var CLIP_PAGE_LIMIT = 500;
19708
20594
  /** Tiles per page. The rest are a `Pagination` click away, never dropped. */
19709
20595
  var TILES_PER_PAGE = 60;
19710
- var TONE_BADGE = {
19711
- ok: "success",
19712
- warn: "warning",
19713
- error: "danger"
19714
- };
19715
- var SOURCE_COLUMNS = [
19716
- {
19717
- key: "source",
19718
- header: "Source",
19719
- render: (row) => /* @__PURE__ */ jsxs("div", {
19720
- className: "min-w-0",
19721
- children: [/* @__PURE__ */ jsx("div", {
19722
- className: "font-medium text-foreground",
19723
- children: row.notice.label
19724
- }), /* @__PURE__ */ jsx("div", {
19725
- className: "text-[10px] text-foreground-subtle",
19726
- children: row.notice.source
19727
- })]
19728
- })
19729
- },
19730
- {
19731
- key: "state",
19732
- header: "State",
19733
- nowrap: false,
19734
- render: (row) => /* @__PURE__ */ jsx(Badge, {
19735
- variant: TONE_BADGE[row.notice.tone],
19736
- children: row.notice.headline
19737
- })
19738
- },
19739
- {
19740
- key: "reason",
19741
- header: "Reason",
19742
- nowrap: false,
19743
- render: (row) => row.notice.detail === null ? /* @__PURE__ */ jsx("span", {
19744
- className: "text-foreground-subtle",
19745
- children: "—"
19746
- }) : /* @__PURE__ */ jsx("span", {
19747
- className: "break-words",
19748
- children: row.notice.detail
19749
- })
19750
- },
19751
- {
19752
- key: "read",
19753
- header: "Catalog read",
19754
- render: (row) => /* @__PURE__ */ jsx("span", {
19755
- className: "text-foreground-subtle",
19756
- children: row.catalogAge ?? "live"
19757
- })
19758
- }
19759
- ];
19760
20596
  /** The sources that contributed NOTHING to what is on screen, and why. */
19761
20597
  function SilentSources({ silent }) {
19762
20598
  if (silent.length === 0) return null;
@@ -19843,7 +20679,6 @@ function ClipsSection({ deviceId }) {
19843
20679
  ...clips.error ? { clipsError: clips.error.message } : {},
19844
20680
  ...sources.error ? { sourcesError: sources.error.message } : {}
19845
20681
  });
19846
- const now = Date.now();
19847
20682
  const options = useMemo(() => {
19848
20683
  const byAddon = /* @__PURE__ */ new Map();
19849
20684
  for (const row of sourceRows) {
@@ -19858,10 +20693,6 @@ function ClipsSection({ deviceId }) {
19858
20693
  label: labels.join(" · ")
19859
20694
  }));
19860
20695
  }, [sourceRows]);
19861
- const tableRows = useMemo(() => sourceRows.map((row) => ({
19862
- notice: describeSource(row),
19863
- catalogAge: formatCatalogAge(row.availability.catalogAsOf, now)
19864
- })), [sourceRows]);
19865
20696
  useEffect(() => {
19866
20697
  setPage(1);
19867
20698
  }, [band.fromMs, band.toMs]);
@@ -19967,19 +20798,6 @@ function ClipsSection({ deviceId }) {
19967
20798
  onSelectBucket: handleSelectBucket,
19968
20799
  densityLoading: density.status === "pending"
19969
20800
  }),
19970
- /* @__PURE__ */ jsx("section", {
19971
- "aria-label": "Clip sources",
19972
- className: "space-y-1",
19973
- children: sources.status === "pending" ? /* @__PURE__ */ jsx(Skeleton, { className: "h-16 w-full" }) : tableRows.length === 0 ? /* @__PURE__ */ jsx(EmptyState, {
19974
- icon: Film,
19975
- title: "No provider answered for this camera",
19976
- description: "Nothing claims to hold clips for it."
19977
- }) : /* @__PURE__ */ jsx(DataTable, {
19978
- columns: SOURCE_COLUMNS,
19979
- rows: [...tableRows],
19980
- minWidthPx: 520
19981
- })
19982
- }),
19983
20801
  /* @__PURE__ */ jsx("section", {
19984
20802
  "aria-label": "Clips",
19985
20803
  className: "space-y-2",
@@ -22952,8 +23770,8 @@ function RecordingPanel({ deviceId }) {
22952
23770
  * `type:'widget'` ConfigField. `WidgetSlot` resolves these BEFORE the
22953
23771
  * Module-Federation `WidgetRegistry`. ids are namespaced `host/<name>`. */
22954
23772
  var HOST_WIDGETS = {
22955
- "host/motion-zones-grid": lazy(() => import("./MotionZonesSettings-7c3yiT5E.js").then((m) => ({ default: m.MotionZonesSettings }))),
22956
- "host/privacy-mask-grid": lazy(() => import("./PrivacyMaskSettings-PkYs077O.js").then((m) => ({ default: m.PrivacyMaskSettings }))),
23773
+ "host/motion-zones-grid": lazy(() => import("./MotionZonesSettings-DHDfnZyU.js").then((m) => ({ default: m.MotionZonesSettings }))),
23774
+ "host/privacy-mask-grid": lazy(() => import("./PrivacyMaskSettings-DMkchqO1.js").then((m) => ({ default: m.PrivacyMaskSettings }))),
22957
23775
  "host/ptz-panel": PtzPanel,
22958
23776
  "host/navigation-panel": NavigationPanel,
22959
23777
  "host/consumables-panel": ConsumablesPanel,
@@ -27658,6 +28476,53 @@ function TooltipContent({ className, children, ...props }) {
27658
28476
  });
27659
28477
  }
27660
28478
  //#endregion
28479
+ //#region src/hooks/use-is-mobile.ts
28480
+ var MOBILE_QUERY = "(max-width: 767px)";
28481
+ /**
28482
+ * Mid breakpoint — below this width the sidebar collapses to an
28483
+ * icons-only rail to reclaim canvas space. Above it (and outside
28484
+ * mobile) the full sidebar renders. Threshold matches Tailwind `lg`
28485
+ * so sidebar fans out at the same point grids switch to multi-column.
28486
+ */
28487
+ var MID_QUERY = "(min-width: 768px) and (max-width: 1023px)";
28488
+ /**
28489
+ * `matchMedia` is universal in browsers but absent in bare DOM environments.
28490
+ * These hooks are called from shared primitives (`DataTable` picks its narrow
28491
+ * layout with one), so throwing here takes down the whole page that merely
28492
+ * rendered a table. Where the capability is missing, report the desktop
28493
+ * layout — a widescreen rendering is wrong-looking; a crashed page is gone.
28494
+ */
28495
+ function matchQuery(query) {
28496
+ if (typeof window.matchMedia !== "function") return null;
28497
+ return window.matchMedia(query);
28498
+ }
28499
+ function subscribeQuery(query) {
28500
+ return (callback) => {
28501
+ const mql = matchQuery(query);
28502
+ if (mql === null) return () => {};
28503
+ mql.addEventListener("change", callback);
28504
+ return () => mql.removeEventListener("change", callback);
28505
+ };
28506
+ }
28507
+ function getSnapshot(query) {
28508
+ return () => matchQuery(query)?.matches ?? false;
28509
+ }
28510
+ function getServerSnapshot() {
28511
+ return false;
28512
+ }
28513
+ function useIsMobile() {
28514
+ return useSyncExternalStore(subscribeQuery(MOBILE_QUERY), getSnapshot(MOBILE_QUERY), getServerSnapshot);
28515
+ }
28516
+ /**
28517
+ * True when the viewport is in the medium (`md`) Tailwind range —
28518
+ * 768px ≤ width < 1024px. Use to drive layouts that should pack denser
28519
+ * than full-desktop but more legibly than mobile (e.g. icons-only
28520
+ * sidebar rail, narrower stat tiles).
28521
+ */
28522
+ function useIsMidWidth() {
28523
+ return useSyncExternalStore(subscribeQuery(MID_QUERY), getSnapshot(MID_QUERY), getServerSnapshot);
28524
+ }
28525
+ //#endregion
27661
28526
  //#region src/primitives/bottom-sheet.tsx
27662
28527
  function BottomSheet({ open, onClose, title, children, className }) {
27663
28528
  useEffect(() => {
@@ -30806,290 +31671,916 @@ function ToolbarButton$1({ onClick, title, children }) {
30806
31671
  children
30807
31672
  });
30808
31673
  }
30809
- async function waitForIceGathering(pc) {
30810
- if (pc.iceGatheringState === "complete") return;
30811
- return new Promise((resolve) => {
30812
- let settled = false;
30813
- let poll;
30814
- const finish = () => {
30815
- if (settled) return;
30816
- settled = true;
30817
- if (poll) clearInterval(poll);
30818
- pc.removeEventListener("icegatheringstatechange", handler);
30819
- resolve();
30820
- };
30821
- const handler = () => {
30822
- if (pc.iceGatheringState === "complete") finish();
30823
- };
30824
- pc.addEventListener("icegatheringstatechange", handler);
30825
- const start = Date.now();
30826
- poll = setInterval(() => {
30827
- const sdp = pc.localDescription?.sdp ?? "";
30828
- if (/ typ host/.test(sdp) && Date.now() - start >= 600) finish();
30829
- }, 100);
30830
- setTimeout(finish, 2500);
31674
+ async function waitForIceGathering(pc) {
31675
+ if (pc.iceGatheringState === "complete") return;
31676
+ return new Promise((resolve) => {
31677
+ let settled = false;
31678
+ let poll;
31679
+ const finish = () => {
31680
+ if (settled) return;
31681
+ settled = true;
31682
+ if (poll) clearInterval(poll);
31683
+ pc.removeEventListener("icegatheringstatechange", handler);
31684
+ resolve();
31685
+ };
31686
+ const handler = () => {
31687
+ if (pc.iceGatheringState === "complete") finish();
31688
+ };
31689
+ pc.addEventListener("icegatheringstatechange", handler);
31690
+ const start = Date.now();
31691
+ poll = setInterval(() => {
31692
+ const sdp = pc.localDescription?.sdp ?? "";
31693
+ if (/ typ host/.test(sdp) && Date.now() - start >= 600) finish();
31694
+ }, 100);
31695
+ setTimeout(finish, 2500);
31696
+ });
31697
+ }
31698
+ //#endregion
31699
+ //#region src/composites/cap-settings/scene-monitor-copy.ts
31700
+ /** The lighting variants an operator is OFFERED. The resolver can also report
31701
+ * `night`, `dawn` and `dusk`; those are shown when present but never demanded,
31702
+ * because most installs only ever see day and IR. */
31703
+ var SCENE_CAPTURE_VARIANTS = ["day", "ir"];
31704
+ var VARIANT_LABEL = {
31705
+ day: "Daylight",
31706
+ ir: "Night (IR)",
31707
+ night: "Night",
31708
+ dawn: "Dawn",
31709
+ dusk: "Dusk"
31710
+ };
31711
+ function variantLabel(condition) {
31712
+ return VARIANT_LABEL[condition] ?? condition;
31713
+ }
31714
+ /**
31715
+ * "Daylight ✓ · Night (IR) ✗ — optional; checks in night (ir) are skipped."
31716
+ *
31717
+ * Converts the silent cross-condition fallback this engine used to have into an
31718
+ * operator-visible fact. Without it, a scene with only a daylight reference
31719
+ * simply stops answering after sunset and nothing anywhere says why.
31720
+ *
31721
+ * It used to end *"reports 'can't tell' in night (ir)"*, which was accurate and
31722
+ * read as a defect: the operator saw a ✗ and a complaint for a scene that was
31723
+ * configured exactly as they meant it. The missing half is now named as what it
31724
+ * is — the part you do not have to do — and the sentence says what actually
31725
+ * happens instead, which differs by the scene's own policy.
31726
+ */
31727
+ function coverageLine(monitor) {
31728
+ const covered = new Set(monitor.coveredConditions);
31729
+ const parts = SCENE_CAPTURE_VARIANTS.map((v) => `${variantLabel(v)} ${covered.has(v) ? "✓" : "✗"}`);
31730
+ const extra = [...covered].filter((c) => !SCENE_CAPTURE_VARIANTS.some((v) => v === c));
31731
+ for (const c of extra) parts.push(`${variantLabel(c)} ✓`);
31732
+ const missing = SCENE_CAPTURE_VARIANTS.filter((v) => !covered.has(v));
31733
+ if (missing.length === 0) return parts.join(" · ");
31734
+ if (covered.size === 0) return `${parts.join(" · ")} — nothing captured yet, so this scene is not watching.`;
31735
+ const names = missing.map((v) => variantLabel(v).toLowerCase()).join(" and ");
31736
+ return monitor.onUncoveredCondition === "judge-anyway" ? `${parts.join(" · ")} — ${names} judged against the references you do have.` : `${parts.join(" · ")} — optional; checks in ${names} are skipped.`;
31737
+ }
31738
+ /**
31739
+ * The calm sentence for a scene that is sitting the current light out — `null`
31740
+ * whenever it is checking normally.
31741
+ *
31742
+ * Separate from {@link statusLine} because it is not a verdict and must not
31743
+ * read like one. A paused scene has not failed, has not lost its flag, and
31744
+ * needs nothing from the operator; the only thing worth saying is which light
31745
+ * it is waiting out and that it will pick itself back up.
31746
+ */
31747
+ function suspensionLine(monitor) {
31748
+ if (monitor.suspendedCondition === null) return null;
31749
+ const light = variantLabel(monitor.suspendedCondition).toLowerCase();
31750
+ return `Paused — nothing was captured in ${light}, so checks are on hold until the light changes back. Capture ${light} if you want it watched around the clock.`;
31751
+ }
31752
+ var UNAVAILABLE_SENTENCE = {
31753
+ "no-reference-for-condition": "can’t tell — nothing has been captured for this scene yet. Press “Capture daylight” to photograph what normal looks like.",
31754
+ "view-shifted": "can’t tell — the camera view has moved since the reference was captured. Re-capture it.",
31755
+ "no-vision-profile": "can’t tell — the vision model is unreachable, so the change is on hold.",
31756
+ "encoder-model-changed": "can’t tell — the embedding model changed, so the stored references are unreadable. Re-capture them.",
31757
+ "no-snapshot": "can’t tell — this camera did not return a frame."
31758
+ };
31759
+ /**
31760
+ * The one line under a scene's name. It answers, in order: can it judge, what
31761
+ * does it say, and how long has it said it.
31762
+ */
31763
+ function statusLine(monitor, now) {
31764
+ if (monitor.states.length === 0) return "Not armed yet — capture the initial state to start watching.";
31765
+ if (monitor.verdict === "unknown") return monitor.unavailable !== null ? UNAVAILABLE_SENTENCE[monitor.unavailable] : "can’t tell right now.";
31766
+ const since = monitor.verdict === "diverged" ? monitor.divergedAt : monitor.armedAt;
31767
+ const held = since !== null ? ` for ${humanDuration(Math.max(0, now - since))}` : "";
31768
+ if (monitor.latched) return monitor.verdict === "diverged" ? `CHANGED${held} — press Reset when you have dealt with it.` : `Back to normal, but still flagged as changed${held}. Press Reset to clear it.`;
31769
+ const paused = suspensionLine(monitor);
31770
+ if (paused !== null) return paused;
31771
+ return monitor.verdict === "diverged" ? `CHANGED${held}` : `Normal${held}`;
31772
+ }
31773
+ /** The badge word. `latched` wins over `verdict`, because the latch is the
31774
+ * thing the operator asked to be told and it outlives the live state.
31775
+ *
31776
+ * A scene sitting out an uncovered light reads `Paused`, in the NEUTRAL tone —
31777
+ * never `alarm`, and never the `danger` variant the page maps that to. A
31778
+ * missing IR reference must not be able to paint a red badge on a scene that
31779
+ * is doing exactly what it was configured to do. */
31780
+ function badgeFor(monitor) {
31781
+ if (monitor.states.length === 0) return {
31782
+ text: "Not armed",
31783
+ tone: "unknown"
31784
+ };
31785
+ if (monitor.latched) return {
31786
+ text: "Changed",
31787
+ tone: "alarm"
31788
+ };
31789
+ if (monitor.suspendedCondition !== null) return {
31790
+ text: "Paused",
31791
+ tone: "unknown"
31792
+ };
31793
+ if (monitor.verdict === "unknown") return {
31794
+ text: "Can’t tell",
31795
+ tone: "unknown"
31796
+ };
31797
+ return monitor.verdict === "diverged" ? {
31798
+ text: "Changed",
31799
+ tone: "alarm"
31800
+ } : {
31801
+ text: "Normal",
31802
+ tone: "ok"
31803
+ };
31804
+ }
31805
+ /** A rect covering most of the frame is dominated by weather, sky and parked
31806
+ * cars: the bin is 2 % of the pixels and CLIP will not notice it leaving. The
31807
+ * failure is silent INSENSITIVITY, which is the worst kind — hence a warning
31808
+ * rather than a refusal. */
31809
+ var ROI_AREA_WARN_FRACTION = .4;
31810
+ function roiTooLarge(roi) {
31811
+ return roi.width * roi.height > ROI_AREA_WARN_FRACTION;
31812
+ }
31813
+ function humanDuration(ms) {
31814
+ const s = Math.floor(ms / 1e3);
31815
+ if (s < 60) return `${s}s`;
31816
+ const m = Math.floor(s / 60);
31817
+ if (m < 60) return `${m}m`;
31818
+ const h = Math.floor(m / 60);
31819
+ if (h < 48) return `${h}h`;
31820
+ return `${Math.floor(h / 24)}d`;
31821
+ }
31822
+ //#endregion
31823
+ //#region src/composites/code-block.tsx
31824
+ function CodeBlock({ children, maxHeight = 300, className }) {
31825
+ const [copied, setCopied] = useState(false);
31826
+ const handleCopy = useCallback(() => {
31827
+ navigator.clipboard.writeText(children).then(() => {
31828
+ setCopied(true);
31829
+ setTimeout(() => setCopied(false), 2e3);
31830
+ });
31831
+ }, [children]);
31832
+ return /* @__PURE__ */ jsxs("div", {
31833
+ className: cn("relative group", className),
31834
+ children: [/* @__PURE__ */ jsx(ScrollArea, {
31835
+ style: { maxHeight },
31836
+ children: /* @__PURE__ */ jsx("pre", {
31837
+ className: "font-mono text-xs bg-surface p-3 rounded-md border border-border-subtle",
31838
+ children: /* @__PURE__ */ jsx("code", { children })
31839
+ })
31840
+ }), /* @__PURE__ */ jsx("div", {
31841
+ className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity",
31842
+ children: /* @__PURE__ */ jsx(IconButton, {
31843
+ icon: copied ? Check : Copy,
31844
+ "aria-label": "Copy code",
31845
+ variant: "ghost",
31846
+ size: "sm",
31847
+ onClick: handleCopy
31848
+ })
31849
+ })]
31850
+ });
31851
+ }
31852
+ //#endregion
31853
+ //#region src/composites/confirm-action-button.tsx
31854
+ /**
31855
+ * ConfirmActionButton — destructive-action button with a modal confirm.
31856
+ *
31857
+ * Two-step UX for any operation operators shouldn't trigger by accident:
31858
+ * reboot device, restart addon, regenerate token, etc. The trigger is a
31859
+ * normal Button that opens a Dialog; confirming runs the async action,
31860
+ * the trigger spinner-disables itself for the duration, and the dialog
31861
+ * closes on success. Errors surface inline at the dialog's bottom.
31862
+ *
31863
+ * Generic on `TResult` so callers don't have to discard the return
31864
+ * value. Pass an `icon` to render it inside the trigger (e.g. RotateCw
31865
+ * for reboot, RefreshCw for restart).
31866
+ */
31867
+ function ConfirmActionButton({ label, icon: Icon, title = "Confirm action", description, confirmLabel, triggerVariant = "outline", confirmVariant = "danger", size = "sm", disabled, className, action, onSuccess }) {
31868
+ const [open, setOpen] = useState(false);
31869
+ const [running, setRunning] = useState(false);
31870
+ const [error, setError] = useState(null);
31871
+ const handleConfirm = async () => {
31872
+ setError(null);
31873
+ setRunning(true);
31874
+ try {
31875
+ const result = await action();
31876
+ onSuccess?.(result);
31877
+ setOpen(false);
31878
+ } catch (err) {
31879
+ setError(err instanceof Error ? err.message : String(err));
31880
+ } finally {
31881
+ setRunning(false);
31882
+ }
31883
+ };
31884
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Button, {
31885
+ type: "button",
31886
+ variant: triggerVariant,
31887
+ size,
31888
+ disabled,
31889
+ onClick: () => {
31890
+ setError(null);
31891
+ setOpen(true);
31892
+ },
31893
+ className,
31894
+ children: [Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }), label]
31895
+ }), /* @__PURE__ */ jsx(Dialog, {
31896
+ open,
31897
+ onOpenChange: (next) => !running && setOpen(next),
31898
+ children: /* @__PURE__ */ jsxs(DialogContent, { children: [
31899
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsxs(DialogTitle, {
31900
+ className: "flex items-center gap-2",
31901
+ children: [/* @__PURE__ */ jsx(TriangleAlert, { className: "h-4 w-4 text-amber-400" }), title]
31902
+ }), typeof description === "string" ? /* @__PURE__ */ jsx(DialogDescription, { children: description }) : description] }),
31903
+ error && /* @__PURE__ */ jsx("div", {
31904
+ className: cn("mt-2 px-3 py-2 rounded border border-danger/40 bg-danger/10", "text-xs text-danger"),
31905
+ children: error
31906
+ }),
31907
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
31908
+ type: "button",
31909
+ variant: "ghost",
31910
+ size,
31911
+ disabled: running,
31912
+ onClick: () => setOpen(false),
31913
+ children: "Cancel"
31914
+ }), /* @__PURE__ */ jsxs(Button, {
31915
+ type: "button",
31916
+ variant: confirmVariant,
31917
+ size,
31918
+ disabled: running,
31919
+ onClick: () => {
31920
+ handleConfirm();
31921
+ },
31922
+ children: [running && /* @__PURE__ */ jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }), confirmLabel ?? label]
31923
+ })] })
31924
+ ] })
31925
+ })] });
31926
+ }
31927
+ //#endregion
31928
+ //#region src/composites/copy-button.tsx
31929
+ /**
31930
+ * `CopyButton` — a compact button that copies a string `value` to the
31931
+ * clipboard via `navigator.clipboard.writeText`, showing a brief
31932
+ * "copied" check state. Addon-agnostic; used wherever a secret / URL
31933
+ * needs a one-click copy affordance (export setup panels, etc.).
31934
+ */
31935
+ var COPIED_RESET_MS = 2e3;
31936
+ function CopyButton({ value, label, srLabel, className, disabled }) {
31937
+ const [copied, setCopied] = useState(false);
31938
+ const handleCopy = useCallback(() => {
31939
+ if (!value) return;
31940
+ navigator.clipboard.writeText(value).then(() => {
31941
+ setCopied(true);
31942
+ setTimeout(() => setCopied(false), COPIED_RESET_MS);
31943
+ });
31944
+ }, [value]);
31945
+ return /* @__PURE__ */ jsxs(Button, {
31946
+ size: "sm",
31947
+ variant: "ghost",
31948
+ type: "button",
31949
+ disabled: disabled || value.length === 0,
31950
+ onClick: handleCopy,
31951
+ className: cn(className),
31952
+ "aria-label": copied ? "Copied" : `Copy ${srLabel ?? label ?? "value"}`,
31953
+ children: [copied ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5 text-success" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" }), label ? /* @__PURE__ */ jsx("span", {
31954
+ className: "ml-1",
31955
+ children: copied ? "Copied" : label
31956
+ }) : null]
31957
+ });
31958
+ }
31959
+ //#endregion
31960
+ //#region src/composites/data-table-layout.ts
31961
+ /**
31962
+ * At this many columns and above, `auto` switches a narrow viewport to cards.
31963
+ * Three columns still fit a phone at a readable size; four do not.
31964
+ */
31965
+ var CARD_MODE_MIN_COLUMNS = 4;
31966
+ function resolveTableLayout({ mode, columnCount, isNarrow }) {
31967
+ if (!isNarrow) return "table";
31968
+ if (mode === "scroll") return "table";
31969
+ if (mode === "cards") return "cards";
31970
+ if (columnCount === 0) return "table";
31971
+ return columnCount >= 4 ? "cards" : "table";
31972
+ }
31973
+ //#endregion
31974
+ //#region src/lib/responsive.ts
31975
+ /**
31976
+ * Responsive design tokens — three-tier system.
31977
+ *
31978
+ * The admin-ui targets three width tiers; every component should pick
31979
+ * the right token from this file instead of hand-coding breakpoints.
31980
+ * Adopting the tokens uniformly is what makes the app feel consistent
31981
+ * across operator devices (mobile / tablet / desktop) and what unlocks
31982
+ * targeted tuning (e.g. shrink every label by 1px in one place).
31983
+ *
31984
+ * Tier definitions (Tailwind breakpoints):
31985
+ *
31986
+ * • **L1 — Compact** (`< 640px`, default = mobile portrait)
31987
+ * Single column, tight padding, smallest text, icon-only buttons
31988
+ * where labels can be inferred. The operator can still see every
31989
+ * stat / action — no horizontal scroll, no clipped text. The user
31990
+ * directive: "molta informazione in poco spazio quando la width è
31991
+ * bassa."
31992
+ *
31993
+ * • **L2 — Standard** (`sm` — `640–1023px`, tablet + small laptop)
31994
+ * 2-column grids, side panels become visible, button labels return.
31995
+ * Targets ~768px–1024px viewports — the most common operator sizes.
31996
+ *
31997
+ * • **L3 — Spacious** (`lg+` — `≥ 1024px`, desktop)
31998
+ * 4-column grids, generous padding, full-width header text,
31999
+ * side-by-side composite layouts. The operator has elbow room.
32000
+ *
32001
+ * Conventions:
32002
+ * - **Always start from L1** — the bare class is always the compact
32003
+ * variant, then `sm:` adds room at 640px, `lg:` at 1024px. No
32004
+ * desktop-first breakpoints; no max-width queries.
32005
+ * - **Token strings are static** — kept as `as const` so callers can
32006
+ * compose them via `cn()` / template literals without running a
32007
+ * class generator at runtime.
32008
+ * - **Pair the token with a comment** — the comment in the file
32009
+ * names every breakpoint it crosses, so a reader can predict the
32010
+ * layout without going to Tailwind docs.
32011
+ */
32012
+ /** Container padding for a card-style section (header + body). */
32013
+ var SECTION_CARD = "rounded-lg border border-border bg-surface overflow-hidden";
32014
+ /** Header strip inside a card (between border-b lines). */
32015
+ var SECTION_HEADER = "border-b border-border px-3 sm:px-4 py-1.5 sm:py-2";
32016
+ /** Body padding for a card-style section. */
32017
+ var SECTION_BODY = "p-2 sm:p-3 lg:p-4";
32018
+ /** Gap between cards in a vertical stack. */
32019
+ var STACK_GAP = "space-y-3 sm:space-y-4";
32020
+ /** Gap between cards in a grid (4 cells / row at lg). */
32021
+ var GRID_GAP = "gap-2 sm:gap-3";
32022
+ /** Row padding inside a divided list (e.g. InfoRow). */
32023
+ var LIST_ROW = "px-3 sm:px-4 py-1.5 sm:py-2";
32024
+ /** 1-up at L1, 2-up at L2, 4-up at L3 — quick-stat row. */
32025
+ var GRID_QUICK_STATS = "grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4";
32026
+ /** 1-up at L1, 2-up at L2+ — paired panels (motion + detection rules). */
32027
+ var GRID_PAIRED = "grid grid-cols-1 lg:grid-cols-2";
32028
+ /** Side-by-side layout that stacks below md (canvas + side panel). */
32029
+ var SPLIT_PANEL_OUTER = "flex flex-col-reverse md:flex-row";
32030
+ /** Sidebar narrow lane in a SPLIT_PANEL_OUTER layout. */
32031
+ var SPLIT_PANEL_SIDE = "w-full md:w-44 lg:w-52 md:flex-shrink-0 border-b md:border-b-0 md:border-l border-border";
32032
+ /**
32033
+ * The tier boundary at which a settings label/value row stops stacking.
32034
+ *
32035
+ * Below it (L1 — compact) the row is ONE column: label on its own line, value
32036
+ * on the next at full width. Above it the row is label-left / value-right as
32037
+ * before. The two-column form needs `SETTING_ROW_LABEL`'s lane plus a readable
32038
+ * value beside it; a phone has neither, and the failure mode is not "cramped"
32039
+ * but "the value is the part that gets cut" — the one thing the operator
32040
+ * opened the page to read.
32041
+ */
32042
+ var SETTING_ROW_STACK_BREAKPOINT = "sm";
32043
+ /** Outer row: single column at L1, label/value columns from `sm` up. */
32044
+ var SETTING_ROW = "flex min-w-0 flex-col gap-0.5 py-1.5 sm:flex-row sm:items-center";
32045
+ /** Label lane. Full width (and free to wrap) at L1; a fixed lane from `sm` up. */
32046
+ var SETTING_ROW_LABEL = "min-w-0 text-[11px] leading-tight text-foreground-subtle sm:w-32 sm:shrink-0 sm:pr-2";
32047
+ /**
32048
+ * Value lane — the value text plus its trailing affordances (copy / reveal).
32049
+ * `w-full` at L1 so the value owns the whole row once the label is above it;
32050
+ * `sm:flex-1` makes it share the row again from `sm` up.
32051
+ */
32052
+ var SETTING_ROW_VALUE = "flex w-full min-w-0 items-center gap-1 sm:flex-1";
32053
+ /**
32054
+ * The value text itself. `break-all` lets an opaque token (a key, a URL) wrap
32055
+ * at L1 instead of being cut mid-word; `sm:truncate` restores the single-line
32056
+ * desktop form, where the row is wide enough for truncation to be a choice
32057
+ * rather than data loss.
32058
+ */
32059
+ var SETTING_ROW_VALUE_TEXT = "min-w-0 break-all text-xs text-foreground sm:truncate";
32060
+ /** Section header label (uppercase tracking-wider). */
32061
+ var TEXT_SECTION_LABEL = "text-[10px] sm:text-[11px] font-semibold text-foreground uppercase tracking-wider";
32062
+ /** Field label inside a row. */
32063
+ var TEXT_FIELD_LABEL = "text-[11px] sm:text-xs text-foreground";
32064
+ /** Sub-label / hint text. */
32065
+ var TEXT_HINT = "text-[10px] text-foreground-subtle";
32066
+ /** Primary value (a metric, badge, …). */
32067
+ var TEXT_VALUE = "text-[11px] sm:text-xs font-medium text-foreground";
32068
+ /** Big metric value (StatCard). */
32069
+ var TEXT_METRIC = "text-base sm:text-lg font-semibold leading-tight text-foreground";
32070
+ /** Default compact button. */
32071
+ var BTN_COMPACT = "inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40";
32072
+ /** Primary compact button. */
32073
+ var BTN_COMPACT_PRIMARY = "inline-flex items-center justify-center gap-1 rounded border border-primary/40 bg-primary/15 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-primary hover:bg-primary/25 transition-colors disabled:opacity-40";
32074
+ /** Danger compact button. */
32075
+ var BTN_COMPACT_DANGER = "inline-flex items-center justify-center gap-1 rounded border border-danger/40 bg-danger/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40";
32076
+ /** Warning compact button (e.g. cancel-drawing). */
32077
+ var BTN_COMPACT_WARNING = "inline-flex items-center justify-center gap-1 rounded border border-warning/40 bg-warning/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-warning hover:bg-warning/20 transition-colors disabled:opacity-40";
32078
+ /** Compact text/select/number input. */
32079
+ var INPUT_COMPACT = "w-full rounded border border-border bg-background px-1.5 py-0.5 sm:px-2 sm:py-1 text-[11px] sm:text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none";
32080
+ /** Chip-style toggle (zone / class selectors in ZoneRulesEditor). */
32081
+ var CHIP_BASE = "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors";
32082
+ var CHIP_ACTIVE = "border-primary/50 bg-primary/15 text-primary";
32083
+ var CHIP_INACTIVE = "border-border bg-surface text-foreground-subtle hover:bg-surface-hover";
32084
+ //#endregion
32085
+ //#region src/composites/setting-row.tsx
32086
+ function SettingRow({ label, children, actions, elements = "plain", className, valueClassName }) {
32087
+ const LabelTag = elements === "description" ? "dt" : "span";
32088
+ const ValueTag = elements === "description" ? "dd" : "div";
32089
+ return /* @__PURE__ */ jsxs("div", {
32090
+ "data-setting-row": "",
32091
+ className: cn(SETTING_ROW, className),
32092
+ children: [/* @__PURE__ */ jsx(LabelTag, {
32093
+ "data-setting-row-label": "",
32094
+ className: SETTING_ROW_LABEL,
32095
+ children: label
32096
+ }), /* @__PURE__ */ jsxs(ValueTag, {
32097
+ "data-setting-row-value": "",
32098
+ className: SETTING_ROW_VALUE,
32099
+ children: [/* @__PURE__ */ jsx("span", {
32100
+ "data-setting-row-value-text": "",
32101
+ className: cn(SETTING_ROW_VALUE_TEXT, valueClassName),
32102
+ children
32103
+ }), actions !== void 0 && /* @__PURE__ */ jsx("span", {
32104
+ className: "flex shrink-0 items-center gap-0.5",
32105
+ children: actions
32106
+ })]
32107
+ })]
32108
+ });
32109
+ }
32110
+ //#endregion
32111
+ //#region src/composites/sort-header-button.tsx
32112
+ function SortHeaderButton({ label, active, dir, onSort }) {
32113
+ return /* @__PURE__ */ jsxs("button", {
32114
+ type: "button",
32115
+ onClick: onSort,
32116
+ className: "group/sort inline-flex items-center gap-0.5 hover:text-foreground transition-colors",
32117
+ children: [/* @__PURE__ */ jsx("span", { children: label }), active ? dir === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3 flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronUp, { className: cn("h-3 w-3 flex-shrink-0 opacity-0 transition-opacity", "group-hover/sort:opacity-30") })]
32118
+ });
32119
+ }
32120
+ //#endregion
32121
+ //#region src/composites/table-sort.ts
32122
+ /**
32123
+ * The toggle rule, and the only copy of it.
32124
+ *
32125
+ * none → asc → desc → none, and a click on a DIFFERENT column starts that
32126
+ * column fresh at `asc`. `sameColumn` says whether the clicked column is the
32127
+ * one currently sorted; `currentDir` is its direction (`null` when nothing is
32128
+ * sorted). Returns the next direction, or `null` for "unsorted".
32129
+ *
32130
+ * Split out from {@link nextTableSort} so the device list — whose sort state
32131
+ * keys columns by `columnId`, not `columnKey` — can reuse the rule without a
32132
+ * cast and without a second copy of it.
32133
+ */
32134
+ function nextSortDirection(sameColumn, currentDir) {
32135
+ if (!sameColumn || currentDir === null) return "asc";
32136
+ return currentDir === "asc" ? "desc" : null;
32137
+ }
32138
+ /**
32139
+ * Toggle a column's sort on header click: none → asc → desc → none.
32140
+ * Clicking a DIFFERENT column starts it fresh at `asc`.
32141
+ */
32142
+ function nextTableSort(current, columnKey) {
32143
+ const dir = nextSortDirection(current !== null && current.columnKey === columnKey, current === null ? null : current.dir);
32144
+ return dir === null ? null : {
32145
+ columnKey,
32146
+ dir
32147
+ };
32148
+ }
32149
+ /**
32150
+ * Ascending comparison of two cell values.
32151
+ *
32152
+ * Numbers compare numerically and strings compare with `localeCompare` — a
32153
+ * numeric column must never be ordered as text ("100" before "9"), and a text
32154
+ * column must respect the locale's collation. A mixed column (one row a
32155
+ * number, another a string) falls back to string comparison of both, which is
32156
+ * the only total order available; it is not a shape any caller should build on
32157
+ * purpose.
32158
+ *
32159
+ * `null` is NOT handled here — {@link sortRowsByColumn} pulls it out first,
32160
+ * because its placement is direction-independent and a comparator that is
32161
+ * multiplied by the direction factor cannot express that.
32162
+ */
32163
+ function compareValues(a, b) {
32164
+ if (typeof a === "number" && typeof b === "number") return a - b;
32165
+ return String(a).localeCompare(String(b));
32166
+ }
32167
+ /**
32168
+ * Return a NEW array of `rows` ordered by `sort`.
32169
+ *
32170
+ * `valueOf` is the column's `sortValue` — it is called once per row per
32171
+ * comparison, so it must be cheap (read a field, do not format a string).
32172
+ * `sort === null` ⇒ a fresh shallow copy in the incoming order.
32173
+ */
32174
+ function sortRowsByColumn(rows, sort, valueOf) {
32175
+ if (sort === null) return [...rows];
32176
+ const factor = sort.dir === "asc" ? 1 : -1;
32177
+ return rows.toSorted((a, b) => {
32178
+ const av = valueOf(a);
32179
+ const bv = valueOf(b);
32180
+ if (av === null || bv === null) {
32181
+ if (av === bv) return 0;
32182
+ return av === null ? 1 : -1;
32183
+ }
32184
+ return factor * compareValues(av, bv);
32185
+ });
32186
+ }
32187
+ /** Derive the `<th>` `aria-sort` for `columnKey` from the table's sort state. */
32188
+ function ariaSortForColumn(sort, columnKey) {
32189
+ if (sort === null || sort.columnKey !== columnKey) return "none";
32190
+ return sort.dir === "asc" ? "ascending" : "descending";
32191
+ }
32192
+ //#endregion
32193
+ //#region src/composites/data-table.tsx
32194
+ /**
32195
+ * DataTable — shared responsive table for admin pages.
32196
+ *
32197
+ * Recipes baked in:
32198
+ * - `overflow-x-auto` wrapper so narrow viewports don't clip the
32199
+ * right edge (the rounded border survives the scroll).
32200
+ * - `min-w-[Npx]` on the inner table so columns don't squash below
32201
+ * readable width before the scroll kicks in.
32202
+ * - `whitespace-nowrap` on headers — column titles never wrap to
32203
+ * two lines (`AUTO-KILL` was the regression that triggered this).
32204
+ * - Themed `bg-surface` + `border-border` so contrast works in both
32205
+ * light and dark themes.
32206
+ *
32207
+ * Column model: caller supplies `columns: DataColumn<T>[]` and
32208
+ * `rows: T[]`. Each column declares `header`, optional `align`,
32209
+ * optional `nowrap`, and a `render(row) => ReactNode` that produces
32210
+ * the cell content.
32211
+ *
32212
+ * <DataTable
32213
+ * columns={[
32214
+ * { key: 'username', header: 'Username', render: (u) => u.username },
32215
+ * { key: 'role', header: 'Role', render: (u) => <RoleBadge .../> },
32216
+ * { key: 'actions', header: '', align: 'right', render: (u) => <Actions .../> },
32217
+ * ]}
32218
+ * rows={users}
32219
+ * minWidthPx={560}
32220
+ * />
32221
+ *
32222
+ * If finer header markup is needed, pass `headerRender` instead of
32223
+ * `header` (e.g. for a sortable click affordance).
32224
+ *
32225
+ * ── Narrow viewports ──────────────────────────────────────────────────────
32226
+ * The table stays a table. The wrapper is `overflow-x-auto`, so a phone
32227
+ * scrolls the columns sideways INSIDE the table — the page body never moves
32228
+ * sideways, and the cells stay one line (`whitespace-nowrap`). That is the
32229
+ * default (`mobileMode="scroll"`). Cards are opt-in via `mobileMode="cards"`;
32230
+ * `auto` still applies the old column-count rule for a surface that wants it.
32231
+ * See `resolveTableLayout`.
32232
+ *
32233
+ * ── Scrolling the BODY, not the page ──────────────────────────────────────
32234
+ * `maxBodyHeight` caps the table and scrolls its rows INSIDE the container
32235
+ * with the column header pinned. It is ONE prop, not two, because "this list
32236
+ * scrolls internally" and "its header stays visible" are the same decision: a
32237
+ * capped table whose header scrolls away is a list of unlabelled cells.
32238
+ *
32239
+ * Use it wherever the row count is open-ended (rules, targets, delivery
32240
+ * history) so the page keeps its own header, filters and actions in view while
32241
+ * the operator moves through the rows.
32242
+ */
32243
+ /**
32244
+ * The default cap for an internally-scrolling table.
32245
+ *
32246
+ * `60vh` leaves the page header, its filters and its actions on screen at
32247
+ * every viewport while still showing ~10 rows — and it is a fraction, so it
32248
+ * does not need a breakpoint of its own.
32249
+ */
32250
+ var TABLE_SCROLL_MAX_H = "max-h-[60vh]";
32251
+ var ALIGN_CLASS = {
32252
+ left: "text-left",
32253
+ right: "text-right",
32254
+ center: "text-center"
32255
+ };
32256
+ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyMessage, className, bordered = true, rowClassName, mobileMode = "scroll", maxBodyHeight, defaultSort }) {
32257
+ const isNarrow = useIsMobile();
32258
+ const [sort, setSort] = useState(defaultSort ?? null);
32259
+ const layout = resolveTableLayout({
32260
+ mode: mobileMode,
32261
+ columnCount: columns.length,
32262
+ isNarrow
32263
+ });
32264
+ const scrolls = maxBodyHeight !== void 0;
32265
+ const sortedColumn = useMemo(() => sort === null ? void 0 : columns.find((col) => col.key === sort.columnKey && col.sortValue !== void 0), [columns, sort]);
32266
+ const sortValue = sortedColumn?.sortValue;
32267
+ const displayRows = useMemo(() => sortValue === void 0 ? rows : sortRowsByColumn(rows, sort, sortValue), [
32268
+ rows,
32269
+ sort,
32270
+ sortValue
32271
+ ]);
32272
+ const activeSort = sortedColumn === void 0 ? null : sort;
32273
+ if (rows.length === 0 && emptyMessage) return /* @__PURE__ */ jsx("div", {
32274
+ className: `rounded-lg ${bordered ? "border border-border" : ""} bg-surface px-3 py-4 text-xs text-foreground-subtle text-center ${className ?? ""}`,
32275
+ children: emptyMessage
32276
+ });
32277
+ if (rows.length === 0) return null;
32278
+ if (layout === "cards") return /* @__PURE__ */ jsx("div", {
32279
+ className: `space-y-2 ${scrolls ? `${maxBodyHeight} overflow-y-auto` : ""} ${className ?? ""}`,
32280
+ children: displayRows.map((row, rowIndex) => /* @__PURE__ */ jsx(DataTableCard, {
32281
+ row,
32282
+ rowIndex,
32283
+ columns,
32284
+ bordered,
32285
+ onRowClick,
32286
+ rowClassName
32287
+ }, rowKey ? rowKey(row, rowIndex) : rowIndex))
32288
+ });
32289
+ return /* @__PURE__ */ jsx("div", {
32290
+ className: [
32291
+ "rounded-lg",
32292
+ bordered ? "border border-border" : "",
32293
+ "bg-surface overflow-x-auto",
32294
+ scrolls ? `${maxBodyHeight} overflow-y-auto` : "",
32295
+ className ?? ""
32296
+ ].filter(Boolean).join(" "),
32297
+ children: /* @__PURE__ */ jsxs("table", {
32298
+ className: `w-full text-xs ${scrolls ? "border-separate border-spacing-0" : ""}`,
32299
+ style: { minWidth: `${minWidthPx}px` },
32300
+ children: [/* @__PURE__ */ jsx("thead", {
32301
+ className: "bg-surface",
32302
+ children: /* @__PURE__ */ jsx("tr", { children: columns.map((col) => {
32303
+ const align = col.align ?? "left";
32304
+ const nowrap = col.nowrap ?? true;
32305
+ const sortable = col.sortValue !== void 0;
32306
+ const isSorted = activeSort !== null && activeSort.columnKey === col.key;
32307
+ return /* @__PURE__ */ jsx("th", {
32308
+ "aria-sort": sortable ? ariaSortForColumn(activeSort, col.key) : void 0,
32309
+ title: sortable ? void 0 : col.notSortableReason,
32310
+ className: [
32311
+ "px-3 py-2 text-foreground-subtle font-medium bg-surface border-b border-border",
32312
+ scrolls ? "sticky top-0 z-10" : "",
32313
+ ALIGN_CLASS[align],
32314
+ nowrap ? "whitespace-nowrap" : "",
32315
+ col.width ?? ""
32316
+ ].filter(Boolean).join(" "),
32317
+ children: sortable ? /* @__PURE__ */ jsx(SortHeaderButton, {
32318
+ label: col.headerRender ? col.headerRender() : col.header,
32319
+ active: isSorted,
32320
+ dir: isSorted && activeSort !== null ? activeSort.dir : "asc",
32321
+ onSort: () => setSort((prev) => nextTableSort(prev, col.key))
32322
+ }) : col.headerRender ? col.headerRender() : col.header
32323
+ }, col.key);
32324
+ }) })
32325
+ }), /* @__PURE__ */ jsx("tbody", { children: displayRows.map((row, rowIndex) => {
32326
+ const key = rowKey ? rowKey(row, rowIndex) : rowIndex;
32327
+ const extra = rowClassName?.(row, rowIndex) ?? "";
32328
+ const interactive = onRowClick !== void 0;
32329
+ return /* @__PURE__ */ jsx("tr", {
32330
+ onClick: interactive ? () => onRowClick(row, rowIndex) : void 0,
32331
+ className: [interactive ? "cursor-pointer hover:bg-primary/5" : "hover:bg-primary/5", extra].filter(Boolean).join(" "),
32332
+ children: columns.map((col) => {
32333
+ const align = col.align ?? "left";
32334
+ const nowrap = col.nowrap ?? true;
32335
+ return /* @__PURE__ */ jsx("td", {
32336
+ className: [
32337
+ "px-3 py-2 text-foreground border-b border-border",
32338
+ ALIGN_CLASS[align],
32339
+ nowrap ? "whitespace-nowrap" : ""
32340
+ ].filter(Boolean).join(" "),
32341
+ children: col.render(row, rowIndex)
32342
+ }, col.key);
32343
+ })
32344
+ }, key);
32345
+ }) })]
32346
+ })
32347
+ });
32348
+ }
32349
+ /**
32350
+ * One row as a card. Columns that carry a plain-text `header` become labelled
32351
+ * `SettingRow`s — the label is the column title and the value gets the full
32352
+ * card width. Columns with no text header (an actions column, a
32353
+ * `headerRender`-only column) have no label to show, so they render as a
32354
+ * full-width strip at the foot of the card.
32355
+ */
32356
+ function DataTableCard({ row, rowIndex, columns, bordered, onRowClick, rowClassName }) {
32357
+ const labelled = columns.filter((col) => col.header !== void 0 && col.header !== "");
32358
+ const unlabelled = columns.filter((col) => col.header === void 0 || col.header === "");
32359
+ const interactive = onRowClick !== void 0;
32360
+ const extra = rowClassName?.(row, rowIndex) ?? "";
32361
+ return /* @__PURE__ */ jsxs("div", {
32362
+ "data-data-table-card": "",
32363
+ onClick: interactive ? () => onRowClick(row, rowIndex) : void 0,
32364
+ className: [
32365
+ "rounded-lg bg-surface px-3 py-1.5 divide-y divide-border-subtle",
32366
+ bordered ? "border border-border" : "",
32367
+ interactive ? "cursor-pointer hover:bg-primary/5" : "",
32368
+ extra
32369
+ ].filter(Boolean).join(" "),
32370
+ children: [labelled.map((col) => /* @__PURE__ */ jsx(SettingRow, {
32371
+ label: col.header,
32372
+ children: col.render(row, rowIndex)
32373
+ }, col.key)), unlabelled.length > 0 && /* @__PURE__ */ jsx("div", {
32374
+ className: "flex flex-wrap items-center justify-end gap-2 py-1.5",
32375
+ children: unlabelled.map((col) => /* @__PURE__ */ jsx("div", { children: col.render(row, rowIndex) }, col.key))
32376
+ })]
30831
32377
  });
30832
32378
  }
30833
32379
  //#endregion
30834
- //#region src/composites/cap-settings/scene-monitor-copy.ts
30835
- /** The lighting variants an operator is OFFERED. The resolver can also report
30836
- * `night`, `dawn` and `dusk`; those are shown when present but never demanded,
30837
- * because most installs only ever see day and IR. */
30838
- var SCENE_CAPTURE_VARIANTS = ["day", "ir"];
30839
- var VARIANT_LABEL = {
30840
- day: "Daylight",
30841
- ir: "Night (IR)",
30842
- night: "Night",
30843
- dawn: "Dawn",
30844
- dusk: "Dusk"
30845
- };
30846
- function variantLabel(condition) {
30847
- return VARIANT_LABEL[condition] ?? condition;
30848
- }
32380
+ //#region src/composites/device-list/fuzzy-match.ts
30849
32381
  /**
30850
- * "Daylight ✓ · Night (IR) ✗ — optional; checks in night (ir) are skipped."
32382
+ * fuzzy-match — case and separator-insensitive text search helper.
30851
32383
  *
30852
- * Converts the silent cross-condition fallback this engine used to have into an
30853
- * operator-visible fact. Without it, a scene with only a daylight reference
30854
- * simply stops answering after sunset and nothing anywhere says why.
32384
+ * Normalization rule: lowercase + strip all runs of hyphens, underscores and
32385
+ * whitespace entirely. This makes `Tapparella cucina` and `tapparella-cucina`
32386
+ * both normalize to `tapparellacucina`, so a substring match succeeds in
32387
+ * either direction.
32388
+ */
32389
+ /**
32390
+ * Strips hyphens, underscores and whitespace runs from `s` and lowercases it.
30855
32391
  *
30856
- * It used to end *"reports 'can't tell' in night (ir)"*, which was accurate and
30857
- * read as a defect: the operator saw a ✗ and a complaint for a scene that was
30858
- * configured exactly as they meant it. The missing half is now named as what it
30859
- * is — the part you do not have to do — and the sentence says what actually
30860
- * happens instead, which differs by the scene's own policy.
32392
+ * @example
32393
+ * normalizeForSearch('Tapparella cucina') // 'tapparellacucina'
32394
+ * normalizeForSearch('tapparella-cucina') // 'tapparellacucina'
32395
+ * normalizeForSearch('tapparella_cucina') // 'tapparellacucina'
30861
32396
  */
30862
- function coverageLine(monitor) {
30863
- const covered = new Set(monitor.coveredConditions);
30864
- const parts = SCENE_CAPTURE_VARIANTS.map((v) => `${variantLabel(v)} ${covered.has(v) ? "✓" : "✗"}`);
30865
- const extra = [...covered].filter((c) => !SCENE_CAPTURE_VARIANTS.some((v) => v === c));
30866
- for (const c of extra) parts.push(`${variantLabel(c)} ✓`);
30867
- const missing = SCENE_CAPTURE_VARIANTS.filter((v) => !covered.has(v));
30868
- if (missing.length === 0) return parts.join(" · ");
30869
- if (covered.size === 0) return `${parts.join(" · ")} — nothing captured yet, so this scene is not watching.`;
30870
- const names = missing.map((v) => variantLabel(v).toLowerCase()).join(" and ");
30871
- return monitor.onUncoveredCondition === "judge-anyway" ? `${parts.join(" · ")} — ${names} judged against the references you do have.` : `${parts.join(" · ")} — optional; checks in ${names} are skipped.`;
32397
+ function normalizeForSearch(s) {
32398
+ return s.toLowerCase().replace(/[-_\s]+/g, "");
30872
32399
  }
30873
32400
  /**
30874
- * The calm sentence for a scene that is sitting the current light out — `null`
30875
- * whenever it is checking normally.
32401
+ * Returns `true` when the normalized form of `target` contains the normalized
32402
+ * form of `query`. An empty query always matches.
30876
32403
  *
30877
- * Separate from {@link statusLine} because it is not a verdict and must not
30878
- * read like one. A paused scene has not failed, has not lost its flag, and
30879
- * needs nothing from the operator; the only thing worth saying is which light
30880
- * it is waiting out and that it will pick itself back up.
32404
+ * @example
32405
+ * fuzzyMatch('Tapparella cucina', 'tapparella-cucina') // true
32406
+ * fuzzyMatch('tapparella cucina', 'Tapparella-Cucina') // true
32407
+ * fuzzyMatch('xyz', 'tapparella-cucina') // false
30881
32408
  */
30882
- function suspensionLine(monitor) {
30883
- if (monitor.suspendedCondition === null) return null;
30884
- const light = variantLabel(monitor.suspendedCondition).toLowerCase();
30885
- return `Paused — nothing was captured in ${light}, so checks are on hold until the light changes back. Capture ${light} if you want it watched around the clock.`;
32409
+ function fuzzyMatch(query, target) {
32410
+ const nq = normalizeForSearch(query);
32411
+ if (nq === "") return true;
32412
+ return normalizeForSearch(target).includes(nq);
30886
32413
  }
30887
- var UNAVAILABLE_SENTENCE = {
30888
- "no-reference-for-condition": "can’t tell — nothing has been captured for this scene yet. Press “Capture daylight” to photograph what normal looks like.",
30889
- "view-shifted": "can’t tell — the camera view has moved since the reference was captured. Re-capture it.",
30890
- "no-vision-profile": "can’t tell — the vision model is unreachable, so the change is on hold.",
30891
- "encoder-model-changed": "can’t tell — the embedding model changed, so the stored references are unreadable. Re-capture them.",
30892
- "no-snapshot": "can’t tell — this camera did not return a frame."
32414
+ //#endregion
32415
+ //#region src/composites/data-table-filter.ts
32416
+ /**
32417
+ * Per-instance filtering for a `DataTable` (or any row list): a search box
32418
+ * and a set of facet chips, both DERIVED from the rows the instance renders.
32419
+ *
32420
+ * Pure — no React. The state lives with the caller (`useDataTableFilter`), so
32421
+ * two tables on one page each carry their own filter, and the caller keeps the
32422
+ * FILTERED set it renders: a table whose selection acts on "what is on
32423
+ * screen" has to know what that is, which a filter hidden inside the table
32424
+ * could not tell it.
32425
+ *
32426
+ * Two rules, both load-bearing:
32427
+ * - **Facets are derived from the rows present**, most common first. A
32428
+ * hand-listed set goes stale the day a provider adds a type and offers
32429
+ * chips that match nothing.
32430
+ * - **A selected facet no row carries is ignored**, not applied. The chip is
32431
+ * not drawn (there is no row to derive it from), and an invisible filter
32432
+ * that empties the table is a table that looks broken.
32433
+ */
32434
+ var EMPTY_DATA_TABLE_FILTER = {
32435
+ search: "",
32436
+ facets: []
30893
32437
  };
30894
32438
  /**
30895
- * The one line under a scene's name. It answers, in order: can it judge, what
30896
- * does it say, and how long has it said it.
32439
+ * The facet chips for these rows: one per distinct value, most common first,
32440
+ * ties by value.
30897
32441
  */
30898
- function statusLine(monitor, now) {
30899
- if (monitor.states.length === 0) return "Not armed yet — capture the initial state to start watching.";
30900
- if (monitor.verdict === "unknown") return monitor.unavailable !== null ? UNAVAILABLE_SENTENCE[monitor.unavailable] : "can’t tell right now.";
30901
- const since = monitor.verdict === "diverged" ? monitor.divergedAt : monitor.armedAt;
30902
- const held = since !== null ? ` for ${humanDuration(Math.max(0, now - since))}` : "";
30903
- if (monitor.latched) return monitor.verdict === "diverged" ? `CHANGED${held} — press Reset when you have dealt with it.` : `Back to normal, but still flagged as changed${held}. Press Reset to clear it.`;
30904
- const paused = suspensionLine(monitor);
30905
- if (paused !== null) return paused;
30906
- return monitor.verdict === "diverged" ? `CHANGED${held}` : `Normal${held}`;
30907
- }
30908
- /** The badge word. `latched` wins over `verdict`, because the latch is the
30909
- * thing the operator asked to be told and it outlives the live state.
30910
- *
30911
- * A scene sitting out an uncovered light reads `Paused`, in the NEUTRAL tone —
30912
- * never `alarm`, and never the `danger` variant the page maps that to. A
30913
- * missing IR reference must not be able to paint a red badge on a scene that
30914
- * is doing exactly what it was configured to do. */
30915
- function badgeFor(monitor) {
30916
- if (monitor.states.length === 0) return {
30917
- text: "Not armed",
30918
- tone: "unknown"
30919
- };
30920
- if (monitor.latched) return {
30921
- text: "Changed",
30922
- tone: "alarm"
30923
- };
30924
- if (monitor.suspendedCondition !== null) return {
30925
- text: "Paused",
30926
- tone: "unknown"
30927
- };
30928
- if (monitor.verdict === "unknown") return {
30929
- text: "Can’t tell",
30930
- tone: "unknown"
30931
- };
30932
- return monitor.verdict === "diverged" ? {
30933
- text: "Changed",
30934
- tone: "alarm"
30935
- } : {
30936
- text: "Normal",
30937
- tone: "ok"
30938
- };
32442
+ function dataTableFacets(rows, facetValue) {
32443
+ if (facetValue === void 0) return [];
32444
+ const counts = /* @__PURE__ */ new Map();
32445
+ for (const row of rows) {
32446
+ const value = facetValue(row);
32447
+ counts.set(value, (counts.get(value) ?? 0) + 1);
32448
+ }
32449
+ return [...counts.entries()].map(([value, count]) => ({
32450
+ value,
32451
+ count
32452
+ })).toSorted((a, b) => b.count - a.count || a.value.localeCompare(b.value));
30939
32453
  }
30940
- /** A rect covering most of the frame is dominated by weather, sky and parked
30941
- * cars: the bin is 2 % of the pixels and CLIP will not notice it leaving. The
30942
- * failure is silent INSENSITIVITY, which is the worst kind — hence a warning
30943
- * rather than a refusal. */
30944
- var ROI_AREA_WARN_FRACTION = .4;
30945
- function roiTooLarge(roi) {
30946
- return roi.width * roi.height > ROI_AREA_WARN_FRACTION;
32454
+ function isDataTableFilterActive(state) {
32455
+ return state.search.trim() !== "" || state.facets.length > 0;
30947
32456
  }
30948
- function humanDuration(ms) {
30949
- const s = Math.floor(ms / 1e3);
30950
- if (s < 60) return `${s}s`;
30951
- const m = Math.floor(s / 60);
30952
- if (m < 60) return `${m}m`;
30953
- const h = Math.floor(m / 60);
30954
- if (h < 48) return `${h}h`;
30955
- return `${Math.floor(h / 24)}d`;
32457
+ /** A new state with `value` added to, or removed from, the selected facets. */
32458
+ function toggleDataTableFacet(state, value) {
32459
+ return {
32460
+ ...state,
32461
+ facets: state.facets.includes(value) ? state.facets.filter((v) => v !== value) : [...state.facets, value]
32462
+ };
30956
32463
  }
30957
- //#endregion
30958
- //#region src/composites/code-block.tsx
30959
- function CodeBlock({ children, maxHeight = 300, className }) {
30960
- const [copied, setCopied] = useState(false);
30961
- const handleCopy = useCallback(() => {
30962
- navigator.clipboard.writeText(children).then(() => {
30963
- setCopied(true);
30964
- setTimeout(() => setCopied(false), 2e3);
30965
- });
30966
- }, [children]);
30967
- return /* @__PURE__ */ jsxs("div", {
30968
- className: cn("relative group", className),
30969
- children: [/* @__PURE__ */ jsx(ScrollArea, {
30970
- style: { maxHeight },
30971
- children: /* @__PURE__ */ jsx("pre", {
30972
- className: "font-mono text-xs bg-surface p-3 rounded-md border border-border-subtle",
30973
- children: /* @__PURE__ */ jsx("code", { children })
30974
- })
30975
- }), /* @__PURE__ */ jsx("div", {
30976
- className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity",
30977
- children: /* @__PURE__ */ jsx(IconButton, {
30978
- icon: copied ? Check : Copy,
30979
- "aria-label": "Copy code",
30980
- variant: "ghost",
30981
- size: "sm",
30982
- onClick: handleCopy
30983
- })
30984
- })]
32464
+ /**
32465
+ * The rows that survive the filter, in their incoming order.
32466
+ *
32467
+ * A selected facet that none of `rows` carries is dropped from the effective
32468
+ * selection (see the header), so a chip that is not on screen never filters.
32469
+ */
32470
+ function filterDataTableRows(rows, state, config) {
32471
+ const needle = state.search.trim();
32472
+ const facetValue = config.facetValue;
32473
+ const present = new Set(dataTableFacets(rows, facetValue).map((f) => f.value));
32474
+ const selected = new Set(state.facets.filter((v) => present.has(v)));
32475
+ return rows.filter((row) => {
32476
+ if (selected.size > 0 && facetValue !== void 0 && !selected.has(facetValue(row))) return false;
32477
+ if (needle !== "" && !config.searchText(row).some((text) => fuzzyMatch(needle, text))) return false;
32478
+ return true;
30985
32479
  });
30986
32480
  }
30987
32481
  //#endregion
30988
- //#region src/composites/confirm-action-button.tsx
32482
+ //#region src/composites/data-table-filter-bar.tsx
30989
32483
  /**
30990
- * ConfirmActionButton — destructive-action button with a modal confirm.
32484
+ * The controls of one table's filter: a search box and the facet chips.
30991
32485
  *
30992
- * Two-step UX for any operation operators shouldn't trigger by accident:
30993
- * reboot device, restart addon, regenerate token, etc. The trigger is a
30994
- * normal Button that opens a Dialog; confirming runs the async action,
30995
- * the trigger spinner-disables itself for the duration, and the dialog
30996
- * closes on success. Errors surface inline at the dialog's bottom.
32486
+ * Controlled — the state comes from `useDataTableFilter` and goes back through
32487
+ * the two callbacks; this component owns nothing, so it can sit above a
32488
+ * `DataTable`, a card's list, or anything else that renders the filtered rows.
30997
32489
  *
30998
- * Generic on `TResult` so callers don't have to discard the return
30999
- * value. Pass an `icon` to render it inside the trigger (e.g. RotateCw
31000
- * for reboot, RefreshCw for restart).
32490
+ * Every visible string is a prop: this library carries no translations, and
32491
+ * the caller's i18n does.
31001
32492
  */
31002
- function ConfirmActionButton({ label, icon: Icon, title = "Confirm action", description, confirmLabel, triggerVariant = "outline", confirmVariant = "danger", size = "sm", disabled, className, action, onSuccess }) {
31003
- const [open, setOpen] = useState(false);
31004
- const [running, setRunning] = useState(false);
31005
- const [error, setError] = useState(null);
31006
- const handleConfirm = async () => {
31007
- setError(null);
31008
- setRunning(true);
31009
- try {
31010
- const result = await action();
31011
- onSuccess?.(result);
31012
- setOpen(false);
31013
- } catch (err) {
31014
- setError(err instanceof Error ? err.message : String(err));
31015
- } finally {
31016
- setRunning(false);
31017
- }
31018
- };
31019
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Button, {
31020
- type: "button",
31021
- variant: triggerVariant,
31022
- size,
31023
- disabled,
31024
- onClick: () => {
31025
- setError(null);
31026
- setOpen(true);
31027
- },
31028
- className,
31029
- children: [Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }), label]
31030
- }), /* @__PURE__ */ jsx(Dialog, {
31031
- open,
31032
- onOpenChange: (next) => !running && setOpen(next),
31033
- children: /* @__PURE__ */ jsxs(DialogContent, { children: [
31034
- /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsxs(DialogTitle, {
31035
- className: "flex items-center gap-2",
31036
- children: [/* @__PURE__ */ jsx(TriangleAlert, { className: "h-4 w-4 text-amber-400" }), title]
31037
- }), typeof description === "string" ? /* @__PURE__ */ jsx(DialogDescription, { children: description }) : description] }),
31038
- error && /* @__PURE__ */ jsx("div", {
31039
- className: cn("mt-2 px-3 py-2 rounded border border-danger/40 bg-danger/10", "text-xs text-danger"),
31040
- children: error
32493
+ var CHIP_ON = "rounded-full border border-primary bg-primary/10 px-2 py-0.5 text-[10px] text-foreground";
32494
+ var CHIP_OFF = "rounded-full border border-border px-2 py-0.5 text-[10px] text-foreground-muted hover:bg-surface-hover";
32495
+ function DataTableFilterBar({ state, facets, labels, onSearch, onToggleFacet, onClear, facetLabel }) {
32496
+ const active = state.search.trim() !== "" || state.facets.length > 0;
32497
+ const showFacets = facets.length > 1;
32498
+ return /* @__PURE__ */ jsxs("div", {
32499
+ className: "flex flex-wrap items-center gap-2",
32500
+ children: [
32501
+ /* @__PURE__ */ jsxs("label", {
32502
+ className: "relative min-w-[12rem] flex-1",
32503
+ children: [/* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-foreground-subtle" }), /* @__PURE__ */ jsx("input", {
32504
+ type: "search",
32505
+ value: state.search,
32506
+ onChange: (e) => onSearch(e.target.value),
32507
+ placeholder: labels.searchPlaceholder,
32508
+ "aria-label": labels.searchLabel,
32509
+ className: "w-full rounded border border-border bg-background py-1.5 pl-7 pr-2 text-xs text-foreground"
32510
+ })]
31041
32511
  }),
31042
- /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
31043
- type: "button",
31044
- variant: "ghost",
31045
- size,
31046
- disabled: running,
31047
- onClick: () => setOpen(false),
31048
- children: "Cancel"
31049
- }), /* @__PURE__ */ jsxs(Button, {
32512
+ showFacets && /* @__PURE__ */ jsx("div", {
32513
+ role: "group",
32514
+ "aria-label": labels.facetsLabel,
32515
+ className: "flex flex-wrap gap-1",
32516
+ children: facets.map((facet) => {
32517
+ const pressed = state.facets.includes(facet.value);
32518
+ return /* @__PURE__ */ jsxs("button", {
32519
+ type: "button",
32520
+ onClick: () => onToggleFacet(facet.value),
32521
+ "aria-pressed": pressed,
32522
+ className: pressed ? CHIP_ON : CHIP_OFF,
32523
+ children: [
32524
+ facetLabel ? facetLabel(facet.value) : facet.value,
32525
+ " ",
32526
+ /* @__PURE__ */ jsx("span", {
32527
+ className: "text-foreground-subtle tabular-nums",
32528
+ children: facet.count
32529
+ })
32530
+ ]
32531
+ }, facet.value);
32532
+ })
32533
+ }),
32534
+ active && /* @__PURE__ */ jsxs("button", {
31050
32535
  type: "button",
31051
- variant: confirmVariant,
31052
- size,
31053
- disabled: running,
31054
- onClick: () => {
31055
- handleConfirm();
31056
- },
31057
- children: [running && /* @__PURE__ */ jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }), confirmLabel ?? label]
31058
- })] })
31059
- ] })
31060
- })] });
32536
+ onClick: onClear,
32537
+ className: "flex items-center gap-1 text-[11px] text-foreground-subtle hover:text-foreground",
32538
+ children: [/* @__PURE__ */ jsx(X, { className: "h-3 w-3" }), labels.clearLabel]
32539
+ })
32540
+ ]
32541
+ });
31061
32542
  }
31062
32543
  //#endregion
31063
- //#region src/composites/copy-button.tsx
32544
+ //#region src/composites/use-data-table-filter.ts
31064
32545
  /**
31065
- * `CopyButton` — a compact button that copies a string `value` to the
31066
- * clipboard via `navigator.clipboard.writeText`, showing a brief
31067
- * "copied" check state. Addon-agnostic; used wherever a secret / URL
31068
- * needs a one-click copy affordance (export setup panels, etc.).
32546
+ * The React half of `data-table-filter.ts`: one filter state per call site,
32547
+ * so every table on a page filters on its own.
32548
+ *
32549
+ * The caller renders `rows` (the filtered set) and hands `state` + the two
32550
+ * setters to a `DataTableFilterBar`. It keeps the filtered set because
32551
+ * anything that acts on "the rows on screen" — a select-all, a bulk action —
32552
+ * must act on exactly these and nothing the filter hid.
31069
32553
  */
31070
- var COPIED_RESET_MS = 2e3;
31071
- function CopyButton({ value, label, srLabel, className, disabled }) {
31072
- const [copied, setCopied] = useState(false);
31073
- const handleCopy = useCallback(() => {
31074
- if (!value) return;
31075
- navigator.clipboard.writeText(value).then(() => {
31076
- setCopied(true);
31077
- setTimeout(() => setCopied(false), COPIED_RESET_MS);
31078
- });
31079
- }, [value]);
31080
- return /* @__PURE__ */ jsxs(Button, {
31081
- size: "sm",
31082
- variant: "ghost",
31083
- type: "button",
31084
- disabled: disabled || value.length === 0,
31085
- onClick: handleCopy,
31086
- className: cn(className),
31087
- "aria-label": copied ? "Copied" : `Copy ${srLabel ?? label ?? "value"}`,
31088
- children: [copied ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5 text-success" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" }), label ? /* @__PURE__ */ jsx("span", {
31089
- className: "ml-1",
31090
- children: copied ? "Copied" : label
31091
- }) : null]
31092
- });
32554
+ function useDataTableFilter(rows, config) {
32555
+ const [state, setState] = useState(EMPTY_DATA_TABLE_FILTER);
32556
+ const setSearch = useCallback((search) => {
32557
+ setState((prev) => ({
32558
+ ...prev,
32559
+ search
32560
+ }));
32561
+ }, []);
32562
+ const toggleFacet = useCallback((value) => {
32563
+ setState((prev) => toggleDataTableFacet(prev, value));
32564
+ }, []);
32565
+ const clear = useCallback(() => setState(EMPTY_DATA_TABLE_FILTER), []);
32566
+ const { searchText, facetValue } = config;
32567
+ return {
32568
+ state,
32569
+ setSearch,
32570
+ toggleFacet,
32571
+ clear,
32572
+ facets: useMemo(() => dataTableFacets(rows, facetValue), [rows, facetValue]),
32573
+ rows: useMemo(() => filterDataTableRows(rows, state, {
32574
+ searchText,
32575
+ facetValue
32576
+ }), [
32577
+ rows,
32578
+ state,
32579
+ searchText,
32580
+ facetValue
32581
+ ]),
32582
+ active: isDataTableFilterActive(state)
32583
+ };
31093
32584
  }
31094
32585
  //#endregion
31095
32586
  //#region src/composites/detection-colors.ts
@@ -44867,35 +46358,129 @@ function deviceRoleMetaOf(role) {
44867
46358
  return DEVICE_ROLE_META[role] ?? FALLBACK_DEVICE_ROLE_META;
44868
46359
  }
44869
46360
  /**
44870
- * Icons an operator may pick for a per-device `display.icon` override, keyed by
44871
- * a stable kebab-case name. Built ONLY from the lucide icons already imported by
44872
- * this module — no new imports, no dynamic indexing — so it stays bundle-size
44873
- * neutral and the picker offers a curated, sensor-relevant set. Unknown keys
44874
- * resolve to `undefined` (caller keeps the role/type default).
46361
+ * Icons an operator may pick for a per-device `display.icon` override (and for
46362
+ * a per-role default), keyed by a stable kebab-case name. Named imports only —
46363
+ * no dynamic indexing into lucide, so the bundle carries exactly this set.
46364
+ * Unknown keys resolve to `undefined` (caller falls through to the next level).
46365
+ *
46366
+ * The vocabulary is the one the VIEWER draws from too (its own icon module,
46367
+ * keyed by these same strings): a key added here that the phone cannot draw
46368
+ * falls through to the next resolution level there, which reads as "my change
46369
+ * did nothing". So the KEY is the contract — a stable kebab-case string, never
46370
+ * a glyph identity — and `device-meta.test.ts` pins that every key resolves
46371
+ * and that the set never loses a key an operator may already have persisted.
46372
+ *
46373
+ * Grouped by what an operator is naming: a device, a light or appliance, a
46374
+ * sensor or the weather it reads, a room, or what moves through it. `gauge2`
46375
+ * is a legacy alias kept for rows that persisted it.
44875
46376
  */
44876
46377
  var DISPLAY_ICON_REGISTRY = {
46378
+ camera: Camera,
46379
+ network: Network,
46380
+ "toggle-left": ToggleLeft,
46381
+ "toggle-right": ToggleRight,
46382
+ "circle-dot": CircleDot,
46383
+ "refresh-cw": RefreshCw,
46384
+ box: Box,
46385
+ "scroll-text": ScrollText,
46386
+ workflow: Workflow,
46387
+ lock: Lock,
46388
+ "lock-open": LockOpen,
46389
+ blinds: Blinds,
46390
+ "air-vent": AirVent,
46391
+ "monitor-play": MonitorPlay,
46392
+ "sliders-horizontal": SlidersHorizontal,
46393
+ "map-pin": MapPin,
46394
+ bot: Bot,
46395
+ tractor: Tractor,
46396
+ image: Image,
46397
+ bone: Bone,
46398
+ "door-closed": DoorClosed,
46399
+ "door-open": DoorOpen,
46400
+ crosshair: Crosshair,
46401
+ eye: Eye,
46402
+ "eye-off": EyeOff,
46403
+ smartphone: Smartphone,
46404
+ phone: Phone,
46405
+ tablet: Tablet,
46406
+ laptop: Laptop,
46407
+ monitor: Monitor,
46408
+ tv: Tv,
46409
+ speaker: Speaker,
46410
+ printer: Printer,
46411
+ projector: Projector,
46412
+ "gamepad-2": Gamepad2,
46413
+ radio: Radio,
46414
+ router: Router,
46415
+ bluetooth: Bluetooth,
46416
+ cpu: Cpu,
46417
+ "hard-drive": HardDrive,
46418
+ server: Server,
46419
+ mic: Mic,
46420
+ "mic-off": MicOff,
46421
+ video: Video,
46422
+ "video-off": VideoOff,
46423
+ music: Music,
46424
+ plug: Plug,
46425
+ "plug-zap": PlugZap,
46426
+ power: Power,
46427
+ "power-off": PowerOff,
46428
+ cable: Cable,
46429
+ battery: Battery,
46430
+ "battery-charging": BatteryCharging,
46431
+ "battery-full": BatteryFull,
46432
+ "battery-low": BatteryLow,
46433
+ key: Key,
46434
+ "key-round": KeyRound,
46435
+ mailbox: Mailbox,
46436
+ package: Package,
46437
+ shield: Shield,
46438
+ "shield-check": ShieldCheck,
46439
+ "shield-off": ShieldOff,
46440
+ lightbulb: Lightbulb,
46441
+ lamp: Lamp,
46442
+ "lamp-ceiling": LampCeiling,
46443
+ "lamp-desk": LampDesk,
46444
+ "lamp-floor": LampFloor,
46445
+ flashlight: Flashlight,
46446
+ heater: Heater,
46447
+ snowflake: Snowflake,
46448
+ "thermometer-sun": ThermometerSun,
46449
+ "thermometer-snowflake": ThermometerSnowflake,
46450
+ refrigerator: Refrigerator,
46451
+ microwave: Microwave,
46452
+ "washing-machine": WashingMachine,
46453
+ "cooking-pot": CookingPot,
46454
+ utensils: Utensils,
44877
46455
  thermometer: Thermometer,
44878
46456
  droplets: Droplets,
44879
46457
  droplet: Droplet,
44880
46458
  gauge: Gauge,
46459
+ gauge2: Gauge,
44881
46460
  sun: Sun,
44882
46461
  "sun-medium": SunMedium,
44883
46462
  sunrise: Sunrise,
44884
46463
  moon: Moon,
44885
46464
  wind: Wind,
46465
+ cloud: Cloud,
44886
46466
  "cloud-rain": CloudRain,
44887
46467
  "cloud-sun": CloudSun,
44888
46468
  waves: Waves,
44889
46469
  sprout: Sprout,
46470
+ leaf: Leaf,
46471
+ flower: Flower,
44890
46472
  zap: Zap,
44891
46473
  flame: Flame,
44892
46474
  bell: Bell,
46475
+ "bell-ring": BellRing,
46476
+ "bell-off": BellOff,
44893
46477
  siren: Siren,
44894
46478
  radar: Radar,
44895
46479
  activity: Activity,
44896
46480
  hash: Hash,
44897
46481
  clock: Clock,
44898
- gauge2: Gauge,
46482
+ timer: Timer,
46483
+ calendar: Calendar,
44899
46484
  pipette: Pipette,
44900
46485
  fan: Fan,
44901
46486
  bath: Bath,
@@ -44904,9 +46489,49 @@ var DISPLAY_ICON_REGISTRY = {
44904
46489
  "shield-alert": ShieldAlert,
44905
46490
  vibrate: Vibrate,
44906
46491
  wifi: Wifi,
46492
+ "wifi-off": WifiOff,
44907
46493
  "volume-2": Volume2,
44908
- lightbulb: Lightbulb,
44909
- flashlight: Flashlight
46494
+ "volume-x": VolumeX,
46495
+ heart: Heart,
46496
+ "heart-pulse": HeartPulse,
46497
+ star: Star,
46498
+ sparkles: Sparkles,
46499
+ house: House,
46500
+ sofa: Sofa,
46501
+ "bed-double": BedDouble,
46502
+ bed: Bed,
46503
+ warehouse: Warehouse,
46504
+ trees: Trees,
46505
+ "tree-pine": TreePine,
46506
+ fence: Fence,
46507
+ store: Store,
46508
+ building: Building,
46509
+ "building-2": Building2,
46510
+ mountain: Mountain,
46511
+ umbrella: Umbrella,
46512
+ dumbbell: Dumbbell,
46513
+ wrench: Wrench,
46514
+ hammer: Hammer,
46515
+ drill: Drill,
46516
+ "waves-ladder": WavesLadder,
46517
+ "circle-parking": CircleParking,
46518
+ briefcase: Briefcase,
46519
+ route: Route,
46520
+ car: Car,
46521
+ bike: Bike,
46522
+ bus: Bus,
46523
+ truck: Truck,
46524
+ plane: Plane,
46525
+ "train-front": TrainFront,
46526
+ sailboat: Sailboat,
46527
+ dog: Dog,
46528
+ cat: Cat,
46529
+ bird: Bird,
46530
+ "paw-print": PawPrint,
46531
+ baby: Baby,
46532
+ user: User,
46533
+ users: Users,
46534
+ "person-standing": PersonStanding
44910
46535
  };
44911
46536
  /** Resolve a `display.icon` name to a lucide component, or `undefined` when the
44912
46537
  * name is not in the curated `DISPLAY_ICON_REGISTRY`. */
@@ -45091,12 +46716,35 @@ function resolveFlags(props) {
45091
46716
  showChildrenAccordion: props.showChildrenAccordion ?? d.showChildrenAccordion
45092
46717
  };
45093
46718
  }
45094
- function deviceLeadIcon(device) {
46719
+ /**
46720
+ * The row's lead icon — the ONE resolution order, the same one
46721
+ * `resolveSensorDisplay` applies to unit and precision:
46722
+ *
46723
+ * device override → operator role default → built-in role glyph → type glyph
46724
+ *
46725
+ * `roleDefaults` is what the nearest `RoleDisplayDefaultsProvider` publishes;
46726
+ * callers outside a provider pass nothing and the second level is skipped.
46727
+ * Each level FALLS THROUGH when it names a glyph the registry cannot draw —
46728
+ * an unknown key at any level must never leave the row without an icon, and
46729
+ * must never shadow a lower level that would have drawn one.
46730
+ *
46731
+ * "Set as default for all X sensors" writes the second level. It was written
46732
+ * for a year and read by nothing: this function went straight from the device
46733
+ * override to `DEVICE_ROLE_META`.
46734
+ */
46735
+ function deviceLeadIcon(device, roleDefaults) {
45095
46736
  if (device.display?.icon) {
45096
46737
  const overridden = resolveDisplayIcon(device.display.icon);
45097
46738
  if (overridden) return overridden;
45098
46739
  }
45099
- if (device.role) return deviceRoleMetaOf(device.role).icon;
46740
+ if (device.role) {
46741
+ const roleDefaultKey = roleDefaults?.[device.role]?.icon;
46742
+ if (roleDefaultKey !== void 0) {
46743
+ const fromRoleDefault = resolveDisplayIcon(roleDefaultKey);
46744
+ if (fromRoleDefault) return fromRoleDefault;
46745
+ }
46746
+ return deviceRoleMetaOf(device.role).icon;
46747
+ }
45100
46748
  return deviceTypeMetaOf(device.type).icon;
45101
46749
  }
45102
46750
  /**
@@ -45253,6 +46901,7 @@ function effectiveType(device, containerChildren) {
45253
46901
  */
45254
46902
  function effectiveIconDevice(device, containerChildren) {
45255
46903
  if (device.type !== DeviceType.Container) return device;
46904
+ if (device.display?.icon !== void 0 && resolveDisplayIcon(device.display.icon) !== void 0) return device;
45256
46905
  const children = containerChildren ?? [];
45257
46906
  if (children.length === 0) return device;
45258
46907
  const primary = resolveContainerPrimary(children, device.linkDeviceId, device.primaryChildEntityId);
@@ -45632,7 +47281,7 @@ function RebootQuickAction({ trpc, deviceId, deviceName }) {
45632
47281
  * or a standalone test) the hook returns a stable empty array — the same
45633
47282
  * graceful default the old optional prop had.
45634
47283
  */
45635
- var EMPTY$1 = [];
47284
+ var EMPTY$2 = [];
45636
47285
  var ContainerChildrenContext = createContext(null);
45637
47286
  function ContainerChildrenProvider({ value, children }) {
45638
47287
  return /* @__PURE__ */ jsx(ContainerChildrenContext.Provider, {
@@ -45647,7 +47296,7 @@ function ContainerChildrenProvider({ value, children }) {
45647
47296
  * rendered outside a list, degrades exactly like the old optional prop.
45648
47297
  */
45649
47298
  function useContainerChildren(deviceId) {
45650
- return useContext(ContainerChildrenContext)?.get(deviceId) ?? EMPTY$1;
47299
+ return useContext(ContainerChildrenContext)?.get(deviceId) ?? EMPTY$2;
45651
47300
  }
45652
47301
  //#endregion
45653
47302
  //#region src/composites/device-item/actions.tsx
@@ -45873,6 +47522,33 @@ function PtzQuickAction({ trpc, deviceId }) {
45873
47522
  }), document.body)] });
45874
47523
  }
45875
47524
  //#endregion
47525
+ //#region src/composites/device-item/role-display-defaults-context.tsx
47526
+ var EMPTY$1 = {};
47527
+ var RoleDisplayDefaultsContext = createContext(EMPTY$1);
47528
+ function RoleDisplayDefaultsProvider({ value, children }) {
47529
+ return /* @__PURE__ */ jsx(RoleDisplayDefaultsContext.Provider, {
47530
+ value,
47531
+ children
47532
+ });
47533
+ }
47534
+ /** The defaults published by the nearest provider — an empty record outside
47535
+ * one, never `undefined`, so a caller can index it without a guard. */
47536
+ function useRoleDisplayDefaults() {
47537
+ return useContext(RoleDisplayDefaultsContext);
47538
+ }
47539
+ /**
47540
+ * Reads the defaults from the hub and publishes them. Until the query lands
47541
+ * the children see no defaults — the built-in role glyph, which is what they
47542
+ * would see with no operator default at all, so nothing flashes wrong.
47543
+ */
47544
+ function RoleDisplayDefaultsFromServer({ children }) {
47545
+ const { data } = useDeviceManagerGetRoleDisplayDefaults({}, { staleTime: 6e4 });
47546
+ return /* @__PURE__ */ jsx(RoleDisplayDefaultsProvider, {
47547
+ value: data?.defaults ?? EMPTY$1,
47548
+ children
47549
+ });
47550
+ }
47551
+ //#endregion
45876
47552
  //#region src/composites/device-item/children-accordion.tsx
45877
47553
  /**
45878
47554
  * <ChildrenAccordion> — accessory + adopted children rows shown when
@@ -45925,7 +47601,7 @@ function ChildRow$1({ trpc, child, onNavigate, parentName }) {
45925
47601
  },
45926
47602
  className: "w-full flex items-center gap-2 px-3 py-1.5 text-left hover:bg-surface-hover transition-colors cursor-pointer",
45927
47603
  children: [
45928
- /* @__PURE__ */ jsx(deviceLeadIcon(child), { className: "h-3 w-3 text-foreground-subtle flex-shrink-0" }),
47604
+ /* @__PURE__ */ jsx(deviceLeadIcon(child, useRoleDisplayDefaults()), { className: "h-3 w-3 text-foreground-subtle flex-shrink-0" }),
45929
47605
  /* @__PURE__ */ jsx("span", {
45930
47606
  className: "text-[10.5px] text-foreground flex-1 truncate",
45931
47607
  children: childListName(child, parentName)
@@ -46304,7 +47980,9 @@ var CHEVRON_SLOT_CLASS = {
46304
47980
  stacked: "h-4 w-4 mt-0.5"
46305
47981
  };
46306
47982
  function DeviceItemHeader({ device, variant, flags, parent, integrationIcon, hasChildren, expanded, onToggleExpand, onNavigateToParent, stacked = false, nameOverflow = "truncate" }) {
46307
- const Icon = deviceLeadIcon(effectiveIconDevice(device, useContainerChildren(device.id)));
47983
+ const containerChildren = useContainerChildren(device.id);
47984
+ const roleDefaults = useRoleDisplayDefaults();
47985
+ const Icon = deviceLeadIcon(effectiveIconDevice(device, containerChildren), roleDefaults);
46308
47986
  const slotClass = stacked ? CHEVRON_SLOT_CLASS.stacked : CHEVRON_SLOT_CLASS.horizontal;
46309
47987
  const lineClass = nameOverflow === "scroll" ? NAME_TEXT_CLASS : "truncate";
46310
47988
  return /* @__PURE__ */ jsxs("div", {
@@ -47111,41 +48789,6 @@ function groupTopLevelAndAccessories(devices, options) {
47111
48789
  };
47112
48790
  }
47113
48791
  //#endregion
47114
- //#region src/composites/device-list/fuzzy-match.ts
47115
- /**
47116
- * fuzzy-match — case and separator-insensitive text search helper.
47117
- *
47118
- * Normalization rule: lowercase + strip all runs of hyphens, underscores and
47119
- * whitespace entirely. This makes `Tapparella cucina` and `tapparella-cucina`
47120
- * both normalize to `tapparellacucina`, so a substring match succeeds in
47121
- * either direction.
47122
- */
47123
- /**
47124
- * Strips hyphens, underscores and whitespace runs from `s` and lowercases it.
47125
- *
47126
- * @example
47127
- * normalizeForSearch('Tapparella cucina') // 'tapparellacucina'
47128
- * normalizeForSearch('tapparella-cucina') // 'tapparellacucina'
47129
- * normalizeForSearch('tapparella_cucina') // 'tapparellacucina'
47130
- */
47131
- function normalizeForSearch(s) {
47132
- return s.toLowerCase().replace(/[-_\s]+/g, "");
47133
- }
47134
- /**
47135
- * Returns `true` when the normalized form of `target` contains the normalized
47136
- * form of `query`. An empty query always matches.
47137
- *
47138
- * @example
47139
- * fuzzyMatch('Tapparella cucina', 'tapparella-cucina') // true
47140
- * fuzzyMatch('tapparella cucina', 'Tapparella-Cucina') // true
47141
- * fuzzyMatch('xyz', 'tapparella-cucina') // false
47142
- */
47143
- function fuzzyMatch(query, target) {
47144
- const nq = normalizeForSearch(query);
47145
- if (nq === "") return true;
47146
- return normalizeForSearch(target).includes(nq);
47147
- }
47148
- //#endregion
47149
48792
  //#region src/composites/device-list/multi-select.tsx
47150
48793
  /**
47151
48794
  * Compact multi-select dropdown — a single chip-sized trigger ("Label · N")
@@ -47588,7 +49231,7 @@ function topLevelIndentLevel(device, parentType) {
47588
49231
  if (HUB_LIKE_PARENT_TYPES.has(parentType.toLowerCase())) return 1;
47589
49232
  return 0;
47590
49233
  }
47591
- function TableLayout({ rows, accessoriesByParent, autoExpandedParents, devices, visibleColumns, trpc, resolveIntegrationIcon, resolveParent, onNavigate, renderRowAction, onDeleteDevice, selectable, rowClickSelects, activeSelected, onToggleSelection, sort, onSort }) {
49234
+ function TableLayout({ rows, accessoriesByParent, expandedParents, onToggleExpand, devices, visibleColumns, trpc, resolveIntegrationIcon, resolveParent, onNavigate, renderRowAction, onDeleteDevice, selectable, rowClickSelects, activeSelected, onToggleSelection, sort, onSort }) {
47592
49235
  const showType = visibleColumns.includes("type");
47593
49236
  const showFeatures = visibleColumns.includes("features");
47594
49237
  const showManufacturer = visibleColumns.includes("manufacturer");
@@ -47647,7 +49290,6 @@ function TableLayout({ rows, accessoriesByParent, autoExpandedParents, devices,
47647
49290
  }) }), /* @__PURE__ */ jsx("tbody", { children: rows.map((d) => {
47648
49291
  const accessories = accessoriesByParent.get(d.id) ?? [];
47649
49292
  const hasAccessories = accessories.length > 0;
47650
- const autoExpand = autoExpandedParents.has(d.id);
47651
49293
  const parentRowParent = d.parentDeviceId !== null ? resolveParent?.(d.parentDeviceId) ?? null : null;
47652
49294
  const parentType = d.parentDeviceId !== null ? parentTypeById.get(d.parentDeviceId) ?? null : null;
47653
49295
  const selection = selectable ? {
@@ -47658,7 +49300,8 @@ function TableLayout({ rows, accessoriesByParent, autoExpandedParents, devices,
47658
49300
  parent: d,
47659
49301
  accessories,
47660
49302
  hasAccessories,
47661
- forceExpanded: autoExpand,
49303
+ expanded: expandedParents.has(d.id),
49304
+ onToggleExpand: () => onToggleExpand(d.id),
47662
49305
  trpc,
47663
49306
  integrationIcon: showIcon ? resolveIntegrationIcon?.(d.addonId) ?? null : null,
47664
49307
  showType,
@@ -47676,16 +49319,7 @@ function TableLayout({ rows, accessoriesByParent, autoExpandedParents, devices,
47676
49319
  })
47677
49320
  });
47678
49321
  }
47679
- function TableRowGroup({ parent, accessories, hasAccessories, forceExpanded, trpc, integrationIcon, showType, showManufacturer, showFeatures, parentRowParent, indentLevel, onNavigate, renderRowAction, onDeleteDevice, selection, rowClickSelects }) {
47680
- const [expanded, setExpanded] = useState(forceExpanded);
47681
- const prevForce = useRef(forceExpanded);
47682
- useEffect(() => {
47683
- if (prevForce.current !== forceExpanded) {
47684
- setExpanded(forceExpanded);
47685
- prevForce.current = forceExpanded;
47686
- }
47687
- }, [forceExpanded]);
47688
- const onToggleExpand = () => setExpanded((v) => !v);
49322
+ function TableRowGroup({ parent, accessories, hasAccessories, expanded, onToggleExpand, trpc, integrationIcon, showType, showManufacturer, showFeatures, parentRowParent, indentLevel, onNavigate, renderRowAction, onDeleteDevice, selection, rowClickSelects }) {
47689
49323
  const showAccessoryRows = hasAccessories && expanded;
47690
49324
  const grouped = useMemo(() => groupChildrenByLayout(parent.stableId, accessories, parent.childLayout), [
47691
49325
  parent.stableId,
@@ -47952,13 +49586,15 @@ function DeviceModeList(props) {
47952
49586
  ]);
47953
49587
  const grouped = useMemo(() => groupTopLevelAndAccessories(filtered), [filtered]);
47954
49588
  const sortedTopLevel = useMemo(() => sortRows(grouped.topLevel, sort), [grouped.topLevel, sort]);
47955
- const autoExpandedParents = useMemo(() => {
47956
- if (url.state.q.trim() === "") return /* @__PURE__ */ new Set();
47957
- const q = url.state.q;
47958
- const matching = /* @__PURE__ */ new Set();
47959
- for (const [parentId, accessories] of grouped.accessoriesByParent.entries()) if (accessories.some((a) => fuzzyMatch(q, a.name) || fuzzyMatch(q, a.stableId))) matching.add(parentId);
47960
- return matching;
47961
- }, [grouped.accessoriesByParent, url.state.q]);
49589
+ const [openParents, setOpenParents] = useState(() => /* @__PURE__ */ new Set());
49590
+ const toggleParent = useCallback((id) => {
49591
+ setOpenParents((prev) => {
49592
+ const next = new Set(prev);
49593
+ if (next.has(id)) next.delete(id);
49594
+ else next.add(id);
49595
+ return next;
49596
+ });
49597
+ }, []);
47962
49598
  const totalItems = grouped.topLevel.length;
47963
49599
  const totalPages = Math.max(1, Math.ceil(totalItems / currentPageSize));
47964
49600
  const safePage = Math.min(url.state.page, totalPages);
@@ -48028,7 +49664,8 @@ function DeviceModeList(props) {
48028
49664
  children: /* @__PURE__ */ jsx(TableLayout, {
48029
49665
  rows: pageRows,
48030
49666
  accessoriesByParent: grouped.accessoriesByParent,
48031
- autoExpandedParents,
49667
+ expandedParents: openParents,
49668
+ onToggleExpand: toggleParent,
48032
49669
  visibleColumns,
48033
49670
  sort,
48034
49671
  onSort,
@@ -48796,6 +50433,145 @@ function DeviceGrid({ children, minCardWidth = 220, gap = 3, className }) {
48796
50433
  });
48797
50434
  }
48798
50435
  //#endregion
50436
+ //#region src/composites/icon-picker.tsx
50437
+ /**
50438
+ * icon-picker — the ONE control for choosing an icon, wherever admin-ui asks.
50439
+ *
50440
+ * There were two: a device one over `DISPLAY_ICON_REGISTRY` and a room one
50441
+ * over `LOCATION_ICON_IDS`, identical apart from the vocabulary they walked.
50442
+ * That was tolerable while the device set was 56 glyphs in a flat grid. It is
50443
+ * not at 157: a picker that only lets the operator HUNT is a picker they stop
50444
+ * using, and the two copies were already drifting — only one of them had an
50445
+ * i18n'd label.
50446
+ *
50447
+ * So the vocabulary, the grouping and the search all come from
50448
+ * `@camstack/types`' `display-icon-vocabulary`, which is the same module the
50449
+ * viewer's sheet searches. What is left here is the web half: a popover, a
50450
+ * grid, and a text field.
50451
+ *
50452
+ * ## What it does NOT own
50453
+ *
50454
+ * - **The glyphs.** `resolveGlyph` is a prop, because this package's table is
50455
+ * `lucide-react` and the viewer's is `lucide-react-native`. A key this build
50456
+ * cannot draw is SKIPPED rather than rendered as a hole — an empty tile
50457
+ * reads as a rendering bug, not as a missing choice.
50458
+ * - **The words.** Every string is a prop. This package has no i18n (one file
50459
+ * in it imports react-i18next, and that is the exception), and a control
50460
+ * that reached for a translation would force it on every consumer.
50461
+ * - **The write.** `onPick` is called and that is all; whether it is a form
50462
+ * value or an immediate mutation is the caller's business, as it already was
50463
+ * in both pickers this replaces.
50464
+ *
50465
+ * ## The clear tile is never filtered away
50466
+ *
50467
+ * The "inherit" / "no icon" choice sits above the sections and ignores the
50468
+ * search. A query that hid it would strand the operator on a glyph they picked
50469
+ * by accident with no way back to the default — the one action a picker must
50470
+ * always offer.
50471
+ */
50472
+ function IconPicker({ value, onPick, resolveGlyph, fallbackGlyph, labels, only, extraWords, clearGlyph, labelFor, disabled = false }) {
50473
+ const [open, setOpen] = useState(false);
50474
+ const [query, setQuery] = useState("");
50475
+ const allowed = useMemo(() => only === void 0 ? null : new Set(only), [only]);
50476
+ const sections = useMemo(() => {
50477
+ const hits = searchDisplayIcons(query, extraWords);
50478
+ const byGroup = /* @__PURE__ */ new Map();
50479
+ for (const hit of hits) {
50480
+ const { key, group } = hit.entry;
50481
+ if (allowed !== null && !allowed.has(key)) continue;
50482
+ if (resolveGlyph(key) === void 0) continue;
50483
+ const bucket = byGroup.get(group);
50484
+ if (bucket === void 0) byGroup.set(group, [key]);
50485
+ else bucket.push(key);
50486
+ }
50487
+ return DISPLAY_ICON_GROUPS.flatMap((group) => {
50488
+ const keys = byGroup.get(group);
50489
+ return keys === void 0 || keys.length === 0 ? [] : [{
50490
+ group,
50491
+ keys
50492
+ }];
50493
+ });
50494
+ }, [
50495
+ query,
50496
+ extraWords,
50497
+ allowed,
50498
+ resolveGlyph
50499
+ ]);
50500
+ const Current = (value === null ? void 0 : resolveGlyph(value)) ?? fallbackGlyph;
50501
+ const choose = async (next) => {
50502
+ setOpen(false);
50503
+ setQuery("");
50504
+ await onPick(next);
50505
+ };
50506
+ const Clear = clearGlyph ?? fallbackGlyph;
50507
+ return /* @__PURE__ */ jsxs("div", {
50508
+ className: "relative flex shrink-0 items-center gap-2",
50509
+ children: [/* @__PURE__ */ jsx("button", {
50510
+ type: "button",
50511
+ disabled,
50512
+ onClick: () => setOpen((o) => !o),
50513
+ "aria-expanded": open,
50514
+ "aria-label": labels.trigger,
50515
+ title: labels.trigger,
50516
+ className: "rounded border border-border p-1 text-foreground-muted hover:bg-surface-hover disabled:opacity-50",
50517
+ children: /* @__PURE__ */ jsx(Current, { className: "h-4 w-4" })
50518
+ }), open && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
50519
+ type: "button",
50520
+ "aria-label": labels.close,
50521
+ onClick: () => setOpen(false),
50522
+ className: "fixed inset-0 z-10 cursor-default"
50523
+ }), /* @__PURE__ */ jsxs("div", {
50524
+ role: "group",
50525
+ "aria-label": labels.panel,
50526
+ className: "absolute left-0 top-full z-20 mt-1 max-h-80 w-72 overflow-y-auto rounded-md border border-border bg-surface p-2 shadow-lg",
50527
+ children: [
50528
+ /* @__PURE__ */ jsx("input", {
50529
+ type: "search",
50530
+ value: query,
50531
+ autoFocus: true,
50532
+ onChange: (e) => setQuery(e.target.value),
50533
+ placeholder: labels.searchPlaceholder,
50534
+ "aria-label": labels.searchPlaceholder,
50535
+ className: "mb-2 w-full rounded border border-border bg-surface-raised px-2 py-1 text-xs text-foreground placeholder:text-foreground-subtle"
50536
+ }),
50537
+ /* @__PURE__ */ jsxs("button", {
50538
+ type: "button",
50539
+ onClick: () => void choose(null),
50540
+ "aria-pressed": value === null,
50541
+ className: "mb-2 flex w-full items-center gap-1.5 rounded px-1.5 py-1 text-[11px] text-foreground-subtle hover:bg-surface-hover",
50542
+ children: [/* @__PURE__ */ jsx(Clear, { className: "h-3.5 w-3.5" }), labels.clear]
50543
+ }),
50544
+ sections.length === 0 ? /* @__PURE__ */ jsx("p", {
50545
+ className: "px-1.5 py-2 text-[11px] text-foreground-subtle",
50546
+ children: labels.noMatches
50547
+ }) : sections.map(({ group, keys }) => /* @__PURE__ */ jsxs("section", {
50548
+ className: "mb-2 last:mb-0",
50549
+ children: [/* @__PURE__ */ jsx("h4", {
50550
+ className: "px-1.5 pb-1 text-[10px] uppercase tracking-wide text-foreground-subtle",
50551
+ children: labels.groups[group]
50552
+ }), /* @__PURE__ */ jsx("div", {
50553
+ className: "grid grid-cols-7 gap-1",
50554
+ children: keys.map((key) => {
50555
+ const Glyph = resolveGlyph(key);
50556
+ if (Glyph === void 0) return null;
50557
+ const selected = value === key;
50558
+ return /* @__PURE__ */ jsx("button", {
50559
+ type: "button",
50560
+ onClick: () => void choose(key),
50561
+ "aria-pressed": selected,
50562
+ "aria-label": labelFor?.(key) ?? key,
50563
+ title: labelFor?.(key) ?? key,
50564
+ className: selected ? "flex items-center justify-center rounded border border-primary bg-primary/10 p-1.5 text-foreground" : "flex items-center justify-center rounded border border-transparent p-1.5 text-foreground-muted hover:bg-surface-hover",
50565
+ children: /* @__PURE__ */ jsx(Glyph, { className: "h-4 w-4" })
50566
+ }, key);
50567
+ })
50568
+ })]
50569
+ }, group))
50570
+ ]
50571
+ })] })]
50572
+ });
50573
+ }
50574
+ //#endregion
48799
50575
  //#region src/composites/device-selector-picker.tsx
48800
50576
  /**
48801
50577
  * <DeviceSelectorPicker> — the operator-facing editor for a v3
@@ -53743,12 +55519,12 @@ function mirror(input) {
53743
55519
  * Render inside `<Suspense>` at all call sites. */
53744
55520
  var MaskShapeCanvas = lazy(() => import("./MaskShapeCanvas-DI4BY7W2.js").then((m) => ({ default: m.MaskShapeCanvas })));
53745
55521
  /** Lazy-wrapped `MotionZonesSettings` — code-split off the main bundle. */
53746
- var MotionZonesSettings = lazy(() => import("./MotionZonesSettings-7c3yiT5E.js").then((m) => ({ default: m.MotionZonesSettings })));
55522
+ var MotionZonesSettings = lazy(() => import("./MotionZonesSettings-DHDfnZyU.js").then((m) => ({ default: m.MotionZonesSettings })));
53747
55523
  /** Lazy-wrapped `SceneMonitorEditor` — code-split off the main bundle for the
53748
55524
  * same reason: it mounts `MaskShapeCanvas`, which chains react-konva. Render
53749
55525
  * inside `<Suspense>`; the admin-ui `/scenes` dialog is its only caller. */
53750
- var SceneMonitorEditor = lazy(() => import("./SceneMonitorEditor-BvDy3x3k.js").then((m) => ({ default: m.SceneMonitorEditor })));
55526
+ var SceneMonitorEditor = lazy(() => import("./SceneMonitorEditor-vfWTm6qv.js").then((m) => ({ default: m.SceneMonitorEditor })));
53751
55527
  /** Lazy-wrapped `PrivacyMaskSettings` — code-split off the main bundle. */
53752
- var PrivacyMaskSettings = lazy(() => import("./PrivacyMaskSettings-PkYs077O.js").then((m) => ({ default: m.PrivacyMaskSettings })));
55528
+ var PrivacyMaskSettings = lazy(() => import("./PrivacyMaskSettings-DMkchqO1.js").then((m) => ({ default: m.PrivacyMaskSettings })));
53753
55529
  //#endregion
53754
- export { AddonGlobalSettingsForm, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, Badge, BatteryBadge, BottomSheet, Breadcrumb, BrightnessPanel, Button, ButtonControl, ButtonHeroCard, CARD_MODE_MIN_COLUMNS, CENTER, CHIP_ACTIVE, CHIP_BASE, CHIP_INACTIVE, CLASS_COLORS, COLUMN_BREAKPOINT_CLASS, COLUMN_PRIORITY, COMMIT_DEDUPE_TOLERANCE_MS, COMMIT_DEDUPE_WINDOW_MS, CONTROL_CAP_NAMES, CONTROL_FILLS, CameraStreamPlayer, Card, Checkbox, ChildSectionAccordion, ClimatePanel, CodeBlock, CollapsibleCard, ConfigFormBuilder, FormField as ConfigFormField, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, CustomFieldRenderersProvider, DEFAULT_COLOR, DEVICE_COLUMNS, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EVENT_KIND_ICONS, EmptyState, ErrorBox, EventKindGlyph, EventStream, FILL, FLEET_LIST_GC_TIME_MS, FLEET_LIST_QUERY_KEY, FLEET_LIST_STALE_TIME_MS, FanHeroCard, FanInlineControl, FanPanel, FilterBar, FloatingEventStream, FloatingLogStream, FloatingPanel, FormField$1 as FormField, GRID_GAP, GRID_PAIRED, GRID_QUICK_STATS, GripTrack, GroupedModelSelector, HOST_WIDGETS, HlsVideo, HoverZoomImage, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, IconAction, IconButton, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, OfflineBadge, PHASE_CONFIG, PRIORITY, PTZOverlay, PageHeader, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PipelineTreeMatrix, PlayerOverlaysProvider, Popover, PopoverContent, PopoverRowAction, PopoverTrigger, PrimaryChildPicker, PrivacyMaskSettings, ProviderBadge, PtzPanel, QrCode, RECONNECT_POLICY, RECORDED_PLAYBACK_MODES, RIGHT, ROI_AREA_WARN_FRACTION, ROLE_DESCRIPTOR, RadialGauge, RecordedPlaybackProvider, RecordingPanel, ResponseLog, SCENE_CAPTURE_VARIANTS, SECTION_BODY, SECTION_CARD, SECTION_HEADER, SETTING_ROW, SETTING_ROW_LABEL, SETTING_ROW_STACK_BREAKPOINT, SETTING_ROW_VALUE, SETTING_ROW_VALUE_TEXT, SNAPSHOT_MEDIA_PATH, SPLIT_PANEL_OUTER, SPLIT_PANEL_SIDE, STACK_GAP, STATE_COLOR, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, Select, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideOverPanel, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepTimings, StepTreeMaster, Stepper, StreamBrokerSelector, StreamDebugOverlay, StreamPanel, Switch, SwitchHeroCard, SwitchInlineControl, SwitchPanel, SystemProvider, TABLE_SCROLL_MAX_H, TEXT_FIELD_LABEL, TEXT_HINT, TEXT_METRIC, TEXT_SECTION_LABEL, TEXT_VALUE, TIMEZONES, Tabs, TabsContent, TabsList, TabsTrigger, TapToggle, ThemeProvider, ThermostatHeroCard, ThermostatInlineControl, TimezoneSelector, Tooltip, TooltipContent, TooltipTrigger, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, ImageOff as a, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, ariaSortForColumn, badgeFor, buildStepTreeFromSchema, Camera as c, childEntityId, childListName, classifyCapability, cn, columnsForContext, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, ensureMfHostInit, eventKindLabel, filterDeviceOptions, findTimezone, formatControlDateTime, formatLastSeen, formatNumeric, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, isAbsentProvider, isFieldVisible, createLucideIcon as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, Grid2x2 as o, openTopLayer, overrideEntityIdFromLink, parseRecordedServerMessage, providerIcons, RotateCcw as r, resetHubMountForTests, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolvePrimaryChild, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, routerBasename, EyeOff as s, scrubReducer, selectedDeviceOptions, serializeRecordedCommand, shouldCommit, shouldEmit, shouldUseSingleNode, sortRows, sortRowsByColumn, statusIcons, statusLine, stepHasModelForFormat, stepModelOptions, stripParentNamePrefix, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, trpc, useAccessoriesGetStatus, useAccessoriesSetChildHidden, useAddonPagesListPages, useAddonSettingsGetDeviceSettings, useAddonSettingsGetGlobalSettings, useAddonSettingsGetIntegrationSettings, useAddonSettingsUpdateDeviceSettings, useAddonSettingsUpdateGlobalSettings, useAddonWidgetsListWidgets, useAddonsApplyAutoUpdateToAll, useAddonsCancelJob, useAddonsCustom, useAddonsForceRefresh, useAddonsGetAddonAutoUpdate, useAddonsGetAutoUpdateSettings, useAddonsGetJob, useAddonsGetLastRestart, useAddonsGetLogs, useAddonsGetVersions, useAddonsInstallFromWorkspace, useAddonsInstallPackage, useAddonsIsWorkspaceAvailable, useAddonsList, useAddonsListCapabilityProviders, useAddonsListFrameworkPackages, useAddonsListJobs, useAddonsListPackages, useAddonsListUpdates, useAddonsListWorkspacePackages, useAddonsOnAddonLogs, useAddonsReloadPackages, useAddonsRestartAddon, useAddonsRestartServer, useAddonsRetryLoad, useAddonsRollbackPackage, useAddonsSearchAvailable, useAddonsSetAddonAutoUpdate, useAddonsSetAutoUpdateSettings, useAddonsSetCapabilityProviderEnabled, useAddonsStartJob, useAddonsUninstallPackage, useAddonsUpdatePackage, useAirQualitySensorGetStatus, useAlarmPanelArm, useAlarmPanelDisarm, useAlarmPanelGetStatus, useAlarmPanelTrigger, useAlert, useAlertsDismiss, useAlertsEmit, useAlertsGetUnreadCount, useAlertsList, useAlertsMarkAllRead, useAlertsMarkRead, useAlertsUpdate, useAllWidgets, useAmbientLightSensorGetStatus, useAudioAnalysisApplyDeviceSettingsPatch, useAudioAnalysisGetDeviceLiveContribution, useAudioAnalysisGetDeviceSettingsContribution, useAudioAnalysisResolveDeviceSettings, useAudioAnalyzerAnalyseChunk, useAudioAnalyzerAttachDevice, useAudioAnalyzerClassify, useAudioAnalyzerDetachDevice, useAudioAnalyzerDispose, useAudioAnalyzerIsReady, useAudioAnalyzerReprobeAudioEngine, useAudioCodecCanHandle, useAudioCodecCloseSession, useAudioCodecCreateDecodeSession, useAudioCodecCreateEncodeSession, useAudioCodecFlushEncode, useAudioCodecListActiveSessions, useAudioCodecListSupportedCodecs, useAudioCodecPullEncoded, useAudioCodecPullPcm, useAudioCodecPushEncodedFrame, useAudioCodecPushPcm, useAudioMetricsGetCurrentSnapshot, useAudioMetricsGetHistory, useAutomationControlDisable, useAutomationControlEnable, useAutomationControlGetStatus, useAutomationControlTrigger, useBackupCancel, useBackupDelete, useBackupDeleteSchedule, useBackupGetEntries, useBackupList, useBackupListArchives, useBackupListDestinations, useBackupListLocations, useBackupListRuns, useBackupListSchedules, useBackupPreviewSchedule, useBackupRestore, useBackupTrigger, useBackupUpsertDestinationPolicy, useBackupUpsertSchedule, useBatteryGetStatus, useBatteryWakeForStream, useBinaryGetStatus, useBrightnessGetStatus, useBrightnessSetBrightness, useBrokerAdd, useBrokerGet, useBrokerGetBrokerConfig, useBrokerGetSettings, useBrokerGetSettingsSchema, useBrokerGetState, useBrokerGetStatus, useBrokerList, useBrokerListProviders, useBrokerPublish, useBrokerRemove, useBrokerSetSettings, useBrokerSubscribe, useBrokerTestConnection, useBrokerTestSettings, useBrokerUnsubscribe, useButtonPress, useCameraCredentialsGetCredentials, useCameraCredentialsGetStatus, useCameraGridLayoutApplyDeviceSettingsPatch, useCameraGridLayoutGetDeviceLiveContribution, useCameraGridLayoutGetDeviceSettingsContribution, useCameraGridLayoutGetLayout, useCameraGridLayoutSaveLayout, useCameraPipelineConfigApplyDeviceSettingsPatch, useCameraPipelineConfigGetDeviceLiveContribution, useCameraPipelineConfigGetDeviceSettingsContribution, useCameraStreamsGetBrokerStreams, useCameraStreamsGetCameraStreams, useCameraStreamsGetProfileRtspEntries, useCameraStreamsGetRtspEntries, useCameraStreamsPickStream, useCapabilityPresence, useCarbonMonoxideGetStatus, useClimateControlGetStatus, useClimateControlSetFanMode, useClimateControlSetMode, useClimateControlSetPreset, useClimateControlSetSwingHorizontal, useClimateControlSetSwingVertical, useClimateControlSetTarget, useClimateControlSetTargetHumidity, useClimateControlSetTargetRange, useClusterNodes, useClusterTopology, useColorGetStatus, useColorSetColor, useConfirm, useConnectionTestDescribeTest, useConnectionTestTestSettings, useConnectivityGetStatus, useConsumablesGetStatus, useConsumablesReset, useContactGetStatus, useContainerChildren, useControlGetStatus, useControlSetValue, useCoreBlocksCompile, useCoreBlocksCreate, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderCreateSession, useDecoderDestroySession, useDecoderGetFrame, useDecoderGetInfo, useDecoderGetShmStats, useDecoderGetStats, useDecoderListActiveSessions, useDecoderOpenStream, useDecoderPullFrames, useDecoderPullHandles, useDecoderPushPacket, useDecoderReprobeHwaccel, useDecoderSupportsCodec, useDecoderUpdateConfig, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdoptionAdopt, useDeviceAdoptionGetCandidate, useDeviceAdoptionGetStatus, useDeviceAdoptionListCandidateFilters, useDeviceAdoptionListCandidates, useDeviceAdoptionRefresh, useDeviceAdoptionRelease, useDeviceAdoptionResync, useDeviceAutotrack, useDeviceBattery, useDeviceCapSlice, useDeviceCapability, useDeviceDetections, useDeviceDiscoveryAdoptDevice, useDeviceDiscoveryGetStatus, useDeviceDiscoveryListDiscovered, useDeviceDiscoveryRefreshDiscovery, useDeviceDiscoveryReleaseDevice, useDeviceExportApplyDeviceSettingsPatch, useDeviceExportExposeDevice, useDeviceExportGetDeviceLiveContribution, useDeviceExportGetDeviceSettingsContribution, useDeviceExportGetStatus, useDeviceExportListExposedDevices, useDeviceExportListSupportedDeviceKinds, useDeviceExportUnexposeDevice, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyDeviceSettingsPatch, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveContribution, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceSettingsContribution, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListLocationDescriptions, useDeviceManagerListLocationIcons, useDeviceManagerListLocations, useDeviceManagerListPersistedByAddon, useDeviceManagerListSiteZones, useDeviceManagerListWrappersForCap, useDeviceManagerLoadConfig, useDeviceManagerLoadMeta, useDeviceManagerLoadRuntimeState, useDeviceManagerMigrateDevice, useDeviceManagerPersistConfig, useDeviceManagerProbeStreams, useDeviceManagerProviderCreationType, useDeviceManagerProviderDiscoveryParamsSchema, useDeviceManagerRegisterDevice, useDeviceManagerRemove, useDeviceManagerRemoveByIntegration, useDeviceManagerRemoveDevice, useDeviceManagerRemoveLocation, useDeviceManagerRemoveSiteZone, useDeviceManagerRenameLocation, useDeviceManagerRenameSiteZone, useDeviceManagerRunDeviceAction, useDeviceManagerSetChildLayout, useDeviceManagerSetDisabled, useDeviceManagerSetDisplay, useDeviceManagerSetIntegrationId, useDeviceManagerSetLinkDeviceId, useDeviceManagerSetLocation, useDeviceManagerSetLocationDescription, useDeviceManagerSetLocationIcon, useDeviceManagerSetLocationZone, useDeviceManagerSetMetadata, useDeviceManagerSetName, useDeviceManagerSetPrimaryChildEntityId, useDeviceManagerSetRole, useDeviceManagerSetRoleDisplayDefaults, useDeviceManagerSetSiteZone, useDeviceManagerSetStreamProfileMap, useDeviceManagerSetType, useDeviceManagerSetWrapperActive, useDeviceManagerTestCreationField, useDeviceManagerTestField, useDeviceManagerUpdateConfig, useDeviceManagerUpdateDeviceField, useDeviceManagerUpdateDeviceFieldsBatch, useDeviceNetworkLink, useDeviceOpsGetConfigEntries, useDeviceOpsGetRawState, useDeviceOpsGetSettingsSchema, useDeviceOpsGetStreamSources, useDeviceOpsRemoveDevice, useDeviceOpsRunAction, useDeviceOpsSetConfig, useDeviceProviderAdoptDiscoveredDevice, useDeviceProviderCreateDevice, useDeviceProviderDiscoverDevices, useDeviceProviderGetChildCreationSchema, useDeviceProviderGetDevices, useDeviceProviderGetDiscoveryParamsSchema, useDeviceProviderGetManualCreationType, useDeviceProviderGetStatus, useDeviceProviderReloadDevice, useDeviceProviderStart, useDeviceProviderStop, useDeviceProviderSupportsDiscovery, useDeviceProviderSupportsManualCreation, useDeviceProviderTestCreationField, useDeviceProxy, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetSnapshot, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellApplyDeviceSettingsPatch, useDoorbellEvents, useDoorbellGetDeviceLiveContribution, useDoorbellGetDeviceSettingsContribution, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, useEventsGetEventClipUrl, useEventsGetEventThumbnail, useEventsGetEvents, useFaceGalleryAssignFace, useFaceGalleryAssignFaces, useFaceGalleryAuditIdentitySamples, useFaceGalleryCreateIdentity, useFaceGalleryDeleteFace, useFaceGalleryDeleteIdentity, useFaceGalleryGetFaceByTrack, useFaceGalleryGetFaceMedia, useFaceGalleryListIdentities, useFaceGalleryListIdentitySamples, useFaceGalleryListRecentFaces, useFaceGalleryRemoveSample, useFaceGalleryRenameIdentity, useFaceGallerySuggestFaceClusters, useFaceGalleryUnassignFace, useFaceGalleryUnassignFaces, useFanControlGetStatus, useFanControlSetDirection, useFanControlSetOscillating, useFanControlSetPercentage, useFanControlSetPreset, useFeatureProbeGetStatus, useFloodGetStatus, useGasGetStatus, useHumidifierGetStatus, useHumidifierSetMode, useHumidifierSetOn, useHumidifierSetTargetHumidity, useHumiditySensorGetStatus, useImageGetStatus, useImageSettingsGetOptions, useImageSettingsGetStatus, useImageSettingsSetSettings, useIntegrationsCreate, useIntegrationsDelete, useIntegrationsGet, useIntegrationsGetAvailableTypes, useIntegrationsGetByAddonId, useIntegrationsGetSettings, useIntegrationsList, useIntegrationsSetSettings, useIntegrationsTestConnection, useIntegrationsUpdate, useIntercomEndTalkSession, useIntercomGetStatus, useIntercomHandleAnswer, useIntercomPushTalkAudio, useIntercomStartSession, useIntercomStartTalkSession, useIntercomStopSession, useIsMidWidth, useIsMobile, useLawnMowerControlDock, useLawnMowerControlGetStatus, useLawnMowerControlPause, useLawnMowerControlStartMowing, useLiveBuffer, useLiveEvent, useLlmCancel, useLlmDeleteModel, useLlmDeleteProfile, useLlmGenerate, useLlmGenerateVision, useLlmGetDefaults, useLlmGetRuntimeStatus, useLlmGetUsage, useLlmInstallModel, useLlmListModelCatalog, useLlmListModels, useLlmListNodeModels, useLlmListProfileKinds, useLlmListProfiles, useLlmListRuntimeNodes, useLlmResolveModelRef, useLlmSetDefault, useLlmStartRuntime, useLlmStopRuntime, useLlmTestProfile, useLlmUpsertProfile, useLocalNetworkDownloadCa, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAllowedAddresses, useLocalNetworkSetNotificationEndpoint, useLocalNetworkSetViewerEndpoints, useLocalNetworkUploadCertificate, useLockControlGetStatus, useLockControlLock, useLockControlOpen, useLockControlUnlock, useMediaPlayerGetStatus, useMediaPlayerNext, useMediaPlayerPause, useMediaPlayerPlay, useMediaPlayerPlayMedia, useMediaPlayerPrevious, useMediaPlayerSeek, useMediaPlayerSelectSource, useMediaPlayerSetMute, useMediaPlayerSetRepeat, useMediaPlayerSetShuffle, useMediaPlayerSetVolume, useMediaPlayerStop, useMeshNetworkGetStatus, useMeshNetworkJoin, useMeshNetworkLeave, useMeshNetworkListPeers, useMeshNetworkLogout, useMeshNetworkStartLogin, useMeshNetworkTestConnection, useMetricsProviderCollectSnapshot, useMetricsProviderGetAddonStats, useMetricsProviderGetCached, useMetricsProviderGetCpuTemperature, useMetricsProviderGetCurrent, useMetricsProviderGetDiskSpace, useMetricsProviderGetGpuInfo, useMetricsProviderGetLoadSeries, useMetricsProviderGetProcessStats, useMetricsProviderListAddonInstances, useMetricsProviderListNodeProcesses, useMotionDetectionAnalyze, useMotionDetectionApplyDeviceSettingsPatch, useMotionDetectionGetDeviceLiveContribution, useMotionDetectionGetDeviceSettingsContribution, useMotionDetectionRemoveCamera, useMotionDetectionReset, useMotionGetStatus, useMotionIsDetected, useMotionTriggerGetStatus, useMotionTriggerSetMotionTrigger, useMotionZonesGetOptions, useMotionZonesGetStatus, useMotionZonesSetZone, useMqttBrokerAddBroker, useMqttBrokerGetBrokerConfig, useMqttBrokerGetStatus, useMqttBrokerListBrokers, useMqttBrokerRemoveBroker, useMqttBrokerStartEmbeddedBroker, useMqttBrokerStopEmbeddedBroker, useMqttBrokerTestConnection, useNativeObjectDetectionGetOptions, useNativeObjectDetectionGetStatus, useNativeObjectDetectionSetEnabled, useNativeObjectDetectionSetSettings, useNavigation, useNavigationGetFeatures, useNavigationGetStatus, useNavigationGoToPoint, useNavigationListActions, useNavigationMove, useNavigationPlaySound, useNavigationRunAction, useNavigationSetLightLevel, useNavigationSetLightMode, useNavigationSetLightOn, useNavigationStop, useNetworkAccessGetEndpoint, useNetworkAccessGetStatus, useNetworkAccessListEndpoints, useNetworkAccessStart, useNetworkAccessStop, useNetworkLinkGetStatus, useNetworkQualityGetAllStats, useNetworkQualityGetDeviceStats, useNetworkQualityReportClientStats, useNodesClusterAddonStatus, useNodesDeployAddon, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesCancelSnooze, useNotificationRulesCreateRule, useNotificationRulesCreateSnooze, useNotificationRulesDeleteRule, useNotificationRulesGetAlarmConfig, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSnoozes, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdSetOverlay, usePTZ, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetSummary, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentSummaries, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListSummaries, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsRunReplayFrameProcessor, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDeleteTemplate, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorListTemplates, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSaveTemplate, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorUpdateTemplate, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteTemplate, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListTemplates, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSaveTemplate, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentDetectWeight, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineOrchestratorUpdateTemplate, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePlateGalleryAssignPlate, usePlateGalleryAssignPlates, usePlateGalleryCorrectPlateText, usePlateGalleryCreateVehicle, usePlateGalleryDeletePlate, usePlateGalleryDeleteVehicle, usePlateGalleryGetPlateByTrack, usePlateGalleryGetPlateMedia, usePlateGalleryListPlates, usePlateGalleryListVehicleSamples, usePlateGalleryListVehicles, usePlateGalleryRemoveVehicleSample, usePlateGalleryRenameVehicle, usePlateGallerySearchPlates, usePlateGallerySuggestPlateClusters, usePlateGalleryUnassignPlate, usePlateGalleryUnassignPlates, usePlayerOverlayLayer, usePlayerOverlayLayers, usePlayerToolbarButton, usePlayerToolbarButtons, usePowerMeterGetStatus, usePresenceGetStatus, usePressureSensorGetStatus, usePrivacyMaskGetOptions, usePrivacyMaskGetStatus, usePrivacyMaskSetAudioEnabled, usePrivacyMaskSetMask, usePrompt, usePtzAutotrackGetSettings, usePtzAutotrackGetStatus, usePtzAutotrackSetEnabled, usePtzAutotrackSetSettings, usePtzCaptureHomeHere, usePtzContinuousMove, usePtzDeletePreset, usePtzGetHomePreset, usePtzGetHomeReturn, usePtzGetOptions, usePtzGetPosition, usePtzGetPresets, usePtzGetStatus, usePtzGoHome, usePtzGoToPreset, usePtzMove, usePtzSavePreset, usePtzSetAutofocus, usePtzSetHomePreset, usePtzSetHomeReturn, usePtzStop, useRebootReboot, useRecordedPlayback, useRecordingApplyDeviceSettingsPatch, useRecordingCancelRelocateJob, useRecordingCancelStorageMigrationMove, useRecordingDeleteFootprint, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetAvailabilityBatch, useRecordingGetDaysWithRecordings, useRecordingGetDaysWithRecordingsBatch, useRecordingGetDeviceConfig, useRecordingGetDeviceLiveContribution, useRecordingGetDeviceSettingsContribution, useRecordingGetPlacement, useRecordingGetPlaybackManifest, useRecordingGetRelocateResidue, useRecordingGetStatus, useRecordingGetStorageMigrationMoveStatus, useRecordingGetStorageUsage, useRecordingListOpsLog, useRecordingListRelocateJobs, useRecordingLocateSegment, useRecordingPauseForStorageMigration, useRecordingPlanStorageRebalance, useRecordingPruneFootage, useRecordingReadGopBytes, useRecordingReadSegmentBytes, useRecordingReadWindowBytes, useRecordingReconcileLedgerAgainstDisk, useRecordingRefreshStorageLocationsForMigration, useRecordingRelocateFootage, useRecordingRenderClip, useRecordingRenderGif, useRecordingRescanStorage, useRecordingResumeForStorageMigration, useRecordingSetDeviceConfig, useRecordingSetDevicePlacement, useRecordingSignalGetStatus, useRecordingStartStorageMigrationMove, useRecordingStartStorageRebalance, useRemoteComponent, useSceneMonitorCaptureReference, useSceneMonitorCreateScene, useSceneMonitorDeleteReference, useSceneMonitorDeleteScene, useSceneMonitorGetStatus, useSceneMonitorListScenes, useSceneMonitorListScenesBatch, useSceneMonitorRecheckNow, useSceneMonitorResetScene, useSceneMonitorUpdateScene, useScriptRunnerGetStatus, useScriptRunnerRun, useScriptRunnerStop, useScrubController, useServerManagementApplyServerUpdate, useServerManagementCheckServerUpdate, useServerManagementGetServerPackageStatus, useServerManagementRestartServer, useServerManagementRollbackServerUpdate, useSettingsStoreAggregate, useSettingsStoreCount, useSettingsStoreDeclareCollection, useSettingsStoreDelete, useSettingsStoreDeleteWhere, useSettingsStoreGet, useSettingsStoreHistogram, useSettingsStoreInsert, useSettingsStoreInsertMany, useSettingsStoreIsEmpty, useSettingsStoreQuery, useSettingsStoreSet, useSettingsStoreUpdate, useSettingsStoreUpdateWhere, useSettingsStoreUpsert, useSmokeGetStatus, useSnapshotApplyDeviceSettingsPatch, useSnapshotGetDebugState, useSnapshotGetDeviceLiveContribution, useSnapshotGetDeviceSettingsContribution, useSnapshotGetSnapshot, useSnapshotGetSnapshotLinks, useSnapshotGetSnapshotOverview, useSnapshotGetStatus, useSnapshotInvalidateCache, useStationaryOverlay, useStorageAbortUpload, useStorageBeginDownload, useStorageBeginUpload, useStorageDelete, useStorageDeleteLocation, useStorageEndDownload, useStorageExists, useStorageFinalizeUpload, useStorageGetAvailableSpace, useStorageList, useStorageListDrainProgress, useStorageListLocationDeclarations, useStorageListLocations, useStorageListProviders, useStorageMigrationCancel, useStorageMigrationCleanupCancel, useStorageMigrationCleanupStart, useStorageMigrationCleanupStatus, useStorageMigrationDrain, useStorageMigrationHistory, useStorageMigrationMovers, useStorageMigrationPlan, useStorageMigrationResidue, useStorageMigrationStart, useStorageMigrationStatus, useStorageRead, useStorageReadChunk, useStorageResolve, useStorageTestConfig, useStorageTestLocation, useStorageUpsertLocation, useStorageWrite, useStorageWriteChunk, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerPullFrameHandles, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerSubscribeFrames, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, useStreamBrokerUnsubscribeFrames, useStreamCatalogGetCatalog, useStreamParamsGetConfigSchema, useStreamParamsGetOptions, useStreamParamsGetStatus, useStreamParamsSetProfile, useStreamSignalsListSignals, useSwitchGetStatus, useSwitchSetState, useSystem, useSystemDetectSiteLocation, useSystemFeatureFlags, useSystemForceRetentionCleanup, useSystemGetFailureContributions, useSystemGetLoadContributions, useSystemGetLoggingSettings, useSystemGetRequestCensus, useSystemGetRetentionConfig, useSystemGetSiteLocation, useSystemHealth, useSystemInfo, useSystemMutation, useSystemNetworkAddresses, useSystemQuery, useSystemSetLoggingSettings, useSystemSetRetentionConfig, useSystemSetSiteLocation, useTamperGetStatus, useTemperatureSensorGetStatus, useTerminalSessionAdoptLegacyMonitor, useTerminalSessionClose, useTerminalSessionCreateInstance, useTerminalSessionDeleteInstance, useTerminalSessionListInstances, useTerminalSessionListLegacyCameras, useTerminalSessionListProfiles, useTerminalSessionListSessions, useTerminalSessionOpenSession, useTerminalSessionPullOutput, useTerminalSessionResize, useTerminalSessionSetInstanceEnabled, useTerminalSessionUpdateInstance, useTerminalSessionWriteInput, useThemeMode, useToastOnToast, useTurnProviderGetTurnServers, useUpdateGetStatus, useUpdateInstallUpdate, useUserManagementConfirmTotp, useUserManagementCreateApiKey, useUserManagementCreateScopedToken, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementGetTotpStatus, useUserManagementListApiKeys, useUserManagementListOauthSessions, useUserManagementListScopedTokens, useUserManagementListUsers, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeApiKey, useUserManagementRevokeOauthSession, useUserManagementRevokeScopedToken, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUpdateUser, useUserManagementValidateApiKey, useUserManagementValidateCredentials, useUserManagementValidateScopedToken, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsGetClipPlayback, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionCloseSession, useWebrtcSessionCreateSession, useWebrtcSessionGetIceCandidates, useWebrtcSessionGetSessionDebug, useWebrtcSessionGetSessionState, useWebrtcSessionHandleAnswer, useWebrtcSessionHandleOffer, useWebrtcSessionHasAdaptiveBitrate, useWebrtcSessionListStreams, useWidget, useWidgetMetadata, useWidgetRegistry, useZoneAnalyticsGetCameraHistory, useZoneAnalyticsGetCurrentSnapshot, useZoneAnalyticsGetCurrentSnapshotBatch, useZoneAnalyticsGetUnzonedHistory, useZoneAnalyticsGetZoneHistory, useZoneEditing, useZoneRulesListRules, useZoneRulesSetRules, useZonesAddZone, useZonesListZones, useZonesRemoveZone, useZonesUpdateZone, vacuumStateMeta, validateScopes, valveStateMeta, variantLabel, waterHeaterPhase, waterHeaterTint, weatherConditionMeta, weatherTint };
55530
+ export { AddonGlobalSettingsForm, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, Badge, BatteryBadge, BottomSheet, Breadcrumb, BrightnessPanel, Button, ButtonControl, ButtonHeroCard, CARD_MODE_MIN_COLUMNS, CENTER, CHIP_ACTIVE, CHIP_BASE, CHIP_INACTIVE, CLASS_COLORS, COLUMN_BREAKPOINT_CLASS, COLUMN_PRIORITY, COMMIT_DEDUPE_TOLERANCE_MS, COMMIT_DEDUPE_WINDOW_MS, CONTROL_CAP_NAMES, CONTROL_FILLS, CameraStreamPlayer, Card, Checkbox, ChildSectionAccordion, ClimatePanel, CodeBlock, CollapsibleCard, ConfigFormBuilder, FormField as ConfigFormField, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, CustomFieldRenderersProvider, DEFAULT_COLOR, DEVICE_COLUMNS, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DataTableFilterBar, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EMPTY_DATA_TABLE_FILTER, EVENT_KIND_ICONS, EmptyState, ErrorBox, EventKindGlyph, EventStream, FILL, FLEET_LIST_GC_TIME_MS, FLEET_LIST_QUERY_KEY, FLEET_LIST_STALE_TIME_MS, FanHeroCard, FanInlineControl, FanPanel, FilterBar, FloatingEventStream, FloatingLogStream, FloatingPanel, FormField$1 as FormField, GRID_GAP, GRID_PAIRED, GRID_QUICK_STATS, GripTrack, GroupedModelSelector, HOST_WIDGETS, HlsVideo, HoverZoomImage, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, OfflineBadge, PHASE_CONFIG, PRIORITY, PTZOverlay, PageHeader, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PipelineTreeMatrix, PlayerOverlaysProvider, Popover, PopoverContent, PopoverRowAction, PopoverTrigger, PrimaryChildPicker, PrivacyMaskSettings, ProviderBadge, PtzPanel, QrCode, RECONNECT_POLICY, RECORDED_PLAYBACK_MODES, RIGHT, ROI_AREA_WARN_FRACTION, ROLE_DESCRIPTOR, RadialGauge, RecordedPlaybackProvider, RecordingPanel, ResponseLog, RoleDisplayDefaultsFromServer, RoleDisplayDefaultsProvider, SCENE_CAPTURE_VARIANTS, SECTION_BODY, SECTION_CARD, SECTION_HEADER, SETTING_ROW, SETTING_ROW_LABEL, SETTING_ROW_STACK_BREAKPOINT, SETTING_ROW_VALUE, SETTING_ROW_VALUE_TEXT, SNAPSHOT_MEDIA_PATH, SPLIT_PANEL_OUTER, SPLIT_PANEL_SIDE, STACK_GAP, STATE_COLOR, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, Select, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideOverPanel, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepTimings, StepTreeMaster, Stepper, StreamBrokerSelector, StreamDebugOverlay, StreamPanel, Switch, SwitchHeroCard, SwitchInlineControl, SwitchPanel, SystemProvider, TABLE_SCROLL_MAX_H, TEXT_FIELD_LABEL, TEXT_HINT, TEXT_METRIC, TEXT_SECTION_LABEL, TEXT_VALUE, TIMEZONES, Tabs, TabsContent, TabsList, TabsTrigger, TapToggle, ThemeProvider, ThermostatHeroCard, ThermostatInlineControl, TimezoneSelector, Tooltip, TooltipContent, TooltipTrigger, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, MicOff as a, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, ariaSortForColumn, badgeFor, buildStepTreeFromSchema, EyeOff as c, childEntityId, childListName, classifyCapability, cn, columnsForContext, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, dataTableFacets, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, ensureMfHostInit, eventKindLabel, filterDataTableRows, filterDeviceOptions, findTimezone, formatControlDateTime, formatLastSeen, formatNumeric, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, isAbsentProvider, isDataTableFilterActive, isFieldVisible, Camera as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, ImageOff as o, openTopLayer, overrideEntityIdFromLink, parseRecordedServerMessage, providerIcons, RotateCcw as r, resetHubMountForTests, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolvePrimaryChild, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, routerBasename, Grid2x2 as s, scrubReducer, selectedDeviceOptions, serializeRecordedCommand, shouldCommit, shouldEmit, shouldUseSingleNode, sortRows, sortRowsByColumn, statusIcons, statusLine, stepHasModelForFormat, stepModelOptions, stripParentNamePrefix, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, toggleDataTableFacet, trpc, createLucideIcon as u, useAccessoriesGetStatus, useAccessoriesSetChildHidden, useAddonPagesListPages, useAddonSettingsGetDeviceSettings, useAddonSettingsGetGlobalSettings, useAddonSettingsGetIntegrationSettings, useAddonSettingsUpdateDeviceSettings, useAddonSettingsUpdateGlobalSettings, useAddonWidgetsListWidgets, useAddonsApplyAutoUpdateToAll, useAddonsCancelJob, useAddonsCustom, useAddonsForceRefresh, useAddonsGetAddonAutoUpdate, useAddonsGetAutoUpdateSettings, useAddonsGetJob, useAddonsGetLastRestart, useAddonsGetLogs, useAddonsGetVersions, useAddonsInstallFromWorkspace, useAddonsInstallPackage, useAddonsIsWorkspaceAvailable, useAddonsList, useAddonsListCapabilityProviders, useAddonsListFrameworkPackages, useAddonsListJobs, useAddonsListPackages, useAddonsListUpdates, useAddonsListWorkspacePackages, useAddonsOnAddonLogs, useAddonsReloadPackages, useAddonsRestartAddon, useAddonsRestartServer, useAddonsRetryLoad, useAddonsRollbackPackage, useAddonsSearchAvailable, useAddonsSetAddonAutoUpdate, useAddonsSetAutoUpdateSettings, useAddonsSetCapabilityProviderEnabled, useAddonsStartJob, useAddonsUninstallPackage, useAddonsUpdatePackage, useAirQualitySensorGetStatus, useAlarmPanelArm, useAlarmPanelDisarm, useAlarmPanelGetStatus, useAlarmPanelTrigger, useAlert, useAlertsDismiss, useAlertsEmit, useAlertsGetUnreadCount, useAlertsList, useAlertsMarkAllRead, useAlertsMarkRead, useAlertsUpdate, useAllWidgets, useAmbientLightSensorGetStatus, useAudioAnalysisApplyDeviceSettingsPatch, useAudioAnalysisGetDeviceLiveContribution, useAudioAnalysisGetDeviceSettingsContribution, useAudioAnalysisResolveDeviceSettings, useAudioAnalyzerAnalyseChunk, useAudioAnalyzerAttachDevice, useAudioAnalyzerClassify, useAudioAnalyzerDetachDevice, useAudioAnalyzerDispose, useAudioAnalyzerIsReady, useAudioAnalyzerReprobeAudioEngine, useAudioCodecCanHandle, useAudioCodecCloseSession, useAudioCodecCreateDecodeSession, useAudioCodecCreateEncodeSession, useAudioCodecFlushEncode, useAudioCodecListActiveSessions, useAudioCodecListSupportedCodecs, useAudioCodecPullEncoded, useAudioCodecPullPcm, useAudioCodecPushEncodedFrame, useAudioCodecPushPcm, useAudioMetricsGetCurrentSnapshot, useAudioMetricsGetHistory, useAutomationControlDisable, useAutomationControlEnable, useAutomationControlGetStatus, useAutomationControlTrigger, useBackupCancel, useBackupDelete, useBackupDeleteSchedule, useBackupGetEntries, useBackupList, useBackupListArchives, useBackupListDestinations, useBackupListLocations, useBackupListRuns, useBackupListSchedules, useBackupPreviewSchedule, useBackupRestore, useBackupTrigger, useBackupUpsertDestinationPolicy, useBackupUpsertSchedule, useBatteryGetStatus, useBatteryWakeForStream, useBinaryGetStatus, useBrightnessGetStatus, useBrightnessSetBrightness, useBrokerAdd, useBrokerGet, useBrokerGetBrokerConfig, useBrokerGetSettings, useBrokerGetSettingsSchema, useBrokerGetState, useBrokerGetStatus, useBrokerList, useBrokerListProviders, useBrokerPublish, useBrokerRemove, useBrokerSetSettings, useBrokerSubscribe, useBrokerTestConnection, useBrokerTestSettings, useBrokerUnsubscribe, useButtonPress, useCameraCredentialsGetCredentials, useCameraCredentialsGetStatus, useCameraGridLayoutApplyDeviceSettingsPatch, useCameraGridLayoutGetDeviceLiveContribution, useCameraGridLayoutGetDeviceSettingsContribution, useCameraGridLayoutGetLayout, useCameraGridLayoutSaveLayout, useCameraPipelineConfigApplyDeviceSettingsPatch, useCameraPipelineConfigGetDeviceLiveContribution, useCameraPipelineConfigGetDeviceSettingsContribution, useCameraStreamsGetBrokerStreams, useCameraStreamsGetCameraStreams, useCameraStreamsGetProfileRtspEntries, useCameraStreamsGetRtspEntries, useCameraStreamsPickStream, useCapabilityPresence, useCarbonMonoxideGetStatus, useClimateControlGetStatus, useClimateControlSetFanMode, useClimateControlSetMode, useClimateControlSetPreset, useClimateControlSetSwingHorizontal, useClimateControlSetSwingVertical, useClimateControlSetTarget, useClimateControlSetTargetHumidity, useClimateControlSetTargetRange, useClusterNodes, useClusterTopology, useColorGetStatus, useColorSetColor, useConfirm, useConnectionTestDescribeTest, useConnectionTestTestSettings, useConnectivityGetStatus, useConsumablesGetStatus, useConsumablesReset, useContactGetStatus, useContainerChildren, useControlGetStatus, useControlSetValue, useCoreBlocksCompile, useCoreBlocksCreate, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderCreateSession, useDecoderDestroySession, useDecoderGetFrame, useDecoderGetInfo, useDecoderGetShmStats, useDecoderGetStats, useDecoderListActiveSessions, useDecoderOpenStream, useDecoderPullFrames, useDecoderPullHandles, useDecoderPushPacket, useDecoderReprobeHwaccel, useDecoderSupportsCodec, useDecoderUpdateConfig, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdoptionAdopt, useDeviceAdoptionGetCandidate, useDeviceAdoptionGetStatus, useDeviceAdoptionListCandidateFilters, useDeviceAdoptionListCandidates, useDeviceAdoptionRefresh, useDeviceAdoptionRelease, useDeviceAdoptionResync, useDeviceAutotrack, useDeviceBattery, useDeviceCapSlice, useDeviceCapability, useDeviceDetections, useDeviceDiscoveryAdoptDevice, useDeviceDiscoveryGetStatus, useDeviceDiscoveryListDiscovered, useDeviceDiscoveryRefreshDiscovery, useDeviceDiscoveryReleaseDevice, useDeviceExportApplyDeviceSettingsPatch, useDeviceExportExposeDevice, useDeviceExportGetDeviceLiveContribution, useDeviceExportGetDeviceSettingsContribution, useDeviceExportGetStatus, useDeviceExportListExposedDevices, useDeviceExportListSupportedDeviceKinds, useDeviceExportUnexposeDevice, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyDeviceSettingsPatch, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveContribution, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceSettingsContribution, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListLocationDescriptions, useDeviceManagerListLocationIcons, useDeviceManagerListLocations, useDeviceManagerListPersistedByAddon, useDeviceManagerListSiteZones, useDeviceManagerListWrappersForCap, useDeviceManagerLoadConfig, useDeviceManagerLoadMeta, useDeviceManagerLoadRuntimeState, useDeviceManagerMigrateDevice, useDeviceManagerPersistConfig, useDeviceManagerProbeStreams, useDeviceManagerProviderCreationType, useDeviceManagerProviderDiscoveryParamsSchema, useDeviceManagerRegisterDevice, useDeviceManagerRemove, useDeviceManagerRemoveByIntegration, useDeviceManagerRemoveDevice, useDeviceManagerRemoveLocation, useDeviceManagerRemoveSiteZone, useDeviceManagerRenameLocation, useDeviceManagerRenameSiteZone, useDeviceManagerRunDeviceAction, useDeviceManagerSetChildLayout, useDeviceManagerSetDisabled, useDeviceManagerSetDisplay, useDeviceManagerSetIntegrationId, useDeviceManagerSetLinkDeviceId, useDeviceManagerSetLocation, useDeviceManagerSetLocationDescription, useDeviceManagerSetLocationIcon, useDeviceManagerSetLocationZone, useDeviceManagerSetMetadata, useDeviceManagerSetName, useDeviceManagerSetPrimaryChildEntityId, useDeviceManagerSetRole, useDeviceManagerSetRoleDisplayDefaults, useDeviceManagerSetSiteZone, useDeviceManagerSetStreamProfileMap, useDeviceManagerSetType, useDeviceManagerSetWrapperActive, useDeviceManagerTestCreationField, useDeviceManagerTestField, useDeviceManagerUpdateConfig, useDeviceManagerUpdateDeviceField, useDeviceManagerUpdateDeviceFieldsBatch, useDeviceNetworkLink, useDeviceOpsGetConfigEntries, useDeviceOpsGetRawState, useDeviceOpsGetSettingsSchema, useDeviceOpsGetStreamSources, useDeviceOpsRemoveDevice, useDeviceOpsRunAction, useDeviceOpsSetConfig, useDeviceProviderAdoptDiscoveredDevice, useDeviceProviderCreateDevice, useDeviceProviderDiscoverDevices, useDeviceProviderGetChildCreationSchema, useDeviceProviderGetDevices, useDeviceProviderGetDiscoveryParamsSchema, useDeviceProviderGetManualCreationType, useDeviceProviderGetStatus, useDeviceProviderReloadDevice, useDeviceProviderStart, useDeviceProviderStop, useDeviceProviderSupportsDiscovery, useDeviceProviderSupportsManualCreation, useDeviceProviderTestCreationField, useDeviceProxy, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetSnapshot, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellApplyDeviceSettingsPatch, useDoorbellEvents, useDoorbellGetDeviceLiveContribution, useDoorbellGetDeviceSettingsContribution, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, useEventsGetEventClipUrl, useEventsGetEventThumbnail, useEventsGetEvents, useFaceGalleryAssignFace, useFaceGalleryAssignFaces, useFaceGalleryAuditIdentitySamples, useFaceGalleryCreateIdentity, useFaceGalleryDeleteFace, useFaceGalleryDeleteIdentity, useFaceGalleryGetFaceByTrack, useFaceGalleryGetFaceMedia, useFaceGalleryListIdentities, useFaceGalleryListIdentitySamples, useFaceGalleryListRecentFaces, useFaceGalleryRemoveSample, useFaceGalleryRenameIdentity, useFaceGallerySuggestFaceClusters, useFaceGalleryUnassignFace, useFaceGalleryUnassignFaces, useFanControlGetStatus, useFanControlSetDirection, useFanControlSetOscillating, useFanControlSetPercentage, useFanControlSetPreset, useFeatureProbeGetStatus, useFloodGetStatus, useGasGetStatus, useHumidifierGetStatus, useHumidifierSetMode, useHumidifierSetOn, useHumidifierSetTargetHumidity, useHumiditySensorGetStatus, useImageGetStatus, useImageSettingsGetOptions, useImageSettingsGetStatus, useImageSettingsSetSettings, useIntegrationsCreate, useIntegrationsDelete, useIntegrationsGet, useIntegrationsGetAvailableTypes, useIntegrationsGetByAddonId, useIntegrationsGetSettings, useIntegrationsList, useIntegrationsSetSettings, useIntegrationsTestConnection, useIntegrationsUpdate, useIntercomEndTalkSession, useIntercomGetStatus, useIntercomHandleAnswer, useIntercomPushTalkAudio, useIntercomStartSession, useIntercomStartTalkSession, useIntercomStopSession, useIsMidWidth, useIsMobile, useLawnMowerControlDock, useLawnMowerControlGetStatus, useLawnMowerControlPause, useLawnMowerControlStartMowing, useLiveBuffer, useLiveEvent, useLlmCancel, useLlmDeleteModel, useLlmDeleteProfile, useLlmGenerate, useLlmGenerateVision, useLlmGetDefaults, useLlmGetRuntimeStatus, useLlmGetUsage, useLlmInstallModel, useLlmListModelCatalog, useLlmListModels, useLlmListNodeModels, useLlmListProfileKinds, useLlmListProfiles, useLlmListRuntimeNodes, useLlmResolveModelRef, useLlmSetDefault, useLlmStartRuntime, useLlmStopRuntime, useLlmTestProfile, useLlmUpsertProfile, useLocalNetworkDownloadCa, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAllowedAddresses, useLocalNetworkSetNotificationEndpoint, useLocalNetworkSetViewerEndpoints, useLocalNetworkUploadCertificate, useLockControlGetStatus, useLockControlLock, useLockControlOpen, useLockControlUnlock, useMediaPlayerGetStatus, useMediaPlayerNext, useMediaPlayerPause, useMediaPlayerPlay, useMediaPlayerPlayMedia, useMediaPlayerPrevious, useMediaPlayerSeek, useMediaPlayerSelectSource, useMediaPlayerSetMute, useMediaPlayerSetRepeat, useMediaPlayerSetShuffle, useMediaPlayerSetVolume, useMediaPlayerStop, useMeshNetworkGetStatus, useMeshNetworkJoin, useMeshNetworkLeave, useMeshNetworkListPeers, useMeshNetworkLogout, useMeshNetworkStartLogin, useMeshNetworkTestConnection, useMetricsProviderCollectSnapshot, useMetricsProviderGetAddonStats, useMetricsProviderGetCached, useMetricsProviderGetCpuTemperature, useMetricsProviderGetCurrent, useMetricsProviderGetDiskSpace, useMetricsProviderGetGpuInfo, useMetricsProviderGetLoadSeries, useMetricsProviderGetProcessStats, useMetricsProviderListAddonInstances, useMetricsProviderListNodeProcesses, useMotionDetectionAnalyze, useMotionDetectionApplyDeviceSettingsPatch, useMotionDetectionGetDeviceLiveContribution, useMotionDetectionGetDeviceSettingsContribution, useMotionDetectionRemoveCamera, useMotionDetectionReset, useMotionGetStatus, useMotionIsDetected, useMotionTriggerGetStatus, useMotionTriggerSetMotionTrigger, useMotionZonesGetOptions, useMotionZonesGetStatus, useMotionZonesSetZone, useMqttBrokerAddBroker, useMqttBrokerGetBrokerConfig, useMqttBrokerGetStatus, useMqttBrokerListBrokers, useMqttBrokerRemoveBroker, useMqttBrokerStartEmbeddedBroker, useMqttBrokerStopEmbeddedBroker, useMqttBrokerTestConnection, useNativeObjectDetectionGetOptions, useNativeObjectDetectionGetStatus, useNativeObjectDetectionSetEnabled, useNativeObjectDetectionSetSettings, useNavigation, useNavigationGetFeatures, useNavigationGetStatus, useNavigationGoToPoint, useNavigationListActions, useNavigationMove, useNavigationPlaySound, useNavigationRunAction, useNavigationSetLightLevel, useNavigationSetLightMode, useNavigationSetLightOn, useNavigationStop, useNetworkAccessGetEndpoint, useNetworkAccessGetStatus, useNetworkAccessListEndpoints, useNetworkAccessStart, useNetworkAccessStop, useNetworkLinkGetStatus, useNetworkQualityGetAllStats, useNetworkQualityGetDeviceStats, useNetworkQualityReportClientStats, useNodesClusterAddonStatus, useNodesDeployAddon, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesCancelSnooze, useNotificationRulesCreateRule, useNotificationRulesCreateSnooze, useNotificationRulesDeleteRule, useNotificationRulesGetAlarmConfig, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSnoozes, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdSetOverlay, usePTZ, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTracks, usePipelineAnalyticsCompleteRetrainTrack, usePipelineAnalyticsCountRelocatableMedia, usePipelineAnalyticsCountUnstampedEventMedia, usePipelineAnalyticsDeleteDeviceEvents, usePipelineAnalyticsDeleteTracks, usePipelineAnalyticsDeselectRetrainFrame, usePipelineAnalyticsGetActiveTracks, usePipelineAnalyticsGetAudioEvents, usePipelineAnalyticsGetDeviceLiveContribution, usePipelineAnalyticsGetDeviceSettingsContribution, usePipelineAnalyticsGetEventDensity, usePipelineAnalyticsGetEventDensityBatch, usePipelineAnalyticsGetEventMedia, usePipelineAnalyticsGetEventMediaFootprintByKind, usePipelineAnalyticsGetEventStoreFootprint, usePipelineAnalyticsGetKeyEvents, usePipelineAnalyticsGetKeyEventsBatch, usePipelineAnalyticsGetMediaReclaimStatus, usePipelineAnalyticsGetMotionEvents, usePipelineAnalyticsGetObjectEmbeddingRebuildStatus, usePipelineAnalyticsGetObjectEvents, usePipelineAnalyticsGetRetrainExportUrl, usePipelineAnalyticsGetRetrainFrameImage, usePipelineAnalyticsGetSensorEvents, usePipelineAnalyticsGetStorageMigrationMoveStatus, usePipelineAnalyticsGetSummary, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentSummaries, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListSummaries, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsRunReplayFrameProcessor, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDeleteTemplate, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorListTemplates, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSaveTemplate, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorUpdateTemplate, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorDeleteTemplate, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorListTemplates, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSaveTemplate, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentDetectWeight, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, usePipelineOrchestratorUpdateTemplate, usePipelineRunnerAttachCamera, usePipelineRunnerDetachCamera, usePipelineRunnerGetAllCameraMetrics, usePipelineRunnerGetCameraMetrics, usePipelineRunnerGetLocalCameras, usePipelineRunnerGetLocalLoad, usePipelineRunnerGetLocalMetrics, usePipelineRunnerGetNativeCrop, usePipelineRunnerGetParkedTrackFrame, usePipelineRunnerParkTrackFrame, usePipelineRunnerReleaseParkedTrackFrames, usePipelineRunnerReportMotion, usePipelineRunnerRequestOccupancyBurst, usePipelineRunnerRunDetailSubtree, usePipelineRunnerRunStatelessStep, usePlateGalleryAssignPlate, usePlateGalleryAssignPlates, usePlateGalleryCorrectPlateText, usePlateGalleryCreateVehicle, usePlateGalleryDeletePlate, usePlateGalleryDeleteVehicle, usePlateGalleryGetPlateByTrack, usePlateGalleryGetPlateMedia, usePlateGalleryListPlates, usePlateGalleryListVehicleSamples, usePlateGalleryListVehicles, usePlateGalleryRemoveVehicleSample, usePlateGalleryRenameVehicle, usePlateGallerySearchPlates, usePlateGallerySuggestPlateClusters, usePlateGalleryUnassignPlate, usePlateGalleryUnassignPlates, usePlayerOverlayLayer, usePlayerOverlayLayers, usePlayerToolbarButton, usePlayerToolbarButtons, usePowerMeterGetStatus, usePresenceGetStatus, usePressureSensorGetStatus, usePrivacyMaskGetOptions, usePrivacyMaskGetStatus, usePrivacyMaskSetAudioEnabled, usePrivacyMaskSetMask, usePrompt, usePtzAutotrackGetSettings, usePtzAutotrackGetStatus, usePtzAutotrackSetEnabled, usePtzAutotrackSetSettings, usePtzCaptureHomeHere, usePtzContinuousMove, usePtzDeletePreset, usePtzGetHomePreset, usePtzGetHomeReturn, usePtzGetOptions, usePtzGetPosition, usePtzGetPresets, usePtzGetStatus, usePtzGoHome, usePtzGoToPreset, usePtzMove, usePtzSavePreset, usePtzSetAutofocus, usePtzSetHomePreset, usePtzSetHomeReturn, usePtzStop, useRebootReboot, useRecordedPlayback, useRecordingApplyDeviceSettingsPatch, useRecordingCancelRelocateJob, useRecordingCancelStorageMigrationMove, useRecordingDeleteFootprint, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetAvailabilityBatch, useRecordingGetDaysWithRecordings, useRecordingGetDaysWithRecordingsBatch, useRecordingGetDeviceConfig, useRecordingGetDeviceLiveContribution, useRecordingGetDeviceSettingsContribution, useRecordingGetPlacement, useRecordingGetPlaybackManifest, useRecordingGetRelocateResidue, useRecordingGetStatus, useRecordingGetStorageMigrationMoveStatus, useRecordingGetStorageUsage, useRecordingListOpsLog, useRecordingListRelocateJobs, useRecordingLocateSegment, useRecordingPauseForStorageMigration, useRecordingPlanStorageRebalance, useRecordingPruneFootage, useRecordingReadGopBytes, useRecordingReadSegmentBytes, useRecordingReadWindowBytes, useRecordingReconcileLedgerAgainstDisk, useRecordingRefreshStorageLocationsForMigration, useRecordingRelocateFootage, useRecordingRenderClip, useRecordingRenderGif, useRecordingRescanStorage, useRecordingResumeForStorageMigration, useRecordingSetDeviceConfig, useRecordingSetDevicePlacement, useRecordingSignalGetStatus, useRecordingStartStorageMigrationMove, useRecordingStartStorageRebalance, useRemoteComponent, useRoleDisplayDefaults, useSceneMonitorCaptureReference, useSceneMonitorCreateScene, useSceneMonitorDeleteReference, useSceneMonitorDeleteScene, useSceneMonitorGetStatus, useSceneMonitorListScenes, useSceneMonitorListScenesBatch, useSceneMonitorRecheckNow, useSceneMonitorResetScene, useSceneMonitorUpdateScene, useScriptRunnerGetStatus, useScriptRunnerRun, useScriptRunnerStop, useScrubController, useServerManagementApplyServerUpdate, useServerManagementCheckServerUpdate, useServerManagementGetServerPackageStatus, useServerManagementRestartServer, useServerManagementRollbackServerUpdate, useSettingsStoreAggregate, useSettingsStoreCount, useSettingsStoreDeclareCollection, useSettingsStoreDelete, useSettingsStoreDeleteWhere, useSettingsStoreGet, useSettingsStoreHistogram, useSettingsStoreInsert, useSettingsStoreInsertMany, useSettingsStoreIsEmpty, useSettingsStoreQuery, useSettingsStoreSet, useSettingsStoreUpdate, useSettingsStoreUpdateWhere, useSettingsStoreUpsert, useSmokeGetStatus, useSnapshotApplyDeviceSettingsPatch, useSnapshotGetDebugState, useSnapshotGetDeviceLiveContribution, useSnapshotGetDeviceSettingsContribution, useSnapshotGetSnapshot, useSnapshotGetSnapshotLinks, useSnapshotGetSnapshotOverview, useSnapshotGetStatus, useSnapshotInvalidateCache, useStationaryOverlay, useStorageAbortUpload, useStorageBeginDownload, useStorageBeginUpload, useStorageDelete, useStorageDeleteLocation, useStorageEndDownload, useStorageExists, useStorageFinalizeUpload, useStorageGetAvailableSpace, useStorageList, useStorageListDrainProgress, useStorageListLocationDeclarations, useStorageListLocations, useStorageListProviders, useStorageMigrationCancel, useStorageMigrationCleanupCancel, useStorageMigrationCleanupStart, useStorageMigrationCleanupStatus, useStorageMigrationDrain, useStorageMigrationHistory, useStorageMigrationMovers, useStorageMigrationPlan, useStorageMigrationResidue, useStorageMigrationStart, useStorageMigrationStatus, useStorageRead, useStorageReadChunk, useStorageResolve, useStorageTestConfig, useStorageTestLocation, useStorageUpsertLocation, useStorageWrite, useStorageWriteChunk, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerPullFrameHandles, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerSubscribeFrames, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, useStreamBrokerUnsubscribeFrames, useStreamCatalogGetCatalog, useStreamParamsGetConfigSchema, useStreamParamsGetOptions, useStreamParamsGetStatus, useStreamParamsSetProfile, useStreamSignalsListSignals, useSwitchGetStatus, useSwitchSetState, useSystem, useSystemDetectSiteLocation, useSystemFeatureFlags, useSystemForceRetentionCleanup, useSystemGetFailureContributions, useSystemGetLoadContributions, useSystemGetLoggingSettings, useSystemGetRequestCensus, useSystemGetRetentionConfig, useSystemGetSiteLocation, useSystemHealth, useSystemInfo, useSystemMutation, useSystemNetworkAddresses, useSystemQuery, useSystemSetLoggingSettings, useSystemSetRetentionConfig, useSystemSetSiteLocation, useTamperGetStatus, useTemperatureSensorGetStatus, useTerminalSessionAdoptLegacyMonitor, useTerminalSessionClose, useTerminalSessionCreateInstance, useTerminalSessionDeleteInstance, useTerminalSessionListInstances, useTerminalSessionListLegacyCameras, useTerminalSessionListProfiles, useTerminalSessionListSessions, useTerminalSessionOpenSession, useTerminalSessionPullOutput, useTerminalSessionResize, useTerminalSessionSetInstanceEnabled, useTerminalSessionUpdateInstance, useTerminalSessionWriteInput, useThemeMode, useToastOnToast, useTurnProviderGetTurnServers, useUpdateGetStatus, useUpdateInstallUpdate, useUserManagementConfirmTotp, useUserManagementCreateApiKey, useUserManagementCreateScopedToken, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementGetTotpStatus, useUserManagementListApiKeys, useUserManagementListOauthSessions, useUserManagementListScopedTokens, useUserManagementListUsers, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeApiKey, useUserManagementRevokeOauthSession, useUserManagementRevokeScopedToken, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUpdateUser, useUserManagementValidateApiKey, useUserManagementValidateCredentials, useUserManagementValidateScopedToken, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsDialClipStream, useVideoclipsGetClipPlayback, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionCloseSession, useWebrtcSessionCreateSession, useWebrtcSessionGetIceCandidates, useWebrtcSessionGetSessionDebug, useWebrtcSessionGetSessionState, useWebrtcSessionHandleAnswer, useWebrtcSessionHandleOffer, useWebrtcSessionHasAdaptiveBitrate, useWebrtcSessionListStreams, useWidget, useWidgetMetadata, useWidgetRegistry, useZoneAnalyticsGetCameraHistory, useZoneAnalyticsGetCurrentSnapshot, useZoneAnalyticsGetCurrentSnapshotBatch, useZoneAnalyticsGetUnzonedHistory, useZoneAnalyticsGetZoneHistory, useZoneEditing, useZoneRulesListRules, useZoneRulesSetRules, useZonesAddZone, useZonesListZones, useZonesRemoveZone, useZonesUpdateZone, vacuumStateMeta, validateScopes, valveStateMeta, variantLabel, waterHeaterPhase, waterHeaterTint, weatherConditionMeta, weatherTint };