@camstack/ui-library 1.2.247 → 1.2.249

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
@@ -5,9 +5,9 @@ import * as __mfHostTrpcReactQuery from "@trpc/react-query";
5
5
  import { createTRPCReact } from "@trpc/react-query";
6
6
  import * as __mfHostReactJsxRuntime from "react/jsx-runtime";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ 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, EXTENSION_SLOTS, EXTENSION_SLOT_IDS, 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, RECORDING_SOURCE_CAMSTACK_ADDON, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, USE_ROOT_MODEL_SETTING_KEY, buildModelVariantGroups, canConvertUnit, clearModelBoundOverrides, clearModelBoundSetting, clusterStepSettingFieldsFor, collectModelBoundKeys, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, effectiveStepSettings, findTimezone, formatParkedFor, hasModelBoundOverrides, isRootSuppliableStepId, modelBindingKey, normalizeUnit, publicEventCategories, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveDisplayIconKey, resolveModelBoundSetting, resolveRecordingProfiles, resolveRootSupply, resolveVariantModelId, resolveViewableDeviceIds, searchDisplayIcons, selectAssignedProfileSlots, stepSettingSource, tryConvertUnit, unitsForDimension, withFieldFrom, withoutField, writeModelBoundSetting } from "@camstack/types";
8
9
  import * as __mfHostReactDOM from "react-dom";
9
10
  import { createPortal } from "react-dom";
10
- 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, EXTENSION_SLOTS, EXTENSION_SLOT_IDS, 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, RECORDING_SOURCE_CAMSTACK_ADDON, RecordingConfigSchema, RecordingStatusSchema, SOURCE_CAP_ACTIVE_FIELD, STATIONARY_OVERLAY_STYLE, TIMEZONES, USE_ROOT_MODEL_SETTING_KEY, buildModelVariantGroups, canConvertUnit, clearModelBoundOverrides, clearModelBoundSetting, clusterStepSettingFieldsFor, collectModelBoundKeys, createDeviceProxy, createLazyTrpcSource, createSliceHandle, deriveRecordingMode, describeModelVariant, effectiveStepSettings, findTimezone, formatParkedFor, hasModelBoundOverrides, isRootSuppliableStepId, modelBindingKey, normalizeUnit, publicEventCategories, resolveContainerPrimaryChild, resolveDeviceControlKind, resolveModelBoundSetting, resolveRecordingProfiles, resolveRootSupply, resolveVariantModelId, resolveViewableDeviceIds, searchDisplayIcons, selectAssignedProfileSlots, stepSettingSource, tryConvertUnit, unitsForDimension, withFieldFrom, withoutField, writeModelBoundSetting } from "@camstack/types";
11
11
  import * as __mfHostTanstackQuery from "@tanstack/react-query";
12
12
  import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
13
13
  import * as __mfHostReactDOMClient from "react-dom/client";
@@ -6442,6 +6442,756 @@ function useClusterNodes() {
6442
6442
  };
6443
6443
  }
6444
6444
  //#endregion
6445
+ //#region src/composites/device-meta.ts
6446
+ var DEVICE_TYPE_META = {
6447
+ [DeviceType.Camera]: {
6448
+ icon: Camera,
6449
+ label: "Camera"
6450
+ },
6451
+ [DeviceType.Hub]: {
6452
+ icon: Network,
6453
+ label: "Hub"
6454
+ },
6455
+ [DeviceType.Light]: {
6456
+ icon: Lightbulb,
6457
+ label: "Light"
6458
+ },
6459
+ [DeviceType.Siren]: {
6460
+ icon: Siren,
6461
+ label: "Siren"
6462
+ },
6463
+ [DeviceType.Switch]: {
6464
+ icon: ToggleLeft,
6465
+ label: "Switch"
6466
+ },
6467
+ [DeviceType.Sensor]: {
6468
+ icon: Activity,
6469
+ label: "Sensor"
6470
+ },
6471
+ [DeviceType.Thermostat]: {
6472
+ icon: Thermometer,
6473
+ label: "Thermostat"
6474
+ },
6475
+ [DeviceType.Climate]: {
6476
+ icon: AirVent,
6477
+ label: "Air conditioner"
6478
+ },
6479
+ [DeviceType.Button]: {
6480
+ icon: CircleDot,
6481
+ label: "Button"
6482
+ },
6483
+ [DeviceType.EventEmitter]: {
6484
+ icon: Zap,
6485
+ label: "Event Emitter"
6486
+ },
6487
+ [DeviceType.Update]: {
6488
+ icon: RefreshCw,
6489
+ label: "Update"
6490
+ },
6491
+ [DeviceType.Generic]: {
6492
+ icon: Box,
6493
+ label: "Generic"
6494
+ },
6495
+ [DeviceType.Notifier]: {
6496
+ icon: Bell,
6497
+ label: "Notifier"
6498
+ },
6499
+ [DeviceType.Script]: {
6500
+ icon: ScrollText,
6501
+ label: "Script"
6502
+ },
6503
+ [DeviceType.Automation]: {
6504
+ icon: Workflow,
6505
+ label: "Automation"
6506
+ },
6507
+ [DeviceType.Lock]: {
6508
+ icon: Lock,
6509
+ label: "Lock"
6510
+ },
6511
+ [DeviceType.Cover]: {
6512
+ icon: Blinds,
6513
+ label: "Cover"
6514
+ },
6515
+ [DeviceType.Valve]: {
6516
+ icon: Pipette,
6517
+ label: "Valve"
6518
+ },
6519
+ [DeviceType.Humidifier]: {
6520
+ icon: Waves,
6521
+ label: "Humidifier"
6522
+ },
6523
+ [DeviceType.WaterHeater]: {
6524
+ icon: Bath,
6525
+ label: "Water heater"
6526
+ },
6527
+ [DeviceType.Fan]: {
6528
+ icon: Fan,
6529
+ label: "Fan"
6530
+ },
6531
+ [DeviceType.MediaPlayer]: {
6532
+ icon: MonitorPlay,
6533
+ label: "Media player"
6534
+ },
6535
+ [DeviceType.AlarmPanel]: {
6536
+ icon: ShieldAlert,
6537
+ label: "Alarm panel"
6538
+ },
6539
+ [DeviceType.Control]: {
6540
+ icon: SlidersHorizontal,
6541
+ label: "Control"
6542
+ },
6543
+ [DeviceType.Presence]: {
6544
+ icon: MapPin,
6545
+ label: "Presence"
6546
+ },
6547
+ [DeviceType.Weather]: {
6548
+ icon: CloudSun,
6549
+ label: "Weather"
6550
+ },
6551
+ [DeviceType.Vacuum]: {
6552
+ icon: Bot,
6553
+ label: "Vacuum"
6554
+ },
6555
+ [DeviceType.LawnMower]: {
6556
+ icon: Tractor,
6557
+ label: "Lawn mower"
6558
+ },
6559
+ [DeviceType.Container]: {
6560
+ icon: Box,
6561
+ label: "Container"
6562
+ },
6563
+ [DeviceType.Image]: {
6564
+ icon: Image,
6565
+ label: "Image"
6566
+ },
6567
+ [DeviceType.PetFeeder]: {
6568
+ icon: Bone,
6569
+ label: "Pet feeder"
6570
+ }
6571
+ };
6572
+ var DEVICE_ROLE_META = {
6573
+ [DeviceRole.Siren]: {
6574
+ icon: Siren,
6575
+ label: "Siren"
6576
+ },
6577
+ [DeviceRole.Floodlight]: {
6578
+ icon: Lightbulb,
6579
+ label: "Floodlight"
6580
+ },
6581
+ [DeviceRole.Spotlight]: {
6582
+ icon: Flashlight,
6583
+ label: "Spotlight"
6584
+ },
6585
+ [DeviceRole.PirSensor]: {
6586
+ icon: Radar,
6587
+ label: "PIR sensor"
6588
+ },
6589
+ [DeviceRole.Chime]: {
6590
+ icon: Bell,
6591
+ label: "Chime"
6592
+ },
6593
+ [DeviceRole.Autotrack]: {
6594
+ icon: Crosshair,
6595
+ label: "Auto-track"
6596
+ },
6597
+ [DeviceRole.Nightvision]: {
6598
+ icon: Moon,
6599
+ label: "Night vision"
6600
+ },
6601
+ [DeviceRole.PrivacyMask]: {
6602
+ icon: EyeOff,
6603
+ label: "Privacy mask"
6604
+ },
6605
+ [DeviceRole.Doorbell]: {
6606
+ icon: DoorClosed,
6607
+ label: "Doorbell"
6608
+ },
6609
+ [DeviceRole.BinaryHelper]: {
6610
+ icon: ToggleLeft,
6611
+ label: "Binary helper"
6612
+ },
6613
+ [DeviceRole.MotionSensor]: {
6614
+ icon: Footprints,
6615
+ label: "Motion sensor"
6616
+ },
6617
+ [DeviceRole.ContactSensor]: {
6618
+ icon: DoorOpen,
6619
+ label: "Contact sensor"
6620
+ },
6621
+ [DeviceRole.LeakSensor]: {
6622
+ icon: Droplet,
6623
+ label: "Leak sensor"
6624
+ },
6625
+ [DeviceRole.SmokeSensor]: {
6626
+ icon: AlarmSmoke,
6627
+ label: "Smoke sensor"
6628
+ },
6629
+ [DeviceRole.COSensor]: {
6630
+ icon: Wind,
6631
+ label: "CO sensor"
6632
+ },
6633
+ [DeviceRole.GasSensor]: {
6634
+ icon: Flame,
6635
+ label: "Gas sensor"
6636
+ },
6637
+ [DeviceRole.TamperSensor]: {
6638
+ icon: ShieldAlert,
6639
+ label: "Tamper sensor"
6640
+ },
6641
+ [DeviceRole.VibrationSensor]: {
6642
+ icon: Vibrate,
6643
+ label: "Vibration sensor"
6644
+ },
6645
+ [DeviceRole.ConnectivitySensor]: {
6646
+ icon: Wifi,
6647
+ label: "Connectivity"
6648
+ },
6649
+ [DeviceRole.SoundSensor]: {
6650
+ icon: Volume2,
6651
+ label: "Sound sensor"
6652
+ },
6653
+ [DeviceRole.BinarySensor]: {
6654
+ icon: ToggleLeft,
6655
+ label: "Binary sensor"
6656
+ },
6657
+ [DeviceRole.TemperatureSensor]: {
6658
+ icon: Thermometer,
6659
+ label: "Temperature"
6660
+ },
6661
+ [DeviceRole.HumiditySensor]: {
6662
+ icon: Droplets,
6663
+ label: "Humidity"
6664
+ },
6665
+ [DeviceRole.AmbientLightSensor]: {
6666
+ icon: Sun,
6667
+ label: "Ambient light"
6668
+ },
6669
+ [DeviceRole.PressureSensor]: {
6670
+ icon: Gauge,
6671
+ label: "Pressure"
6672
+ },
6673
+ [DeviceRole.WindSensor]: {
6674
+ icon: Wind,
6675
+ label: "Wind"
6676
+ },
6677
+ [DeviceRole.RainSensor]: {
6678
+ icon: CloudRain,
6679
+ label: "Rain"
6680
+ },
6681
+ [DeviceRole.UvSensor]: {
6682
+ icon: SunMedium,
6683
+ label: "UV index"
6684
+ },
6685
+ [DeviceRole.SolarRadiationSensor]: {
6686
+ icon: Sunrise,
6687
+ label: "Solar radiation"
6688
+ },
6689
+ [DeviceRole.SoilMoistureSensor]: {
6690
+ icon: Sprout,
6691
+ label: "Soil moisture"
6692
+ },
6693
+ [DeviceRole.PowerSensor]: {
6694
+ icon: Zap,
6695
+ label: "Power"
6696
+ },
6697
+ [DeviceRole.EnergySensor]: {
6698
+ icon: Zap,
6699
+ label: "Energy"
6700
+ },
6701
+ [DeviceRole.VoltageSensor]: {
6702
+ icon: Zap,
6703
+ label: "Voltage"
6704
+ },
6705
+ [DeviceRole.CurrentSensor]: {
6706
+ icon: Zap,
6707
+ label: "Current"
6708
+ },
6709
+ [DeviceRole.AirQualitySensor]: {
6710
+ icon: Wind,
6711
+ label: "Air quality"
6712
+ },
6713
+ [DeviceRole.BatterySensor]: {
6714
+ icon: Gauge,
6715
+ label: "Battery"
6716
+ },
6717
+ [DeviceRole.NumericSensor]: {
6718
+ icon: Hash,
6719
+ label: "Numeric sensor"
6720
+ },
6721
+ [DeviceRole.EnumSensor]: {
6722
+ icon: List,
6723
+ label: "Enum sensor"
6724
+ },
6725
+ [DeviceRole.DateTimeSensor]: {
6726
+ icon: Clock,
6727
+ label: "Date / time"
6728
+ },
6729
+ [DeviceRole.GenericSensor]: {
6730
+ icon: Gauge,
6731
+ label: "Sensor"
6732
+ },
6733
+ [DeviceRole.NumericControl]: {
6734
+ icon: SlidersHorizontal,
6735
+ label: "Numeric control"
6736
+ },
6737
+ [DeviceRole.SelectControl]: {
6738
+ icon: ListChecks,
6739
+ label: "Select control"
6740
+ },
6741
+ [DeviceRole.TextControl]: {
6742
+ icon: Type,
6743
+ label: "Text control"
6744
+ },
6745
+ [DeviceRole.DateTimeControl]: {
6746
+ icon: Clock,
6747
+ label: "Date / time control"
6748
+ },
6749
+ [DeviceRole.MobilePushNotifier]: {
6750
+ icon: Smartphone,
6751
+ label: "Mobile push"
6752
+ },
6753
+ [DeviceRole.MessagingNotifier]: {
6754
+ icon: MessageSquare,
6755
+ label: "Messaging"
6756
+ },
6757
+ [DeviceRole.EmailNotifier]: {
6758
+ icon: Mail,
6759
+ label: "Email"
6760
+ },
6761
+ [DeviceRole.GenericNotifier]: {
6762
+ icon: Bell,
6763
+ label: "Notifier"
6764
+ }
6765
+ };
6766
+ var DEVICE_TYPE_VALUES$1 = new Set(Object.values(DeviceType));
6767
+ var DEVICE_ROLE_VALUES = new Set(Object.values(DeviceRole));
6768
+ function isDeviceType(value) {
6769
+ return DEVICE_TYPE_VALUES$1.has(value);
6770
+ }
6771
+ function isDeviceRole(value) {
6772
+ return DEVICE_ROLE_VALUES.has(value);
6773
+ }
6774
+ /** Meta for a known `DeviceType`. */
6775
+ function deviceTypeMeta(type) {
6776
+ return DEVICE_TYPE_META[type];
6777
+ }
6778
+ /** Meta for a known `DeviceRole`. */
6779
+ function deviceRoleMeta(role) {
6780
+ return DEVICE_ROLE_META[role];
6781
+ }
6782
+ var FALLBACK_DEVICE_TYPE_META = DEVICE_TYPE_META[DeviceType.Generic];
6783
+ var FALLBACK_DEVICE_ROLE_META = DEVICE_ROLE_META[DeviceRole.GenericSensor];
6784
+ /**
6785
+ * Runtime-string-safe lookup: device data crosses process / network boundaries
6786
+ * as plain strings, so an unrecognised value falls back to the `Generic` meta
6787
+ * instead of throwing.
6788
+ *
6789
+ * This also guards mixed-version module-federation loads where the host
6790
+ * `@camstack/types` enum has a new member before the loaded ui-library bundle
6791
+ * has the matching `DEVICE_TYPE_META` entry.
6792
+ */
6793
+ function deviceTypeMetaOf(type) {
6794
+ if (!isDeviceType(type)) return FALLBACK_DEVICE_TYPE_META;
6795
+ return DEVICE_TYPE_META[type] ?? FALLBACK_DEVICE_TYPE_META;
6796
+ }
6797
+ /** Runtime-string-safe role lookup; unknown roles fall back to `GenericSensor`. */
6798
+ function deviceRoleMetaOf(role) {
6799
+ if (!isDeviceRole(role)) return FALLBACK_DEVICE_ROLE_META;
6800
+ return DEVICE_ROLE_META[role] ?? FALLBACK_DEVICE_ROLE_META;
6801
+ }
6802
+ /**
6803
+ * Icons an operator may pick for a per-device `display.icon` override (and for
6804
+ * a per-role default), keyed by a stable kebab-case name. Named imports only —
6805
+ * no dynamic indexing into lucide, so the bundle carries exactly this set.
6806
+ * Unknown keys resolve to `undefined` (caller falls through to the next level).
6807
+ *
6808
+ * The vocabulary is the one the VIEWER draws from too (its own icon module,
6809
+ * keyed by these same strings): a key added here that the phone cannot draw
6810
+ * falls through to the next resolution level there, which reads as "my change
6811
+ * did nothing". So the KEY is the contract — a stable kebab-case string, never
6812
+ * a glyph identity — and `device-meta.test.ts` pins that every key resolves
6813
+ * and that the set never loses a key an operator may already have persisted.
6814
+ *
6815
+ * Grouped by what an operator is naming: a device, a light or appliance, a
6816
+ * sensor or the weather it reads, a room, or what moves through it. `gauge2`
6817
+ * is a legacy alias kept for rows that persisted it.
6818
+ */
6819
+ var DISPLAY_ICON_REGISTRY = {
6820
+ camera: Camera,
6821
+ network: Network,
6822
+ "toggle-left": ToggleLeft,
6823
+ "toggle-right": ToggleRight,
6824
+ "circle-dot": CircleDot,
6825
+ "refresh-cw": RefreshCw,
6826
+ box: Box,
6827
+ "scroll-text": ScrollText,
6828
+ workflow: Workflow,
6829
+ lock: Lock,
6830
+ "lock-open": LockOpen,
6831
+ blinds: Blinds,
6832
+ "air-vent": AirVent,
6833
+ "monitor-play": MonitorPlay,
6834
+ "sliders-horizontal": SlidersHorizontal,
6835
+ "map-pin": MapPin,
6836
+ bot: Bot,
6837
+ tractor: Tractor,
6838
+ image: Image,
6839
+ bone: Bone,
6840
+ "door-closed": DoorClosed,
6841
+ "door-open": DoorOpen,
6842
+ crosshair: Crosshair,
6843
+ eye: Eye,
6844
+ "eye-off": EyeOff,
6845
+ smartphone: Smartphone,
6846
+ phone: Phone,
6847
+ tablet: Tablet,
6848
+ laptop: Laptop,
6849
+ monitor: Monitor,
6850
+ tv: Tv,
6851
+ speaker: Speaker,
6852
+ printer: Printer,
6853
+ projector: Projector,
6854
+ "gamepad-2": Gamepad2,
6855
+ radio: Radio,
6856
+ router: Router,
6857
+ bluetooth: Bluetooth,
6858
+ cpu: Cpu,
6859
+ "hard-drive": HardDrive,
6860
+ server: Server,
6861
+ mic: Mic,
6862
+ "mic-off": MicOff,
6863
+ video: Video,
6864
+ "video-off": VideoOff,
6865
+ music: Music,
6866
+ plug: Plug,
6867
+ "plug-zap": PlugZap,
6868
+ power: Power,
6869
+ "power-off": PowerOff,
6870
+ cable: Cable,
6871
+ battery: Battery,
6872
+ "battery-charging": BatteryCharging,
6873
+ "battery-full": BatteryFull,
6874
+ "battery-low": BatteryLow,
6875
+ key: Key,
6876
+ "key-round": KeyRound,
6877
+ mailbox: Mailbox,
6878
+ package: Package,
6879
+ shield: Shield,
6880
+ "shield-check": ShieldCheck,
6881
+ "shield-off": ShieldOff,
6882
+ lightbulb: Lightbulb,
6883
+ lamp: Lamp,
6884
+ "lamp-ceiling": LampCeiling,
6885
+ "lamp-desk": LampDesk,
6886
+ "lamp-floor": LampFloor,
6887
+ flashlight: Flashlight,
6888
+ heater: Heater,
6889
+ snowflake: Snowflake,
6890
+ "thermometer-sun": ThermometerSun,
6891
+ "thermometer-snowflake": ThermometerSnowflake,
6892
+ refrigerator: Refrigerator,
6893
+ microwave: Microwave,
6894
+ "washing-machine": WashingMachine,
6895
+ "cooking-pot": CookingPot,
6896
+ utensils: Utensils,
6897
+ thermometer: Thermometer,
6898
+ droplets: Droplets,
6899
+ droplet: Droplet,
6900
+ gauge: Gauge,
6901
+ gauge2: Gauge,
6902
+ sun: Sun,
6903
+ "sun-medium": SunMedium,
6904
+ sunrise: Sunrise,
6905
+ moon: Moon,
6906
+ wind: Wind,
6907
+ cloud: Cloud,
6908
+ "cloud-rain": CloudRain,
6909
+ "cloud-sun": CloudSun,
6910
+ waves: Waves,
6911
+ sprout: Sprout,
6912
+ leaf: Leaf,
6913
+ flower: Flower,
6914
+ zap: Zap,
6915
+ flame: Flame,
6916
+ bell: Bell,
6917
+ "bell-ring": BellRing,
6918
+ "bell-off": BellOff,
6919
+ siren: Siren,
6920
+ radar: Radar,
6921
+ activity: Activity,
6922
+ hash: Hash,
6923
+ clock: Clock,
6924
+ timer: Timer,
6925
+ calendar: Calendar,
6926
+ pipette: Pipette,
6927
+ fan: Fan,
6928
+ bath: Bath,
6929
+ footprints: Footprints,
6930
+ "alarm-smoke": AlarmSmoke,
6931
+ "shield-alert": ShieldAlert,
6932
+ vibrate: Vibrate,
6933
+ wifi: Wifi,
6934
+ "wifi-off": WifiOff,
6935
+ "volume-2": Volume2,
6936
+ "volume-x": VolumeX,
6937
+ heart: Heart,
6938
+ "heart-pulse": HeartPulse,
6939
+ star: Star,
6940
+ sparkles: Sparkles,
6941
+ house: House,
6942
+ sofa: Sofa,
6943
+ "bed-double": BedDouble,
6944
+ bed: Bed,
6945
+ warehouse: Warehouse,
6946
+ trees: Trees,
6947
+ "tree-pine": TreePine,
6948
+ fence: Fence,
6949
+ store: Store,
6950
+ building: Building,
6951
+ "building-2": Building2,
6952
+ mountain: Mountain,
6953
+ umbrella: Umbrella,
6954
+ dumbbell: Dumbbell,
6955
+ wrench: Wrench,
6956
+ hammer: Hammer,
6957
+ drill: Drill,
6958
+ "waves-ladder": WavesLadder,
6959
+ "circle-parking": CircleParking,
6960
+ briefcase: Briefcase,
6961
+ route: Route,
6962
+ car: Car,
6963
+ bike: Bike,
6964
+ bus: Bus,
6965
+ truck: Truck,
6966
+ plane: Plane,
6967
+ "train-front": TrainFront,
6968
+ sailboat: Sailboat,
6969
+ dog: Dog,
6970
+ cat: Cat,
6971
+ bird: Bird,
6972
+ "paw-print": PawPrint,
6973
+ baby: Baby,
6974
+ user: User,
6975
+ users: Users,
6976
+ "person-standing": PersonStanding
6977
+ };
6978
+ /** Resolve a `display.icon` name to a lucide component, or `undefined` when the
6979
+ * name is not in the curated `DISPLAY_ICON_REGISTRY`. */
6980
+ function resolveDisplayIcon(name) {
6981
+ return Object.hasOwn(DISPLAY_ICON_REGISTRY, name) ? DISPLAY_ICON_REGISTRY[name] : void 0;
6982
+ }
6983
+ /**
6984
+ * EXHAUSTIVE device-type filter options — one entry per `DeviceType` member,
6985
+ * derived from `DEVICE_TYPE_META` so the set is always complete and a newly
6986
+ * added `DeviceType` automatically appears in every type filter (Devices page,
6987
+ * adoption modal, …) without touching any consumer.
6988
+ *
6989
+ * The previous per-consumer logic built options from the types PRESENT in the
6990
+ * list (or a hand-maintained subset), so recently-added types (vacuum, lawn
6991
+ * mower, valve, humidifier, water heater, weather, image, …) were silently
6992
+ * missing from the dropdown. This is the single source of truth instead.
6993
+ *
6994
+ * `id` is the raw `DeviceType` string (matches the filtering predicate, which
6995
+ * compares against `device.type`); `label` + `icon` come from the meta map.
6996
+ * Ordered by `DeviceType` declaration order for a stable, intentional layout.
6997
+ */
6998
+ var ALL_DEVICE_TYPE_FILTER_OPTIONS = Object.values(DeviceType).map((type) => {
6999
+ const meta = deviceTypeMetaOf(type);
7000
+ return {
7001
+ id: type,
7002
+ label: meta.label,
7003
+ icon: meta.icon
7004
+ };
7005
+ });
7006
+ function allDeviceTypeFilterOptions() {
7007
+ return ALL_DEVICE_TYPE_FILTER_OPTIONS;
7008
+ }
7009
+ //#endregion
7010
+ //#region src/composites/icon-picker.tsx
7011
+ /**
7012
+ * icon-picker — the ONE control for choosing an icon, wherever admin-ui asks.
7013
+ *
7014
+ * There were two: a device one over `DISPLAY_ICON_REGISTRY` and a room one
7015
+ * over `LOCATION_ICON_IDS`, identical apart from the vocabulary they walked.
7016
+ * That was tolerable while the device set was 56 glyphs in a flat grid. It is
7017
+ * not at 157: a picker that only lets the operator HUNT is a picker they stop
7018
+ * using, and the two copies were already drifting — only one of them had an
7019
+ * i18n'd label.
7020
+ *
7021
+ * So the vocabulary, the grouping and the search all come from
7022
+ * `@camstack/types`' `display-icon-vocabulary`, which is the same module the
7023
+ * viewer's sheet searches. What is left here is the web half: a popover, a
7024
+ * grid, and a text field.
7025
+ *
7026
+ * ## What it does NOT own
7027
+ *
7028
+ * - **The glyphs.** `resolveGlyph` is a prop, because this package's table is
7029
+ * `lucide-react` and the viewer's is `lucide-react-native`. A key this build
7030
+ * cannot draw is SKIPPED rather than rendered as a hole — an empty tile
7031
+ * reads as a rendering bug, not as a missing choice.
7032
+ * - **The words.** Every string is a prop. This package has no i18n (one file
7033
+ * in it imports react-i18next, and that is the exception), and a control
7034
+ * that reached for a translation would force it on every consumer.
7035
+ * - **The write.** `onPick` is called and that is all; whether it is a form
7036
+ * value or an immediate mutation is the caller's business, as it already was
7037
+ * in both pickers this replaces.
7038
+ *
7039
+ * ## The clear tile is never filtered away
7040
+ *
7041
+ * The "inherit" / "no icon" choice sits above the sections and ignores the
7042
+ * search. A query that hid it would strand the operator on a glyph they picked
7043
+ * by accident with no way back to the default — the one action a picker must
7044
+ * always offer.
7045
+ */
7046
+ function IconPicker({ value, onPick, resolveGlyph, fallbackGlyph, labels, only, extraWords, clearGlyph, labelFor, disabled = false }) {
7047
+ const [open, setOpen] = useState(false);
7048
+ const [query, setQuery] = useState("");
7049
+ const allowed = useMemo(() => only === void 0 ? null : new Set(only), [only]);
7050
+ const sections = useMemo(() => {
7051
+ const hits = searchDisplayIcons(query, extraWords);
7052
+ const byGroup = /* @__PURE__ */ new Map();
7053
+ for (const hit of hits) {
7054
+ const { key, group } = hit.entry;
7055
+ if (allowed !== null && !allowed.has(key)) continue;
7056
+ if (resolveGlyph(key) === void 0) continue;
7057
+ const bucket = byGroup.get(group);
7058
+ if (bucket === void 0) byGroup.set(group, [key]);
7059
+ else bucket.push(key);
7060
+ }
7061
+ return DISPLAY_ICON_GROUPS.flatMap((group) => {
7062
+ const keys = byGroup.get(group);
7063
+ return keys === void 0 || keys.length === 0 ? [] : [{
7064
+ group,
7065
+ keys
7066
+ }];
7067
+ });
7068
+ }, [
7069
+ query,
7070
+ extraWords,
7071
+ allowed,
7072
+ resolveGlyph
7073
+ ]);
7074
+ const Current = (value === null ? void 0 : resolveGlyph(value)) ?? fallbackGlyph;
7075
+ const choose = async (next) => {
7076
+ setOpen(false);
7077
+ setQuery("");
7078
+ await onPick(next);
7079
+ };
7080
+ const Clear = clearGlyph ?? fallbackGlyph;
7081
+ return /* @__PURE__ */ jsxs("div", {
7082
+ className: "relative flex shrink-0 items-center gap-2",
7083
+ children: [/* @__PURE__ */ jsx("button", {
7084
+ type: "button",
7085
+ disabled,
7086
+ onClick: () => setOpen((o) => !o),
7087
+ "aria-expanded": open,
7088
+ "aria-label": labels.trigger,
7089
+ title: labels.trigger,
7090
+ className: "rounded border border-border p-1 text-foreground-muted hover:bg-surface-hover disabled:opacity-50",
7091
+ children: /* @__PURE__ */ jsx(Current, { className: "h-4 w-4" })
7092
+ }), open && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
7093
+ type: "button",
7094
+ "aria-label": labels.close,
7095
+ onClick: () => setOpen(false),
7096
+ className: "fixed inset-0 z-10 cursor-default"
7097
+ }), /* @__PURE__ */ jsxs("div", {
7098
+ role: "group",
7099
+ "aria-label": labels.panel,
7100
+ 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",
7101
+ children: [
7102
+ /* @__PURE__ */ jsx("input", {
7103
+ type: "search",
7104
+ value: query,
7105
+ autoFocus: true,
7106
+ onChange: (e) => setQuery(e.target.value),
7107
+ placeholder: labels.searchPlaceholder,
7108
+ "aria-label": labels.searchPlaceholder,
7109
+ className: "mb-2 w-full rounded border border-border bg-surface-raised px-2 py-1 text-xs text-foreground placeholder:text-foreground-subtle"
7110
+ }),
7111
+ /* @__PURE__ */ jsxs("button", {
7112
+ type: "button",
7113
+ onClick: () => void choose(null),
7114
+ "aria-pressed": value === null,
7115
+ 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",
7116
+ children: [/* @__PURE__ */ jsx(Clear, { className: "h-3.5 w-3.5" }), labels.clear]
7117
+ }),
7118
+ sections.length === 0 ? /* @__PURE__ */ jsx("p", {
7119
+ className: "px-1.5 py-2 text-[11px] text-foreground-subtle",
7120
+ children: labels.noMatches
7121
+ }) : sections.map(({ group, keys }) => /* @__PURE__ */ jsxs("section", {
7122
+ className: "mb-2 last:mb-0",
7123
+ children: [/* @__PURE__ */ jsx("h4", {
7124
+ className: "px-1.5 pb-1 text-[10px] uppercase tracking-wide text-foreground-subtle",
7125
+ children: labels.groups[group]
7126
+ }), /* @__PURE__ */ jsx("div", {
7127
+ className: "grid grid-cols-7 gap-1",
7128
+ children: keys.map((key) => {
7129
+ const Glyph = resolveGlyph(key);
7130
+ if (Glyph === void 0) return null;
7131
+ const selected = value === key;
7132
+ return /* @__PURE__ */ jsx("button", {
7133
+ type: "button",
7134
+ onClick: () => void choose(key),
7135
+ "aria-pressed": selected,
7136
+ "aria-label": labelFor?.(key) ?? key,
7137
+ title: labelFor?.(key) ?? key,
7138
+ 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",
7139
+ children: /* @__PURE__ */ jsx(Glyph, { className: "h-4 w-4" })
7140
+ }, key);
7141
+ })
7142
+ })]
7143
+ }, group))
7144
+ ]
7145
+ })] })]
7146
+ });
7147
+ }
7148
+ //#endregion
7149
+ //#region src/composites/config-icon-field.tsx
7150
+ /**
7151
+ * The control behind a `type: 'icon'` settings field (D780).
7152
+ *
7153
+ * The shared `<IconPicker>` over the display-icon vocabulary, with the device
7154
+ * glyph table — the same control and the same keys the device and room
7155
+ * pickers use. An icon field always draws something, so clearing is "back to
7156
+ * the field's default", and a stored value the vocabulary does not know (a
7157
+ * free-text lucide name from before D780) is drawn as that default.
7158
+ */
7159
+ function labelsFor(label) {
7160
+ return {
7161
+ trigger: `Choose an icon for ${label}`,
7162
+ panel: `${label} icon`,
7163
+ close: "Close",
7164
+ searchPlaceholder: "Search icons",
7165
+ clear: "Default icon",
7166
+ noMatches: "No icon matches",
7167
+ groups: {
7168
+ device: "Devices",
7169
+ lighting: "Lighting",
7170
+ sensing: "Sensing",
7171
+ place: "Places",
7172
+ life: "Life"
7173
+ }
7174
+ };
7175
+ }
7176
+ function ConfigIconFieldControl({ label, value, defaultKey, disabled, onChange }) {
7177
+ const key = resolveDisplayIconKey(value, defaultKey);
7178
+ const DefaultGlyph = resolveDisplayIcon(defaultKey) ?? ShieldCheck;
7179
+ return /* @__PURE__ */ jsxs("div", {
7180
+ className: "flex items-center gap-2",
7181
+ children: [/* @__PURE__ */ jsx(IconPicker, {
7182
+ value: key === "" ? null : key,
7183
+ onPick: (next) => onChange(next ?? defaultKey),
7184
+ resolveGlyph: resolveDisplayIcon,
7185
+ fallbackGlyph: DefaultGlyph,
7186
+ labels: labelsFor(label),
7187
+ disabled
7188
+ }), /* @__PURE__ */ jsx("span", {
7189
+ className: "text-[11px] text-foreground-subtle font-mono",
7190
+ children: key
7191
+ })]
7192
+ });
7193
+ }
7194
+ //#endregion
6445
7195
  //#region src/generated/system-hooks.ts
6446
7196
  /**
6447
7197
  * Per-method React-Query hooks for every `scope: 'system'` capability.
@@ -6481,6 +7231,8 @@ var useAddonsIsWorkspaceAvailable = trpc.addons.isWorkspaceAvailable.useQuery;
6481
7231
  var useAddonsListWorkspacePackages = trpc.addons.listWorkspacePackages.useQuery;
6482
7232
  /** Generated alias around `trpc.addons.uninstallPackage.useMutation`. */
6483
7233
  var useAddonsUninstallPackage = trpc.addons.uninstallPackage.useMutation;
7234
+ /** Generated alias around `trpc.addons.listInstallations.useQuery`. */
7235
+ var useAddonsListInstallations = trpc.addons.listInstallations.useQuery;
6484
7236
  /** Generated alias around `trpc.addons.reloadPackages.useMutation`. */
6485
7237
  var useAddonsReloadPackages = trpc.addons.reloadPackages.useMutation;
6486
7238
  /** Generated alias around `trpc.addons.searchAvailable.useQuery`. */
@@ -7777,6 +8529,10 @@ var usePipelineAnalyticsCompleteRetrainTrack = trpc.pipelineAnalytics.completeRe
7777
8529
  var usePipelineAnalyticsRestageRetrainTrack = trpc.pipelineAnalytics.restageRetrainTrack.useMutation;
7778
8530
  /** Generated alias around `trpc.pipelineAnalytics.getRetrainExportUrl.useQuery`. */
7779
8531
  var usePipelineAnalyticsGetRetrainExportUrl = trpc.pipelineAnalytics.getRetrainExportUrl.useQuery;
8532
+ /** Generated alias around `trpc.pipelineAnalytics.setRetrainFrameComplete.useMutation`. */
8533
+ var usePipelineAnalyticsSetRetrainFrameComplete = trpc.pipelineAnalytics.setRetrainFrameComplete.useMutation;
8534
+ /** Generated alias around `trpc.pipelineAnalytics.writeRetrainArchive.useMutation`. */
8535
+ var usePipelineAnalyticsWriteRetrainArchive = trpc.pipelineAnalytics.writeRetrainArchive.useMutation;
7780
8536
  /** Generated alias around `trpc.pipelineAnalytics.getEventMedia.useQuery`. */
7781
8537
  var usePipelineAnalyticsGetEventMedia = trpc.pipelineAnalytics.getEventMedia.useQuery;
7782
8538
  /** Generated alias around `trpc.pipelineAnalytics.getTrackMedia.useQuery`. */
@@ -8565,6 +9321,14 @@ var useUserManagementOauthExchangeCode = trpc.userManagement.oauthExchangeCode.u
8565
9321
  var useUserManagementOauthRefresh = trpc.userManagement.oauthRefresh.useMutation;
8566
9322
  /** Generated alias around `trpc.userManagement.oauthVerifyAccessToken.useQuery`. */
8567
9323
  var useUserManagementOauthVerifyAccessToken = trpc.userManagement.oauthVerifyAccessToken.useQuery;
9324
+ /** Generated alias around `trpc.userManagement.listExternalIdentities.useQuery`. */
9325
+ var useUserManagementListExternalIdentities = trpc.userManagement.listExternalIdentities.useQuery;
9326
+ /** Generated alias around `trpc.userManagement.findUserByExternalIdentity.useQuery`. */
9327
+ var useUserManagementFindUserByExternalIdentity = trpc.userManagement.findUserByExternalIdentity.useQuery;
9328
+ /** Generated alias around `trpc.userManagement.linkExternalIdentity.useMutation`. */
9329
+ var useUserManagementLinkExternalIdentity = trpc.userManagement.linkExternalIdentity.useMutation;
9330
+ /** Generated alias around `trpc.userManagement.unlinkExternalIdentity.useMutation`. */
9331
+ var useUserManagementUnlinkExternalIdentity = trpc.userManagement.unlinkExternalIdentity.useMutation;
8568
9332
  /** Generated alias around `trpc.userManagement.listOauthSessions.useQuery`. */
8569
9333
  var useUserManagementListOauthSessions = trpc.userManagement.listOauthSessions.useQuery;
8570
9334
  /** Generated alias around `trpc.userManagement.revokeOauthSession.useMutation`. */
@@ -13957,7 +14721,7 @@ function DialogSurface({ state, onClose }) {
13957
14721
  setError(null);
13958
14722
  }
13959
14723
  }) : /* @__PURE__ */ jsx("p", {
13960
- className: "mt-2 text-xs text-foreground-subtle leading-relaxed",
14724
+ className: "mt-2 text-xs text-foreground-subtle leading-relaxed whitespace-pre-line",
13961
14725
  children: state.options.message
13962
14726
  });
13963
14727
  const footer = state.kind === "alert" ? /* @__PURE__ */ jsx("button", {
@@ -27140,6 +27904,23 @@ function ColorField({ field, value, onChange, disabled, translationFn }) {
27140
27904
  })]
27141
27905
  });
27142
27906
  }
27907
+ function IconField({ field, value, onChange, disabled, translationFn }) {
27908
+ const defaultKey = typeof field.default === "string" ? field.default : "";
27909
+ return /* @__PURE__ */ jsx(FieldWrapper, {
27910
+ label: field.label,
27911
+ description: field.description,
27912
+ required: field.required,
27913
+ span: field.span,
27914
+ translationFn,
27915
+ children: /* @__PURE__ */ jsx(ConfigIconFieldControl, {
27916
+ label: resolveLabel(field.label, translationFn) ?? field.label,
27917
+ value,
27918
+ defaultKey,
27919
+ disabled: disabled || field.disabled,
27920
+ onChange
27921
+ })
27922
+ });
27923
+ }
27143
27924
  function ProbeField({ field, value, onChange, disabled, translationFn, onTestField, onAction, externalProbe }) {
27144
27925
  const [localStatus, setLocalStatus] = useState("idle");
27145
27926
  const [localResult, setLocalResult] = useState(null);
@@ -27774,8 +28555,16 @@ function AddonActionButtonField({ field, values, disabled, onAction }) {
27774
28555
  const [loading, setLoading] = useState(false);
27775
28556
  const [status, setStatus] = useState(null);
27776
28557
  const confirm = useConfirm();
28558
+ const prompt = usePrompt();
27777
28559
  const deviceId = useDeviceId();
27778
28560
  const handleClick = async () => {
28561
+ const asked = field.prompt ? await prompt({
28562
+ title: field.prompt.title ?? field.label,
28563
+ ...field.prompt.message !== void 0 ? { message: field.prompt.message } : {},
28564
+ ...field.prompt.placeholder !== void 0 ? { placeholder: field.prompt.placeholder } : {},
28565
+ confirmLabel: field.buttonLabel
28566
+ }) : null;
28567
+ if (field.prompt && asked === null) return;
27779
28568
  if (field.confirmMessage) {
27780
28569
  if (!await confirm({
27781
28570
  title: field.label,
@@ -27786,6 +28575,7 @@ function AddonActionButtonField({ field, values, disabled, onAction }) {
27786
28575
  }
27787
28576
  if (!onAction) return;
27788
28577
  const params = resolveActionParams(field, values);
28578
+ if (field.prompt && asked !== null) params[field.prompt.param] = asked;
27789
28579
  if (field.includeDeviceId === true && deviceId !== null && deviceId !== void 0) params["deviceId"] = deviceId;
27790
28580
  setLoading(true);
27791
28581
  setStatus(null);
@@ -28246,6 +29036,13 @@ function FormField({ field, values, onChange, disabled, translationFn, onTestFie
28246
29036
  disabled,
28247
29037
  translationFn
28248
29038
  });
29039
+ case "icon": return /* @__PURE__ */ jsx(IconField, {
29040
+ field,
29041
+ value,
29042
+ onChange: handleChange,
29043
+ disabled,
29044
+ translationFn
29045
+ });
28249
29046
  case "node-select": return /* @__PURE__ */ jsx(NodeSelectField, {
28250
29047
  field,
28251
29048
  value,
@@ -49395,1248 +50192,683 @@ function SwitchInlineControl({ trpc, deviceId, features, optimistic }) {
49395
50192
  optimistic
49396
50193
  });
49397
50194
  }
49398
- function useLockCapGuard(trpc, deviceId) {
49399
- const { cap } = useDeviceCapability({
49400
- trpc,
49401
- deviceId,
49402
- cap: (d) => d.lockControl,
49403
- slice: (d) => d.state.lockControl
49404
- });
49405
- return cap !== void 0;
49406
- }
49407
- function LockInlineControl({ trpc, deviceId, features, optimistic }) {
49408
- if (!useLockCapGuard(trpc, deviceId)) return null;
49409
- return /* @__PURE__ */ jsx(LockPanel, {
49410
- trpc,
49411
- deviceId,
49412
- features,
49413
- layout: "compact",
49414
- optimistic
49415
- });
49416
- }
49417
- function LightInlineControl({ trpc, deviceId, features, optimistic }) {
49418
- if (!useSwitchCapGuard(trpc, deviceId)) return null;
49419
- return /* @__PURE__ */ jsxs("div", {
49420
- className: "inline-flex items-center gap-2",
49421
- children: [/* @__PURE__ */ jsx(SwitchPanel, {
49422
- trpc,
49423
- deviceId,
49424
- features,
49425
- layout: "compact",
49426
- optimistic
49427
- }), /* @__PURE__ */ jsx(BrightnessPanel, {
49428
- trpc,
49429
- deviceId,
49430
- features,
49431
- layout: "compact",
49432
- optimistic
49433
- })]
49434
- });
49435
- }
49436
- function useFanCapGuard(trpc, deviceId) {
49437
- const { cap } = useDeviceCapability({
49438
- trpc,
49439
- deviceId,
49440
- cap: (d) => d.fanControl,
49441
- slice: (d) => d.state.fanControl
49442
- });
49443
- return cap !== void 0;
49444
- }
49445
- function FanInlineControl({ trpc, deviceId, features, optimistic }) {
49446
- if (!useFanCapGuard(trpc, deviceId)) return null;
49447
- return /* @__PURE__ */ jsxs("div", {
49448
- className: "inline-flex items-center gap-2",
49449
- children: [/* @__PURE__ */ jsx(SwitchPanel, {
49450
- trpc,
49451
- deviceId,
49452
- features,
49453
- layout: "compact",
49454
- optimistic
49455
- }), /* @__PURE__ */ jsx(FanPanel, {
49456
- trpc,
49457
- deviceId,
49458
- features,
49459
- layout: "compact",
49460
- optimistic
49461
- })]
49462
- });
49463
- }
49464
- function useClimateCapGuard(trpc, deviceId) {
49465
- const { cap } = useDeviceCapability({
49466
- trpc,
49467
- deviceId,
49468
- cap: (d) => d.climateControl,
49469
- slice: (d) => d.state.climateControl
49470
- });
49471
- return cap !== void 0;
49472
- }
49473
- function ThermostatInlineControl({ trpc, deviceId, features, optimistic }) {
49474
- if (!useClimateCapGuard(trpc, deviceId)) return null;
49475
- return /* @__PURE__ */ jsx(ClimatePanel, {
49476
- trpc,
49477
- deviceId,
49478
- features,
49479
- layout: "compact",
49480
- optimistic
49481
- });
49482
- }
49483
- function AcInlineControl({ trpc, deviceId, features, optimistic }) {
49484
- if (!useClimateCapGuard(trpc, deviceId)) return null;
49485
- return /* @__PURE__ */ jsx(AcPanel, {
49486
- trpc,
49487
- deviceId,
49488
- features,
49489
- layout: "compact",
49490
- optimistic
49491
- });
49492
- }
49493
- function AcHeroCard({ trpc, deviceId, features, optimistic }) {
49494
- if (!useClimateCapGuard(trpc, deviceId)) return null;
49495
- return /* @__PURE__ */ jsx(AcPanel, {
49496
- trpc,
49497
- deviceId,
49498
- features,
49499
- layout: "full",
49500
- optimistic
49501
- });
49502
- }
49503
- function useMediaPlayerCapGuard(trpc, deviceId) {
49504
- const { cap } = useDeviceCapability({
49505
- trpc,
49506
- deviceId,
49507
- cap: (d) => d.mediaPlayer,
49508
- slice: (d) => d.state.mediaPlayer
49509
- });
49510
- return cap !== void 0;
49511
- }
49512
- function MediaPlayerInlineControl({ trpc, deviceId, features, optimistic }) {
49513
- if (!useMediaPlayerCapGuard(trpc, deviceId)) return null;
49514
- return /* @__PURE__ */ jsx(MediaPlayerPanel, {
49515
- trpc,
49516
- deviceId,
49517
- features,
49518
- layout: "compact",
49519
- optimistic
49520
- });
49521
- }
49522
- function useControlCapGuard(trpc, deviceId) {
49523
- const { cap } = useDeviceCapability({
49524
- trpc,
49525
- deviceId,
49526
- cap: (d) => d.control,
49527
- slice: (d) => d.state.control
49528
- });
49529
- return cap !== void 0;
49530
- }
49531
- function ControlInlineControl({ trpc, deviceId, features, optimistic }) {
49532
- if (!useControlCapGuard(trpc, deviceId)) return null;
49533
- return /* @__PURE__ */ jsx(ControlPanel, {
49534
- trpc,
49535
- deviceId,
49536
- features,
49537
- layout: "compact",
49538
- optimistic
49539
- });
49540
- }
49541
- function ControlHeroCard({ trpc, deviceId, features, optimistic }) {
49542
- if (!useControlCapGuard(trpc, deviceId)) return null;
49543
- return /* @__PURE__ */ jsx(HeroShell, { children: /* @__PURE__ */ jsx(ControlPanel, {
49544
- trpc,
49545
- deviceId,
49546
- features,
49547
- layout: "full",
49548
- optimistic
49549
- }) });
49550
- }
49551
- //#endregion
49552
- //#region src/composites/device-controls/control-registry.tsx
49553
- /**
49554
- * Presentation binding: the shared `DeviceControlKind` (decided in
49555
- * `@camstack/types` `resolveDeviceControlKind`) → this platform's web
49556
- * components. Exhaustive over `DeviceControlKind` — omitting a kind fails the
49557
- * build here. The type→kind DECISION is single-sourced in `@camstack/types`;
49558
- * this map only binds a kind to its web widgets.
49559
- */
49560
- var CONTROL_KIND_COMPONENTS = {
49561
- cover: {
49562
- InlineControl: CoverInlineControl,
49563
- HeroCard: CoverHeroCard
49564
- },
49565
- valve: {
49566
- InlineControl: ValveInlineControl,
49567
- HeroCard: ValveHeroCard
49568
- },
49569
- humidifier: {
49570
- InlineControl: HumidifierInlineControl,
49571
- HeroCard: HumidifierHeroCard
49572
- },
49573
- "water-heater": {
49574
- InlineControl: WaterHeaterInlineControl,
49575
- HeroCard: WaterHeaterHeroCard
49576
- },
49577
- switch: {
49578
- InlineControl: SwitchInlineControl,
49579
- HeroCard: SwitchHeroCard
49580
- },
49581
- light: {
49582
- InlineControl: LightInlineControl,
49583
- HeroCard: LightHeroCard
49584
- },
49585
- fan: {
49586
- InlineControl: FanInlineControl,
49587
- HeroCard: FanHeroCard
49588
- },
49589
- sensor: {
49590
- InlineControl: SensorInlineControl,
49591
- HeroCard: SensorHeroCard
49592
- },
49593
- thermostat: {
49594
- InlineControl: ThermostatInlineControl,
49595
- HeroCard: ThermostatHeroCard
49596
- },
49597
- climate: {
49598
- InlineControl: AcInlineControl,
49599
- HeroCard: AcHeroCard
49600
- },
49601
- button: {
49602
- InlineControl: ButtonControl,
49603
- HeroCard: ButtonHeroCard
49604
- },
49605
- update: {
49606
- InlineControl: UpdateInlineControl,
49607
- HeroCard: UpdateHeroCard
49608
- },
49609
- lock: {
49610
- InlineControl: LockInlineControl,
49611
- HeroCard: LockHeroCard
49612
- },
49613
- "media-player": {
49614
- InlineControl: MediaPlayerInlineControl,
49615
- HeroCard: MediaPlayerHeroCard
49616
- },
49617
- alarm: {
49618
- InlineControl: AlarmInlineControl,
49619
- HeroCard: AlarmHeroCard
49620
- },
49621
- control: {
49622
- InlineControl: ControlInlineControl,
49623
- HeroCard: ControlHeroCard
49624
- },
49625
- weather: {
49626
- InlineControl: WeatherInlineControl,
49627
- HeroCard: WeatherHeroCard
49628
- },
49629
- vacuum: {
49630
- InlineControl: VacuumInlineControl,
49631
- HeroCard: VacuumHeroCard
49632
- },
49633
- "lawn-mower": {
49634
- InlineControl: LawnMowerInlineControl,
49635
- HeroCard: LawnMowerHeroCard
49636
- },
49637
- image: {
49638
- InlineControl: ImageInlineControl,
49639
- HeroCard: ImageHeroCard
49640
- },
49641
- "pet-feeder": {
49642
- InlineControl: PetFeederInlineControl,
49643
- HeroCard: PetFeederHeroCard
49644
- },
49645
- script: {
49646
- InlineControl: ScriptInlineControl,
49647
- HeroCard: ScriptHeroCard
49648
- },
49649
- automation: {
49650
- InlineControl: AutomationInlineControl,
49651
- HeroCard: AutomationHeroCard
49652
- },
49653
- dummy: {
49654
- InlineControl: DummyInline,
49655
- HeroCard: DummyHeroCard
49656
- }
49657
- };
49658
- /**
49659
- * Exhaustive record over DeviceType, DERIVED from the shared decision
49660
- * (`DEVICE_TYPE_CONTROL_KIND`) composed with the web `CONTROL_KIND_COMPONENTS`
49661
- * binding — so the type→control mapping can never diverge from the single
49662
- * source in `@camstack/types`. Preserved as a public export for consumers/tests
49663
- * that index it by `DeviceType`.
49664
- *
49665
- * The `Object.fromEntries` result is a `{ [k: string]: DeviceTypeControl }`;
49666
- * `Object.values(DeviceType)` (a string enum) yields exactly the enum's members,
49667
- * so the record is fully populated — the assertion narrows that documented
49668
- * enum-record projection boundary.
49669
- */
49670
- var DEVICE_TYPE_CONTROL = Object.fromEntries(Object.values(DeviceType).map((type) => [type, CONTROL_KIND_COMPONENTS[DEVICE_TYPE_CONTROL_KIND[type]]]));
49671
- /**
49672
- * Per-type FILL flag.
49673
- *
49674
- * true — range / choice / button controls (cover ▲■▼ triad, thermostat
49675
- * setpoint stepper, media/control/button action buttons, alarm
49676
- * segmented control). The child STRETCHES to the full column width.
49677
- * false — readouts, tap-toggles, icon controls (lock), and dummy/placeholder
49678
- * types. The child keeps its NATURAL width; where it sits in the
49679
- * column (flush right vs centered) is decided by the caller via a
49680
- * `ControlPlacement` — see `resolveControlAlign`.
49681
- *
49682
- * Dummy types (Camera, Hub, Generic, Weather, Vacuum, Container, and placeholder
49683
- * types Notifier/Script/Automation whose InlineControl renders "—") are `false` —
49684
- * the dash placeholder must not be stretched to the full column width. (AlarmPanel
49685
- * has a real segmented inline control and is `true`.) When a later task gives a
49686
- * remaining placeholder type a real stretchy inline control, flip its flag to true.
49687
- *
49688
- * Exhaustive over DeviceType — a missing member is a TypeScript build error.
49689
- */
49690
- var CONTROL_FILLS = {
49691
- [DeviceType.Cover]: true,
49692
- [DeviceType.Valve]: true,
49693
- [DeviceType.Thermostat]: true,
49694
- [DeviceType.Climate]: true,
49695
- [DeviceType.Control]: true,
49696
- [DeviceType.Button]: true,
49697
- [DeviceType.MediaPlayer]: true,
49698
- [DeviceType.AlarmPanel]: true,
49699
- [DeviceType.Lock]: false,
49700
- [DeviceType.Vacuum]: false,
49701
- [DeviceType.LawnMower]: false,
49702
- [DeviceType.Humidifier]: false,
49703
- [DeviceType.Switch]: false,
49704
- [DeviceType.Siren]: false,
49705
- [DeviceType.Light]: false,
49706
- [DeviceType.Fan]: false,
49707
- [DeviceType.WaterHeater]: false,
49708
- [DeviceType.Sensor]: false,
49709
- [DeviceType.Presence]: false,
49710
- [DeviceType.EventEmitter]: false,
49711
- [DeviceType.Notifier]: false,
49712
- [DeviceType.Script]: false,
49713
- [DeviceType.Automation]: false,
49714
- [DeviceType.Camera]: false,
49715
- [DeviceType.Hub]: false,
49716
- [DeviceType.Update]: false,
49717
- [DeviceType.Generic]: false,
49718
- [DeviceType.Weather]: false,
49719
- [DeviceType.Container]: false,
49720
- [DeviceType.Image]: false,
49721
- [DeviceType.PetFeeder]: false
49722
- };
49723
- var DEVICE_TYPE_VALUES$1 = new Set(Object.values(DeviceType));
49724
- /**
49725
- * Runtime-string-safe lookup: a device row's `type` crosses the wire as a plain
49726
- * string. The type→control-kind DECISION is single-sourced in `@camstack/types`
49727
- * (`resolveDeviceControlKind`, null for an unrecognised type); this maps the
49728
- * resolved kind onto the web components.
49729
- */
49730
- function resolveDeviceControl(type) {
49731
- const kind = resolveDeviceControlKind(type);
49732
- return kind ? CONTROL_KIND_COMPONENTS[kind] : null;
49733
- }
49734
- /**
49735
- * Runtime-string-safe alignment lookup for the fixed-width control column.
49736
- *
49737
- * A device's `type` crosses the wire as a plain string;
49738
- * `DEVICE_TYPE_VALUES.has(type)` narrows it to `DeviceType` before indexing
49739
- * `CONTROL_FILLS`, making the cast sound. The `'table'` placement is
49740
- * content-width for EVERY type (returns `FIT`), so a wide control never
49741
- * overflows a fixed box — the FILL flag is irrelevant there. For the fixed-box
49742
- * placements a FILL type always stretches (`FILL`) and a natural-width type is
49743
- * placed by the caller's `placement` — `'center'` → `CENTER`, `'right'` →
49744
- * `RIGHT` (card / minimal view). An unrecognised type falls back to
49745
- * natural-width placement.
49746
- */
49747
- function resolveControlAlign(type, placement) {
49748
- if (placement === "table") return "fit";
49749
- return DEVICE_TYPE_VALUES$1.has(type) && CONTROL_FILLS[type] ? FILL : placement === "center" ? CENTER : RIGHT;
49750
- }
49751
- //#endregion
49752
- //#region src/lib/format-last-seen.ts
49753
- /**
49754
- * Relative "last seen" formatter for the offline affordance.
49755
- *
49756
- * Renders a short relative-time label from a millisecond epoch:
49757
- * "just now", "5m ago", "3h ago", "2d ago". Returns `null` for missing
49758
- * inputs, or inputs below {@link MIN_PLAUSIBLE_TIMESTAMP_MS} (a
49759
- * placeholder or a seeded "known value, unknown change time" stamp), so
49760
- * callers can render nothing rather than a misleading "—", "NaN ago", or
49761
- * (for a seeded `1`) "20000 days ago".
49762
- *
49763
- * Future timestamps (clock skew between the device and the browser)
49764
- * collapse to "just now" instead of a negative duration.
49765
- */
49766
- var SECOND_MS = 1e3;
49767
- var MINUTE_MS = 60 * SECOND_MS;
49768
- var HOUR_MS = 60 * MINUTE_MS;
49769
- var DAY_MS = 24 * HOUR_MS;
49770
- var JUST_NOW_MS = 30 * SECOND_MS;
49771
- /**
49772
- * The earliest timestamp a real "last seen" could plausibly carry. Below
49773
- * this, a value is a placeholder or a seeded "known value, unknown change
49774
- * time" stamp (e.g. Homematic's `HM_SEEDED_CHANGED_AT = 1`) — never a real
49775
- * instant. Year 2000 predates every device this renders.
49776
- */
49777
- var MIN_PLAUSIBLE_TIMESTAMP_MS = Date.UTC(2e3, 0, 1);
49778
- function formatLastSeen(timestampMs) {
49779
- if (timestampMs === null || timestampMs === void 0 || timestampMs < MIN_PLAUSIBLE_TIMESTAMP_MS) return null;
49780
- const delta = Date.now() - timestampMs;
49781
- if (delta < JUST_NOW_MS) return "just now";
49782
- if (delta < HOUR_MS) return `${String(Math.floor(delta / MINUTE_MS))}m ago`;
49783
- if (delta < DAY_MS) return `${String(Math.floor(delta / HOUR_MS))}h ago`;
49784
- return `${String(Math.floor(delta / DAY_MS))}d ago`;
49785
- }
49786
- //#endregion
49787
- //#region src/composites/device-controls/offline-badge.tsx
49788
- function OfflineBadge({ lastChangedAt, className }) {
49789
- const lastSeen = formatLastSeen(lastChangedAt);
49790
- return /* @__PURE__ */ jsxs("span", {
49791
- title: lastSeen === null ? "Unavailable" : `Unavailable · last seen ${lastSeen}`,
49792
- className: cn("inline-flex items-center gap-1 rounded-full px-2 py-0.5", "bg-surface-hover text-foreground-subtle text-[10px] font-medium", "border border-border", className),
49793
- children: [
49794
- /* @__PURE__ */ jsx(WifiOff, {
49795
- className: "h-3 w-3 flex-shrink-0",
49796
- "aria-hidden": "true"
49797
- }),
49798
- /* @__PURE__ */ jsx("span", { children: "Unavailable" }),
49799
- lastSeen !== null ? /* @__PURE__ */ jsx("span", {
49800
- className: "text-foreground-subtle/70",
49801
- children: `· last seen ${lastSeen}`
49802
- }) : null
49803
- ]
49804
- });
49805
- }
49806
- //#endregion
49807
- //#region src/composites/device-controls/primary-child.ts
49808
- /**
49809
- * Which child a container is rendered AS — this surface's name for the shared
49810
- * rule.
49811
- *
49812
- * The list and the resolution used to live here, in a COPY that carried a
49813
- * comment asking the Home Assistant adoption mapping and the viewer's panel to
49814
- * stay in sync with it. Three lists and three comments is not one rule, it is
49815
- * three chances to drift. Both now come from `@camstack/types`, which all of
49816
- * them already depend on; what remains here is the adapter for this module's
49817
- * historical `ChildRef` shape.
49818
- */
49819
- /** The shared precedence, under this module's historical name. */
49820
- var PRIORITY = CONTAINER_CHILD_PRIORITY;
49821
- /**
49822
- * Resolve a container's primary child: the operator's pick when it still
49823
- * matches a live child, else the highest-priority type.
49824
- *
49825
- * `entityId` here is `sourceInfo?.id ?? stableId` (see `containerChildToRef`).
49826
- * The shared resolver matches its canonical `stableId` key first and accepts
49827
- * that legacy value too, so a pick stored under either keeps resolving.
49828
- */
49829
- function resolvePrimaryChild(children, overrideEntityId, containerName) {
49830
- const picked = resolveContainerPrimaryChild(children.map((c) => ({
49831
- id: c.id,
49832
- stableId: c.entityId,
49833
- type: c.type,
49834
- ...c.role !== void 0 ? { role: c.role } : {},
49835
- ...c.name !== void 0 ? { name: c.name } : {}
49836
- })), overrideEntityId, containerName);
49837
- return picked === null ? null : children.find((c) => c.id === picked.id) ?? null;
49838
- }
49839
- //#endregion
49840
- //#region src/composites/device-controls/container-primary.ts
49841
- /**
49842
- * Re-sync-stable identity of a child. Prefers the upstream-system dispatch key
49843
- * (`sourceInfo.id` — e.g. HA `entity_id`); falls back to `stableId` for
49844
- * providers that never populated SourceInfo. Both survive a re-sync that may
49845
- * reallocate the numeric `id`.
49846
- */
49847
- function childEntityId(child) {
49848
- return child.sourceInfo?.id ?? child.stableId;
49849
- }
49850
- /** Project a raw child row onto the pure resolver's {@link ChildRef} shape. */
49851
- function containerChildToRef(child) {
49852
- return {
49853
- id: child.id,
49854
- entityId: childEntityId(child),
49855
- type: child.type,
49856
- ...child.role !== void 0 && child.role !== null ? { role: child.role } : {},
49857
- ...child.name !== void 0 ? { name: child.name } : {}
49858
- };
49859
- }
49860
- /**
49861
- * Resolve the entityId override from the container's persisted `linkDeviceId`.
49862
- * Returns the linked child's stable entityId, or `undefined` when there is no
49863
- * link or the link is stale (points to a numeric id no longer present) — in
49864
- * which case the resolver falls back to the priority default.
49865
- */
49866
- function overrideEntityIdFromLink(children, linkDeviceId) {
49867
- if (linkDeviceId === null || linkDeviceId === void 0) return void 0;
49868
- const linked = children.find((c) => c.id === linkDeviceId);
49869
- return linked === void 0 ? void 0 : childEntityId(linked);
49870
- }
49871
- /**
49872
- * Full container → primary-child resolution: project children to refs, resolve
49873
- * the override entityId, and delegate to the pure resolver. Returns `null` for a
49874
- * container with no children (caller degrades gracefully).
49875
- *
49876
- * Override precedence:
49877
- * 1. `primaryChildEntityId` — the DURABLE override (re-sync/rename-stable),
49878
- * passed straight to the resolver which matches on `entityId`. Wins when a
49879
- * non-empty string is supplied.
49880
- * 2. `linkDeviceId` — LEGACY numeric override, re-derived to an entityId from
49881
- * the live child set. Consulted only when there is no durable override.
49882
- *
49883
- * When neither resolves to a live child, the resolver falls back to the
49884
- * priority default.
49885
- */
49886
- function resolveContainerPrimary(children, linkDeviceId, primaryChildEntityId) {
49887
- return resolvePrimaryChild(children.map(containerChildToRef), primaryChildEntityId !== null && primaryChildEntityId !== void 0 && primaryChildEntityId !== "" ? primaryChildEntityId : overrideEntityIdFromLink(children, linkDeviceId));
49888
- }
49889
- //#endregion
49890
- //#region src/composites/device-controls/container-primary-hero.tsx
49891
- function ContainerPrimaryHero({ trpc, children, linkDeviceId, primaryChildEntityId }) {
49892
- const primary = resolveContainerPrimary(children, linkDeviceId, primaryChildEntityId);
49893
- const primaryChild = primary === null ? void 0 : children.find((c) => c.id === primary.id);
49894
- if (primaryChild === void 0) return /* @__PURE__ */ jsx("div", {
49895
- className: "flex h-full w-full items-center justify-center p-4 text-[11px] italic text-foreground-subtle",
49896
- children: "No child entities to display."
50195
+ function useLockCapGuard(trpc, deviceId) {
50196
+ const { cap } = useDeviceCapability({
50197
+ trpc,
50198
+ deviceId,
50199
+ cap: (d) => d.lockControl,
50200
+ slice: (d) => d.state.lockControl
49897
50201
  });
49898
- return /* @__PURE__ */ jsx("div", {
49899
- className: "flex h-full w-full flex-col items-stretch gap-3 p-3 sm:p-4",
49900
- children: /* @__PURE__ */ jsx(resolveDeviceControl(primaryChild.type)?.HeroCard ?? DummyHeroCard, {
50202
+ return cap !== void 0;
50203
+ }
50204
+ function LockInlineControl({ trpc, deviceId, features, optimistic }) {
50205
+ if (!useLockCapGuard(trpc, deviceId)) return null;
50206
+ return /* @__PURE__ */ jsx(LockPanel, {
50207
+ trpc,
50208
+ deviceId,
50209
+ features,
50210
+ layout: "compact",
50211
+ optimistic
50212
+ });
50213
+ }
50214
+ function LightInlineControl({ trpc, deviceId, features, optimistic }) {
50215
+ if (!useSwitchCapGuard(trpc, deviceId)) return null;
50216
+ return /* @__PURE__ */ jsxs("div", {
50217
+ className: "inline-flex items-center gap-2",
50218
+ children: [/* @__PURE__ */ jsx(SwitchPanel, {
49901
50219
  trpc,
49902
- deviceId: primaryChild.id,
49903
- features: primaryChild.features
49904
- })
50220
+ deviceId,
50221
+ features,
50222
+ layout: "compact",
50223
+ optimistic
50224
+ }), /* @__PURE__ */ jsx(BrightnessPanel, {
50225
+ trpc,
50226
+ deviceId,
50227
+ features,
50228
+ layout: "compact",
50229
+ optimistic
50230
+ })]
49905
50231
  });
49906
50232
  }
49907
- //#endregion
49908
- //#region src/composites/device-controls/primary-child-picker.tsx
49909
- var BASE_SELECT_CLASS = "rounded-md border border-border bg-surface px-1.5 py-0.5 text-[11px] text-foreground";
49910
- function PrimaryChildPicker({ childrenList, selectedId, onSetPrimary, disabled, className }) {
49911
- return /* @__PURE__ */ jsx("select", {
49912
- value: selectedId,
49913
- disabled,
49914
- onChange: (e) => {
49915
- const nextId = Number(e.target.value);
49916
- if (!Number.isFinite(nextId) || nextId === selectedId) return;
49917
- const picked = childrenList.find((c) => c.id === nextId);
49918
- if (picked !== void 0) onSetPrimary(picked.stableId);
49919
- },
49920
- className: className === void 0 ? BASE_SELECT_CLASS : `${BASE_SELECT_CLASS} ${className}`,
49921
- children: childrenList.map((c) => /* @__PURE__ */ jsxs("option", {
49922
- value: c.id,
49923
- children: [
49924
- c.name,
49925
- " (",
49926
- c.type,
49927
- ")"
49928
- ]
49929
- }, c.id))
50233
+ function useFanCapGuard(trpc, deviceId) {
50234
+ const { cap } = useDeviceCapability({
50235
+ trpc,
50236
+ deviceId,
50237
+ cap: (d) => d.fanControl,
50238
+ slice: (d) => d.state.fanControl
49930
50239
  });
50240
+ return cap !== void 0;
49931
50241
  }
49932
- //#endregion
49933
- //#region src/composites/device-list/batch-toolbar.tsx
49934
- function DeviceBatchToolbar({ selectedIds, onClear, remove, disable, enable }) {
49935
- const [pendingDelete, setPendingDelete] = useState(false);
49936
- if (selectedIds.size === 0) return null;
49937
- const ids = [...selectedIds];
49938
- const count = ids.length;
49939
- const handleDisable = () => {
49940
- for (const id of ids) disable({ deviceId: id });
49941
- onClear();
49942
- };
49943
- const handleEnable = () => {
49944
- for (const id of ids) enable({ deviceId: id });
49945
- onClear();
49946
- };
49947
- const handleDeleteFirst = () => {
49948
- setPendingDelete(true);
49949
- };
49950
- const handleDeleteConfirm = () => {
49951
- for (const id of ids) remove({ deviceId: id });
49952
- setPendingDelete(false);
49953
- onClear();
49954
- };
49955
- const handleDeleteCancel = () => {
49956
- setPendingDelete(false);
49957
- };
49958
- const handleClear = () => {
49959
- setPendingDelete(false);
49960
- onClear();
49961
- };
50242
+ function FanInlineControl({ trpc, deviceId, features, optimistic }) {
50243
+ if (!useFanCapGuard(trpc, deviceId)) return null;
49962
50244
  return /* @__PURE__ */ jsxs("div", {
49963
- className: "flex items-center gap-2 px-3 py-2 rounded-lg border border-border bg-surface-hover",
49964
- children: [
49965
- /* @__PURE__ */ jsxs("span", {
49966
- className: "text-xs font-medium text-foreground-subtle shrink-0",
49967
- children: [count, " selected"]
49968
- }),
49969
- /* @__PURE__ */ jsx("div", {
49970
- className: "h-3.5 w-px bg-border shrink-0",
49971
- "aria-hidden": "true"
49972
- }),
49973
- /* @__PURE__ */ jsxs("div", {
49974
- className: "flex items-center gap-1.5 flex-wrap",
49975
- children: [
49976
- /* @__PURE__ */ jsx("button", {
49977
- type: "button",
49978
- onClick: handleDisable,
49979
- className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
49980
- children: "Disable"
49981
- }),
49982
- /* @__PURE__ */ jsx("button", {
49983
- type: "button",
49984
- onClick: handleEnable,
49985
- className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
49986
- children: "Enable"
49987
- }),
49988
- pendingDelete ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("button", {
49989
- type: "button",
49990
- onClick: handleDeleteConfirm,
49991
- className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-red-500/50 bg-red-500/10 text-red-400 hover:bg-red-500/20"),
49992
- children: [
49993
- "Confirm delete ",
49994
- count,
49995
- "?"
49996
- ]
49997
- }), /* @__PURE__ */ jsx("button", {
49998
- type: "button",
49999
- onClick: handleDeleteCancel,
50000
- className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
50001
- children: "Cancel"
50002
- })] }) : /* @__PURE__ */ jsx("button", {
50003
- type: "button",
50004
- onClick: handleDeleteFirst,
50005
- className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-red-500/40 bg-red-500/10 text-red-400 hover:bg-red-500/20"),
50006
- children: "Delete"
50007
- }),
50008
- /* @__PURE__ */ jsx("button", {
50009
- type: "button",
50010
- onClick: handleClear,
50011
- className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
50012
- children: "Clear"
50013
- })
50014
- ]
50015
- })
50016
- ]
50245
+ className: "inline-flex items-center gap-2",
50246
+ children: [/* @__PURE__ */ jsx(SwitchPanel, {
50247
+ trpc,
50248
+ deviceId,
50249
+ features,
50250
+ layout: "compact",
50251
+ optimistic
50252
+ }), /* @__PURE__ */ jsx(FanPanel, {
50253
+ trpc,
50254
+ deviceId,
50255
+ features,
50256
+ layout: "compact",
50257
+ optimistic
50258
+ })]
50017
50259
  });
50018
50260
  }
50019
- //#endregion
50020
- //#region src/composites/device-list/batch-actions-bar.tsx
50021
- /**
50022
- * <DeviceBatchActionsBar> — responsive wrapper around <DeviceBatchToolbar>.
50023
- *
50024
- * Surfaces the available bulk actions once devices are selected:
50025
- * - L2+ (`sm` and up): the toolbar renders inline as a row of buttons.
50026
- * - L1 (`< sm`): a compact "Actions · N" trigger opens a popover that
50027
- * hosts the SAME <DeviceBatchToolbar>, so the action logic (inline
50028
- * delete-confirm, clear) is reused verbatim — never forked.
50029
- *
50030
- * Renders nothing while the selection is empty (delegated to the toolbar).
50031
- */
50032
- function DeviceBatchActionsBar(props) {
50033
- const [open, setOpen] = useState(false);
50034
- const rootRef = useRef(null);
50035
- const count = props.selectedIds.size;
50036
- useEffect(() => {
50037
- if (!open) return;
50038
- const onOutside = (e) => {
50039
- const target = e.target instanceof Node ? e.target : null;
50040
- if (target && rootRef.current && !rootRef.current.contains(target)) setOpen(false);
50041
- };
50042
- const onKey = (e) => {
50043
- if (e.key === "Escape") setOpen(false);
50044
- };
50045
- document.addEventListener("mousedown", onOutside);
50046
- document.addEventListener("touchstart", onOutside);
50047
- document.addEventListener("keydown", onKey);
50048
- return () => {
50049
- document.removeEventListener("mousedown", onOutside);
50050
- document.removeEventListener("touchstart", onOutside);
50051
- document.removeEventListener("keydown", onKey);
50052
- };
50053
- }, [open]);
50054
- if (count === 0) return null;
50055
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
50056
- className: "hidden sm:block",
50057
- children: /* @__PURE__ */ jsx(DeviceBatchToolbar, { ...props })
50058
- }), /* @__PURE__ */ jsxs("div", {
50059
- ref: rootRef,
50060
- "data-testid": "batch-actions-compact",
50061
- className: "relative sm:hidden",
50062
- children: [/* @__PURE__ */ jsxs("button", {
50063
- type: "button",
50064
- onClick: () => setOpen((v) => !v),
50065
- "aria-haspopup": "menu",
50066
- "aria-expanded": open,
50067
- className: "inline-flex items-center gap-1.5 h-7 px-2.5 rounded-full border border-primary/40 bg-primary/15 text-[10.5px] font-medium text-primary",
50068
- children: [/* @__PURE__ */ jsxs("span", { children: ["Actions · ", String(count)] }), /* @__PURE__ */ jsx(ChevronDown, { className: `h-3 w-3 transition-transform ${open ? "rotate-180" : ""}` })]
50069
- }), open && /* @__PURE__ */ jsx("div", {
50070
- role: "menu",
50071
- className: "absolute left-0 top-full mt-1 z-30 rounded-lg border border-border bg-surface shadow-md",
50072
- children: /* @__PURE__ */ jsx(DeviceBatchToolbar, { ...props })
50073
- })]
50074
- })] });
50261
+ function useClimateCapGuard(trpc, deviceId) {
50262
+ const { cap } = useDeviceCapability({
50263
+ trpc,
50264
+ deviceId,
50265
+ cap: (d) => d.climateControl,
50266
+ slice: (d) => d.state.climateControl
50267
+ });
50268
+ return cap !== void 0;
50075
50269
  }
50076
- //#endregion
50077
- //#region src/composites/device-meta.ts
50078
- var DEVICE_TYPE_META = {
50079
- [DeviceType.Camera]: {
50080
- icon: Camera,
50081
- label: "Camera"
50082
- },
50083
- [DeviceType.Hub]: {
50084
- icon: Network,
50085
- label: "Hub"
50086
- },
50087
- [DeviceType.Light]: {
50088
- icon: Lightbulb,
50089
- label: "Light"
50090
- },
50091
- [DeviceType.Siren]: {
50092
- icon: Siren,
50093
- label: "Siren"
50094
- },
50095
- [DeviceType.Switch]: {
50096
- icon: ToggleLeft,
50097
- label: "Switch"
50098
- },
50099
- [DeviceType.Sensor]: {
50100
- icon: Activity,
50101
- label: "Sensor"
50102
- },
50103
- [DeviceType.Thermostat]: {
50104
- icon: Thermometer,
50105
- label: "Thermostat"
50106
- },
50107
- [DeviceType.Climate]: {
50108
- icon: AirVent,
50109
- label: "Air conditioner"
50110
- },
50111
- [DeviceType.Button]: {
50112
- icon: CircleDot,
50113
- label: "Button"
50114
- },
50115
- [DeviceType.EventEmitter]: {
50116
- icon: Zap,
50117
- label: "Event Emitter"
50118
- },
50119
- [DeviceType.Update]: {
50120
- icon: RefreshCw,
50121
- label: "Update"
50122
- },
50123
- [DeviceType.Generic]: {
50124
- icon: Box,
50125
- label: "Generic"
50126
- },
50127
- [DeviceType.Notifier]: {
50128
- icon: Bell,
50129
- label: "Notifier"
50130
- },
50131
- [DeviceType.Script]: {
50132
- icon: ScrollText,
50133
- label: "Script"
50134
- },
50135
- [DeviceType.Automation]: {
50136
- icon: Workflow,
50137
- label: "Automation"
50138
- },
50139
- [DeviceType.Lock]: {
50140
- icon: Lock,
50141
- label: "Lock"
50142
- },
50143
- [DeviceType.Cover]: {
50144
- icon: Blinds,
50145
- label: "Cover"
50146
- },
50147
- [DeviceType.Valve]: {
50148
- icon: Pipette,
50149
- label: "Valve"
50150
- },
50151
- [DeviceType.Humidifier]: {
50152
- icon: Waves,
50153
- label: "Humidifier"
50154
- },
50155
- [DeviceType.WaterHeater]: {
50156
- icon: Bath,
50157
- label: "Water heater"
50158
- },
50159
- [DeviceType.Fan]: {
50160
- icon: Fan,
50161
- label: "Fan"
50162
- },
50163
- [DeviceType.MediaPlayer]: {
50164
- icon: MonitorPlay,
50165
- label: "Media player"
50166
- },
50167
- [DeviceType.AlarmPanel]: {
50168
- icon: ShieldAlert,
50169
- label: "Alarm panel"
50170
- },
50171
- [DeviceType.Control]: {
50172
- icon: SlidersHorizontal,
50173
- label: "Control"
50174
- },
50175
- [DeviceType.Presence]: {
50176
- icon: MapPin,
50177
- label: "Presence"
50178
- },
50179
- [DeviceType.Weather]: {
50180
- icon: CloudSun,
50181
- label: "Weather"
50182
- },
50183
- [DeviceType.Vacuum]: {
50184
- icon: Bot,
50185
- label: "Vacuum"
50186
- },
50187
- [DeviceType.LawnMower]: {
50188
- icon: Tractor,
50189
- label: "Lawn mower"
50190
- },
50191
- [DeviceType.Container]: {
50192
- icon: Box,
50193
- label: "Container"
50194
- },
50195
- [DeviceType.Image]: {
50196
- icon: Image,
50197
- label: "Image"
50198
- },
50199
- [DeviceType.PetFeeder]: {
50200
- icon: Bone,
50201
- label: "Pet feeder"
50202
- }
50203
- };
50204
- var DEVICE_ROLE_META = {
50205
- [DeviceRole.Siren]: {
50206
- icon: Siren,
50207
- label: "Siren"
50208
- },
50209
- [DeviceRole.Floodlight]: {
50210
- icon: Lightbulb,
50211
- label: "Floodlight"
50212
- },
50213
- [DeviceRole.Spotlight]: {
50214
- icon: Flashlight,
50215
- label: "Spotlight"
50216
- },
50217
- [DeviceRole.PirSensor]: {
50218
- icon: Radar,
50219
- label: "PIR sensor"
50220
- },
50221
- [DeviceRole.Chime]: {
50222
- icon: Bell,
50223
- label: "Chime"
50224
- },
50225
- [DeviceRole.Autotrack]: {
50226
- icon: Crosshair,
50227
- label: "Auto-track"
50228
- },
50229
- [DeviceRole.Nightvision]: {
50230
- icon: Moon,
50231
- label: "Night vision"
50232
- },
50233
- [DeviceRole.PrivacyMask]: {
50234
- icon: EyeOff,
50235
- label: "Privacy mask"
50236
- },
50237
- [DeviceRole.Doorbell]: {
50238
- icon: DoorClosed,
50239
- label: "Doorbell"
50240
- },
50241
- [DeviceRole.BinaryHelper]: {
50242
- icon: ToggleLeft,
50243
- label: "Binary helper"
50244
- },
50245
- [DeviceRole.MotionSensor]: {
50246
- icon: Footprints,
50247
- label: "Motion sensor"
50248
- },
50249
- [DeviceRole.ContactSensor]: {
50250
- icon: DoorOpen,
50251
- label: "Contact sensor"
50252
- },
50253
- [DeviceRole.LeakSensor]: {
50254
- icon: Droplet,
50255
- label: "Leak sensor"
50256
- },
50257
- [DeviceRole.SmokeSensor]: {
50258
- icon: AlarmSmoke,
50259
- label: "Smoke sensor"
50260
- },
50261
- [DeviceRole.COSensor]: {
50262
- icon: Wind,
50263
- label: "CO sensor"
50264
- },
50265
- [DeviceRole.GasSensor]: {
50266
- icon: Flame,
50267
- label: "Gas sensor"
50268
- },
50269
- [DeviceRole.TamperSensor]: {
50270
- icon: ShieldAlert,
50271
- label: "Tamper sensor"
50272
- },
50273
- [DeviceRole.VibrationSensor]: {
50274
- icon: Vibrate,
50275
- label: "Vibration sensor"
50276
- },
50277
- [DeviceRole.ConnectivitySensor]: {
50278
- icon: Wifi,
50279
- label: "Connectivity"
50280
- },
50281
- [DeviceRole.SoundSensor]: {
50282
- icon: Volume2,
50283
- label: "Sound sensor"
50284
- },
50285
- [DeviceRole.BinarySensor]: {
50286
- icon: ToggleLeft,
50287
- label: "Binary sensor"
50288
- },
50289
- [DeviceRole.TemperatureSensor]: {
50290
- icon: Thermometer,
50291
- label: "Temperature"
50292
- },
50293
- [DeviceRole.HumiditySensor]: {
50294
- icon: Droplets,
50295
- label: "Humidity"
50296
- },
50297
- [DeviceRole.AmbientLightSensor]: {
50298
- icon: Sun,
50299
- label: "Ambient light"
50300
- },
50301
- [DeviceRole.PressureSensor]: {
50302
- icon: Gauge,
50303
- label: "Pressure"
50270
+ function ThermostatInlineControl({ trpc, deviceId, features, optimistic }) {
50271
+ if (!useClimateCapGuard(trpc, deviceId)) return null;
50272
+ return /* @__PURE__ */ jsx(ClimatePanel, {
50273
+ trpc,
50274
+ deviceId,
50275
+ features,
50276
+ layout: "compact",
50277
+ optimistic
50278
+ });
50279
+ }
50280
+ function AcInlineControl({ trpc, deviceId, features, optimistic }) {
50281
+ if (!useClimateCapGuard(trpc, deviceId)) return null;
50282
+ return /* @__PURE__ */ jsx(AcPanel, {
50283
+ trpc,
50284
+ deviceId,
50285
+ features,
50286
+ layout: "compact",
50287
+ optimistic
50288
+ });
50289
+ }
50290
+ function AcHeroCard({ trpc, deviceId, features, optimistic }) {
50291
+ if (!useClimateCapGuard(trpc, deviceId)) return null;
50292
+ return /* @__PURE__ */ jsx(AcPanel, {
50293
+ trpc,
50294
+ deviceId,
50295
+ features,
50296
+ layout: "full",
50297
+ optimistic
50298
+ });
50299
+ }
50300
+ function useMediaPlayerCapGuard(trpc, deviceId) {
50301
+ const { cap } = useDeviceCapability({
50302
+ trpc,
50303
+ deviceId,
50304
+ cap: (d) => d.mediaPlayer,
50305
+ slice: (d) => d.state.mediaPlayer
50306
+ });
50307
+ return cap !== void 0;
50308
+ }
50309
+ function MediaPlayerInlineControl({ trpc, deviceId, features, optimistic }) {
50310
+ if (!useMediaPlayerCapGuard(trpc, deviceId)) return null;
50311
+ return /* @__PURE__ */ jsx(MediaPlayerPanel, {
50312
+ trpc,
50313
+ deviceId,
50314
+ features,
50315
+ layout: "compact",
50316
+ optimistic
50317
+ });
50318
+ }
50319
+ function useControlCapGuard(trpc, deviceId) {
50320
+ const { cap } = useDeviceCapability({
50321
+ trpc,
50322
+ deviceId,
50323
+ cap: (d) => d.control,
50324
+ slice: (d) => d.state.control
50325
+ });
50326
+ return cap !== void 0;
50327
+ }
50328
+ function ControlInlineControl({ trpc, deviceId, features, optimistic }) {
50329
+ if (!useControlCapGuard(trpc, deviceId)) return null;
50330
+ return /* @__PURE__ */ jsx(ControlPanel, {
50331
+ trpc,
50332
+ deviceId,
50333
+ features,
50334
+ layout: "compact",
50335
+ optimistic
50336
+ });
50337
+ }
50338
+ function ControlHeroCard({ trpc, deviceId, features, optimistic }) {
50339
+ if (!useControlCapGuard(trpc, deviceId)) return null;
50340
+ return /* @__PURE__ */ jsx(HeroShell, { children: /* @__PURE__ */ jsx(ControlPanel, {
50341
+ trpc,
50342
+ deviceId,
50343
+ features,
50344
+ layout: "full",
50345
+ optimistic
50346
+ }) });
50347
+ }
50348
+ //#endregion
50349
+ //#region src/composites/device-controls/control-registry.tsx
50350
+ /**
50351
+ * Presentation binding: the shared `DeviceControlKind` (decided in
50352
+ * `@camstack/types` `resolveDeviceControlKind`) → this platform's web
50353
+ * components. Exhaustive over `DeviceControlKind` — omitting a kind fails the
50354
+ * build here. The type→kind DECISION is single-sourced in `@camstack/types`;
50355
+ * this map only binds a kind to its web widgets.
50356
+ */
50357
+ var CONTROL_KIND_COMPONENTS = {
50358
+ cover: {
50359
+ InlineControl: CoverInlineControl,
50360
+ HeroCard: CoverHeroCard
50304
50361
  },
50305
- [DeviceRole.WindSensor]: {
50306
- icon: Wind,
50307
- label: "Wind"
50362
+ valve: {
50363
+ InlineControl: ValveInlineControl,
50364
+ HeroCard: ValveHeroCard
50308
50365
  },
50309
- [DeviceRole.RainSensor]: {
50310
- icon: CloudRain,
50311
- label: "Rain"
50366
+ humidifier: {
50367
+ InlineControl: HumidifierInlineControl,
50368
+ HeroCard: HumidifierHeroCard
50312
50369
  },
50313
- [DeviceRole.UvSensor]: {
50314
- icon: SunMedium,
50315
- label: "UV index"
50370
+ "water-heater": {
50371
+ InlineControl: WaterHeaterInlineControl,
50372
+ HeroCard: WaterHeaterHeroCard
50316
50373
  },
50317
- [DeviceRole.SolarRadiationSensor]: {
50318
- icon: Sunrise,
50319
- label: "Solar radiation"
50374
+ switch: {
50375
+ InlineControl: SwitchInlineControl,
50376
+ HeroCard: SwitchHeroCard
50320
50377
  },
50321
- [DeviceRole.SoilMoistureSensor]: {
50322
- icon: Sprout,
50323
- label: "Soil moisture"
50378
+ light: {
50379
+ InlineControl: LightInlineControl,
50380
+ HeroCard: LightHeroCard
50324
50381
  },
50325
- [DeviceRole.PowerSensor]: {
50326
- icon: Zap,
50327
- label: "Power"
50382
+ fan: {
50383
+ InlineControl: FanInlineControl,
50384
+ HeroCard: FanHeroCard
50328
50385
  },
50329
- [DeviceRole.EnergySensor]: {
50330
- icon: Zap,
50331
- label: "Energy"
50386
+ sensor: {
50387
+ InlineControl: SensorInlineControl,
50388
+ HeroCard: SensorHeroCard
50332
50389
  },
50333
- [DeviceRole.VoltageSensor]: {
50334
- icon: Zap,
50335
- label: "Voltage"
50390
+ thermostat: {
50391
+ InlineControl: ThermostatInlineControl,
50392
+ HeroCard: ThermostatHeroCard
50336
50393
  },
50337
- [DeviceRole.CurrentSensor]: {
50338
- icon: Zap,
50339
- label: "Current"
50394
+ climate: {
50395
+ InlineControl: AcInlineControl,
50396
+ HeroCard: AcHeroCard
50340
50397
  },
50341
- [DeviceRole.AirQualitySensor]: {
50342
- icon: Wind,
50343
- label: "Air quality"
50398
+ button: {
50399
+ InlineControl: ButtonControl,
50400
+ HeroCard: ButtonHeroCard
50344
50401
  },
50345
- [DeviceRole.BatterySensor]: {
50346
- icon: Gauge,
50347
- label: "Battery"
50402
+ update: {
50403
+ InlineControl: UpdateInlineControl,
50404
+ HeroCard: UpdateHeroCard
50348
50405
  },
50349
- [DeviceRole.NumericSensor]: {
50350
- icon: Hash,
50351
- label: "Numeric sensor"
50406
+ lock: {
50407
+ InlineControl: LockInlineControl,
50408
+ HeroCard: LockHeroCard
50352
50409
  },
50353
- [DeviceRole.EnumSensor]: {
50354
- icon: List,
50355
- label: "Enum sensor"
50410
+ "media-player": {
50411
+ InlineControl: MediaPlayerInlineControl,
50412
+ HeroCard: MediaPlayerHeroCard
50356
50413
  },
50357
- [DeviceRole.DateTimeSensor]: {
50358
- icon: Clock,
50359
- label: "Date / time"
50414
+ alarm: {
50415
+ InlineControl: AlarmInlineControl,
50416
+ HeroCard: AlarmHeroCard
50360
50417
  },
50361
- [DeviceRole.GenericSensor]: {
50362
- icon: Gauge,
50363
- label: "Sensor"
50418
+ control: {
50419
+ InlineControl: ControlInlineControl,
50420
+ HeroCard: ControlHeroCard
50364
50421
  },
50365
- [DeviceRole.NumericControl]: {
50366
- icon: SlidersHorizontal,
50367
- label: "Numeric control"
50422
+ weather: {
50423
+ InlineControl: WeatherInlineControl,
50424
+ HeroCard: WeatherHeroCard
50368
50425
  },
50369
- [DeviceRole.SelectControl]: {
50370
- icon: ListChecks,
50371
- label: "Select control"
50426
+ vacuum: {
50427
+ InlineControl: VacuumInlineControl,
50428
+ HeroCard: VacuumHeroCard
50372
50429
  },
50373
- [DeviceRole.TextControl]: {
50374
- icon: Type,
50375
- label: "Text control"
50430
+ "lawn-mower": {
50431
+ InlineControl: LawnMowerInlineControl,
50432
+ HeroCard: LawnMowerHeroCard
50376
50433
  },
50377
- [DeviceRole.DateTimeControl]: {
50378
- icon: Clock,
50379
- label: "Date / time control"
50434
+ image: {
50435
+ InlineControl: ImageInlineControl,
50436
+ HeroCard: ImageHeroCard
50380
50437
  },
50381
- [DeviceRole.MobilePushNotifier]: {
50382
- icon: Smartphone,
50383
- label: "Mobile push"
50438
+ "pet-feeder": {
50439
+ InlineControl: PetFeederInlineControl,
50440
+ HeroCard: PetFeederHeroCard
50384
50441
  },
50385
- [DeviceRole.MessagingNotifier]: {
50386
- icon: MessageSquare,
50387
- label: "Messaging"
50442
+ script: {
50443
+ InlineControl: ScriptInlineControl,
50444
+ HeroCard: ScriptHeroCard
50388
50445
  },
50389
- [DeviceRole.EmailNotifier]: {
50390
- icon: Mail,
50391
- label: "Email"
50446
+ automation: {
50447
+ InlineControl: AutomationInlineControl,
50448
+ HeroCard: AutomationHeroCard
50392
50449
  },
50393
- [DeviceRole.GenericNotifier]: {
50394
- icon: Bell,
50395
- label: "Notifier"
50450
+ dummy: {
50451
+ InlineControl: DummyInline,
50452
+ HeroCard: DummyHeroCard
50396
50453
  }
50397
50454
  };
50455
+ /**
50456
+ * Exhaustive record over DeviceType, DERIVED from the shared decision
50457
+ * (`DEVICE_TYPE_CONTROL_KIND`) composed with the web `CONTROL_KIND_COMPONENTS`
50458
+ * binding — so the type→control mapping can never diverge from the single
50459
+ * source in `@camstack/types`. Preserved as a public export for consumers/tests
50460
+ * that index it by `DeviceType`.
50461
+ *
50462
+ * The `Object.fromEntries` result is a `{ [k: string]: DeviceTypeControl }`;
50463
+ * `Object.values(DeviceType)` (a string enum) yields exactly the enum's members,
50464
+ * so the record is fully populated — the assertion narrows that documented
50465
+ * enum-record projection boundary.
50466
+ */
50467
+ var DEVICE_TYPE_CONTROL = Object.fromEntries(Object.values(DeviceType).map((type) => [type, CONTROL_KIND_COMPONENTS[DEVICE_TYPE_CONTROL_KIND[type]]]));
50468
+ /**
50469
+ * Per-type FILL flag.
50470
+ *
50471
+ * true — range / choice / button controls (cover ▲■▼ triad, thermostat
50472
+ * setpoint stepper, media/control/button action buttons, alarm
50473
+ * segmented control). The child STRETCHES to the full column width.
50474
+ * false — readouts, tap-toggles, icon controls (lock), and dummy/placeholder
50475
+ * types. The child keeps its NATURAL width; where it sits in the
50476
+ * column (flush right vs centered) is decided by the caller via a
50477
+ * `ControlPlacement` — see `resolveControlAlign`.
50478
+ *
50479
+ * Dummy types (Camera, Hub, Generic, Weather, Vacuum, Container, and placeholder
50480
+ * types Notifier/Script/Automation whose InlineControl renders "—") are `false` —
50481
+ * the dash placeholder must not be stretched to the full column width. (AlarmPanel
50482
+ * has a real segmented inline control and is `true`.) When a later task gives a
50483
+ * remaining placeholder type a real stretchy inline control, flip its flag to true.
50484
+ *
50485
+ * Exhaustive over DeviceType — a missing member is a TypeScript build error.
50486
+ */
50487
+ var CONTROL_FILLS = {
50488
+ [DeviceType.Cover]: true,
50489
+ [DeviceType.Valve]: true,
50490
+ [DeviceType.Thermostat]: true,
50491
+ [DeviceType.Climate]: true,
50492
+ [DeviceType.Control]: true,
50493
+ [DeviceType.Button]: true,
50494
+ [DeviceType.MediaPlayer]: true,
50495
+ [DeviceType.AlarmPanel]: true,
50496
+ [DeviceType.Lock]: false,
50497
+ [DeviceType.Vacuum]: false,
50498
+ [DeviceType.LawnMower]: false,
50499
+ [DeviceType.Humidifier]: false,
50500
+ [DeviceType.Switch]: false,
50501
+ [DeviceType.Siren]: false,
50502
+ [DeviceType.Light]: false,
50503
+ [DeviceType.Fan]: false,
50504
+ [DeviceType.WaterHeater]: false,
50505
+ [DeviceType.Sensor]: false,
50506
+ [DeviceType.Presence]: false,
50507
+ [DeviceType.EventEmitter]: false,
50508
+ [DeviceType.Notifier]: false,
50509
+ [DeviceType.Script]: false,
50510
+ [DeviceType.Automation]: false,
50511
+ [DeviceType.Camera]: false,
50512
+ [DeviceType.Hub]: false,
50513
+ [DeviceType.Update]: false,
50514
+ [DeviceType.Generic]: false,
50515
+ [DeviceType.Weather]: false,
50516
+ [DeviceType.Container]: false,
50517
+ [DeviceType.Image]: false,
50518
+ [DeviceType.PetFeeder]: false
50519
+ };
50398
50520
  var DEVICE_TYPE_VALUES = new Set(Object.values(DeviceType));
50399
- var DEVICE_ROLE_VALUES = new Set(Object.values(DeviceRole));
50400
- function isDeviceType(value) {
50401
- return DEVICE_TYPE_VALUES.has(value);
50402
- }
50403
- function isDeviceRole(value) {
50404
- return DEVICE_ROLE_VALUES.has(value);
50405
- }
50406
- /** Meta for a known `DeviceType`. */
50407
- function deviceTypeMeta(type) {
50408
- return DEVICE_TYPE_META[type];
50409
- }
50410
- /** Meta for a known `DeviceRole`. */
50411
- function deviceRoleMeta(role) {
50412
- return DEVICE_ROLE_META[role];
50521
+ /**
50522
+ * Runtime-string-safe lookup: a device row's `type` crosses the wire as a plain
50523
+ * string. The type→control-kind DECISION is single-sourced in `@camstack/types`
50524
+ * (`resolveDeviceControlKind`, null for an unrecognised type); this maps the
50525
+ * resolved kind onto the web components.
50526
+ */
50527
+ function resolveDeviceControl(type) {
50528
+ const kind = resolveDeviceControlKind(type);
50529
+ return kind ? CONTROL_KIND_COMPONENTS[kind] : null;
50413
50530
  }
50414
- var FALLBACK_DEVICE_TYPE_META = DEVICE_TYPE_META[DeviceType.Generic];
50415
- var FALLBACK_DEVICE_ROLE_META = DEVICE_ROLE_META[DeviceRole.GenericSensor];
50416
50531
  /**
50417
- * Runtime-string-safe lookup: device data crosses process / network boundaries
50418
- * as plain strings, so an unrecognised value falls back to the `Generic` meta
50419
- * instead of throwing.
50532
+ * Runtime-string-safe alignment lookup for the fixed-width control column.
50420
50533
  *
50421
- * This also guards mixed-version module-federation loads where the host
50422
- * `@camstack/types` enum has a new member before the loaded ui-library bundle
50423
- * has the matching `DEVICE_TYPE_META` entry.
50534
+ * A device's `type` crosses the wire as a plain string;
50535
+ * `DEVICE_TYPE_VALUES.has(type)` narrows it to `DeviceType` before indexing
50536
+ * `CONTROL_FILLS`, making the cast sound. The `'table'` placement is
50537
+ * content-width for EVERY type (returns `FIT`), so a wide control never
50538
+ * overflows a fixed box — the FILL flag is irrelevant there. For the fixed-box
50539
+ * placements a FILL type always stretches (`FILL`) and a natural-width type is
50540
+ * placed by the caller's `placement` — `'center'` → `CENTER`, `'right'` →
50541
+ * `RIGHT` (card / minimal view). An unrecognised type falls back to
50542
+ * natural-width placement.
50424
50543
  */
50425
- function deviceTypeMetaOf(type) {
50426
- if (!isDeviceType(type)) return FALLBACK_DEVICE_TYPE_META;
50427
- return DEVICE_TYPE_META[type] ?? FALLBACK_DEVICE_TYPE_META;
50428
- }
50429
- /** Runtime-string-safe role lookup; unknown roles fall back to `GenericSensor`. */
50430
- function deviceRoleMetaOf(role) {
50431
- if (!isDeviceRole(role)) return FALLBACK_DEVICE_ROLE_META;
50432
- return DEVICE_ROLE_META[role] ?? FALLBACK_DEVICE_ROLE_META;
50544
+ function resolveControlAlign(type, placement) {
50545
+ if (placement === "table") return "fit";
50546
+ return DEVICE_TYPE_VALUES.has(type) && CONTROL_FILLS[type] ? FILL : placement === "center" ? CENTER : RIGHT;
50433
50547
  }
50548
+ //#endregion
50549
+ //#region src/lib/format-last-seen.ts
50434
50550
  /**
50435
- * Icons an operator may pick for a per-device `display.icon` override (and for
50436
- * a per-role default), keyed by a stable kebab-case name. Named imports only —
50437
- * no dynamic indexing into lucide, so the bundle carries exactly this set.
50438
- * Unknown keys resolve to `undefined` (caller falls through to the next level).
50551
+ * Relative "last seen" formatter for the offline affordance.
50439
50552
  *
50440
- * The vocabulary is the one the VIEWER draws from too (its own icon module,
50441
- * keyed by these same strings): a key added here that the phone cannot draw
50442
- * falls through to the next resolution level there, which reads as "my change
50443
- * did nothing". So the KEY is the contract — a stable kebab-case string, never
50444
- * a glyph identity — and `device-meta.test.ts` pins that every key resolves
50445
- * and that the set never loses a key an operator may already have persisted.
50553
+ * Renders a short relative-time label from a millisecond epoch:
50554
+ * "just now", "5m ago", "3h ago", "2d ago". Returns `null` for missing
50555
+ * inputs, or inputs below {@link MIN_PLAUSIBLE_TIMESTAMP_MS} (a
50556
+ * placeholder or a seeded "known value, unknown change time" stamp), so
50557
+ * callers can render nothing rather than a misleading "—", "NaN ago", or
50558
+ * (for a seeded `1`) "20000 days ago".
50446
50559
  *
50447
- * Grouped by what an operator is naming: a device, a light or appliance, a
50448
- * sensor or the weather it reads, a room, or what moves through it. `gauge2`
50449
- * is a legacy alias kept for rows that persisted it.
50560
+ * Future timestamps (clock skew between the device and the browser)
50561
+ * collapse to "just now" instead of a negative duration.
50450
50562
  */
50451
- var DISPLAY_ICON_REGISTRY = {
50452
- camera: Camera,
50453
- network: Network,
50454
- "toggle-left": ToggleLeft,
50455
- "toggle-right": ToggleRight,
50456
- "circle-dot": CircleDot,
50457
- "refresh-cw": RefreshCw,
50458
- box: Box,
50459
- "scroll-text": ScrollText,
50460
- workflow: Workflow,
50461
- lock: Lock,
50462
- "lock-open": LockOpen,
50463
- blinds: Blinds,
50464
- "air-vent": AirVent,
50465
- "monitor-play": MonitorPlay,
50466
- "sliders-horizontal": SlidersHorizontal,
50467
- "map-pin": MapPin,
50468
- bot: Bot,
50469
- tractor: Tractor,
50470
- image: Image,
50471
- bone: Bone,
50472
- "door-closed": DoorClosed,
50473
- "door-open": DoorOpen,
50474
- crosshair: Crosshair,
50475
- eye: Eye,
50476
- "eye-off": EyeOff,
50477
- smartphone: Smartphone,
50478
- phone: Phone,
50479
- tablet: Tablet,
50480
- laptop: Laptop,
50481
- monitor: Monitor,
50482
- tv: Tv,
50483
- speaker: Speaker,
50484
- printer: Printer,
50485
- projector: Projector,
50486
- "gamepad-2": Gamepad2,
50487
- radio: Radio,
50488
- router: Router,
50489
- bluetooth: Bluetooth,
50490
- cpu: Cpu,
50491
- "hard-drive": HardDrive,
50492
- server: Server,
50493
- mic: Mic,
50494
- "mic-off": MicOff,
50495
- video: Video,
50496
- "video-off": VideoOff,
50497
- music: Music,
50498
- plug: Plug,
50499
- "plug-zap": PlugZap,
50500
- power: Power,
50501
- "power-off": PowerOff,
50502
- cable: Cable,
50503
- battery: Battery,
50504
- "battery-charging": BatteryCharging,
50505
- "battery-full": BatteryFull,
50506
- "battery-low": BatteryLow,
50507
- key: Key,
50508
- "key-round": KeyRound,
50509
- mailbox: Mailbox,
50510
- package: Package,
50511
- shield: Shield,
50512
- "shield-check": ShieldCheck,
50513
- "shield-off": ShieldOff,
50514
- lightbulb: Lightbulb,
50515
- lamp: Lamp,
50516
- "lamp-ceiling": LampCeiling,
50517
- "lamp-desk": LampDesk,
50518
- "lamp-floor": LampFloor,
50519
- flashlight: Flashlight,
50520
- heater: Heater,
50521
- snowflake: Snowflake,
50522
- "thermometer-sun": ThermometerSun,
50523
- "thermometer-snowflake": ThermometerSnowflake,
50524
- refrigerator: Refrigerator,
50525
- microwave: Microwave,
50526
- "washing-machine": WashingMachine,
50527
- "cooking-pot": CookingPot,
50528
- utensils: Utensils,
50529
- thermometer: Thermometer,
50530
- droplets: Droplets,
50531
- droplet: Droplet,
50532
- gauge: Gauge,
50533
- gauge2: Gauge,
50534
- sun: Sun,
50535
- "sun-medium": SunMedium,
50536
- sunrise: Sunrise,
50537
- moon: Moon,
50538
- wind: Wind,
50539
- cloud: Cloud,
50540
- "cloud-rain": CloudRain,
50541
- "cloud-sun": CloudSun,
50542
- waves: Waves,
50543
- sprout: Sprout,
50544
- leaf: Leaf,
50545
- flower: Flower,
50546
- zap: Zap,
50547
- flame: Flame,
50548
- bell: Bell,
50549
- "bell-ring": BellRing,
50550
- "bell-off": BellOff,
50551
- siren: Siren,
50552
- radar: Radar,
50553
- activity: Activity,
50554
- hash: Hash,
50555
- clock: Clock,
50556
- timer: Timer,
50557
- calendar: Calendar,
50558
- pipette: Pipette,
50559
- fan: Fan,
50560
- bath: Bath,
50561
- footprints: Footprints,
50562
- "alarm-smoke": AlarmSmoke,
50563
- "shield-alert": ShieldAlert,
50564
- vibrate: Vibrate,
50565
- wifi: Wifi,
50566
- "wifi-off": WifiOff,
50567
- "volume-2": Volume2,
50568
- "volume-x": VolumeX,
50569
- heart: Heart,
50570
- "heart-pulse": HeartPulse,
50571
- star: Star,
50572
- sparkles: Sparkles,
50573
- house: House,
50574
- sofa: Sofa,
50575
- "bed-double": BedDouble,
50576
- bed: Bed,
50577
- warehouse: Warehouse,
50578
- trees: Trees,
50579
- "tree-pine": TreePine,
50580
- fence: Fence,
50581
- store: Store,
50582
- building: Building,
50583
- "building-2": Building2,
50584
- mountain: Mountain,
50585
- umbrella: Umbrella,
50586
- dumbbell: Dumbbell,
50587
- wrench: Wrench,
50588
- hammer: Hammer,
50589
- drill: Drill,
50590
- "waves-ladder": WavesLadder,
50591
- "circle-parking": CircleParking,
50592
- briefcase: Briefcase,
50593
- route: Route,
50594
- car: Car,
50595
- bike: Bike,
50596
- bus: Bus,
50597
- truck: Truck,
50598
- plane: Plane,
50599
- "train-front": TrainFront,
50600
- sailboat: Sailboat,
50601
- dog: Dog,
50602
- cat: Cat,
50603
- bird: Bird,
50604
- "paw-print": PawPrint,
50605
- baby: Baby,
50606
- user: User,
50607
- users: Users,
50608
- "person-standing": PersonStanding
50609
- };
50610
- /** Resolve a `display.icon` name to a lucide component, or `undefined` when the
50611
- * name is not in the curated `DISPLAY_ICON_REGISTRY`. */
50612
- function resolveDisplayIcon(name) {
50613
- return Object.hasOwn(DISPLAY_ICON_REGISTRY, name) ? DISPLAY_ICON_REGISTRY[name] : void 0;
50563
+ var SECOND_MS = 1e3;
50564
+ var MINUTE_MS = 60 * SECOND_MS;
50565
+ var HOUR_MS = 60 * MINUTE_MS;
50566
+ var DAY_MS = 24 * HOUR_MS;
50567
+ var JUST_NOW_MS = 30 * SECOND_MS;
50568
+ /**
50569
+ * The earliest timestamp a real "last seen" could plausibly carry. Below
50570
+ * this, a value is a placeholder or a seeded "known value, unknown change
50571
+ * time" stamp (e.g. Homematic's `HM_SEEDED_CHANGED_AT = 1`) — never a real
50572
+ * instant. Year 2000 predates every device this renders.
50573
+ */
50574
+ var MIN_PLAUSIBLE_TIMESTAMP_MS = Date.UTC(2e3, 0, 1);
50575
+ function formatLastSeen(timestampMs) {
50576
+ if (timestampMs === null || timestampMs === void 0 || timestampMs < MIN_PLAUSIBLE_TIMESTAMP_MS) return null;
50577
+ const delta = Date.now() - timestampMs;
50578
+ if (delta < JUST_NOW_MS) return "just now";
50579
+ if (delta < HOUR_MS) return `${String(Math.floor(delta / MINUTE_MS))}m ago`;
50580
+ if (delta < DAY_MS) return `${String(Math.floor(delta / HOUR_MS))}h ago`;
50581
+ return `${String(Math.floor(delta / DAY_MS))}d ago`;
50582
+ }
50583
+ //#endregion
50584
+ //#region src/composites/device-controls/offline-badge.tsx
50585
+ function OfflineBadge({ lastChangedAt, className }) {
50586
+ const lastSeen = formatLastSeen(lastChangedAt);
50587
+ return /* @__PURE__ */ jsxs("span", {
50588
+ title: lastSeen === null ? "Unavailable" : `Unavailable · last seen ${lastSeen}`,
50589
+ className: cn("inline-flex items-center gap-1 rounded-full px-2 py-0.5", "bg-surface-hover text-foreground-subtle text-[10px] font-medium", "border border-border", className),
50590
+ children: [
50591
+ /* @__PURE__ */ jsx(WifiOff, {
50592
+ className: "h-3 w-3 flex-shrink-0",
50593
+ "aria-hidden": "true"
50594
+ }),
50595
+ /* @__PURE__ */ jsx("span", { children: "Unavailable" }),
50596
+ lastSeen !== null ? /* @__PURE__ */ jsx("span", {
50597
+ className: "text-foreground-subtle/70",
50598
+ children: `· last seen ${lastSeen}`
50599
+ }) : null
50600
+ ]
50601
+ });
50614
50602
  }
50603
+ //#endregion
50604
+ //#region src/composites/device-controls/primary-child.ts
50615
50605
  /**
50616
- * EXHAUSTIVE device-type filter options — one entry per `DeviceType` member,
50617
- * derived from `DEVICE_TYPE_META` so the set is always complete and a newly
50618
- * added `DeviceType` automatically appears in every type filter (Devices page,
50619
- * adoption modal, …) without touching any consumer.
50606
+ * Which child a container is rendered AS — this surface's name for the shared
50607
+ * rule.
50620
50608
  *
50621
- * The previous per-consumer logic built options from the types PRESENT in the
50622
- * list (or a hand-maintained subset), so recently-added types (vacuum, lawn
50623
- * mower, valve, humidifier, water heater, weather, image, …) were silently
50624
- * missing from the dropdown. This is the single source of truth instead.
50609
+ * The list and the resolution used to live here, in a COPY that carried a
50610
+ * comment asking the Home Assistant adoption mapping and the viewer's panel to
50611
+ * stay in sync with it. Three lists and three comments is not one rule, it is
50612
+ * three chances to drift. Both now come from `@camstack/types`, which all of
50613
+ * them already depend on; what remains here is the adapter for this module's
50614
+ * historical `ChildRef` shape.
50615
+ */
50616
+ /** The shared precedence, under this module's historical name. */
50617
+ var PRIORITY = CONTAINER_CHILD_PRIORITY;
50618
+ /**
50619
+ * Resolve a container's primary child: the operator's pick when it still
50620
+ * matches a live child, else the highest-priority type.
50625
50621
  *
50626
- * `id` is the raw `DeviceType` string (matches the filtering predicate, which
50627
- * compares against `device.type`); `label` + `icon` come from the meta map.
50628
- * Ordered by `DeviceType` declaration order for a stable, intentional layout.
50622
+ * `entityId` here is `sourceInfo?.id ?? stableId` (see `containerChildToRef`).
50623
+ * The shared resolver matches its canonical `stableId` key first and accepts
50624
+ * that legacy value too, so a pick stored under either keeps resolving.
50629
50625
  */
50630
- var ALL_DEVICE_TYPE_FILTER_OPTIONS = Object.values(DeviceType).map((type) => {
50631
- const meta = deviceTypeMetaOf(type);
50626
+ function resolvePrimaryChild(children, overrideEntityId, containerName) {
50627
+ const picked = resolveContainerPrimaryChild(children.map((c) => ({
50628
+ id: c.id,
50629
+ stableId: c.entityId,
50630
+ type: c.type,
50631
+ ...c.role !== void 0 ? { role: c.role } : {},
50632
+ ...c.name !== void 0 ? { name: c.name } : {}
50633
+ })), overrideEntityId, containerName);
50634
+ return picked === null ? null : children.find((c) => c.id === picked.id) ?? null;
50635
+ }
50636
+ //#endregion
50637
+ //#region src/composites/device-controls/container-primary.ts
50638
+ /**
50639
+ * Re-sync-stable identity of a child. Prefers the upstream-system dispatch key
50640
+ * (`sourceInfo.id` — e.g. HA `entity_id`); falls back to `stableId` for
50641
+ * providers that never populated SourceInfo. Both survive a re-sync that may
50642
+ * reallocate the numeric `id`.
50643
+ */
50644
+ function childEntityId(child) {
50645
+ return child.sourceInfo?.id ?? child.stableId;
50646
+ }
50647
+ /** Project a raw child row onto the pure resolver's {@link ChildRef} shape. */
50648
+ function containerChildToRef(child) {
50632
50649
  return {
50633
- id: type,
50634
- label: meta.label,
50635
- icon: meta.icon
50650
+ id: child.id,
50651
+ entityId: childEntityId(child),
50652
+ type: child.type,
50653
+ ...child.role !== void 0 && child.role !== null ? { role: child.role } : {},
50654
+ ...child.name !== void 0 ? { name: child.name } : {}
50636
50655
  };
50637
- });
50638
- function allDeviceTypeFilterOptions() {
50639
- return ALL_DEVICE_TYPE_FILTER_OPTIONS;
50656
+ }
50657
+ /**
50658
+ * Resolve the entityId override from the container's persisted `linkDeviceId`.
50659
+ * Returns the linked child's stable entityId, or `undefined` when there is no
50660
+ * link or the link is stale (points to a numeric id no longer present) — in
50661
+ * which case the resolver falls back to the priority default.
50662
+ */
50663
+ function overrideEntityIdFromLink(children, linkDeviceId) {
50664
+ if (linkDeviceId === null || linkDeviceId === void 0) return void 0;
50665
+ const linked = children.find((c) => c.id === linkDeviceId);
50666
+ return linked === void 0 ? void 0 : childEntityId(linked);
50667
+ }
50668
+ /**
50669
+ * Full container → primary-child resolution: project children to refs, resolve
50670
+ * the override entityId, and delegate to the pure resolver. Returns `null` for a
50671
+ * container with no children (caller degrades gracefully).
50672
+ *
50673
+ * Override precedence:
50674
+ * 1. `primaryChildEntityId` — the DURABLE override (re-sync/rename-stable),
50675
+ * passed straight to the resolver which matches on `entityId`. Wins when a
50676
+ * non-empty string is supplied.
50677
+ * 2. `linkDeviceId` — LEGACY numeric override, re-derived to an entityId from
50678
+ * the live child set. Consulted only when there is no durable override.
50679
+ *
50680
+ * When neither resolves to a live child, the resolver falls back to the
50681
+ * priority default.
50682
+ */
50683
+ function resolveContainerPrimary(children, linkDeviceId, primaryChildEntityId) {
50684
+ return resolvePrimaryChild(children.map(containerChildToRef), primaryChildEntityId !== null && primaryChildEntityId !== void 0 && primaryChildEntityId !== "" ? primaryChildEntityId : overrideEntityIdFromLink(children, linkDeviceId));
50685
+ }
50686
+ //#endregion
50687
+ //#region src/composites/device-controls/container-primary-hero.tsx
50688
+ function ContainerPrimaryHero({ trpc, children, linkDeviceId, primaryChildEntityId }) {
50689
+ const primary = resolveContainerPrimary(children, linkDeviceId, primaryChildEntityId);
50690
+ const primaryChild = primary === null ? void 0 : children.find((c) => c.id === primary.id);
50691
+ if (primaryChild === void 0) return /* @__PURE__ */ jsx("div", {
50692
+ className: "flex h-full w-full items-center justify-center p-4 text-[11px] italic text-foreground-subtle",
50693
+ children: "No child entities to display."
50694
+ });
50695
+ return /* @__PURE__ */ jsx("div", {
50696
+ className: "flex h-full w-full flex-col items-stretch gap-3 p-3 sm:p-4",
50697
+ children: /* @__PURE__ */ jsx(resolveDeviceControl(primaryChild.type)?.HeroCard ?? DummyHeroCard, {
50698
+ trpc,
50699
+ deviceId: primaryChild.id,
50700
+ features: primaryChild.features
50701
+ })
50702
+ });
50703
+ }
50704
+ //#endregion
50705
+ //#region src/composites/device-controls/primary-child-picker.tsx
50706
+ var BASE_SELECT_CLASS = "rounded-md border border-border bg-surface px-1.5 py-0.5 text-[11px] text-foreground";
50707
+ function PrimaryChildPicker({ childrenList, selectedId, onSetPrimary, disabled, className }) {
50708
+ return /* @__PURE__ */ jsx("select", {
50709
+ value: selectedId,
50710
+ disabled,
50711
+ onChange: (e) => {
50712
+ const nextId = Number(e.target.value);
50713
+ if (!Number.isFinite(nextId) || nextId === selectedId) return;
50714
+ const picked = childrenList.find((c) => c.id === nextId);
50715
+ if (picked !== void 0) onSetPrimary(picked.stableId);
50716
+ },
50717
+ className: className === void 0 ? BASE_SELECT_CLASS : `${BASE_SELECT_CLASS} ${className}`,
50718
+ children: childrenList.map((c) => /* @__PURE__ */ jsxs("option", {
50719
+ value: c.id,
50720
+ children: [
50721
+ c.name,
50722
+ " (",
50723
+ c.type,
50724
+ ")"
50725
+ ]
50726
+ }, c.id))
50727
+ });
50728
+ }
50729
+ //#endregion
50730
+ //#region src/composites/device-list/batch-toolbar.tsx
50731
+ function DeviceBatchToolbar({ selectedIds, onClear, remove, disable, enable }) {
50732
+ const [pendingDelete, setPendingDelete] = useState(false);
50733
+ if (selectedIds.size === 0) return null;
50734
+ const ids = [...selectedIds];
50735
+ const count = ids.length;
50736
+ const handleDisable = () => {
50737
+ for (const id of ids) disable({ deviceId: id });
50738
+ onClear();
50739
+ };
50740
+ const handleEnable = () => {
50741
+ for (const id of ids) enable({ deviceId: id });
50742
+ onClear();
50743
+ };
50744
+ const handleDeleteFirst = () => {
50745
+ setPendingDelete(true);
50746
+ };
50747
+ const handleDeleteConfirm = () => {
50748
+ for (const id of ids) remove({ deviceId: id });
50749
+ setPendingDelete(false);
50750
+ onClear();
50751
+ };
50752
+ const handleDeleteCancel = () => {
50753
+ setPendingDelete(false);
50754
+ };
50755
+ const handleClear = () => {
50756
+ setPendingDelete(false);
50757
+ onClear();
50758
+ };
50759
+ return /* @__PURE__ */ jsxs("div", {
50760
+ className: "flex items-center gap-2 px-3 py-2 rounded-lg border border-border bg-surface-hover",
50761
+ children: [
50762
+ /* @__PURE__ */ jsxs("span", {
50763
+ className: "text-xs font-medium text-foreground-subtle shrink-0",
50764
+ children: [count, " selected"]
50765
+ }),
50766
+ /* @__PURE__ */ jsx("div", {
50767
+ className: "h-3.5 w-px bg-border shrink-0",
50768
+ "aria-hidden": "true"
50769
+ }),
50770
+ /* @__PURE__ */ jsxs("div", {
50771
+ className: "flex items-center gap-1.5 flex-wrap",
50772
+ children: [
50773
+ /* @__PURE__ */ jsx("button", {
50774
+ type: "button",
50775
+ onClick: handleDisable,
50776
+ className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
50777
+ children: "Disable"
50778
+ }),
50779
+ /* @__PURE__ */ jsx("button", {
50780
+ type: "button",
50781
+ onClick: handleEnable,
50782
+ className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
50783
+ children: "Enable"
50784
+ }),
50785
+ pendingDelete ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("button", {
50786
+ type: "button",
50787
+ onClick: handleDeleteConfirm,
50788
+ className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-red-500/50 bg-red-500/10 text-red-400 hover:bg-red-500/20"),
50789
+ children: [
50790
+ "Confirm delete ",
50791
+ count,
50792
+ "?"
50793
+ ]
50794
+ }), /* @__PURE__ */ jsx("button", {
50795
+ type: "button",
50796
+ onClick: handleDeleteCancel,
50797
+ className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
50798
+ children: "Cancel"
50799
+ })] }) : /* @__PURE__ */ jsx("button", {
50800
+ type: "button",
50801
+ onClick: handleDeleteFirst,
50802
+ className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-red-500/40 bg-red-500/10 text-red-400 hover:bg-red-500/20"),
50803
+ children: "Delete"
50804
+ }),
50805
+ /* @__PURE__ */ jsx("button", {
50806
+ type: "button",
50807
+ onClick: handleClear,
50808
+ className: cn("inline-flex items-center h-6 px-2.5 rounded-md border text-[10.5px] font-medium transition-colors", "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface"),
50809
+ children: "Clear"
50810
+ })
50811
+ ]
50812
+ })
50813
+ ]
50814
+ });
50815
+ }
50816
+ //#endregion
50817
+ //#region src/composites/device-list/batch-actions-bar.tsx
50818
+ /**
50819
+ * <DeviceBatchActionsBar> — responsive wrapper around <DeviceBatchToolbar>.
50820
+ *
50821
+ * Surfaces the available bulk actions once devices are selected:
50822
+ * - L2+ (`sm` and up): the toolbar renders inline as a row of buttons.
50823
+ * - L1 (`< sm`): a compact "Actions · N" trigger opens a popover that
50824
+ * hosts the SAME <DeviceBatchToolbar>, so the action logic (inline
50825
+ * delete-confirm, clear) is reused verbatim — never forked.
50826
+ *
50827
+ * Renders nothing while the selection is empty (delegated to the toolbar).
50828
+ */
50829
+ function DeviceBatchActionsBar(props) {
50830
+ const [open, setOpen] = useState(false);
50831
+ const rootRef = useRef(null);
50832
+ const count = props.selectedIds.size;
50833
+ useEffect(() => {
50834
+ if (!open) return;
50835
+ const onOutside = (e) => {
50836
+ const target = e.target instanceof Node ? e.target : null;
50837
+ if (target && rootRef.current && !rootRef.current.contains(target)) setOpen(false);
50838
+ };
50839
+ const onKey = (e) => {
50840
+ if (e.key === "Escape") setOpen(false);
50841
+ };
50842
+ document.addEventListener("mousedown", onOutside);
50843
+ document.addEventListener("touchstart", onOutside);
50844
+ document.addEventListener("keydown", onKey);
50845
+ return () => {
50846
+ document.removeEventListener("mousedown", onOutside);
50847
+ document.removeEventListener("touchstart", onOutside);
50848
+ document.removeEventListener("keydown", onKey);
50849
+ };
50850
+ }, [open]);
50851
+ if (count === 0) return null;
50852
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
50853
+ className: "hidden sm:block",
50854
+ children: /* @__PURE__ */ jsx(DeviceBatchToolbar, { ...props })
50855
+ }), /* @__PURE__ */ jsxs("div", {
50856
+ ref: rootRef,
50857
+ "data-testid": "batch-actions-compact",
50858
+ className: "relative sm:hidden",
50859
+ children: [/* @__PURE__ */ jsxs("button", {
50860
+ type: "button",
50861
+ onClick: () => setOpen((v) => !v),
50862
+ "aria-haspopup": "menu",
50863
+ "aria-expanded": open,
50864
+ className: "inline-flex items-center gap-1.5 h-7 px-2.5 rounded-full border border-primary/40 bg-primary/15 text-[10.5px] font-medium text-primary",
50865
+ children: [/* @__PURE__ */ jsxs("span", { children: ["Actions · ", String(count)] }), /* @__PURE__ */ jsx(ChevronDown, { className: `h-3 w-3 transition-transform ${open ? "rotate-180" : ""}` })]
50866
+ }), open && /* @__PURE__ */ jsx("div", {
50867
+ role: "menu",
50868
+ className: "absolute left-0 top-full mt-1 z-30 rounded-lg border border-border bg-surface shadow-md",
50869
+ children: /* @__PURE__ */ jsx(DeviceBatchToolbar, { ...props })
50870
+ })]
50871
+ })] });
50640
50872
  }
50641
50873
  //#endregion
50642
50874
  //#region src/hooks/use-debounced-string.ts
@@ -50657,6 +50889,59 @@ function useDebouncedString(value, delayMs) {
50657
50889
  return debounced;
50658
50890
  }
50659
50891
  //#endregion
50892
+ //#region src/hooks/use-persisted-page-size.ts
50893
+ /**
50894
+ * usePersistedPageSize — a "rows per page" choice remembered per viewer.
50895
+ *
50896
+ * The caller names the storage key, the allowed sizes and the default. Each
50897
+ * surface with its own default or option set keeps its own key, so one
50898
+ * surface's choice never lands on another that cannot show it (the device
50899
+ * list's global key stays `useDeviceListPageSize`'s, with its own options).
50900
+ *
50901
+ * `PAGE_SIZE_ALL` (0) is the "All" option: one page holding every row.
50902
+ *
50903
+ * Storage is a convenience, never a requirement: every read and write is
50904
+ * guarded, and a blocked / private-mode / missing storage simply means the
50905
+ * choice lasts until the page is left. A stored value that is not one of the
50906
+ * options (an older option set, a hand-edited value) is ignored.
50907
+ */
50908
+ /** The "All" option — one page holding every row. */
50909
+ var PAGE_SIZE_ALL = 0;
50910
+ function readStored(key, options, fallback) {
50911
+ if (key === null || typeof window === "undefined") return fallback;
50912
+ try {
50913
+ const raw = window.localStorage.getItem(key);
50914
+ if (raw === null) return fallback;
50915
+ const parsed = Number.parseInt(raw, 10);
50916
+ return Number.isFinite(parsed) && options.includes(parsed) ? parsed : fallback;
50917
+ } catch {
50918
+ return fallback;
50919
+ }
50920
+ }
50921
+ function writeStored(key, value) {
50922
+ if (key === null || typeof window === "undefined") return;
50923
+ try {
50924
+ window.localStorage.setItem(key, String(value));
50925
+ } catch {}
50926
+ }
50927
+ /** @returns `[size, setSize]`; `setSize` ignores a size that is not an option. */
50928
+ function usePersistedPageSize({ storageKey, options, defaultSize }) {
50929
+ const seed = options.includes(defaultSize) ? defaultSize : options[0] ?? defaultSize;
50930
+ const [size, setSize] = useState(() => readStored(storageKey, options, seed));
50931
+ return [size, useCallback((next) => {
50932
+ if (!options.includes(next)) return;
50933
+ setSize(next);
50934
+ writeStored(storageKey, next);
50935
+ }, [options, storageKey])];
50936
+ }
50937
+ /**
50938
+ * The number of rows one page holds for a chosen size: "All" is every row
50939
+ * (at least 1, so the pager arithmetic never divides by zero).
50940
+ */
50941
+ function effectivePageSize(size, totalItems) {
50942
+ return size === 0 ? Math.max(1, totalItems) : size;
50943
+ }
50944
+ //#endregion
50660
50945
  //#region src/hooks/use-device-list-page-size.ts
50661
50946
  /**
50662
50947
  * useDeviceListPageSize — global page-size preference for the device-list
@@ -50667,8 +50952,9 @@ function useDebouncedString(value, delayMs) {
50667
50952
  * value is validated against {@link DEVICE_LIST_PAGE_SIZE_OPTIONS}; any
50668
50953
  * garbage / out-of-range value falls back to the provided default.
50669
50954
  *
50670
- * SSR / jsdom-safe: every `window` access is guarded so the hook can run in
50671
- * a non-browser environment without throwing.
50955
+ * A thin binding of `usePersistedPageSize` to that key and option set; a
50956
+ * surface with a different default or options uses the generic hook with a
50957
+ * key of its own.
50672
50958
  */
50673
50959
  /** Selectable per-page sizes. The table default (50) is intentionally one of them. */
50674
50960
  var DEVICE_LIST_PAGE_SIZE_OPTIONS = [
@@ -50679,33 +50965,6 @@ var DEVICE_LIST_PAGE_SIZE_OPTIONS = [
50679
50965
  ];
50680
50966
  /** Single global key shared across every device-list surface. */
50681
50967
  var DEVICE_LIST_PAGE_SIZE_KEY = "camstack.device-list.pageSize";
50682
- function isAllowed(value) {
50683
- return DEVICE_LIST_PAGE_SIZE_OPTIONS.includes(value);
50684
- }
50685
- /**
50686
- * Normalize a caller-supplied `defaultSize` to an allowed option, falling back
50687
- * to the canonical default so a stray value can never seed a phantom size.
50688
- */
50689
- function safeDefault(defaultSize) {
50690
- return isAllowed(defaultSize) ? defaultSize : 50;
50691
- }
50692
- function readStored(defaultSize) {
50693
- if (typeof window === "undefined") return defaultSize;
50694
- try {
50695
- const raw = window.localStorage.getItem(DEVICE_LIST_PAGE_SIZE_KEY);
50696
- if (raw === null) return defaultSize;
50697
- const parsed = Number.parseInt(raw, 10);
50698
- return Number.isFinite(parsed) && isAllowed(parsed) ? parsed : defaultSize;
50699
- } catch {
50700
- return defaultSize;
50701
- }
50702
- }
50703
- function writeStored(value) {
50704
- if (typeof window === "undefined") return;
50705
- try {
50706
- window.localStorage.setItem(DEVICE_LIST_PAGE_SIZE_KEY, String(value));
50707
- } catch {}
50708
- }
50709
50968
  /**
50710
50969
  * @param defaultSize fallback when nothing valid is stored. If it is not itself
50711
50970
  * a member of {@link DEVICE_LIST_PAGE_SIZE_OPTIONS}, it is replaced by
@@ -50713,13 +50972,11 @@ function writeStored(value) {
50713
50972
  * @returns `[size, setSize]` — `setSize` ignores values outside the allowed set.
50714
50973
  */
50715
50974
  function useDeviceListPageSize(defaultSize) {
50716
- const seed = safeDefault(defaultSize);
50717
- const [size, setSize] = useState(() => readStored(seed));
50718
- return [size, useCallback((next) => {
50719
- if (!isAllowed(next)) return;
50720
- setSize(next);
50721
- writeStored(next);
50722
- }, [])];
50975
+ return usePersistedPageSize({
50976
+ storageKey: DEVICE_LIST_PAGE_SIZE_KEY,
50977
+ options: DEVICE_LIST_PAGE_SIZE_OPTIONS,
50978
+ defaultSize: DEVICE_LIST_PAGE_SIZE_OPTIONS.includes(defaultSize) ? defaultSize : 50
50979
+ });
50723
50980
  }
50724
50981
  //#endregion
50725
50982
  //#region src/composites/device-item/helpers.ts
@@ -53017,6 +53274,29 @@ function groupTopLevelAndAccessories(devices, options) {
53017
53274
  };
53018
53275
  }
53019
53276
  //#endregion
53277
+ //#region src/composites/device-list/page-size-select.tsx
53278
+ function pageSizeLabel(size) {
53279
+ return size === 0 ? "All" : String(size);
53280
+ }
53281
+ function PageSizeSelect({ value, options, onChange, ariaLabel }) {
53282
+ return /* @__PURE__ */ jsxs("div", {
53283
+ className: "inline-flex items-center gap-1.5",
53284
+ children: [/* @__PURE__ */ jsx("span", {
53285
+ "aria-hidden": "true",
53286
+ children: "Per page"
53287
+ }), /* @__PURE__ */ jsx("select", {
53288
+ "aria-label": ariaLabel,
53289
+ value,
53290
+ onChange: (e) => onChange(Number.parseInt(e.target.value, 10)),
53291
+ className: "h-7 px-1.5 rounded-md border border-border bg-surface text-[11px] text-foreground focus:outline-none focus:ring-1 focus:ring-primary/40",
53292
+ children: options.map((opt) => /* @__PURE__ */ jsx("option", {
53293
+ value: opt,
53294
+ children: pageSizeLabel(opt)
53295
+ }, opt))
53296
+ })]
53297
+ });
53298
+ }
53299
+ //#endregion
53020
53300
  //#region src/composites/device-list/multi-select.tsx
53021
53301
  /**
53022
53302
  * Compact multi-select dropdown — a single chip-sized trigger ("Label · N")
@@ -53931,23 +54211,11 @@ function DeviceModeList(props) {
53931
54211
  totalItems,
53932
54212
  " ",
53933
54213
  totalItems === 1 ? "device" : "devices"
53934
- ] }), /* @__PURE__ */ jsxs("div", {
53935
- className: "inline-flex items-center gap-1.5",
53936
- children: [/* @__PURE__ */ jsx("span", {
53937
- "aria-hidden": "true",
53938
- children: "Per page"
53939
- }), /* @__PURE__ */ jsx("select", {
53940
- "aria-label": "Devices per page",
53941
- value: tablePageSize,
53942
- onChange: (e) => {
53943
- setTablePageSize(Number.parseInt(e.target.value, 10));
53944
- },
53945
- className: "h-7 px-1.5 rounded-md border border-border bg-surface text-[11px] text-foreground focus:outline-none focus:ring-1 focus:ring-primary/40",
53946
- children: DEVICE_LIST_PAGE_SIZE_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", {
53947
- value: opt,
53948
- children: opt
53949
- }, opt))
53950
- })]
54214
+ ] }), /* @__PURE__ */ jsx(PageSizeSelect, {
54215
+ ariaLabel: "Devices per page",
54216
+ value: tablePageSize,
54217
+ options: DEVICE_LIST_PAGE_SIZE_OPTIONS,
54218
+ onChange: setTablePageSize
53951
54219
  })]
53952
54220
  }), /* @__PURE__ */ jsx(Pagination, {
53953
54221
  currentPage: safePage,
@@ -53991,6 +54259,7 @@ function useDeviceListRealtimeSync() {
53991
54259
  }
53992
54260
  //#endregion
53993
54261
  //#region src/composites/device-list/generic-mode.tsx
54262
+ var FIXED_PAGE_SIZE = 100;
53994
54263
  /**
53995
54264
  * Generic render-prop list: search + pagination chrome shared with the device
53996
54265
  * list, over an arbitrary item type. Local (non-URL) state — intended for
@@ -53998,7 +54267,12 @@ function useDeviceListRealtimeSync() {
53998
54267
  * `renderItem`.
53999
54268
  */
54000
54269
  function GenericModeList(props) {
54001
- const { items, getKey, getSearchText, renderItem, getFilterType, mapFilterOption, filterOptions, filterLabel = "Type", initialTypeFilters = [], columns, renderExpanded, isExpanded, rowClassName, onRowClick, isLoading = false, searchPlaceholder = "Search", emptyLabel = "No items found.", pageSize = 100, toolbar } = props;
54270
+ const { items, getKey, getSearchText, renderItem, getFilterType, mapFilterOption, filterOptions, filterLabel = "Type", initialTypeFilters = [], columns, renderExpanded, isExpanded, rowClassName, onRowClick, isLoading = false, searchPlaceholder = "Search", emptyLabel = "No items found.", pageSize: fixedPageSize = FIXED_PAGE_SIZE, pageSizeSelector, toolbar } = props;
54271
+ const [chosenPageSize, setChosenPageSize] = usePersistedPageSize(pageSizeSelector ?? {
54272
+ storageKey: null,
54273
+ options: [fixedPageSize],
54274
+ defaultSize: fixedPageSize
54275
+ });
54002
54276
  const [searchInput, setSearchInput] = useState("");
54003
54277
  const debouncedSearch = useDebouncedString(searchInput, 300);
54004
54278
  const [typeFilters, setTypeFilters] = useState(() => [...initialTypeFilters]);
@@ -54047,6 +54321,7 @@ function GenericModeList(props) {
54047
54321
  getFilterType
54048
54322
  ]);
54049
54323
  const totalItems = filtered.length;
54324
+ const pageSize = pageSizeSelector ? effectivePageSize(chosenPageSize, totalItems) : fixedPageSize;
54050
54325
  const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
54051
54326
  const safePage = Math.min(page, totalPages);
54052
54327
  const startIdx = (safePage - 1) * pageSize;
@@ -54130,7 +54405,23 @@ function GenericModeList(props) {
54130
54405
  }),
54131
54406
  /* @__PURE__ */ jsx("div", {
54132
54407
  className: "shrink-0",
54133
- children: /* @__PURE__ */ jsx(Pagination, {
54408
+ children: pageSizeSelector && totalItems > 0 ? /* @__PURE__ */ jsxs("div", {
54409
+ className: "flex items-center justify-between gap-4 flex-wrap pt-2 text-[11px] text-foreground-subtle",
54410
+ children: [/* @__PURE__ */ jsxs("div", {
54411
+ className: "inline-flex items-center gap-2",
54412
+ children: [totalItems <= pageSize && /* @__PURE__ */ jsxs("span", { children: [totalItems, " total"] }), /* @__PURE__ */ jsx(PageSizeSelect, {
54413
+ ariaLabel: "Rows per page",
54414
+ value: chosenPageSize,
54415
+ options: pageSizeSelector.options,
54416
+ onChange: setChosenPageSize
54417
+ })]
54418
+ }), /* @__PURE__ */ jsx(Pagination, {
54419
+ currentPage: safePage,
54420
+ totalItems,
54421
+ pageSize,
54422
+ onPageChange: setPage
54423
+ })]
54424
+ }) : /* @__PURE__ */ jsx(Pagination, {
54134
54425
  currentPage: safePage,
54135
54426
  totalItems,
54136
54427
  pageSize,
@@ -54259,6 +54550,24 @@ var DeviceItemRowSchema = z.object({
54259
54550
  });
54260
54551
  var SupportedKindsSchema = z.array(z.string());
54261
54552
  var STATUS_POLL_INTERVAL_MS = 1e4;
54553
+ /** Where the viewer's "rows per page" choice for this table is remembered. */
54554
+ var DEVICE_EXPORT_PAGE_SIZE_KEY = "camstack.device-export.pageSize";
54555
+ /**
54556
+ * The exposed-devices table's page sizes. Its own key and options, not the
54557
+ * Devices page's (25/50/100/200, default 50): the operator asked for a short
54558
+ * default here (25) and an "All" for a quick scan of every exportable device.
54559
+ */
54560
+ var DEVICE_EXPORT_PAGE_SIZE = {
54561
+ options: [
54562
+ 10,
54563
+ 25,
54564
+ 50,
54565
+ 100,
54566
+ 0
54567
+ ],
54568
+ defaultSize: 25,
54569
+ storageKey: DEVICE_EXPORT_PAGE_SIZE_KEY
54570
+ };
54262
54571
  /**
54263
54572
  * The fleet-list poll. Deliberately the same 30 s as the window
54264
54573
  * `applyFleetQueryDefaults` registers for `deviceManager.listAll` (D274) —
@@ -54343,6 +54652,35 @@ function SetupSection({ setup }) {
54343
54652
  })]
54344
54653
  });
54345
54654
  }
54655
+ /** Parse `getStatus` against the canonical cap schema (loose wire output). */
54656
+ function parseStatus(data) {
54657
+ const parsed = DeviceExportStatusSchema.safeParse(data);
54658
+ return parsed.success ? parsed.data : null;
54659
+ }
54660
+ /**
54661
+ * The exporter's error and Setup block on their own — for a page that shows
54662
+ * them above its settings while the devices table sits at the bottom. Renders
54663
+ * nothing when the exporter reports neither. Shares `getStatus`'s query key
54664
+ * with the panel, so mounting both costs one request.
54665
+ */
54666
+ function DeviceExportSetup({ addonId }) {
54667
+ const statusQuery = useDeviceExportGetStatus({
54668
+ nodeId: "hub",
54669
+ addonId
54670
+ }, {
54671
+ refetchInterval: STATUS_POLL_INTERVAL_MS,
54672
+ retry: false
54673
+ });
54674
+ const status = useMemo(() => parseStatus(statusQuery.data), [statusQuery.data]);
54675
+ if (!status?.error && !status?.setup) return null;
54676
+ return /* @__PURE__ */ jsxs("div", {
54677
+ className: "rounded-lg border border-border bg-surface overflow-hidden",
54678
+ children: [status.error && /* @__PURE__ */ jsx("div", {
54679
+ className: "px-2 sm:px-4 py-3 border-b border-border",
54680
+ children: /* @__PURE__ */ jsx(ErrorBox, { message: status.error })
54681
+ }), status.setup && /* @__PURE__ */ jsx(SetupSection, { setup: status.setup })]
54682
+ });
54683
+ }
54346
54684
  /**
54347
54685
  * Per-row Expose/Exposed toggle. Reflects whether the row's device is exposed
54348
54686
  * to THIS exporter and flips it through the SAME runner the bulk buttons use —
@@ -54421,7 +54759,7 @@ function BulkSummary({ outcome, onDismiss }) {
54421
54759
  * Generic device-export panel. Addon-agnostic — only the `device-export`
54422
54760
  * cap drives it.
54423
54761
  */
54424
- function DeviceExportPanel({ addonId, onOpenDevice }) {
54762
+ function DeviceExportPanel({ addonId, onOpenDevice, showSetup = true }) {
54425
54763
  const queryClient = useQueryClient();
54426
54764
  const statusQuery = useDeviceExportGetStatus({
54427
54765
  nodeId: "hub",
@@ -54447,10 +54785,7 @@ function DeviceExportPanel({ addonId, onOpenDevice }) {
54447
54785
  }, [queryClient]);
54448
54786
  const exposeMutation = useDeviceExportExposeDevice({ onSuccess: invalidate });
54449
54787
  const unexposeMutation = useDeviceExportUnexposeDevice({ onSuccess: invalidate });
54450
- const status = useMemo(() => {
54451
- const parsed = DeviceExportStatusSchema.safeParse(statusQuery.data);
54452
- return parsed.success ? parsed.data : null;
54453
- }, [statusQuery.data]);
54788
+ const status = useMemo(() => parseStatus(statusQuery.data), [statusQuery.data]);
54454
54789
  const exposed = useMemo(() => {
54455
54790
  const parsed = ExposedDeviceArraySchema.safeParse(exposedQuery.data);
54456
54791
  return parsed.success ? parsed.data : [];
@@ -54673,11 +55008,11 @@ function DeviceExportPanel({ addonId, onOpenDevice }) {
54673
55008
  ]
54674
55009
  }), loading && /* @__PURE__ */ jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin text-foreground-subtle" })]
54675
55010
  }),
54676
- status?.error && /* @__PURE__ */ jsx("div", {
55011
+ showSetup && status?.error && /* @__PURE__ */ jsx("div", {
54677
55012
  className: "px-2 sm:px-4 py-3 border-b border-border",
54678
55013
  children: /* @__PURE__ */ jsx(ErrorBox, { message: status.error })
54679
55014
  }),
54680
- status?.setup && /* @__PURE__ */ jsx(SetupSection, { setup: status.setup }),
55015
+ showSetup && status?.setup && /* @__PURE__ */ jsx(SetupSection, { setup: status.setup }),
54681
55016
  outcome !== null && /* @__PURE__ */ jsx(BulkSummary, {
54682
55017
  outcome,
54683
55018
  onDismiss: dismissOutcome
@@ -54697,6 +55032,7 @@ function DeviceExportPanel({ addonId, onOpenDevice }) {
54697
55032
  columns,
54698
55033
  onRowClick: onOpenDevice ? onRowClick : void 0,
54699
55034
  toolbar: selectionToolbar,
55035
+ pageSizeSelector: DEVICE_EXPORT_PAGE_SIZE,
54700
55036
  searchPlaceholder: "Search by name or stableId",
54701
55037
  emptyLabel: "No device matches this search."
54702
55038
  }) : /* @__PURE__ */ jsx(EmptyState, {
@@ -54722,145 +55058,6 @@ function DeviceGrid({ children, minCardWidth = 220, gap = 3, className }) {
54722
55058
  });
54723
55059
  }
54724
55060
  //#endregion
54725
- //#region src/composites/icon-picker.tsx
54726
- /**
54727
- * icon-picker — the ONE control for choosing an icon, wherever admin-ui asks.
54728
- *
54729
- * There were two: a device one over `DISPLAY_ICON_REGISTRY` and a room one
54730
- * over `LOCATION_ICON_IDS`, identical apart from the vocabulary they walked.
54731
- * That was tolerable while the device set was 56 glyphs in a flat grid. It is
54732
- * not at 157: a picker that only lets the operator HUNT is a picker they stop
54733
- * using, and the two copies were already drifting — only one of them had an
54734
- * i18n'd label.
54735
- *
54736
- * So the vocabulary, the grouping and the search all come from
54737
- * `@camstack/types`' `display-icon-vocabulary`, which is the same module the
54738
- * viewer's sheet searches. What is left here is the web half: a popover, a
54739
- * grid, and a text field.
54740
- *
54741
- * ## What it does NOT own
54742
- *
54743
- * - **The glyphs.** `resolveGlyph` is a prop, because this package's table is
54744
- * `lucide-react` and the viewer's is `lucide-react-native`. A key this build
54745
- * cannot draw is SKIPPED rather than rendered as a hole — an empty tile
54746
- * reads as a rendering bug, not as a missing choice.
54747
- * - **The words.** Every string is a prop. This package has no i18n (one file
54748
- * in it imports react-i18next, and that is the exception), and a control
54749
- * that reached for a translation would force it on every consumer.
54750
- * - **The write.** `onPick` is called and that is all; whether it is a form
54751
- * value or an immediate mutation is the caller's business, as it already was
54752
- * in both pickers this replaces.
54753
- *
54754
- * ## The clear tile is never filtered away
54755
- *
54756
- * The "inherit" / "no icon" choice sits above the sections and ignores the
54757
- * search. A query that hid it would strand the operator on a glyph they picked
54758
- * by accident with no way back to the default — the one action a picker must
54759
- * always offer.
54760
- */
54761
- function IconPicker({ value, onPick, resolveGlyph, fallbackGlyph, labels, only, extraWords, clearGlyph, labelFor, disabled = false }) {
54762
- const [open, setOpen] = useState(false);
54763
- const [query, setQuery] = useState("");
54764
- const allowed = useMemo(() => only === void 0 ? null : new Set(only), [only]);
54765
- const sections = useMemo(() => {
54766
- const hits = searchDisplayIcons(query, extraWords);
54767
- const byGroup = /* @__PURE__ */ new Map();
54768
- for (const hit of hits) {
54769
- const { key, group } = hit.entry;
54770
- if (allowed !== null && !allowed.has(key)) continue;
54771
- if (resolveGlyph(key) === void 0) continue;
54772
- const bucket = byGroup.get(group);
54773
- if (bucket === void 0) byGroup.set(group, [key]);
54774
- else bucket.push(key);
54775
- }
54776
- return DISPLAY_ICON_GROUPS.flatMap((group) => {
54777
- const keys = byGroup.get(group);
54778
- return keys === void 0 || keys.length === 0 ? [] : [{
54779
- group,
54780
- keys
54781
- }];
54782
- });
54783
- }, [
54784
- query,
54785
- extraWords,
54786
- allowed,
54787
- resolveGlyph
54788
- ]);
54789
- const Current = (value === null ? void 0 : resolveGlyph(value)) ?? fallbackGlyph;
54790
- const choose = async (next) => {
54791
- setOpen(false);
54792
- setQuery("");
54793
- await onPick(next);
54794
- };
54795
- const Clear = clearGlyph ?? fallbackGlyph;
54796
- return /* @__PURE__ */ jsxs("div", {
54797
- className: "relative flex shrink-0 items-center gap-2",
54798
- children: [/* @__PURE__ */ jsx("button", {
54799
- type: "button",
54800
- disabled,
54801
- onClick: () => setOpen((o) => !o),
54802
- "aria-expanded": open,
54803
- "aria-label": labels.trigger,
54804
- title: labels.trigger,
54805
- className: "rounded border border-border p-1 text-foreground-muted hover:bg-surface-hover disabled:opacity-50",
54806
- children: /* @__PURE__ */ jsx(Current, { className: "h-4 w-4" })
54807
- }), open && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
54808
- type: "button",
54809
- "aria-label": labels.close,
54810
- onClick: () => setOpen(false),
54811
- className: "fixed inset-0 z-10 cursor-default"
54812
- }), /* @__PURE__ */ jsxs("div", {
54813
- role: "group",
54814
- "aria-label": labels.panel,
54815
- 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",
54816
- children: [
54817
- /* @__PURE__ */ jsx("input", {
54818
- type: "search",
54819
- value: query,
54820
- autoFocus: true,
54821
- onChange: (e) => setQuery(e.target.value),
54822
- placeholder: labels.searchPlaceholder,
54823
- "aria-label": labels.searchPlaceholder,
54824
- className: "mb-2 w-full rounded border border-border bg-surface-raised px-2 py-1 text-xs text-foreground placeholder:text-foreground-subtle"
54825
- }),
54826
- /* @__PURE__ */ jsxs("button", {
54827
- type: "button",
54828
- onClick: () => void choose(null),
54829
- "aria-pressed": value === null,
54830
- 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",
54831
- children: [/* @__PURE__ */ jsx(Clear, { className: "h-3.5 w-3.5" }), labels.clear]
54832
- }),
54833
- sections.length === 0 ? /* @__PURE__ */ jsx("p", {
54834
- className: "px-1.5 py-2 text-[11px] text-foreground-subtle",
54835
- children: labels.noMatches
54836
- }) : sections.map(({ group, keys }) => /* @__PURE__ */ jsxs("section", {
54837
- className: "mb-2 last:mb-0",
54838
- children: [/* @__PURE__ */ jsx("h4", {
54839
- className: "px-1.5 pb-1 text-[10px] uppercase tracking-wide text-foreground-subtle",
54840
- children: labels.groups[group]
54841
- }), /* @__PURE__ */ jsx("div", {
54842
- className: "grid grid-cols-7 gap-1",
54843
- children: keys.map((key) => {
54844
- const Glyph = resolveGlyph(key);
54845
- if (Glyph === void 0) return null;
54846
- const selected = value === key;
54847
- return /* @__PURE__ */ jsx("button", {
54848
- type: "button",
54849
- onClick: () => void choose(key),
54850
- "aria-pressed": selected,
54851
- "aria-label": labelFor?.(key) ?? key,
54852
- title: labelFor?.(key) ?? key,
54853
- 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",
54854
- children: /* @__PURE__ */ jsx(Glyph, { className: "h-4 w-4" })
54855
- }, key);
54856
- })
54857
- })]
54858
- }, group))
54859
- ]
54860
- })] })]
54861
- });
54862
- }
54863
- //#endregion
54864
55061
  //#region src/composites/device-selector-picker.tsx
54865
55062
  /**
54866
55063
  * <DeviceSelectorPicker> — the operator-facing editor for a v3
@@ -60994,4 +61191,4 @@ var SceneMonitorEditor = lazy(() => import("./SceneMonitorEditor-vfWTm6qv.js").t
60994
61191
  /** Lazy-wrapped `PrivacyMaskSettings` — code-split off the main bundle. */
60995
61192
  var PrivacyMaskSettings = lazy(() => import("./PrivacyMaskSettings-DMkchqO1.js").then((m) => ({ default: m.PrivacyMaskSettings })));
60996
61193
  //#endregion
60997
- export { AddonGlobalSettingsForm, AdminLinkQuickAction, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, BackToStepsButton, 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, ConfigNotificationTargetMultiSelectFieldView, ConfigNotificationTargetSelectFieldView, 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_PICKER_GROUP_STORAGE_KEY, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DataTableFilterBar, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceFilterBar, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DevicePicker, DeviceQuickDetailProvider, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, DevicesFailedLine, DevicesLoadingLine, DevicesWidenWarning, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EMPTY_DATA_TABLE_FILTER, EVENT_KIND_ICONS, EmptyState, EndpointResultsCard, EndpointTestCard, ErrorBox, EventKindGlyph, EventStream, ExtensionsPanel, 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, GateBadge, GateControl, GripTrack, GroupedModelSelector, HOST_WIDGETS, HUB_SESSION_RUN_MS, HlsVideo, HoverZoomImage, HubSessionTestCard, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, INPUT_SHELL, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LayeredSettingsForm, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NatResultCard, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, NotificationTargetSelectField, NotificationTargetsField, OPTION_SELECT_SEARCH_MIN_OPTIONS, OfflineBadge, OptionSelect, PHASE_CONFIG, PICKER_CHIP_LIMIT, PICKER_DEFAULT_GROUP_BY, PICKER_GROUP_BY_MODES, PICKER_GROUP_COLLAPSE_AT, PICKER_NONE_KEY, PICKER_NOUN_PLURAL, PICKER_NO_FILTERS, PICKER_PAGE_SIZE, PICKER_SEARCH_DEBOUNCE_MS, PICKER_WINDOW, PRIORITY, PTZOverlay, PageHeader, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PlaceholderChipField, 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, RootModelSourceControl, RootSuppliedModelNote, RunReport, 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, STEP_DOCK_WIDTH_PX, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, SectionCard, SegmentedChoice, Select, SelectedChip, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepDetailDock, StepInspectorPanel, StepModelRow, StepTimings, 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, UnitPicker, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, MicOff as a, acceleratorLabel, acceleratorShortLabel, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, applyPickerFilters, ariaSortForColumn, badgeFor, bindsToModel, buildPeerConnectionConfig, buildStepTreeFromSchema, EyeOff as c, catalogHasDraft, childEntityId, childListName, chipOverflow, classifyAddressScope, classifyCapability, classifySessionVerdict, clearPickerGroup, cn, columnsForContext, compareSrflxMappings, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, dataTableFacets, defaultOfField, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceIntegrationResolver, deviceListStateOf, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, dockBox, draftFromQuery, emptyDevicesWidens, emptySessionRun, ensureMfHostInit, eventKindLabel, filterDataTableRows, filterDeviceOptions, filterOptions as filterOptionSelectOptions, filterPickerDevices, finalizeSessionRun, findTimezone, flattenPickerGrouping, flattenPickerRows, fleetViewOf, formatControlDateTime, formatLastSeen, formatNumeric, formatSettingValue, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, groupPickerDevices, groupPickerDevicesBy, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, insertAtSelection, isAbsentProvider, isDataTableFilterActive, isFieldVisible, isGroupExpanded, isValueField, Camera as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextGridPosition, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, ImageOff as o, offListSelections, openTopLayer, optionSearchText as optionSelectSearchText, orphanDeviceLabel, overrideEntityIdFromLink, pageRows, parentDetailOf, parseIceCandidate, parsePickerGroupBy, parseRecordedServerMessage, partitionSelected as partitionOptionSelectSelected, partitionSuggested, pickerFacetFilterShown, pickerFacetKey, pickerFacetOptions, pickerFiltersActive, pickerGroupKey, pickerHiddenSelectedCount, pickerLocationKey, pickerQueryTokens, pickerRowFacts, pickerSearchText, pickerZoneFilterSuspended, pinnedStreamChoices, providerIcons, RotateCcw as r, readStoredGroupBy, reduceSessionRun, resetHubMountForTests, resetPickerFilters, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDeviceIntegration, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolveSearchable as resolveOptionSelectSearchable, resolveParentNames, resolvePrimaryChild, resolveSelectedDevices, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, rootSourceState, routerBasename, Grid2x2 as s, sameLocationSuggestions, scrubReducer, searchSteps, selectPickerGroup, selectedDeviceOptions, serializeRecordedCommand, settingsModelIdFor, shouldCommit, shouldEmit, shouldShowAddNewFooter, shouldShowUseQueryRow, shouldUseSingleNode, showsNoCamerasHint, sortRows, sortRowsByColumn, statusIcons, statusLine, stepFieldDomId, stepHasModelForFormat, stepLocalFields, stepModelOptions, stripParentNamePrefix, summarizeHubCandidates, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, toggleDataTableFacet, togglePickerDevice, togglePickerKey, trpc, typeLabel, 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, useCalendarsGetPreferences, useCalendarsListCalendars, useCalendarsListEvents, useCalendarsSetCalendarPreference, 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, useCoreBlocksCreateComposition, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetBlockSettings, useCoreBlocksGetComposition, useCoreBlocksGetCustomization, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksListComposableCaps, useCoreBlocksListCompositions, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoreBlocksUpdateBlockSettings, useCoreBlocksUpdateComposition, useCoreBlocksValidateComposition, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderGetInfo, useDecoderReprobeHwaccel, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdminLink, useDeviceAdminLinkGetAdminLink, 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, useDeviceExtensionListCandidates, useDeviceExtensionListSlots, useDeviceExtensionListSources, useDeviceExtensionSetSlot, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerGetWrapperActivation, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListDeviceIdsByCaps, 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, useDeviceQuickDetailOpen, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateClaimFields, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetNativeCapSlice, useDeviceStateGetSnapshot, useDeviceStateListClaims, useDeviceStatePatchOwnedFields, useDeviceStateReleaseClaim, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellEvents, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, 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, useLocalNetworkAddCustomAddress, useLocalNetworkDownloadCa, useLocalNetworkGetAddresses, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetHubAddresses, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkRemoveCustomAddress, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAddressRole, 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, useNodesDirectory, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputGetTarget, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputProbeTargetConfig, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesActivateAlarmProfile, useNotificationRulesCancelSnooze, useNotificationRulesCreateAlarmProfile, useNotificationRulesCreateRule, useNotificationRulesCreateSequence, useNotificationRulesCreateSnooze, useNotificationRulesDeleteAlarmProfile, useNotificationRulesDeleteRule, useNotificationRulesDeleteSequence, useNotificationRulesGetAlarmConfig, useNotificationRulesGetAlarmSensors, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesGetRuleLastRuns, useNotificationRulesGetSequence, useNotificationRulesGetTemplateCatalog, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSequences, useNotificationRulesListSnoozes, useNotificationRulesPreviewStateSummary, useNotificationRulesPreviewTemplate, useNotificationRulesRenameAlarmProfile, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotificationRulesUpdateSequence, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerDeleteTemplate, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerListTemplates, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdManagerUpsertTemplate, useOsdSetOverlay, usePTZ, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePickerSiteZones, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTrackRelation, 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, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTrackRelations, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsSetTrackPurity, usePipelineAnalyticsSetTrackRelation, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorClearModelBoundDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyAutoTune, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetClusterModelChoice, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetEffectiveShares, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetPlacementStats, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorPlanAutoTune, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorRequestOccupancyLook, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraSensors, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepSettings, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetLoadBalancingShares, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorSetShareSource, usePipelineOrchestratorSuggestShares, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, 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, useRecordingArchiveApplyDeviceSettingsPatch, useRecordingArchiveCancelRelocateJob, useRecordingArchiveCancelStorageMigrationMove, useRecordingArchiveDeleteFootprint, useRecordingArchiveGetAvailabilityBatch, useRecordingArchiveGetDaysWithRecordingsBatch, useRecordingArchiveGetDeviceConfig, useRecordingArchiveGetDeviceLiveContribution, useRecordingArchiveGetDeviceSettingsContribution, useRecordingArchiveGetPlacement, useRecordingArchiveGetRelocateResidue, useRecordingArchiveGetStatus, useRecordingArchiveGetStorageMigrationMoveStatus, useRecordingArchiveGetStorageUsage, useRecordingArchiveListOpsLog, useRecordingArchiveListRelocateJobs, useRecordingArchiveLocateSegment, useRecordingArchivePauseForStorageMigration, useRecordingArchivePlanStorageRebalance, useRecordingArchivePruneFootage, useRecordingArchiveReadGopBytes, useRecordingArchiveReadSegmentBytes, useRecordingArchiveReadWindowBytes, useRecordingArchiveReconcileLedgerAgainstDisk, useRecordingArchiveRefreshStorageLocationsForMigration, useRecordingArchiveRelocateFootage, useRecordingArchiveRenderClip, useRecordingArchiveRenderGif, useRecordingArchiveRescanStorage, useRecordingArchiveResumeForStorageMigration, useRecordingArchiveSetDeviceConfig, useRecordingArchiveSetDevicePlacement, useRecordingArchiveStartStorageMigrationMove, useRecordingArchiveStartStorageRebalance, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetDaysWithRecordings, useRecordingGetPlayback, useRecordingGetPlaybackOptions, useRecordingListSources, useRecordingOnboardGetOptions, useRecordingOnboardGetStatus, useRecordingOnboardSetSettings, useRecordingSignalGetStatus, 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, useStoredGroupBy, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, 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, useUrlQueryParam, 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, useVideoclipsGetPlaybackOptions, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsOfferClipBytes, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionApplyDownlinkProbe, 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, withResolvedParentDetail, withUseRootModel, writeStoredGroupBy };
61194
+ export { AddonGlobalSettingsForm, AdminLinkQuickAction, AgentStepEditor, AlarmHeroCard, AlarmInlineControl as AlarmPanelInlineControl, AppShell, ArcKnob, AudioClassificationList, AudioLevelWaveform, AudioWaveform, AutomationHeroCard, AutomationInlineControl, AutotrackSection, BTN_COMPACT, BTN_COMPACT_DANGER, BTN_COMPACT_PRIMARY, BTN_COMPACT_WARNING, BackToStepsButton, 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, ConfigNotificationTargetMultiSelectFieldView, ConfigNotificationTargetSelectFieldView, ConfigSchemaField, ConfirmActionButton, ConfirmDialogProvider, ConsumablesPanel, ContainerChildrenProvider, ContainerPrimaryHero, ControlColumn, ControlHeroCard, ControlInlineControl, ControlPanel, CopyButton, CoverHeroCard, CoverInlineControl, CoverPanel, CustomFieldRenderersProvider, DEFAULT_COLOR, DEVICE_COLUMNS, DEVICE_EXPORT_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_KEY, DEVICE_LIST_PAGE_SIZE_OPTIONS, DEVICE_PICKER_GROUP_STORAGE_KEY, DEVICE_ROLE_META, DEVICE_TYPE_CONTROL, DEVICE_TYPE_META, DISPLAY_ICON_REGISTRY, DataTable, DataTableFilterBar, DetectionCanvas, DetectionOverlay, DetectionResultTree, DevShell, DeviceActivityPanel, DeviceBatchToolbar, DeviceCard, DeviceContextProvider, DeviceExportPanel, DeviceExportSetup, DeviceFilterBar, DeviceGrid, DeviceItem, DeviceList, DeviceMultiSelectField, DevicePicker, DeviceQuickDetailProvider, DeviceSelectField, DeviceSelectorPicker, DeviceStepMatrix, DevicesFailedLine, DevicesLoadingLine, DevicesWidenWarning, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DiscoveryPanel, DoorbellRecentPanel, Dropdown, DropdownContent, DropdownItem, DropdownTrigger, DummyHeroCard, DummyInline, EMPTY_DATA_TABLE_FILTER, EVENT_KIND_ICONS, EmptyState, EndpointResultsCard, EndpointTestCard, ErrorBox, EventKindGlyph, EventStream, ExtensionsPanel, 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, GateBadge, GateControl, GripTrack, GroupedModelSelector, HOST_WIDGETS, HUB_SESSION_RUN_MS, HlsVideo, HoverZoomImage, HubSessionTestCard, HumidifierHeroCard, HumidifierInlineControl, INPUT_COMPACT, INPUT_SHELL, IconAction, IconButton, IconPicker, ImageHeroCard, ImageInlineControl, ImageSelector, InferenceConfigSelector, Input, KebabMenu, KeyValueList, LIST_ROW, Label, LawnMowerHeroCard, LawnMowerInlineControl, LayeredSettingsForm, LightHeroCard, LightInlineControl, LockHeroCard, LockInlineControl, LockPanel, LogStream, LoginForm, MODE_COLOR, MaskShapeCanvas, MediaPlayerHeroCard, MediaPlayerInlineControl, MediaPlayerPanel, MobileDrawer, ModelPicker, MotionZonesSettings, NAVIGATION_DRIVE_INTERVAL_MS, NatResultCard, NavigationPanel, NetworkLinkBadge, NodeMultiSelectField, NodePicker, NodeSelectField, NotificationTargetSelectField, NotificationTargetsField, OPTION_SELECT_SEARCH_MIN_OPTIONS, OfflineBadge, OptionSelect, PAGE_SIZE_ALL, PHASE_CONFIG, PICKER_CHIP_LIMIT, PICKER_DEFAULT_GROUP_BY, PICKER_GROUP_BY_MODES, PICKER_GROUP_COLLAPSE_AT, PICKER_NONE_KEY, PICKER_NOUN_PLURAL, PICKER_NO_FILTERS, PICKER_PAGE_SIZE, PICKER_SEARCH_DEBOUNCE_MS, PICKER_WINDOW, PRIORITY, PTZOverlay, PageHeader, PageSizeSelect, PhaseIcon, PipelineBuilder, PipelineRuntimeSelector, PipelineStep, PlaceholderChipField, 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, RootModelSourceControl, RootSuppliedModelNote, RunReport, 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, STEP_DOCK_WIDTH_PX, SceneMonitorEditor, ScopePicker, ScriptHeroCard, ScriptInlineControl, ScrollArea, SectionCard, SegmentedChoice, Select, SelectedChip, SemanticBadge, SensorHeroCard, SensorInlineControl, SensorValueAtom, Separator, SettingRow, Sidebar, SidebarItem, Skeleton, SlideToggle, SnapshotButton, SortHeaderButton, StatCard, StateValuesStream, StatusBadge, StepDetailDock, StepInspectorPanel, StepModelRow, StepTimings, 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, UnitPicker, VacuumHeroCard, VacuumInlineControl, ValueReadout, ValveHeroCard, ValveInlineControl, VersionBadge, VodPlaybackProvider, WaterHeaterHeroCard, WaterHeaterInlineControl, WeatherHeroCard, WeatherInlineControl, WidgetMetricCard, WidgetPanel, WidgetRegistryProvider, WidgetSlot, ZoneEditingProvider, MicOff as a, acceleratorLabel, acceleratorShortLabel, agentColumnKey, allDeviceTypeFilterOptions, applyFleetQueryDefaults, applyPickerFilters, ariaSortForColumn, badgeFor, bindsToModel, buildPeerConnectionConfig, buildStepTreeFromSchema, EyeOff as c, catalogHasDraft, childEntityId, childListName, chipOverflow, classifyAddressScope, classifyCapability, classifySessionVerdict, clearPickerGroup, cn, columnsForContext, compareSrflxMappings, containerChildToRef, countableDevices, coverHighlight, coverageLine, createSharedContext, createTheme, cursorFractionFor, darkColors, dataTableFacets, defaultOfField, defaultTheme, deriveDeviceKind, deriveWebrtcDebugStats, describeDeviceSelector, deviceIntegrationResolver, deviceListStateOf, deviceMatchesFilter, deviceOptionLabel, deviceRoleMeta, deviceRoleMetaOf, deviceTypeLabel, deviceTypeMeta, deviceTypeMetaOf, devicesToOptions, dockBox, draftFromQuery, effectivePageSize, emptyDevicesWidens, emptySessionRun, ensureMfHostInit, eventKindLabel, filterDataTableRows, filterDeviceOptions, filterOptions as filterOptionSelectOptions, filterPickerDevices, finalizeSessionRun, findTimezone, flattenPickerGrouping, flattenPickerRows, fleetViewOf, formatControlDateTime, formatLastSeen, formatNumeric, formatSettingValue, freezeVerdict, fuzzyMatch, getClassColor, getPhaseVisual, groupAgentColumns, groupChildrenByLayout, groupPickerDevices, groupPickerDevicesBy, hardwareLabel, hubOrigin, hubPath, hubUrl, hubWsUrl, humanDuration, humidifierTint, Mic as i, initialScrubState, insertAtSelection, isAbsentProvider, isDataTableFilterActive, isFieldVisible, isGroupExpanded, isValueField, Camera as l, lawnMowerActivityMeta, lightColors, loadRemoteBundle, makeScrubBridge, metadataEntries, metadataString, mirror, mountAddonPage, mountPath, Square as n, nextGridPosition, nextReconnectAction, nextSort, nextSortDirection, nextTableSort, normalizeForSearch, ImageOff as o, offListSelections, openTopLayer, optionSearchText as optionSelectSearchText, orphanDeviceLabel, overrideEntityIdFromLink, pageRows, pageSizeLabel, parentDetailOf, parseIceCandidate, parsePickerGroupBy, parseRecordedServerMessage, partitionSelected as partitionOptionSelectSelected, partitionSuggested, pickerFacetFilterShown, pickerFacetKey, pickerFacetOptions, pickerFiltersActive, pickerGroupKey, pickerHiddenSelectedCount, pickerLocationKey, pickerQueryTokens, pickerRowFacts, pickerSearchText, pickerZoneFilterSuspended, pinnedStreamChoices, providerIcons, RotateCcw as r, readStoredGroupBy, reduceSessionRun, resetHubMountForTests, resetPickerFilters, resolveContainerPrimary, resolveControlAlign, resolveDeviceControl, resolveDeviceIntegration, resolveDisplayIcon, resolveEffectiveDefaultModel, resolveEffectiveStepModel, resolveEventKindIcon, resolveSearchable as resolveOptionSelectSearchable, resolveParentNames, resolvePrimaryChild, resolveSelectedDevices, resolveSensorDisplay, resolveStepDefaultModel, resolveTableLayout, roiTooLarge, rootSourceState, routerBasename, Grid2x2 as s, sameLocationSuggestions, scrubReducer, searchSteps, selectPickerGroup, selectedDeviceOptions, serializeRecordedCommand, settingsModelIdFor, shouldCommit, shouldEmit, shouldShowAddNewFooter, shouldShowUseQueryRow, shouldUseSingleNode, showsNoCamerasHint, sortRows, sortRowsByColumn, statusIcons, statusLine, stepFieldDomId, stepHasModelForFormat, stepLocalFields, stepModelOptions, stripParentNamePrefix, summarizeHubCandidates, Trash2 as t, tabForSelector, tankAlert, themeToCss, toStationaryOverlayBox, toggleDataTableFacet, togglePickerDevice, togglePickerKey, trpc, typeLabel, 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, useAddonsListInstallations, 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, useCalendarsGetPreferences, useCalendarsListCalendars, useCalendarsListEvents, useCalendarsSetCalendarPreference, 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, useCoreBlocksCreateComposition, useCoreBlocksDelete, useCoreBlocksGet, useCoreBlocksGetBlockSettings, useCoreBlocksGetComposition, useCoreBlocksGetCustomization, useCoreBlocksGetTypeDefs, useCoreBlocksList, useCoreBlocksListComposableCaps, useCoreBlocksListCompositions, useCoreBlocksRestart, useCoreBlocksSetEnabled, useCoreBlocksUpdate, useCoreBlocksUpdateBlockSettings, useCoreBlocksUpdateComposition, useCoreBlocksValidateComposition, useCoverClose, useCoverGetStatus, useCoverOpen, useCoverSetPosition, useCoverSetTiltPosition, useCoverStop, useCustomFieldRenderer, useDataTableFilter, useDayNightGetOptions, useDayNightGetStatus, useDayNightSetSettings, useDebouncedString, useDecoderGetInfo, useDecoderReprobeHwaccel, useDetectionPipelineApplyDeviceSettingsPatch, useDetectionPipelineGetDeviceLiveContribution, useDetectionPipelineGetDeviceSettingsContribution, useDevShell, useDevice, useDeviceAdminLink, useDeviceAdminLinkGetAdminLink, 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, useDeviceExtensionListCandidates, useDeviceExtensionListSlots, useDeviceExtensionListSources, useDeviceExtensionSetSlot, useDeviceId, useDeviceListPageSize, useDeviceManagerAddLocation, useDeviceManagerAdoptDevice, useDeviceManagerAdoptionAdopt, useDeviceManagerAdoptionCancelJob, useDeviceManagerAdoptionListCandidateFilters, useDeviceManagerAdoptionListCandidates, useDeviceManagerAdoptionListJobs, useDeviceManagerAdoptionRefresh, useDeviceManagerAdoptionRelease, useDeviceManagerAdoptionResync, useDeviceManagerAdoptionStartJob, useDeviceManagerAllocateDeviceId, useDeviceManagerApplyInitialMeta, useDeviceManagerCreateDevice, useDeviceManagerDisable, useDeviceManagerDiscoverAllProviders, useDeviceManagerDiscoverDevices, useDeviceManagerDiscoverProvider, useDeviceManagerDiscoveryProviders, useDeviceManagerEnable, useDeviceManagerGetAllBindings, useDeviceManagerGetBindings, useDeviceManagerGetBindingsBatch, useDeviceManagerGetChildren, useDeviceManagerGetChildrenBatch, useDeviceManagerGetConfigSchema, useDeviceManagerGetCreationSchema, useDeviceManagerGetDevice, useDeviceManagerGetDeviceAggregate, useDeviceManagerGetDeviceLiveInfoAggregate, useDeviceManagerGetDeviceSettingsAggregate, useDeviceManagerGetDeviceStatusAggregate, useDeviceManagerGetDeviceStatusAggregateBatch, useDeviceManagerGetLinkedDevices, useDeviceManagerGetLinkedDevicesBatch, useDeviceManagerGetRoleDisplayDefaults, useDeviceManagerGetSettingsSchema, useDeviceManagerGetStreamProfileMap, useDeviceManagerGetStreamSources, useDeviceManagerGetWireableFields, useDeviceManagerGetWrapperActivation, useDeviceManagerListAll, useDeviceManagerListBindableCapsForDeviceType, useDeviceManagerListDeviceIdsByCaps, 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, useDeviceQuickDetailOpen, useDeviceSnapshot, useDeviceSnapshotImage, useDeviceState, useDeviceStateClaimFields, useDeviceStateGetAllSnapshots, useDeviceStateGetCapSlice, useDeviceStateGetNativeCapSlice, useDeviceStateGetSnapshot, useDeviceStateListClaims, useDeviceStatePatchOwnedFields, useDeviceStateReleaseClaim, useDeviceStateSetCapSlice, useDeviceStateSlice, useDeviceStatusGetStatus, useDeviceWebrtc, useDevices, useDoorbellEvents, useDoorbellGetStatus, useEnumSensorGetStatus, useEventEmitterGetStatus, useEventInvalidation, useEventStreamLatest, useEventStreamMap, 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, useLocalNetworkAddCustomAddress, useLocalNetworkDownloadCa, useLocalNetworkGetAddresses, useLocalNetworkGetAllowedAddresses, useLocalNetworkGetConnectionEndpoints, useLocalNetworkGetHubAddresses, useLocalNetworkGetNotificationEndpoint, useLocalNetworkGetPreferred, useLocalNetworkGetTlsStatus, useLocalNetworkGetViewerEndpoints, useLocalNetworkList, useLocalNetworkRegenerateCertificate, useLocalNetworkRemoveCustomAddress, useLocalNetworkResetAllowlistToBestMatch, useLocalNetworkRevertToGeneratedCertificate, useLocalNetworkSetAddressRole, 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, useNodesDirectory, useNodesExecuteQuery, useNodesGetCapUsageGraph, useNodesGetNodeAddons, useNodesRenameNode, useNodesRestartAddon, useNodesRestartNode, useNodesRestartProcess, useNodesSetProcessLogLevel, useNodesShutdownNode, useNodesTopology, useNodesUndeployAddon, useNotificationOutputDeleteTarget, useNotificationOutputDiscoverTargets, useNotificationOutputGetTarget, useNotificationOutputListTargetKinds, useNotificationOutputListTargets, useNotificationOutputProbeTargetConfig, useNotificationOutputSend, useNotificationOutputSetTargetEnabled, useNotificationOutputTestTarget, useNotificationOutputUpsertTarget, useNotificationRulesActivateAlarmProfile, useNotificationRulesCancelSnooze, useNotificationRulesCreateAlarmProfile, useNotificationRulesCreateRule, useNotificationRulesCreateSequence, useNotificationRulesCreateSnooze, useNotificationRulesDeleteAlarmProfile, useNotificationRulesDeleteRule, useNotificationRulesDeleteSequence, useNotificationRulesGetAlarmConfig, useNotificationRulesGetAlarmSensors, useNotificationRulesGetClipRetentionAsks, useNotificationRulesGetConditionCatalog, useNotificationRulesGetHistory, useNotificationRulesGetRule, useNotificationRulesGetRuleLastRuns, useNotificationRulesGetSequence, useNotificationRulesGetTemplateCatalog, useNotificationRulesListDeviceMutes, useNotificationRulesListRules, useNotificationRulesListSequences, useNotificationRulesListSnoozes, useNotificationRulesPreviewStateSummary, useNotificationRulesPreviewTemplate, useNotificationRulesRenameAlarmProfile, useNotificationRulesResolveArtifactUrl, useNotificationRulesSetAlarmConfig, useNotificationRulesSetDeviceMuted, useNotificationRulesSetRuleEnabled, useNotificationRulesTestRule, useNotificationRulesUpdateRule, useNotificationRulesUpdateSequence, useNotifierCancel, useNotifierGetStatus, useNotifierSend, useNumericSensorGetStatus, useOptimisticSlice, useOptionalSystem, useOptionalWidgetRegistry, useOsdGetStatus, useOsdManagerClearSlotBinding, useOsdManagerCopyDeviceConfiguration, useOsdManagerDeleteTemplate, useOsdManagerGetConditionSupport, useOsdManagerGetDeviceOsd, useOsdManagerGetSourceCatalog, useOsdManagerListTemplates, useOsdManagerPreviewSlot, useOsdManagerRenderDevice, useOsdManagerSetSlotBinding, useOsdManagerUpsertTemplate, useOsdSetOverlay, usePTZ, usePersistedPageSize, usePetFeederCallPet, usePetFeederCancelFeed, usePetFeederFeed, usePetFeederGetStatus, usePetFeederMarkFoodReplenished, usePetFeederPlaySound, usePetFeederResetDesiccant, usePetFeederSetChildLock, usePetFeederSetFeedSound, usePetFeederSetIndicatorLight, usePetFeederSetVolume, usePickerSiteZones, usePipelineAnalyticsApplyDeviceSettingsPatch, usePipelineAnalyticsCancelRelocateMedia, usePipelineAnalyticsCancelStorageMigrationMove, usePipelineAnalyticsClearTrackRelation, 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, usePipelineAnalyticsGetTrack, usePipelineAnalyticsGetTrackMedia, usePipelineAnalyticsGetTrainingExportSummary, usePipelineAnalyticsGetTrainingExportUrl, usePipelineAnalyticsListArchivedDebugNotes, usePipelineAnalyticsListBirthDecisions, usePipelineAnalyticsListEventKinds, usePipelineAnalyticsListEventKindsBatch, usePipelineAnalyticsListEventMedia, usePipelineAnalyticsListOpsLog, usePipelineAnalyticsListRecentTracks, usePipelineAnalyticsListRelocateMediaJobs, usePipelineAnalyticsListRetrainAnnotations, usePipelineAnalyticsListRetrainFrames, usePipelineAnalyticsListRetrainStaging, usePipelineAnalyticsListTrackMedia, usePipelineAnalyticsListTrackRelations, usePipelineAnalyticsListTracks, usePipelineAnalyticsOwnersWithMedia, usePipelineAnalyticsPauseForStorageMigration, usePipelineAnalyticsProposeRetrainAnnotations, usePipelineAnalyticsPruneEvents, usePipelineAnalyticsPruneEventsBefore, usePipelineAnalyticsPruneTracksBefore, usePipelineAnalyticsReadLongTermSeries, usePipelineAnalyticsRebuildObjectEmbeddings, usePipelineAnalyticsReclaimDebugMedia, usePipelineAnalyticsReconcileFromDisk, usePipelineAnalyticsRefreshStorageLocationsForMigration, usePipelineAnalyticsRelocateMedia, usePipelineAnalyticsRestageRetrainTrack, usePipelineAnalyticsResumeForStorageMigration, usePipelineAnalyticsSaveRetrainAnnotations, usePipelineAnalyticsSearchObjectEvents, usePipelineAnalyticsSelectRetrainFrames, usePipelineAnalyticsSetRetrainFrameComplete, usePipelineAnalyticsSetTrackFlags, usePipelineAnalyticsSetTrackPurity, usePipelineAnalyticsSetTrackRelation, usePipelineAnalyticsStartStorageMigrationMove, usePipelineAnalyticsWipeAllAnalytics, usePipelineAnalyticsWipeObjectEmbeddings, usePipelineAnalyticsWriteRetrainArchive, usePipelineExecutorCacheFrameInPool, usePipelineExecutorClearDeviceOverrides, usePipelineExecutorClearModelBoundDeviceOverrides, usePipelineExecutorDeleteModel, usePipelineExecutorDownloadModel, usePipelineExecutorGetAddonModels, usePipelineExecutorGetAudioCapabilities, usePipelineExecutorGetAvailableEngines, usePipelineExecutorGetCapabilities, usePipelineExecutorGetDefaultSteps, usePipelineExecutorGetDetectionConfigSchema, usePipelineExecutorGetEffectiveTuning, usePipelineExecutorGetEngineProvisioning, usePipelineExecutorGetGlobalPipelineConfig, usePipelineExecutorGetGlobalSteps, usePipelineExecutorGetInferenceDeviceHealth, usePipelineExecutorGetOrchestratorConfigSchema, usePipelineExecutorGetReferenceAudio, usePipelineExecutorGetReferenceAudioFiles, usePipelineExecutorGetReferenceImage, usePipelineExecutorGetSchema, usePipelineExecutorGetSelectedEngine, usePipelineExecutorGetVideoPipelineSteps, usePipelineExecutorInferCached, usePipelineExecutorKillEngine, usePipelineExecutorListLoadedEngines, usePipelineExecutorListReferenceImages, usePipelineExecutorRearmInferenceDevice, usePipelineExecutorRunAudioTest, usePipelineExecutorRunPipeline, usePipelineExecutorRunPipelineBatch, usePipelineExecutorSetVideoPipelineSteps, usePipelineExecutorSpinEngine, usePipelineExecutorUncacheFrame, usePipelineExecutorValidatePipeline, usePipelineOrchestratorApplyAutoTune, usePipelineOrchestratorApplyDeviceSettingsPatch, usePipelineOrchestratorAssignAudio, usePipelineOrchestratorAssignPipeline, usePipelineOrchestratorGetAgentLoad, usePipelineOrchestratorGetAgentSettings, usePipelineOrchestratorGetAudioAssignment, usePipelineOrchestratorGetAudioAssignments, usePipelineOrchestratorGetAudioNodeLoad, usePipelineOrchestratorGetCameraMetrics, usePipelineOrchestratorGetCameraSettings, usePipelineOrchestratorGetCameraStatus, usePipelineOrchestratorGetCameraStatuses, usePipelineOrchestratorGetCameraStepOverrides, usePipelineOrchestratorGetCameraSwitches, usePipelineOrchestratorGetCapabilityBindings, usePipelineOrchestratorGetClusterModelChoice, usePipelineOrchestratorGetDeviceLiveContribution, usePipelineOrchestratorGetDeviceSettingsContribution, usePipelineOrchestratorGetEffectiveShares, usePipelineOrchestratorGetGlobalMetrics, usePipelineOrchestratorGetIngestOwner, usePipelineOrchestratorGetNodeInferenceDevices, usePipelineOrchestratorGetPipelineAssignment, usePipelineOrchestratorGetPipelineAssignments, usePipelineOrchestratorGetPipelineDevicePin, usePipelineOrchestratorGetPlacementStats, usePipelineOrchestratorGetReconcileFromDiskStatus, usePipelineOrchestratorListAgentSettings, usePipelineOrchestratorPauseForStorageMigration, usePipelineOrchestratorPlanAutoTune, usePipelineOrchestratorRebalance, usePipelineOrchestratorReconcileFromDisk, usePipelineOrchestratorRemoveAgentSettings, usePipelineOrchestratorRequestOccupancyLook, usePipelineOrchestratorResetNodePipelineDefaults, usePipelineOrchestratorResolvePipeline, usePipelineOrchestratorResumeForStorageMigration, usePipelineOrchestratorSetAgentCapabilities, usePipelineOrchestratorSetAgentDecodeLimits, usePipelineOrchestratorSetAgentInferenceDevices, usePipelineOrchestratorSetAgentMaxCameras, usePipelineOrchestratorSetAgentReachableHost, usePipelineOrchestratorSetCameraPipelineForAgent, usePipelineOrchestratorSetCameraSensors, usePipelineOrchestratorSetCameraStepOverride, usePipelineOrchestratorSetCameraStepSettings, usePipelineOrchestratorSetCameraStepToggle, usePipelineOrchestratorSetCameraSwitch, usePipelineOrchestratorSetCapabilityBinding, usePipelineOrchestratorSetLoadBalancingShares, usePipelineOrchestratorSetPipelineDevicePin, usePipelineOrchestratorSetShareSource, usePipelineOrchestratorSuggestShares, usePipelineOrchestratorUnassignAudio, usePipelineOrchestratorUnassignPipeline, 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, useRecordingArchiveApplyDeviceSettingsPatch, useRecordingArchiveCancelRelocateJob, useRecordingArchiveCancelStorageMigrationMove, useRecordingArchiveDeleteFootprint, useRecordingArchiveGetAvailabilityBatch, useRecordingArchiveGetDaysWithRecordingsBatch, useRecordingArchiveGetDeviceConfig, useRecordingArchiveGetDeviceLiveContribution, useRecordingArchiveGetDeviceSettingsContribution, useRecordingArchiveGetPlacement, useRecordingArchiveGetRelocateResidue, useRecordingArchiveGetStatus, useRecordingArchiveGetStorageMigrationMoveStatus, useRecordingArchiveGetStorageUsage, useRecordingArchiveListOpsLog, useRecordingArchiveListRelocateJobs, useRecordingArchiveLocateSegment, useRecordingArchivePauseForStorageMigration, useRecordingArchivePlanStorageRebalance, useRecordingArchivePruneFootage, useRecordingArchiveReadGopBytes, useRecordingArchiveReadSegmentBytes, useRecordingArchiveReadWindowBytes, useRecordingArchiveReconcileLedgerAgainstDisk, useRecordingArchiveRefreshStorageLocationsForMigration, useRecordingArchiveRelocateFootage, useRecordingArchiveRenderClip, useRecordingArchiveRenderGif, useRecordingArchiveRescanStorage, useRecordingArchiveResumeForStorageMigration, useRecordingArchiveSetDeviceConfig, useRecordingArchiveSetDevicePlacement, useRecordingArchiveStartStorageMigrationMove, useRecordingArchiveStartStorageRebalance, useRecordingExportCancelExport, useRecordingExportCreateExport, useRecordingExportDeleteExport, useRecordingExportGetDownloadUrl, useRecordingExportGetExport, useRecordingExportListExports, useRecordingExportReadExportBytes, useRecordingGetAvailability, useRecordingGetDaysWithRecordings, useRecordingGetPlayback, useRecordingGetPlaybackOptions, useRecordingListSources, useRecordingOnboardGetOptions, useRecordingOnboardGetStatus, useRecordingOnboardSetSettings, useRecordingSignalGetStatus, 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, useStoredGroupBy, useStreamBrokerAcquireEgressTranscode, useStreamBrokerApplyDeviceSettingsPatch, useStreamBrokerAssignProfile, useStreamBrokerFetchEventMedia, useStreamBrokerForgetDeviceHardware, useStreamBrokerGetAllRtspEntries, useStreamBrokerGetBrokerStats, useStreamBrokerGetDeviceAudioMute, useStreamBrokerGetDeviceLiveContribution, useStreamBrokerGetDeviceSettingsContribution, useStreamBrokerGetPreBufferInfo, useStreamBrokerGetRtspEntry, useStreamBrokerGetRtspPort, useStreamBrokerGetStreamUrl, useStreamBrokerGetStreamWithCodec, useStreamBrokerIsRtspEnabled, useStreamBrokerKillClient, useStreamBrokerListAllCameraStreams, useStreamBrokerListAllProfileSlots, useStreamBrokerListClients, useStreamBrokerProbeStream, useStreamBrokerProduceEventMedia, useStreamBrokerPublishCameraStream, useStreamBrokerPullAudioChunks, useStreamBrokerRegenerateRtspToken, useStreamBrokerReleaseEgressTranscode, useStreamBrokerReleaseStreamWithCodec, useStreamBrokerRenderPreBufferClip, useStreamBrokerReportStreamSignal, useStreamBrokerRestartProfile, useStreamBrokerRetractCameraStream, useStreamBrokerSetDeviceAudioMute, useStreamBrokerSetPreBufferDuration, useStreamBrokerSetRtspEnabled, useStreamBrokerSubscribeAudioChunks, useStreamBrokerUnassignProfile, useStreamBrokerUnsubscribeAudioChunks, 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, useUrlQueryParam, useUserManagementConfirmTotp, useUserManagementCreateApiKey, useUserManagementCreateScopedToken, useUserManagementCreateUser, useUserManagementDeleteUser, useUserManagementDisableTotp, useUserManagementFindUserByExternalIdentity, useUserManagementGetTotpStatus, useUserManagementLinkExternalIdentity, useUserManagementListApiKeys, useUserManagementListExternalIdentities, useUserManagementListOauthSessions, useUserManagementListScopedTokens, useUserManagementListUsers, useUserManagementOauthExchangeCode, useUserManagementOauthIssueCode, useUserManagementOauthRefresh, useUserManagementOauthVerifyAccessToken, useUserManagementResetPassword, useUserManagementRevokeApiKey, useUserManagementRevokeOauthSession, useUserManagementRevokeScopedToken, useUserManagementSetUserScopes, useUserManagementSetupTotp, useUserManagementUnlinkExternalIdentity, useUserManagementUpdateUser, useUserManagementValidateApiKey, useUserManagementValidateCredentials, useUserManagementValidateScopedToken, useUserManagementVerifyTotp, useVacuumControlGetStatus, useVacuumControlLocate, useVacuumControlPause, useVacuumControlReturnToBase, useVacuumControlSetFanSpeed, useVacuumControlStart, useVacuumControlStop, useValveClose, useValveGetStatus, useValveOpen, useValveSetPosition, useValveStop, useVibrationGetStatus, useVideoclipsDialClipStream, useVideoclipsGetClipPlayback, useVideoclipsGetPlaybackOptions, useVideoclipsListClips, useVideoclipsListSources, useVideoclipsOfferClipBytes, useVideoclipsReadClipBytes, useVodPlayback, useWaterHeaterGetStatus, useWaterHeaterSetAway, useWaterHeaterSetOperationMode, useWaterHeaterSetTargetTemp, useWeatherGetStatus, useWebrtcSessionAddIceCandidate, useWebrtcSessionApplyDownlinkProbe, 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, withResolvedParentDetail, withUseRootModel, writeStoredGroupBy };