@camstack/addon-post-analysis 1.2.656 → 1.2.658
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/CHANGELOG.md +12 -0
- package/dist/{clip-model-registry-C06M8A8U.mjs → clip-model-registry-OHEqXA-p.mjs} +1968 -1114
- package/dist/{clip-model-registry-BQ_2RsIp.js → clip-model-registry-zi2g3vrD.js} +1967 -1113
- package/dist/embedding-encoder/index.js +5 -5
- package/dist/embedding-encoder/index.mjs +4 -4
- package/dist/pipeline-analytics/_stub.js +2 -2
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-8vah5-KD.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BBL7vKoc.mjs} +3 -3
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Dfps3D5t.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BwWOFFOc.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-0O7AUcsV.mjs → hostInit-BI2sFPq3.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +71 -7
- package/dist/pipeline-analytics/index.mjs +70 -6
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +10 -3
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-YXyP9GJm.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-gv38vKug.mjs +0 -26
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-CaURIwQA.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -715,6 +715,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
715
715
|
EventCategory["NotificationRuleBroken"] = "notification.rule-broken";
|
|
716
716
|
/** The clear of {@link NotificationRuleBroken}: the rule loads and names nothing deleted. */
|
|
717
717
|
EventCategory["NotificationRuleRepaired"] = "notification.rule-repaired";
|
|
718
|
+
/** A migration failed or was blocked; the Alert Center re-reads the ledger. */
|
|
719
|
+
EventCategory["MigrationFailed"] = "migration.failed";
|
|
720
|
+
/** A migration applied or a failure cleared; the Alert Center re-reads the ledger. */
|
|
721
|
+
EventCategory["MigrationApplied"] = "migration.applied";
|
|
718
722
|
EventCategory["DeviceUpdated"] = "device.updated";
|
|
719
723
|
/**
|
|
720
724
|
* Transport-level connectivity. Emitted by the device driver when
|
|
@@ -777,6 +781,378 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
777
781
|
return EventCategory;
|
|
778
782
|
}({});
|
|
779
783
|
//#endregion
|
|
784
|
+
//#region ../types/dist/device-type-CEqjmUnR.mjs
|
|
785
|
+
/**
|
|
786
|
+
import { errMsg } from '@camstack/types'
|
|
787
|
+
* Extract a human-readable message from an unknown error value.
|
|
788
|
+
* Replaces the ubiquitous `errMsg(err)` pattern.
|
|
789
|
+
*/
|
|
790
|
+
function errMsg(err) {
|
|
791
|
+
if (err instanceof Error) return err.message;
|
|
792
|
+
if (typeof err === "string") return err;
|
|
793
|
+
return String(err);
|
|
794
|
+
}
|
|
795
|
+
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
796
|
+
DeviceType["Camera"] = "camera";
|
|
797
|
+
DeviceType["Hub"] = "hub";
|
|
798
|
+
DeviceType["Light"] = "light";
|
|
799
|
+
DeviceType["Siren"] = "siren";
|
|
800
|
+
DeviceType["Switch"] = "switch";
|
|
801
|
+
DeviceType["Sensor"] = "sensor";
|
|
802
|
+
DeviceType["Thermostat"] = "thermostat";
|
|
803
|
+
/** Air-conditioner / heat-pump climate device (HVAC) — shares the
|
|
804
|
+
* `climate-control` cap surface with `Thermostat` but renders a
|
|
805
|
+
* dedicated AC-appropriate control UI (mode chips, fan speed,
|
|
806
|
+
* independent vertical/horizontal swing). Sources: native Gree, and
|
|
807
|
+
* reusable by other AC integrations. */
|
|
808
|
+
DeviceType["Climate"] = "climate";
|
|
809
|
+
DeviceType["Button"] = "button";
|
|
810
|
+
/** Generic stateless event emitter — carries a device's EXACT declared
|
|
811
|
+
* event vocabulary verbatim (no normalization). Installed with the
|
|
812
|
+
* `event-emitter` cap. Sources: HA `event.*` entities (structured) and
|
|
813
|
+
* HA bus events (e.g. `zha_event`, generic). */
|
|
814
|
+
DeviceType["EventEmitter"] = "event-emitter";
|
|
815
|
+
/** Firmware/software update entity — current vs available version,
|
|
816
|
+
* updatable flag, update state, and an install action. Installed with
|
|
817
|
+
* the `update` cap. Sources: Homematic firmware-update channels (and
|
|
818
|
+
* reusable by other providers, e.g. HA `update.*` entities). */
|
|
819
|
+
DeviceType["Update"] = "update";
|
|
820
|
+
DeviceType["Generic"] = "generic";
|
|
821
|
+
/** Generic notification delivery target (HA `notify.<service>`, future
|
|
822
|
+
* Telegram / Discord / ntfy / SMTP, …). One device per delivery
|
|
823
|
+
* endpoint; the `notifier` cap defines the send surface. */
|
|
824
|
+
DeviceType["Notifier"] = "notifier";
|
|
825
|
+
/** Pre-recorded action sequence with optional parameters
|
|
826
|
+
* (HA `script.*`). Runnable via `script-runner` cap. */
|
|
827
|
+
DeviceType["Script"] = "script";
|
|
828
|
+
/** Automation rule (HA `automation.*`) — enable/disable + manual
|
|
829
|
+
* trigger surface exposed via `automation-control` cap. */
|
|
830
|
+
DeviceType["Automation"] = "automation";
|
|
831
|
+
/** Door / smart lock device (HA `lock.*`). `lock-control` cap. */
|
|
832
|
+
DeviceType["Lock"] = "lock";
|
|
833
|
+
/** Window covering, blinds, garage door, valve, etc. (HA `cover.*`,
|
|
834
|
+
* `valve.*`). `cover` cap with sub-roles for variant. */
|
|
835
|
+
DeviceType["Cover"] = "cover";
|
|
836
|
+
/** Pipe / water / gas valve with open/close/stop and optional
|
|
837
|
+
* position (HA `valve.*`). `valve` cap — a cover-sibling actuator
|
|
838
|
+
* modelled on the same open/closed lifecycle. */
|
|
839
|
+
DeviceType["Valve"] = "valve";
|
|
840
|
+
/** Humidifier / dehumidifier with on/off + target humidity + mode
|
|
841
|
+
* (HA `humidifier.*`). `humidifier` cap — a climate-family actuator
|
|
842
|
+
* modelled on the same target / mode lifecycle. */
|
|
843
|
+
DeviceType["Humidifier"] = "humidifier";
|
|
844
|
+
/** Water heater / boiler with target temperature + operation mode +
|
|
845
|
+
* away mode (HA `water_heater.*`). `water-heater` cap — a
|
|
846
|
+
* climate-family actuator. */
|
|
847
|
+
DeviceType["WaterHeater"] = "water-heater";
|
|
848
|
+
/** Ceiling / standing / exhaust fan (HA `fan.*`). `fan-control` cap. */
|
|
849
|
+
DeviceType["Fan"] = "fan";
|
|
850
|
+
/** Audio / video playback endpoint (HA `media_player.*`). Disjoint from
|
|
851
|
+
* the camera surface — those use `Camera`. `media-player` cap. */
|
|
852
|
+
DeviceType["MediaPlayer"] = "media-player";
|
|
853
|
+
/** Security panel / alarm system (HA `alarm_control_panel.*`).
|
|
854
|
+
* `alarm-panel` cap. */
|
|
855
|
+
DeviceType["AlarmPanel"] = "alarm-panel";
|
|
856
|
+
/** Generic user-settable input (HA `number` / `input_number` / `select`
|
|
857
|
+
* / `input_select` / `text` / `input_text` / `input_datetime`).
|
|
858
|
+
* Sub-type via `DeviceRole`: NumericControl / SelectControl /
|
|
859
|
+
* TextControl / DateTimeControl. */
|
|
860
|
+
DeviceType["Control"] = "control";
|
|
861
|
+
/** Person / device-tracker presence (HA `person.*`, `device_tracker.*`).
|
|
862
|
+
* `presence` cap. */
|
|
863
|
+
DeviceType["Presence"] = "presence";
|
|
864
|
+
/** Weather provider (HA `weather.*`). Tier-3, low MVP priority.
|
|
865
|
+
* `weather` cap. */
|
|
866
|
+
DeviceType["Weather"] = "weather";
|
|
867
|
+
/** Robot vacuum (HA `vacuum.*`). Tier-3. `vacuum-control` cap. */
|
|
868
|
+
DeviceType["Vacuum"] = "vacuum";
|
|
869
|
+
/** Robotic lawn mower (HA `lawn_mower.*`). Tier-3.
|
|
870
|
+
* `lawn-mower-control` cap. */
|
|
871
|
+
DeviceType["LawnMower"] = "lawn-mower";
|
|
872
|
+
/** Physical HA device group — parent container for entity-children
|
|
873
|
+
* adopted from a single HA device entry. Not renderable as a
|
|
874
|
+
* standalone device; exists only to anchor child entities. */
|
|
875
|
+
DeviceType["Container"] = "container";
|
|
876
|
+
/** Single still-image entity (HA `image.*`). Read-only display of an
|
|
877
|
+
* `entity_picture` signed URL the browser loads directly. `image` cap. */
|
|
878
|
+
DeviceType["Image"] = "image";
|
|
879
|
+
/** Smart pet feeder — cloud-connected food dispenser with a bowl food
|
|
880
|
+
* level, battery, desiccant life, feeding state and manual-feed /
|
|
881
|
+
* call-pet / maintenance actions. Installed with the `pet-feeder` cap;
|
|
882
|
+
* dual-hopper models (D4S/D4SH) expose per-hopper portions. Sources:
|
|
883
|
+
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
884
|
+
* integrations sharing the same food/desiccant/hopper surface. */
|
|
885
|
+
DeviceType["PetFeeder"] = "pet-feeder";
|
|
886
|
+
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
887
|
+
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
888
|
+
* of a container and is BUILT as a composed device (D967). */
|
|
889
|
+
DeviceType["PetFountain"] = "pet-fountain";
|
|
890
|
+
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
891
|
+
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
892
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
893
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
894
|
+
DeviceType["Dishwasher"] = "dishwasher";
|
|
895
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
896
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
897
|
+
DeviceType["Washer"] = "washer";
|
|
898
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
899
|
+
DeviceType["Dryer"] = "dryer";
|
|
900
|
+
/** The physical bridge box of a vendor ecosystem (Velux KLF-200, and later
|
|
901
|
+
* other radio-to-IP bridges). It carries the box's own facts (firmware,
|
|
902
|
+
* address, connection state) and the actions the box really supports
|
|
903
|
+
* (`reboot`, `device-admin-link`). Products are NOT its children — they are
|
|
904
|
+
* adopted beside it — and its connection settings stay on the integration. */
|
|
905
|
+
DeviceType["Gateway"] = "gateway";
|
|
906
|
+
return DeviceType;
|
|
907
|
+
}({});
|
|
908
|
+
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
909
|
+
DeviceFeature["BatteryOperated"] = "battery-operated";
|
|
910
|
+
DeviceFeature["Rebootable"] = "rebootable";
|
|
911
|
+
/**
|
|
912
|
+
* Device supports an on-demand re-sync of its derived spec with its
|
|
913
|
+
* upstream source — drives the generic Re-sync button. The owning
|
|
914
|
+
* provider implements the action via the `device-adoption.resync` cap.
|
|
915
|
+
*/
|
|
916
|
+
DeviceFeature["Resyncable"] = "resyncable";
|
|
917
|
+
DeviceFeature["NativeSnapshot"] = "native-snapshot";
|
|
918
|
+
DeviceFeature["DoorbellButton"] = "doorbell-button";
|
|
919
|
+
DeviceFeature["TwoWayAudio"] = "two-way-audio";
|
|
920
|
+
DeviceFeature["PanTiltZoom"] = "pan-tilt-zoom";
|
|
921
|
+
/**
|
|
922
|
+
* Camera supports the on-firmware autotrack subsystem (subject-
|
|
923
|
+
* following). Distinct from `PanTiltZoom` because not every PTZ
|
|
924
|
+
* camera ships autotrack — the admin UI uses this flag to gate
|
|
925
|
+
* the autotrack toggle / settings card without re-deriving from
|
|
926
|
+
* the cap registry. Mirrors `ptz-autotrack` cap registration:
|
|
927
|
+
* driver sets this feature when probe confirms the firmware
|
|
928
|
+
* surface, and registers the cap in the same code path.
|
|
929
|
+
*/
|
|
930
|
+
DeviceFeature["PtzAutotrack"] = "ptz-autotrack";
|
|
931
|
+
/**
|
|
932
|
+
* Accessory exposes a "trigger on motion" toggle — the parent camera's
|
|
933
|
+
* motion detection automatically activates this device. Mirrors
|
|
934
|
+
* `motion-trigger` cap registration: drivers set this feature in the
|
|
935
|
+
* same code path that calls `ctx.registerNativeCap(motionTriggerCapability, ...)`.
|
|
936
|
+
*
|
|
937
|
+
* Used by admin UI (gate the in-hero `MotionTriggerToggle` against a
|
|
938
|
+
* fast scalar without binding fetch), notifier rules, and `listAll`
|
|
939
|
+
* filters that want "all devices with on-motion behaviour".
|
|
940
|
+
*/
|
|
941
|
+
DeviceFeature["MotionTrigger"] = "motion-trigger";
|
|
942
|
+
/** Light supports rgb-triplet color via `color` cap. */
|
|
943
|
+
DeviceFeature["LightColorRgb"] = "light-color-rgb";
|
|
944
|
+
/** Light supports HSV color via `color` cap. */
|
|
945
|
+
DeviceFeature["LightColorHsv"] = "light-color-hsv";
|
|
946
|
+
/** Light supports color-temperature (mired) via `color` cap. */
|
|
947
|
+
DeviceFeature["LightColorMired"] = "light-color-mired";
|
|
948
|
+
/** Thermostat supports a `heat_cool` dual setpoint (targetLow +
|
|
949
|
+
* targetHigh). Gates the range slider UI. */
|
|
950
|
+
DeviceFeature["ClimateDualSetpoint"] = "climate-dual-setpoint";
|
|
951
|
+
/** Thermostat exposes target humidity and/or current humidity
|
|
952
|
+
* readings. Gates the humidity controls. */
|
|
953
|
+
DeviceFeature["ClimateHumidity"] = "climate-humidity";
|
|
954
|
+
/** Thermostat exposes a fan-mode selector. */
|
|
955
|
+
DeviceFeature["ClimateFanMode"] = "climate-fan-mode";
|
|
956
|
+
/** Thermostat exposes preset modes (eco / away / sleep / vendor). */
|
|
957
|
+
DeviceFeature["ClimatePreset"] = "climate-preset";
|
|
958
|
+
/** Thermostat exposes a vertical louver swing toggle. Gates the
|
|
959
|
+
* vertical-swing switch in the climate UI. Independent of horizontal. */
|
|
960
|
+
DeviceFeature["ClimateSwingVertical"] = "climate-swing-vertical";
|
|
961
|
+
/** Thermostat exposes a horizontal louver swing toggle. Gates the
|
|
962
|
+
* horizontal-swing switch in the climate UI. Independent of vertical. */
|
|
963
|
+
DeviceFeature["ClimateSwingHorizontal"] = "climate-swing-horizontal";
|
|
964
|
+
/** Cover exposes intermediate position control (0..100). Gates the
|
|
965
|
+
* position slider UI. */
|
|
966
|
+
DeviceFeature["CoverPositionable"] = "cover-positionable";
|
|
967
|
+
/** Cover exposes slat-tilt control. Gates the tilt slider UI. */
|
|
968
|
+
DeviceFeature["CoverTilt"] = "cover-tilt";
|
|
969
|
+
/** Valve exposes intermediate position control (0..100). Gates the
|
|
970
|
+
* position slider / drag surface UI. */
|
|
971
|
+
DeviceFeature["ValvePositionable"] = "valve-positionable";
|
|
972
|
+
/** Fan exposes a speed-percentage setter. Gates the speed slider UI. */
|
|
973
|
+
DeviceFeature["FanSpeed"] = "fan-speed";
|
|
974
|
+
/** Fan exposes a preset mode selector. */
|
|
975
|
+
DeviceFeature["FanPreset"] = "fan-preset";
|
|
976
|
+
/** Fan exposes blade direction (forward/reverse) — typical of
|
|
977
|
+
* ceiling fans. */
|
|
978
|
+
DeviceFeature["FanDirection"] = "fan-direction";
|
|
979
|
+
/** Fan exposes an oscillation toggle. */
|
|
980
|
+
DeviceFeature["FanOscillating"] = "fan-oscillating";
|
|
981
|
+
/** Lock requires a PIN code on lock/unlock. Gates the code-entry
|
|
982
|
+
* field on the UI lock-controls panel. */
|
|
983
|
+
DeviceFeature["LockPinRequired"] = "lock-pin-required";
|
|
984
|
+
/** Lock supports a latch-release ("open door") action distinct from
|
|
985
|
+
* unlock. Mirrors HA `LockEntityFeature.OPEN` (bit 1) in
|
|
986
|
+
* `supported_features`. Gates the Open Door button in the UI. */
|
|
987
|
+
DeviceFeature["LockOpen"] = "lock-open";
|
|
988
|
+
/** Media player exposes a seek-to-position surface. */
|
|
989
|
+
DeviceFeature["MediaPlayerSeek"] = "media-player-seek";
|
|
990
|
+
/** Media player exposes a volume-level setter. */
|
|
991
|
+
DeviceFeature["MediaPlayerVolume"] = "media-player-volume";
|
|
992
|
+
/** Media player exposes a mute toggle distinct from volume=0. */
|
|
993
|
+
DeviceFeature["MediaPlayerMute"] = "media-player-mute";
|
|
994
|
+
/** Media player exposes a shuffle toggle. */
|
|
995
|
+
DeviceFeature["MediaPlayerShuffle"] = "media-player-shuffle";
|
|
996
|
+
/** Media player exposes a repeat mode (off / all / one). */
|
|
997
|
+
DeviceFeature["MediaPlayerRepeat"] = "media-player-repeat";
|
|
998
|
+
/** Media player exposes a source / input selector. */
|
|
999
|
+
DeviceFeature["MediaPlayerSelectSource"] = "media-player-select-source";
|
|
1000
|
+
/** Media player exposes a play-arbitrary-media surface (URL / id). */
|
|
1001
|
+
DeviceFeature["MediaPlayerPlayMedia"] = "media-player-play-media";
|
|
1002
|
+
/** Media player exposes next-track. */
|
|
1003
|
+
DeviceFeature["MediaPlayerNext"] = "media-player-next";
|
|
1004
|
+
/** Media player exposes previous-track. */
|
|
1005
|
+
DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
|
|
1006
|
+
/** Media player exposes stop distinct from pause. */
|
|
1007
|
+
DeviceFeature["MediaPlayerStop"] = "media-player-stop";
|
|
1008
|
+
/** Alarm panel requires a PIN code on arm/disarm. */
|
|
1009
|
+
DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
|
|
1010
|
+
/** Presence device carries GPS coordinates (lat/lng/accuracy) in
|
|
1011
|
+
* addition to a textual location. */
|
|
1012
|
+
DeviceFeature["PresenceGps"] = "presence-gps";
|
|
1013
|
+
/** Notifier accepts an inline / URL image attachment. */
|
|
1014
|
+
DeviceFeature["NotifierImage"] = "notifier-image";
|
|
1015
|
+
/** Notifier accepts a priority hint (high/normal/low). */
|
|
1016
|
+
DeviceFeature["NotifierPriority"] = "notifier-priority";
|
|
1017
|
+
/** Notifier accepts a free-form `data` payload for platform-specific
|
|
1018
|
+
* fields. */
|
|
1019
|
+
DeviceFeature["NotifierData"] = "notifier-data";
|
|
1020
|
+
/** Notifier supports interactive action buttons / callbacks. */
|
|
1021
|
+
DeviceFeature["NotifierActions"] = "notifier-actions";
|
|
1022
|
+
/** Notifier supports per-call recipient targeting (multi-user). */
|
|
1023
|
+
DeviceFeature["NotifierRecipients"] = "notifier-recipients";
|
|
1024
|
+
/** Script runner accepts a variables map on each run invocation. */
|
|
1025
|
+
DeviceFeature["ScriptVariables"] = "script-variables";
|
|
1026
|
+
/** Automation `trigger` accepts a skipCondition flag — fires the
|
|
1027
|
+
* automation's actions while bypassing its condition block. */
|
|
1028
|
+
DeviceFeature["AutomationSkipCondition"] = "automation-skip-condition";
|
|
1029
|
+
/** Robot vacuum exposes a live cleaning map (image child). Gates the
|
|
1030
|
+
* map tile in the vacuum UI. */
|
|
1031
|
+
DeviceFeature["VacuumHasMap"] = "vacuum-has-map";
|
|
1032
|
+
/** Robot vacuum exposes AI obstacle-detection toggles. Gates the AI
|
|
1033
|
+
* switches group. */
|
|
1034
|
+
DeviceFeature["VacuumHasAi"] = "vacuum-has-ai";
|
|
1035
|
+
/** Robot mower exposes a live mowing map (SVG image child). Gates the
|
|
1036
|
+
* mower map tile. */
|
|
1037
|
+
DeviceFeature["MowerHasMap"] = "mower-has-map";
|
|
1038
|
+
/** Robot mower exposes targeted mowing (all-area / zones / edges /
|
|
1039
|
+
* spots) — gates the Mow action + map selectors. */
|
|
1040
|
+
DeviceFeature["MowerHasTargetedMowing"] = "mower-has-targeted-mowing";
|
|
1041
|
+
return DeviceFeature;
|
|
1042
|
+
}({});
|
|
1043
|
+
/**
|
|
1044
|
+
* Semantic role a device plays within its parent. Populated by driver
|
|
1045
|
+
* addons when creating accessory devices (Reolink siren/floodlight/
|
|
1046
|
+
* PIR/chime/autotrack/doorbell, ONVIF relay outputs, …). Used by the
|
|
1047
|
+
* admin UI to pick icons, labels, and widgets — a `Switch` with
|
|
1048
|
+
* `role: Floodlight` renders as a bulb with a brightness slider,
|
|
1049
|
+
* whereas a `Switch` with `role: Siren` renders as a klaxon.
|
|
1050
|
+
*
|
|
1051
|
+
* Undefined for top-level devices (cameras, NVRs, hubs). Persisted in
|
|
1052
|
+
* sqlite as a nullable TEXT column — old rows keep working unchanged.
|
|
1053
|
+
*/
|
|
1054
|
+
var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
1055
|
+
DeviceRole["Siren"] = "siren";
|
|
1056
|
+
DeviceRole["Floodlight"] = "floodlight";
|
|
1057
|
+
DeviceRole["Spotlight"] = "spotlight";
|
|
1058
|
+
DeviceRole["PirSensor"] = "pir-sensor";
|
|
1059
|
+
DeviceRole["Chime"] = "chime";
|
|
1060
|
+
DeviceRole["Autotrack"] = "autotrack";
|
|
1061
|
+
DeviceRole["Nightvision"] = "nightvision";
|
|
1062
|
+
DeviceRole["PrivacyMask"] = "privacy-mask";
|
|
1063
|
+
DeviceRole["Doorbell"] = "doorbell";
|
|
1064
|
+
/** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
|
|
1065
|
+
DeviceRole["CoverBlind"] = "cover-blind";
|
|
1066
|
+
/** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
|
|
1067
|
+
DeviceRole["CoverShutter"] = "cover-shutter";
|
|
1068
|
+
/** Exterior awning. HA `device_class: awning`. */
|
|
1069
|
+
DeviceRole["CoverAwning"] = "cover-awning";
|
|
1070
|
+
/** Curtain / drape. HA `device_class: curtain`. */
|
|
1071
|
+
DeviceRole["CoverCurtain"] = "cover-curtain";
|
|
1072
|
+
/** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
|
|
1073
|
+
DeviceRole["CoverGarage"] = "cover-garage";
|
|
1074
|
+
/** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
|
|
1075
|
+
DeviceRole["CoverGate"] = "cover-gate";
|
|
1076
|
+
/** Door. HA `device_class: door`. A security actuator: exports gate it. */
|
|
1077
|
+
DeviceRole["CoverDoor"] = "cover-door";
|
|
1078
|
+
/** Window. HA `device_class: window`. */
|
|
1079
|
+
DeviceRole["CoverWindow"] = "cover-window";
|
|
1080
|
+
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
1081
|
+
* real Switch device for UI rendering / export adapters. */
|
|
1082
|
+
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
1083
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
1084
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
1085
|
+
DeviceRole["Outlet"] = "outlet";
|
|
1086
|
+
/** Generic motion / occupancy / moving event source. Distinct from
|
|
1087
|
+
* the camera accessory PirSensor role: that one is a camera child;
|
|
1088
|
+
* this is a standalone HA / 3rd-party motion sensor. */
|
|
1089
|
+
DeviceRole["MotionSensor"] = "motion-sensor";
|
|
1090
|
+
DeviceRole["ContactSensor"] = "contact-sensor";
|
|
1091
|
+
DeviceRole["LeakSensor"] = "leak-sensor";
|
|
1092
|
+
DeviceRole["SmokeSensor"] = "smoke-sensor";
|
|
1093
|
+
DeviceRole["COSensor"] = "co-sensor";
|
|
1094
|
+
DeviceRole["GasSensor"] = "gas-sensor";
|
|
1095
|
+
DeviceRole["TamperSensor"] = "tamper-sensor";
|
|
1096
|
+
DeviceRole["VibrationSensor"] = "vibration-sensor";
|
|
1097
|
+
DeviceRole["ConnectivitySensor"] = "connectivity-sensor";
|
|
1098
|
+
DeviceRole["SoundSensor"] = "sound-sensor";
|
|
1099
|
+
/** Fallback for `binary_sensor` without a known `device_class`. */
|
|
1100
|
+
DeviceRole["BinarySensor"] = "binary-sensor";
|
|
1101
|
+
DeviceRole["TemperatureSensor"] = "temperature-sensor";
|
|
1102
|
+
DeviceRole["HumiditySensor"] = "humidity-sensor";
|
|
1103
|
+
DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
|
|
1104
|
+
DeviceRole["PressureSensor"] = "pressure-sensor";
|
|
1105
|
+
/** Wind speed or direction (weather-station `wind-sensor` cap). */
|
|
1106
|
+
DeviceRole["WindSensor"] = "wind-sensor";
|
|
1107
|
+
/** Rain accumulation or rate (weather-station `rain-sensor` cap). */
|
|
1108
|
+
DeviceRole["RainSensor"] = "rain-sensor";
|
|
1109
|
+
/** UV index (weather-station `uv-sensor` cap). */
|
|
1110
|
+
DeviceRole["UvSensor"] = "uv-sensor";
|
|
1111
|
+
/** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
|
|
1112
|
+
* Distinct from AmbientLightSensor (lux). */
|
|
1113
|
+
DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
|
|
1114
|
+
/** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
|
|
1115
|
+
DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
|
|
1116
|
+
DeviceRole["PowerSensor"] = "power-sensor";
|
|
1117
|
+
DeviceRole["EnergySensor"] = "energy-sensor";
|
|
1118
|
+
DeviceRole["VoltageSensor"] = "voltage-sensor";
|
|
1119
|
+
DeviceRole["CurrentSensor"] = "current-sensor";
|
|
1120
|
+
DeviceRole["AirQualitySensor"] = "air-quality-sensor";
|
|
1121
|
+
/** Battery level (numeric % via `sensor` OR low-bool via
|
|
1122
|
+
* `binary_sensor` — the cap distinguishes via the value type). */
|
|
1123
|
+
DeviceRole["BatterySensor"] = "battery-sensor";
|
|
1124
|
+
/** Fallback for `sensor` numeric without a known `device_class`. */
|
|
1125
|
+
DeviceRole["NumericSensor"] = "numeric-sensor";
|
|
1126
|
+
/** String / enum state (HA `sensor` with `state_class: enum` or
|
|
1127
|
+
* `attributes.options`). */
|
|
1128
|
+
DeviceRole["EnumSensor"] = "enum-sensor";
|
|
1129
|
+
/** Date / timestamp state (HA `sensor` with `device_class: timestamp`
|
|
1130
|
+
* or `date`). The slice carries the raw ISO string verbatim (hosted on
|
|
1131
|
+
* the `enum-sensor` cap); the UI renders it locale-formatted. */
|
|
1132
|
+
DeviceRole["DateTimeSensor"] = "datetime-sensor";
|
|
1133
|
+
/** Last-resort fallback when nothing else matches. */
|
|
1134
|
+
DeviceRole["GenericSensor"] = "generic-sensor";
|
|
1135
|
+
DeviceRole["NumericControl"] = "numeric-control";
|
|
1136
|
+
DeviceRole["SelectControl"] = "select-control";
|
|
1137
|
+
DeviceRole["TextControl"] = "text-control";
|
|
1138
|
+
DeviceRole["DateTimeControl"] = "datetime-control";
|
|
1139
|
+
/** Mobile push notifier (HA `notify.mobile_app_*`) — supports
|
|
1140
|
+
* rich features (image, priority, channel routing). */
|
|
1141
|
+
DeviceRole["MobilePushNotifier"] = "mobile-push-notifier";
|
|
1142
|
+
/** Chat / messaging service (HA `notify.telegram_*`,
|
|
1143
|
+
* `notify.discord_*`, etc.). */
|
|
1144
|
+
DeviceRole["MessagingNotifier"] = "messaging-notifier";
|
|
1145
|
+
/** Email-based delivery (HA `notify.smtp`, etc.). */
|
|
1146
|
+
DeviceRole["EmailNotifier"] = "email-notifier";
|
|
1147
|
+
/** Fallback when the notifier service name doesn't match a known
|
|
1148
|
+
* pattern. */
|
|
1149
|
+
DeviceRole["GenericNotifier"] = "generic-notifier";
|
|
1150
|
+
/** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
|
|
1151
|
+
* cap. A `DeviceType.Generic` device. */
|
|
1152
|
+
DeviceRole["IrTransmitter"] = "ir-transmitter";
|
|
1153
|
+
return DeviceRole;
|
|
1154
|
+
}({});
|
|
1155
|
+
//#endregion
|
|
780
1156
|
//#region ../../node_modules/zod/v4/core/core.js
|
|
781
1157
|
var _a$1;
|
|
782
1158
|
function $constructor(name, initializer, params) {
|
|
@@ -5645,7 +6021,7 @@ var ZodIssueCode = {
|
|
|
5645
6021
|
var ZodFirstPartyTypeKind;
|
|
5646
6022
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5647
6023
|
//#endregion
|
|
5648
|
-
//#region ../types/dist/sleep-
|
|
6024
|
+
//#region ../types/dist/sleep-CSYuxssh.mjs
|
|
5649
6025
|
/**
|
|
5650
6026
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5651
6027
|
* window to float samples (D455).
|
|
@@ -6161,6 +6537,102 @@ function emitReadiness(bus, params) {
|
|
|
6161
6537
|
ts
|
|
6162
6538
|
}));
|
|
6163
6539
|
}
|
|
6540
|
+
var NOT_RUN = {
|
|
6541
|
+
declared: false,
|
|
6542
|
+
snapshot: null,
|
|
6543
|
+
applied: [],
|
|
6544
|
+
failed: [],
|
|
6545
|
+
blocked: [],
|
|
6546
|
+
skipped: [],
|
|
6547
|
+
blockOwner: []
|
|
6548
|
+
};
|
|
6549
|
+
/**
|
|
6550
|
+
* Offer `migrations` to the engine and run what it says to run, in its order. Never
|
|
6551
|
+
* throws: an unreachable or refusing engine is logged and reported `declared: false`,
|
|
6552
|
+
* because the hub (and this addon's boot) must not hang on a migration.
|
|
6553
|
+
*/
|
|
6554
|
+
async function runAddonMigrations(host, migrations, logger) {
|
|
6555
|
+
const first = migrations[0];
|
|
6556
|
+
if (first === void 0) return NOT_RUN;
|
|
6557
|
+
const owner = first.meta.owner;
|
|
6558
|
+
const log = logger.withTags({ migrationOwner: owner });
|
|
6559
|
+
const byId = new Map(migrations.map((m) => [m.meta.id, m]));
|
|
6560
|
+
let declaration;
|
|
6561
|
+
try {
|
|
6562
|
+
declaration = await host.declareOwner({
|
|
6563
|
+
owner,
|
|
6564
|
+
metas: migrations.map((m) => m.meta)
|
|
6565
|
+
});
|
|
6566
|
+
} catch (err) {
|
|
6567
|
+
log.error("the migration engine refused or could not take this addon catalogue — none ran", { meta: { error: errMsg(err) } });
|
|
6568
|
+
return {
|
|
6569
|
+
...NOT_RUN,
|
|
6570
|
+
blockOwner: migrations.filter((m) => m.meta.onFailure === "block-owner").map((m) => m.meta.id)
|
|
6571
|
+
};
|
|
6572
|
+
}
|
|
6573
|
+
const applied = [];
|
|
6574
|
+
const failed = [];
|
|
6575
|
+
const blocked = [];
|
|
6576
|
+
const skipped = [];
|
|
6577
|
+
const settle = (id, status) => {
|
|
6578
|
+
if (status === "applied") applied.push(id);
|
|
6579
|
+
else if (status === "failed") failed.push(id);
|
|
6580
|
+
else if (status === "blocked") blocked.push(id);
|
|
6581
|
+
else skipped.push(id);
|
|
6582
|
+
};
|
|
6583
|
+
for (const step of declaration.steps) {
|
|
6584
|
+
const bound = byId.get(step.id);
|
|
6585
|
+
if (bound === void 0 || step.action === "skip") {
|
|
6586
|
+
skipped.push(step.id);
|
|
6587
|
+
continue;
|
|
6588
|
+
}
|
|
6589
|
+
const tags = { migrationId: step.id };
|
|
6590
|
+
try {
|
|
6591
|
+
const gate = await host.startMigration({ id: step.id });
|
|
6592
|
+
if (!gate.proceed) {
|
|
6593
|
+
log.warn("migration not run", {
|
|
6594
|
+
tags,
|
|
6595
|
+
meta: {
|
|
6596
|
+
state: gate.state,
|
|
6597
|
+
reason: gate.reason
|
|
6598
|
+
}
|
|
6599
|
+
});
|
|
6600
|
+
settle(step.id, gate.state === "pending" ? "blocked" : gate.state);
|
|
6601
|
+
continue;
|
|
6602
|
+
}
|
|
6603
|
+
const result = await bound.execute();
|
|
6604
|
+
const outcome = await host.finishMigration({
|
|
6605
|
+
id: step.id,
|
|
6606
|
+
result
|
|
6607
|
+
});
|
|
6608
|
+
if (outcome.status === "applied") log.info("migration applied", {
|
|
6609
|
+
tags,
|
|
6610
|
+
meta: { rowsChanged: outcome.rowsChanged }
|
|
6611
|
+
});
|
|
6612
|
+
else log.error("migration failed", {
|
|
6613
|
+
tags,
|
|
6614
|
+
meta: { error: outcome.error }
|
|
6615
|
+
});
|
|
6616
|
+
settle(step.id, outcome.status);
|
|
6617
|
+
} catch (err) {
|
|
6618
|
+
log.error("migration could not be completed with the engine", {
|
|
6619
|
+
tags,
|
|
6620
|
+
meta: { error: errMsg(err) }
|
|
6621
|
+
});
|
|
6622
|
+
failed.push(step.id);
|
|
6623
|
+
}
|
|
6624
|
+
}
|
|
6625
|
+
const blockOwner = [...failed, ...blocked].filter((id) => byId.get(id)?.meta.onFailure === "block-owner");
|
|
6626
|
+
return {
|
|
6627
|
+
declared: true,
|
|
6628
|
+
snapshot: declaration.snapshot,
|
|
6629
|
+
applied,
|
|
6630
|
+
failed,
|
|
6631
|
+
blocked,
|
|
6632
|
+
skipped,
|
|
6633
|
+
blockOwner
|
|
6634
|
+
};
|
|
6635
|
+
}
|
|
6164
6636
|
/**
|
|
6165
6637
|
* Build a {@link DurableState} over a single store key. Transport-agnostic:
|
|
6166
6638
|
* `read`/`write` are the addon-store or device-store accessors. The whole
|
|
@@ -7216,6 +7688,28 @@ var BaseAddon = class {
|
|
|
7216
7688
|
return normalized;
|
|
7217
7689
|
}
|
|
7218
7690
|
/**
|
|
7691
|
+
* Run this addon's migration catalogue (D987 M3) through the hub's `migrations`
|
|
7692
|
+
* engine. Call it at the point of the boot where the data must already have the new
|
|
7693
|
+
* shape — `onInitialize`, or `onRestoreDevices` for a migration that needs the
|
|
7694
|
+
* restored devices — with the catalogue bound to the addon's ports
|
|
7695
|
+
* (`defineAddonMigrations(ADDON_MIGRATIONS, ports)`).
|
|
7696
|
+
*
|
|
7697
|
+
* An engine that cannot be reached or refuses the catalogue is logged and runs
|
|
7698
|
+
* nothing; the boot continues. A migration that FAILED (or was blocked by one)
|
|
7699
|
+
* and declares `onFailure: 'block-owner'` makes this throw, so the addon does not
|
|
7700
|
+
* serve data whose shape it cannot trust; `tolerate` migrations never do.
|
|
7701
|
+
*/
|
|
7702
|
+
async runMigrations(migrations) {
|
|
7703
|
+
const api = this.ctx.api.migrations;
|
|
7704
|
+
const report = await runAddonMigrations({
|
|
7705
|
+
declareOwner: (input) => api.declareOwner.mutate(input),
|
|
7706
|
+
startMigration: (input) => api.startMigration.mutate(input),
|
|
7707
|
+
finishMigration: (input) => api.finishMigration.mutate(input)
|
|
7708
|
+
}, migrations, this.ctx.logger);
|
|
7709
|
+
if (report.blockOwner.length > 0) throw new Error(`migration(s) ${report.blockOwner.join(", ")} did not apply and block this addon — fix or retry them (migrations.retry), then restart it`);
|
|
7710
|
+
return report;
|
|
7711
|
+
}
|
|
7712
|
+
/**
|
|
7219
7713
|
* Called by the isolated-process runner AFTER `broker.start()`.
|
|
7220
7714
|
* In-process addons never need this because the hub broker is already
|
|
7221
7715
|
* running when `initialize()` fires. For forked children the broker
|
|
@@ -7348,6 +7842,26 @@ var BaseAddon = class {
|
|
|
7348
7842
|
* alternative — skip it — turns a rename into a surface that quietly
|
|
7349
7843
|
* empties, which looks exactly like an addon with nothing to configure.
|
|
7350
7844
|
*/
|
|
7845
|
+
/**
|
|
7846
|
+
* The form schema of ONE integration instance, or `null` to use {@link globalSettingsSchema}.
|
|
7847
|
+
*
|
|
7848
|
+
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7849
|
+
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7850
|
+
* SHAPE of the form only — the values live in `integrations.getSettings`, and the write path is
|
|
7851
|
+
* unchanged (`integrations.setSettings` for an account integration).
|
|
7852
|
+
*/
|
|
7853
|
+
async integrationSettingsSchema(_instance) {
|
|
7854
|
+
return null;
|
|
7855
|
+
}
|
|
7856
|
+
/**
|
|
7857
|
+
* What the create wizard and the integration edit page render for one instance: the addon's
|
|
7858
|
+
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7859
|
+
*/
|
|
7860
|
+
async getIntegrationFormSchema(instance, nodeId) {
|
|
7861
|
+
const scoped = await this.integrationSettingsSchema(instance);
|
|
7862
|
+
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
7863
|
+
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
7864
|
+
}
|
|
7351
7865
|
async getIntegrationSettings(nodeId) {
|
|
7352
7866
|
const declared = this.integrationSettingSections();
|
|
7353
7867
|
if (declared.length === 0) return null;
|
|
@@ -8451,407 +8965,6 @@ function defineRecordKinds(specs) {
|
|
|
8451
8965
|
}
|
|
8452
8966
|
return out;
|
|
8453
8967
|
}
|
|
8454
|
-
var READING_QUANTITIES = [
|
|
8455
|
-
"temperature",
|
|
8456
|
-
"pressure",
|
|
8457
|
-
"speed",
|
|
8458
|
-
"precipitation",
|
|
8459
|
-
"precipitation-rate",
|
|
8460
|
-
"length",
|
|
8461
|
-
"area",
|
|
8462
|
-
"illuminance",
|
|
8463
|
-
"irradiance",
|
|
8464
|
-
"power",
|
|
8465
|
-
"energy",
|
|
8466
|
-
"voltage",
|
|
8467
|
-
"current",
|
|
8468
|
-
"apparent-power",
|
|
8469
|
-
"humidity",
|
|
8470
|
-
"percentage",
|
|
8471
|
-
"concentration-volume",
|
|
8472
|
-
"concentration-mass",
|
|
8473
|
-
"concentration-ppb",
|
|
8474
|
-
"volume",
|
|
8475
|
-
"duration",
|
|
8476
|
-
"duration-ms",
|
|
8477
|
-
"information",
|
|
8478
|
-
"sound-level",
|
|
8479
|
-
"signal-level",
|
|
8480
|
-
"colour-temperature",
|
|
8481
|
-
"angle",
|
|
8482
|
-
"bitrate",
|
|
8483
|
-
"rate",
|
|
8484
|
-
"mass",
|
|
8485
|
-
"index",
|
|
8486
|
-
"ratio",
|
|
8487
|
-
"count",
|
|
8488
|
-
"none",
|
|
8489
|
-
"device"
|
|
8490
|
-
];
|
|
8491
|
-
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8492
|
-
new Set(READING_QUANTITIES);
|
|
8493
|
-
/**
|
|
8494
|
-
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8495
|
-
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8496
|
-
*/
|
|
8497
|
-
var QUANTITY_BASE = {
|
|
8498
|
-
temperature: "°C",
|
|
8499
|
-
pressure: "hPa",
|
|
8500
|
-
speed: "m/s",
|
|
8501
|
-
precipitation: "mm",
|
|
8502
|
-
"precipitation-rate": "mm/h",
|
|
8503
|
-
length: "m",
|
|
8504
|
-
area: "m²",
|
|
8505
|
-
illuminance: "lx",
|
|
8506
|
-
irradiance: "W/m²",
|
|
8507
|
-
power: "W",
|
|
8508
|
-
energy: "kWh",
|
|
8509
|
-
voltage: "V",
|
|
8510
|
-
current: "A",
|
|
8511
|
-
"apparent-power": "VA",
|
|
8512
|
-
humidity: "%",
|
|
8513
|
-
percentage: "%",
|
|
8514
|
-
"concentration-volume": "ppm",
|
|
8515
|
-
"concentration-mass": "µg/m³",
|
|
8516
|
-
"concentration-ppb": "ppb",
|
|
8517
|
-
volume: "L",
|
|
8518
|
-
duration: "s",
|
|
8519
|
-
"duration-ms": "ms",
|
|
8520
|
-
information: "B",
|
|
8521
|
-
"sound-level": "dBFS",
|
|
8522
|
-
"signal-level": "dBm",
|
|
8523
|
-
"colour-temperature": "mired",
|
|
8524
|
-
angle: "°",
|
|
8525
|
-
bitrate: "kbps",
|
|
8526
|
-
rate: "fps",
|
|
8527
|
-
mass: "kg",
|
|
8528
|
-
index: "none",
|
|
8529
|
-
ratio: "none",
|
|
8530
|
-
count: "none",
|
|
8531
|
-
none: "none",
|
|
8532
|
-
device: "device"
|
|
8533
|
-
};
|
|
8534
|
-
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8535
|
-
function baseUnitOf(quantity) {
|
|
8536
|
-
const symbol = QUANTITY_BASE[quantity];
|
|
8537
|
-
if (symbol === "none" || symbol === "device") return void 0;
|
|
8538
|
-
return symbol;
|
|
8539
|
-
}
|
|
8540
|
-
function readingMeta(quantity, extras) {
|
|
8541
|
-
return {
|
|
8542
|
-
quantity,
|
|
8543
|
-
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8544
|
-
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8545
|
-
};
|
|
8546
|
-
}
|
|
8547
|
-
/** Shared Zod schemas used across streaming capabilities. */
|
|
8548
|
-
var CamProfileSchema = _enum([
|
|
8549
|
-
"high",
|
|
8550
|
-
"mid",
|
|
8551
|
-
"low"
|
|
8552
|
-
]);
|
|
8553
|
-
/**
|
|
8554
|
-
* Which rung a per-camera consumer listens on: an explicit profile, or `auto`.
|
|
8555
|
-
*
|
|
8556
|
-
* `auto` is a REAL value, not an absent one — it means "resolve it by the rule
|
|
8557
|
-
* that consumer owns". It lives beside `CamProfile` because a rung is the only
|
|
8558
|
-
* operator-facing way to name a stream: a cam-stream id is broker-internal and
|
|
8559
|
-
* moves when a slot is reassigned, so a stored id silently stops meaning what
|
|
8560
|
-
* the operator picked. Today's one user is the audio analyser, whose rule is
|
|
8561
|
-
* "the lowest AVAILABLE native rung" (D537).
|
|
8562
|
-
*/
|
|
8563
|
-
var AudioStreamPickSchema = union([CamProfileSchema, literal("auto")]);
|
|
8564
|
-
var CamStreamKindSchema = _enum([
|
|
8565
|
-
"pull-rtsp",
|
|
8566
|
-
"pull-rtmp",
|
|
8567
|
-
"pull-http",
|
|
8568
|
-
"pull-flv",
|
|
8569
|
-
"pull-rfc4571",
|
|
8570
|
-
"push-annexb",
|
|
8571
|
-
"derived"
|
|
8572
|
-
]);
|
|
8573
|
-
var CamStreamResolutionSchema = object({
|
|
8574
|
-
width: number().int().positive().meta(readingMeta("none")),
|
|
8575
|
-
height: number().int().positive().meta(readingMeta("none"))
|
|
8576
|
-
});
|
|
8577
|
-
var CameraStreamSchema = object({
|
|
8578
|
-
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
8579
|
-
camStreamId: string().min(1),
|
|
8580
|
-
deviceId: number().int().nonnegative(),
|
|
8581
|
-
kind: CamStreamKindSchema,
|
|
8582
|
-
/** Required for pull-* kinds. Ignored for push-annexb. */
|
|
8583
|
-
url: string().optional(),
|
|
8584
|
-
codec: string().optional(),
|
|
8585
|
-
resolution: CamStreamResolutionSchema.optional(),
|
|
8586
|
-
fps: number().positive().optional(),
|
|
8587
|
-
/** Human label surfaced in the Admin UI "Camera Stream" dropdown. */
|
|
8588
|
-
label: string().optional(),
|
|
8589
|
-
/**
|
|
8590
|
-
* Device-level features the publisher advertised (e.g. `battery-operated`).
|
|
8591
|
-
* The broker, snapshot orchestrator, and prebuffer manager all consult
|
|
8592
|
-
* this list to derive policy — relaxed stall watchdog for battery
|
|
8593
|
-
* cams, prebuffer off by default, longer snapshot rate-limit, etc.
|
|
8594
|
-
*
|
|
8595
|
-
* Single source of truth replacing per-stream flags like the
|
|
8596
|
-
* historical `allowStall`: if the publisher knows the camera is
|
|
8597
|
-
* battery-powered, every downstream service derives the right policy
|
|
8598
|
-
* from this list.
|
|
8599
|
-
*/
|
|
8600
|
-
deviceFeatures: array(string()).optional(),
|
|
8601
|
-
/**
|
|
8602
|
-
* Whether this stream participates in the broker's automatic profile
|
|
8603
|
-
* assignment (`computeInitialAssignment`). Defaults to `true`. Publishers
|
|
8604
|
-
* use `false` when they want a stream to be SELECTABLE in the UI but not
|
|
8605
|
-
* picked by default — e.g. Reolink publishes its native Baichuan streams
|
|
8606
|
-
* as `autoEligible: true` (the recommended path) and its RTSP / RTMP
|
|
8607
|
-
* mirrors as `autoEligible: false` (still pickable per slot, just not
|
|
8608
|
-
* the auto choice). Manual `assignProfile` calls remain valid for
|
|
8609
|
-
* non-eligible streams.
|
|
8610
|
-
*/
|
|
8611
|
-
autoEligible: boolean().optional(),
|
|
8612
|
-
/**
|
|
8613
|
-
* The profile slot the PUBLISHER says this stream is: `low` for a stream
|
|
8614
|
-
* whose only sensible role is the low-bandwidth one, `high` for a main
|
|
8615
|
-
* stream. Consulted by the broker's automatic ranking
|
|
8616
|
-
* (`rankInitialAssignment`) BEFORE the pixel-count heuristic, and only there:
|
|
8617
|
-
* an operator's manual assignment still wins, and an absent hint is the
|
|
8618
|
-
* pixel-ranked default every camera had before this field existed.
|
|
8619
|
-
*
|
|
8620
|
-
* Why it exists: a camera with ONE stream ranked to `mid` — the slot no
|
|
8621
|
-
* storage class is written for on its own (`recordings` is high|mid,
|
|
8622
|
-
* `recordingsLow` is low) and the one profile scrub does not read. The robot
|
|
8623
|
-
* camera's single 720p relay is a `low` in every respect except the slot the
|
|
8624
|
-
* heuristic put it in.
|
|
8625
|
-
*/
|
|
8626
|
-
profileHint: CamProfileSchema.optional(),
|
|
8627
|
-
/**
|
|
8628
|
-
* Transport-specific opaque metadata. The broker passes it through to
|
|
8629
|
-
* the source reader without inspecting it. Currently used by
|
|
8630
|
-
* `pull-rfc4571` streams to carry the upstream SDP (so the reader can
|
|
8631
|
-
* route RTP packets to the right depacketizer without an in-band
|
|
8632
|
-
* DESCRIBE phase). Other kinds typically leave it undefined.
|
|
8633
|
-
*/
|
|
8634
|
-
metadata: record(string(), unknown()).optional()
|
|
8635
|
-
});
|
|
8636
|
-
var ProfileSlotStatusSchema = _enum([
|
|
8637
|
-
"unassigned",
|
|
8638
|
-
"idle",
|
|
8639
|
-
"connecting",
|
|
8640
|
-
"streaming",
|
|
8641
|
-
"error"
|
|
8642
|
-
]);
|
|
8643
|
-
var ProfileSlotSchema = object({
|
|
8644
|
-
deviceId: number().int().nonnegative(),
|
|
8645
|
-
profile: CamProfileSchema,
|
|
8646
|
-
/** Broker id the rest of the system addresses: `${deviceId}/${profile}`. */
|
|
8647
|
-
brokerId: string(),
|
|
8648
|
-
/** `null` when the profile is unassigned. */
|
|
8649
|
-
sourceCamStreamId: string().nullable(),
|
|
8650
|
-
status: ProfileSlotStatusSchema,
|
|
8651
|
-
resolution: CamStreamResolutionSchema.optional(),
|
|
8652
|
-
codec: string().optional(),
|
|
8653
|
-
preBufferSec: number().nonnegative().optional(),
|
|
8654
|
-
errorMessage: string().optional()
|
|
8655
|
-
});
|
|
8656
|
-
/**
|
|
8657
|
-
* Zod schema for StreamSourceEntry — the canonical stream descriptor
|
|
8658
|
-
* exposed by ICameraDevice.getStreamSources() and consumed by the broker.
|
|
8659
|
-
*/
|
|
8660
|
-
var StreamSourceEntrySchema$1 = object({
|
|
8661
|
-
id: string(),
|
|
8662
|
-
label: string(),
|
|
8663
|
-
protocol: _enum([
|
|
8664
|
-
"rtsp",
|
|
8665
|
-
"rtmp",
|
|
8666
|
-
"annexb",
|
|
8667
|
-
"http-mjpeg",
|
|
8668
|
-
"webrtc",
|
|
8669
|
-
"custom"
|
|
8670
|
-
]),
|
|
8671
|
-
url: string().optional(),
|
|
8672
|
-
resolution: object({
|
|
8673
|
-
width: number(),
|
|
8674
|
-
height: number()
|
|
8675
|
-
}).readonly().optional(),
|
|
8676
|
-
fps: number().optional(),
|
|
8677
|
-
bitrate: number().optional(),
|
|
8678
|
-
codec: string().optional(),
|
|
8679
|
-
profileHint: CamProfileSchema.optional()
|
|
8680
|
-
});
|
|
8681
|
-
object({
|
|
8682
|
-
type: string(),
|
|
8683
|
-
url: string(),
|
|
8684
|
-
videoCodec: string().optional(),
|
|
8685
|
-
audioCodec: string().optional(),
|
|
8686
|
-
metadata: record(string(), unknown()).readonly().optional()
|
|
8687
|
-
});
|
|
8688
|
-
/**
|
|
8689
|
-
* Wire schema for `FrameHandle` — a zero-pixel, serialisable reference to a
|
|
8690
|
-
* frame in a shared-memory ring (Phase 5 / D9). Mirrors the `FrameHandle` TS
|
|
8691
|
-
* interface in `interfaces/frame-handle.ts` field-for-field so a cap method
|
|
8692
|
-
* (the runner's native-crop and pipeline-executor inputs) can carry handles
|
|
8693
|
-
* over tRPC / Moleculer.
|
|
8694
|
-
*
|
|
8695
|
-
* The `satisfies` assertion below pins this schema to the interface: if a
|
|
8696
|
-
* field is added to / removed from `FrameHandle` without a matching schema
|
|
8697
|
-
* edit, `z.infer<typeof FrameHandleSchema>` stops being assignable to
|
|
8698
|
-
* `FrameHandle` and the build fails — no silent drift.
|
|
8699
|
-
*/
|
|
8700
|
-
var FrameHandleSchema = object({
|
|
8701
|
-
shmId: string(),
|
|
8702
|
-
slot: number().int().nonnegative(),
|
|
8703
|
-
seq: number().int().nonnegative(),
|
|
8704
|
-
width: number().int().positive(),
|
|
8705
|
-
height: number().int().positive(),
|
|
8706
|
-
format: _enum([
|
|
8707
|
-
"jpeg",
|
|
8708
|
-
"rgb",
|
|
8709
|
-
"bgr",
|
|
8710
|
-
"yuv420",
|
|
8711
|
-
"gray"
|
|
8712
|
-
]),
|
|
8713
|
-
pts: number(),
|
|
8714
|
-
byteLength: number().int().nonnegative(),
|
|
8715
|
-
nodeId: string(),
|
|
8716
|
-
slotCount: number().int().positive()
|
|
8717
|
-
});
|
|
8718
|
-
/**
|
|
8719
|
-
* Wire schema for a decoded audio chunk (Phase 5 / D9). Mirrors the
|
|
8720
|
-
* `DecodedAudioChunk` TS interface in `interfaces/stream-broker.ts`: PCM
|
|
8721
|
-
* sample bytes plus the track parameters a consumer needs to interpret them.
|
|
8722
|
-
*
|
|
8723
|
-
* Audio chunks are tiny (a ~500ms AudioCodecSession window is a few KB of
|
|
8724
|
-
* Float32 PCM), so unlike video frames they ship their bytes INLINE over
|
|
8725
|
-
* tRPC / Moleculer — no shared-memory plane. `data` is typed `Uint8Array`
|
|
8726
|
-
* (the wire-serialisable supertype of `Buffer`); a `Buffer` is assignable to
|
|
8727
|
-
* it.
|
|
8728
|
-
*/
|
|
8729
|
-
var AudioChunkFormatSchema = _enum(AUDIO_CHUNK_FORMATS);
|
|
8730
|
-
var DecodedAudioChunkSchema = object({
|
|
8731
|
-
data: _instanceof(Uint8Array),
|
|
8732
|
-
sampleRate: number().int().positive(),
|
|
8733
|
-
channels: number().int().positive(),
|
|
8734
|
-
timestamp: number(),
|
|
8735
|
-
/**
|
|
8736
|
-
* Byte format of `data`. ABSENT MEANS `f32le` — today's bytes, byte for
|
|
8737
|
-
* byte, for any peer that never heard of this field. A coded window
|
|
8738
|
-
* (`pcmu` / `pcma`, one byte per sample) is only ever emitted to a
|
|
8739
|
-
* subscription that DECLARED it accepts one, so absence can never mean
|
|
8740
|
-
* "coded bytes a consumer will read as floats" (D455).
|
|
8741
|
-
*/
|
|
8742
|
-
format: AudioChunkFormatSchema.optional()
|
|
8743
|
-
});
|
|
8744
|
-
/**
|
|
8745
|
-
* Input for `stream-broker.subscribeAudioChunks` (Phase 5 / D9). Audio ships
|
|
8746
|
-
* its bytes inline: a consumer asks the broker for the decoded audio-chunk
|
|
8747
|
-
* stream of one broker; the broker keeps a per-subscription bounded FIFO queue
|
|
8748
|
-
* the consumer drains via `pullAudioChunks`.
|
|
8749
|
-
*/
|
|
8750
|
-
var SubscribeAudioChunksInputSchema = object({
|
|
8751
|
-
brokerId: string(),
|
|
8752
|
-
/** Short caller-identity tag (`audio-analyzer`, …) for `listClients`. */
|
|
8753
|
-
tag: string().optional(),
|
|
8754
|
-
/**
|
|
8755
|
-
* Byte formats this subscriber can READ, best first. The broker serves the
|
|
8756
|
-
* chunk's own format when it is in this list and expands to `f32le`
|
|
8757
|
-
* otherwise, so a subscriber is never handed bytes it cannot interpret.
|
|
8758
|
-
*
|
|
8759
|
-
* Absent (or without the source format) means `f32le` — the behaviour every
|
|
8760
|
-
* subscriber had before D455, unchanged. This is the negotiation half of
|
|
8761
|
-
* the source-bytes lever: it is what lets the broker and its consumers
|
|
8762
|
-
* deploy one at a time across three nodes.
|
|
8763
|
-
*/
|
|
8764
|
-
accept: array(AudioChunkFormatSchema).readonly().optional()
|
|
8765
|
-
});
|
|
8766
|
-
/** Result of `stream-broker.subscribeAudioChunks`. */
|
|
8767
|
-
var SubscribeAudioChunksResultSchema = object({
|
|
8768
|
-
/** Opaque id passed to `pullAudioChunks` / `unsubscribeAudioChunks`. */
|
|
8769
|
-
subscriptionId: string() });
|
|
8770
|
-
var BrokerStatsSchema = object({
|
|
8771
|
-
status: _enum([
|
|
8772
|
-
"idle",
|
|
8773
|
-
"connecting",
|
|
8774
|
-
"streaming",
|
|
8775
|
-
"error",
|
|
8776
|
-
"stopped"
|
|
8777
|
-
]),
|
|
8778
|
-
inputFps: number(),
|
|
8779
|
-
encodedSubscribers: number(),
|
|
8780
|
-
uptimeMs: number(),
|
|
8781
|
-
bitrateKbps: number(),
|
|
8782
|
-
idrIntervalMs: number(),
|
|
8783
|
-
codec: string().optional(),
|
|
8784
|
-
totalBytes: number(),
|
|
8785
|
-
packetCount: number(),
|
|
8786
|
-
rtspClients: number(),
|
|
8787
|
-
pipeClients: number(),
|
|
8788
|
-
preBufferSec: number(),
|
|
8789
|
-
preBufferMs: number(),
|
|
8790
|
-
preBufferPackets: number(),
|
|
8791
|
-
/**
|
|
8792
|
-
* Detected audio track parameters from the RTSP DESCRIBE / SDP. `null`
|
|
8793
|
-
* when the stream has no audio track or the broker is in cold start.
|
|
8794
|
-
* `supported = false` means the codec was detected but the local
|
|
8795
|
-
* decoder pipeline cannot produce PCM chunks (e.g. AAC without the
|
|
8796
|
-
* AAC pipeline wired). Surfaced in the UI device-overview so operators
|
|
8797
|
-
* can pre-pick the audio-analysis model that matches the codec.
|
|
8798
|
-
*/
|
|
8799
|
-
audio: object({
|
|
8800
|
-
codec: string(),
|
|
8801
|
-
sampleRate: number(),
|
|
8802
|
-
channels: number(),
|
|
8803
|
-
supported: boolean()
|
|
8804
|
-
}).nullable().optional(),
|
|
8805
|
-
/**
|
|
8806
|
-
* BROKER-SIDE AUDIO MUTE (D83). `true` = this broker is deliberately
|
|
8807
|
-
* distributing none of the device's audio, on live or recording.
|
|
8808
|
-
*
|
|
8809
|
-
* Present so a silent camera can be told apart from a broken one on the
|
|
8810
|
-
* stream panel itself, without cross-referencing the switch group: a
|
|
8811
|
-
* broker holding an `audio` track descriptor while `audioMuted` is true is
|
|
8812
|
-
* working exactly as asked. `audioMutedDropped` counts the audio units
|
|
8813
|
-
* thrown away since the current dial — it is how you confirm from stats
|
|
8814
|
-
* alone that the mute is on the packet path and not merely persisted.
|
|
8815
|
-
*/
|
|
8816
|
-
audioMuted: boolean().optional(),
|
|
8817
|
-
audioMutedDropped: number().optional()
|
|
8818
|
-
});
|
|
8819
|
-
/**
|
|
8820
|
-
* Exporter-facing "profile restream" entry. Returned by
|
|
8821
|
-
* `cameraStreams.getProfileRtspEntries` — one per ASSIGNED profile slot
|
|
8822
|
-
* (high/mid/low). `brokerId` is the PROFILE-keyed broker id
|
|
8823
|
-
* (`${deviceId}/${profile}`, e.g. `15/high`); its `url` is a broker
|
|
8824
|
-
* RTSP restream that aliases the profile's assigned source broker, so
|
|
8825
|
-
* every consumer dialling a profile converges on the same single pull.
|
|
8826
|
-
* `codec`/`resolution` describe the assigned SOURCE camStream (for the
|
|
8827
|
-
* `auto` resolution-closest pick). Distinct from `RtspRestreamEntry`
|
|
8828
|
-
* (raw per-camStream, live-view only).
|
|
8829
|
-
*/
|
|
8830
|
-
var ProfileRtspEntrySchema = object({
|
|
8831
|
-
profile: CamProfileSchema,
|
|
8832
|
-
/** Profile-keyed broker id, format `${deviceId}/${profile}` (e.g. `"15/high"`). */
|
|
8833
|
-
brokerId: string(),
|
|
8834
|
-
url: string(),
|
|
8835
|
-
mutedUrl: string(),
|
|
8836
|
-
enabled: boolean(),
|
|
8837
|
-
codec: string().optional(),
|
|
8838
|
-
resolution: CamStreamResolutionSchema.optional()
|
|
8839
|
-
});
|
|
8840
|
-
/**
|
|
8841
|
-
* The model weight formats a catalog entry can ship. Schema-free on purpose:
|
|
8842
|
-
* `types/models.ts` builds Zod schemas from it, but a runner-closure consumer
|
|
8843
|
-
* (the model downloader in `@camstack/system`) needs only the list and must
|
|
8844
|
-
* reach it through `@camstack/types/addon` without building the cap schema
|
|
8845
|
-
* graph (D28).
|
|
8846
|
-
*/
|
|
8847
|
-
var MODEL_FORMATS = [
|
|
8848
|
-
"onnx",
|
|
8849
|
-
"coreml",
|
|
8850
|
-
"openvino",
|
|
8851
|
-
"tflite",
|
|
8852
|
-
"pt",
|
|
8853
|
-
"gguf"
|
|
8854
|
-
];
|
|
8855
8968
|
object({
|
|
8856
8969
|
field: string().min(1),
|
|
8857
8970
|
on: literal("advance")
|
|
@@ -8944,6 +9057,407 @@ function optionalMethod(input, output, options) {
|
|
|
8944
9057
|
function event(data) {
|
|
8945
9058
|
return { data };
|
|
8946
9059
|
}
|
|
9060
|
+
var READING_QUANTITIES = [
|
|
9061
|
+
"temperature",
|
|
9062
|
+
"pressure",
|
|
9063
|
+
"speed",
|
|
9064
|
+
"precipitation",
|
|
9065
|
+
"precipitation-rate",
|
|
9066
|
+
"length",
|
|
9067
|
+
"area",
|
|
9068
|
+
"illuminance",
|
|
9069
|
+
"irradiance",
|
|
9070
|
+
"power",
|
|
9071
|
+
"energy",
|
|
9072
|
+
"voltage",
|
|
9073
|
+
"current",
|
|
9074
|
+
"apparent-power",
|
|
9075
|
+
"humidity",
|
|
9076
|
+
"percentage",
|
|
9077
|
+
"concentration-volume",
|
|
9078
|
+
"concentration-mass",
|
|
9079
|
+
"concentration-ppb",
|
|
9080
|
+
"volume",
|
|
9081
|
+
"duration",
|
|
9082
|
+
"duration-ms",
|
|
9083
|
+
"information",
|
|
9084
|
+
"sound-level",
|
|
9085
|
+
"signal-level",
|
|
9086
|
+
"colour-temperature",
|
|
9087
|
+
"angle",
|
|
9088
|
+
"bitrate",
|
|
9089
|
+
"rate",
|
|
9090
|
+
"mass",
|
|
9091
|
+
"index",
|
|
9092
|
+
"ratio",
|
|
9093
|
+
"count",
|
|
9094
|
+
"none",
|
|
9095
|
+
"device"
|
|
9096
|
+
];
|
|
9097
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
9098
|
+
new Set(READING_QUANTITIES);
|
|
9099
|
+
/**
|
|
9100
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
9101
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
9102
|
+
*/
|
|
9103
|
+
var QUANTITY_BASE = {
|
|
9104
|
+
temperature: "°C",
|
|
9105
|
+
pressure: "hPa",
|
|
9106
|
+
speed: "m/s",
|
|
9107
|
+
precipitation: "mm",
|
|
9108
|
+
"precipitation-rate": "mm/h",
|
|
9109
|
+
length: "m",
|
|
9110
|
+
area: "m²",
|
|
9111
|
+
illuminance: "lx",
|
|
9112
|
+
irradiance: "W/m²",
|
|
9113
|
+
power: "W",
|
|
9114
|
+
energy: "kWh",
|
|
9115
|
+
voltage: "V",
|
|
9116
|
+
current: "A",
|
|
9117
|
+
"apparent-power": "VA",
|
|
9118
|
+
humidity: "%",
|
|
9119
|
+
percentage: "%",
|
|
9120
|
+
"concentration-volume": "ppm",
|
|
9121
|
+
"concentration-mass": "µg/m³",
|
|
9122
|
+
"concentration-ppb": "ppb",
|
|
9123
|
+
volume: "L",
|
|
9124
|
+
duration: "s",
|
|
9125
|
+
"duration-ms": "ms",
|
|
9126
|
+
information: "B",
|
|
9127
|
+
"sound-level": "dBFS",
|
|
9128
|
+
"signal-level": "dBm",
|
|
9129
|
+
"colour-temperature": "mired",
|
|
9130
|
+
angle: "°",
|
|
9131
|
+
bitrate: "kbps",
|
|
9132
|
+
rate: "fps",
|
|
9133
|
+
mass: "kg",
|
|
9134
|
+
index: "none",
|
|
9135
|
+
ratio: "none",
|
|
9136
|
+
count: "none",
|
|
9137
|
+
none: "none",
|
|
9138
|
+
device: "device"
|
|
9139
|
+
};
|
|
9140
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
9141
|
+
function baseUnitOf(quantity) {
|
|
9142
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
9143
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
9144
|
+
return symbol;
|
|
9145
|
+
}
|
|
9146
|
+
function readingMeta(quantity, extras) {
|
|
9147
|
+
return {
|
|
9148
|
+
quantity,
|
|
9149
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
9150
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
9151
|
+
};
|
|
9152
|
+
}
|
|
9153
|
+
/** Shared Zod schemas used across streaming capabilities. */
|
|
9154
|
+
var CamProfileSchema = _enum([
|
|
9155
|
+
"high",
|
|
9156
|
+
"mid",
|
|
9157
|
+
"low"
|
|
9158
|
+
]);
|
|
9159
|
+
/**
|
|
9160
|
+
* Which rung a per-camera consumer listens on: an explicit profile, or `auto`.
|
|
9161
|
+
*
|
|
9162
|
+
* `auto` is a REAL value, not an absent one — it means "resolve it by the rule
|
|
9163
|
+
* that consumer owns". It lives beside `CamProfile` because a rung is the only
|
|
9164
|
+
* operator-facing way to name a stream: a cam-stream id is broker-internal and
|
|
9165
|
+
* moves when a slot is reassigned, so a stored id silently stops meaning what
|
|
9166
|
+
* the operator picked. Today's one user is the audio analyser, whose rule is
|
|
9167
|
+
* "the lowest AVAILABLE native rung" (D537).
|
|
9168
|
+
*/
|
|
9169
|
+
var AudioStreamPickSchema = union([CamProfileSchema, literal("auto")]);
|
|
9170
|
+
var CamStreamKindSchema = _enum([
|
|
9171
|
+
"pull-rtsp",
|
|
9172
|
+
"pull-rtmp",
|
|
9173
|
+
"pull-http",
|
|
9174
|
+
"pull-flv",
|
|
9175
|
+
"pull-rfc4571",
|
|
9176
|
+
"push-annexb",
|
|
9177
|
+
"derived"
|
|
9178
|
+
]);
|
|
9179
|
+
var CamStreamResolutionSchema = object({
|
|
9180
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
9181
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
9182
|
+
});
|
|
9183
|
+
var CameraStreamSchema = object({
|
|
9184
|
+
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
9185
|
+
camStreamId: string().min(1),
|
|
9186
|
+
deviceId: number().int().nonnegative(),
|
|
9187
|
+
kind: CamStreamKindSchema,
|
|
9188
|
+
/** Required for pull-* kinds. Ignored for push-annexb. */
|
|
9189
|
+
url: string().optional(),
|
|
9190
|
+
codec: string().optional(),
|
|
9191
|
+
resolution: CamStreamResolutionSchema.optional(),
|
|
9192
|
+
fps: number().positive().optional(),
|
|
9193
|
+
/** Human label surfaced in the Admin UI "Camera Stream" dropdown. */
|
|
9194
|
+
label: string().optional(),
|
|
9195
|
+
/**
|
|
9196
|
+
* Device-level features the publisher advertised (e.g. `battery-operated`).
|
|
9197
|
+
* The broker, snapshot orchestrator, and prebuffer manager all consult
|
|
9198
|
+
* this list to derive policy — relaxed stall watchdog for battery
|
|
9199
|
+
* cams, prebuffer off by default, longer snapshot rate-limit, etc.
|
|
9200
|
+
*
|
|
9201
|
+
* Single source of truth replacing per-stream flags like the
|
|
9202
|
+
* historical `allowStall`: if the publisher knows the camera is
|
|
9203
|
+
* battery-powered, every downstream service derives the right policy
|
|
9204
|
+
* from this list.
|
|
9205
|
+
*/
|
|
9206
|
+
deviceFeatures: array(string()).optional(),
|
|
9207
|
+
/**
|
|
9208
|
+
* Whether this stream participates in the broker's automatic profile
|
|
9209
|
+
* assignment (`computeInitialAssignment`). Defaults to `true`. Publishers
|
|
9210
|
+
* use `false` when they want a stream to be SELECTABLE in the UI but not
|
|
9211
|
+
* picked by default — e.g. Reolink publishes its native Baichuan streams
|
|
9212
|
+
* as `autoEligible: true` (the recommended path) and its RTSP / RTMP
|
|
9213
|
+
* mirrors as `autoEligible: false` (still pickable per slot, just not
|
|
9214
|
+
* the auto choice). Manual `assignProfile` calls remain valid for
|
|
9215
|
+
* non-eligible streams.
|
|
9216
|
+
*/
|
|
9217
|
+
autoEligible: boolean().optional(),
|
|
9218
|
+
/**
|
|
9219
|
+
* The profile slot the PUBLISHER says this stream is: `low` for a stream
|
|
9220
|
+
* whose only sensible role is the low-bandwidth one, `high` for a main
|
|
9221
|
+
* stream. Consulted by the broker's automatic ranking
|
|
9222
|
+
* (`rankInitialAssignment`) BEFORE the pixel-count heuristic, and only there:
|
|
9223
|
+
* an operator's manual assignment still wins, and an absent hint is the
|
|
9224
|
+
* pixel-ranked default every camera had before this field existed.
|
|
9225
|
+
*
|
|
9226
|
+
* Why it exists: a camera with ONE stream ranked to `mid` — the slot no
|
|
9227
|
+
* storage class is written for on its own (`recordings` is high|mid,
|
|
9228
|
+
* `recordingsLow` is low) and the one profile scrub does not read. The robot
|
|
9229
|
+
* camera's single 720p relay is a `low` in every respect except the slot the
|
|
9230
|
+
* heuristic put it in.
|
|
9231
|
+
*/
|
|
9232
|
+
profileHint: CamProfileSchema.optional(),
|
|
9233
|
+
/**
|
|
9234
|
+
* Transport-specific opaque metadata. The broker passes it through to
|
|
9235
|
+
* the source reader without inspecting it. Currently used by
|
|
9236
|
+
* `pull-rfc4571` streams to carry the upstream SDP (so the reader can
|
|
9237
|
+
* route RTP packets to the right depacketizer without an in-band
|
|
9238
|
+
* DESCRIBE phase). Other kinds typically leave it undefined.
|
|
9239
|
+
*/
|
|
9240
|
+
metadata: record(string(), unknown()).optional()
|
|
9241
|
+
});
|
|
9242
|
+
var ProfileSlotStatusSchema = _enum([
|
|
9243
|
+
"unassigned",
|
|
9244
|
+
"idle",
|
|
9245
|
+
"connecting",
|
|
9246
|
+
"streaming",
|
|
9247
|
+
"error"
|
|
9248
|
+
]);
|
|
9249
|
+
var ProfileSlotSchema = object({
|
|
9250
|
+
deviceId: number().int().nonnegative(),
|
|
9251
|
+
profile: CamProfileSchema,
|
|
9252
|
+
/** Broker id the rest of the system addresses: `${deviceId}/${profile}`. */
|
|
9253
|
+
brokerId: string(),
|
|
9254
|
+
/** `null` when the profile is unassigned. */
|
|
9255
|
+
sourceCamStreamId: string().nullable(),
|
|
9256
|
+
status: ProfileSlotStatusSchema,
|
|
9257
|
+
resolution: CamStreamResolutionSchema.optional(),
|
|
9258
|
+
codec: string().optional(),
|
|
9259
|
+
preBufferSec: number().nonnegative().optional(),
|
|
9260
|
+
errorMessage: string().optional()
|
|
9261
|
+
});
|
|
9262
|
+
/**
|
|
9263
|
+
* Zod schema for StreamSourceEntry — the canonical stream descriptor
|
|
9264
|
+
* exposed by ICameraDevice.getStreamSources() and consumed by the broker.
|
|
9265
|
+
*/
|
|
9266
|
+
var StreamSourceEntrySchema$1 = object({
|
|
9267
|
+
id: string(),
|
|
9268
|
+
label: string(),
|
|
9269
|
+
protocol: _enum([
|
|
9270
|
+
"rtsp",
|
|
9271
|
+
"rtmp",
|
|
9272
|
+
"annexb",
|
|
9273
|
+
"http-mjpeg",
|
|
9274
|
+
"webrtc",
|
|
9275
|
+
"custom"
|
|
9276
|
+
]),
|
|
9277
|
+
url: string().optional(),
|
|
9278
|
+
resolution: object({
|
|
9279
|
+
width: number(),
|
|
9280
|
+
height: number()
|
|
9281
|
+
}).readonly().optional(),
|
|
9282
|
+
fps: number().optional(),
|
|
9283
|
+
bitrate: number().optional(),
|
|
9284
|
+
codec: string().optional(),
|
|
9285
|
+
profileHint: CamProfileSchema.optional()
|
|
9286
|
+
});
|
|
9287
|
+
object({
|
|
9288
|
+
type: string(),
|
|
9289
|
+
url: string(),
|
|
9290
|
+
videoCodec: string().optional(),
|
|
9291
|
+
audioCodec: string().optional(),
|
|
9292
|
+
metadata: record(string(), unknown()).readonly().optional()
|
|
9293
|
+
});
|
|
9294
|
+
/**
|
|
9295
|
+
* Wire schema for `FrameHandle` — a zero-pixel, serialisable reference to a
|
|
9296
|
+
* frame in a shared-memory ring (Phase 5 / D9). Mirrors the `FrameHandle` TS
|
|
9297
|
+
* interface in `interfaces/frame-handle.ts` field-for-field so a cap method
|
|
9298
|
+
* (the runner's native-crop and pipeline-executor inputs) can carry handles
|
|
9299
|
+
* over tRPC / Moleculer.
|
|
9300
|
+
*
|
|
9301
|
+
* The `satisfies` assertion below pins this schema to the interface: if a
|
|
9302
|
+
* field is added to / removed from `FrameHandle` without a matching schema
|
|
9303
|
+
* edit, `z.infer<typeof FrameHandleSchema>` stops being assignable to
|
|
9304
|
+
* `FrameHandle` and the build fails — no silent drift.
|
|
9305
|
+
*/
|
|
9306
|
+
var FrameHandleSchema = object({
|
|
9307
|
+
shmId: string(),
|
|
9308
|
+
slot: number().int().nonnegative(),
|
|
9309
|
+
seq: number().int().nonnegative(),
|
|
9310
|
+
width: number().int().positive(),
|
|
9311
|
+
height: number().int().positive(),
|
|
9312
|
+
format: _enum([
|
|
9313
|
+
"jpeg",
|
|
9314
|
+
"rgb",
|
|
9315
|
+
"bgr",
|
|
9316
|
+
"yuv420",
|
|
9317
|
+
"gray"
|
|
9318
|
+
]),
|
|
9319
|
+
pts: number(),
|
|
9320
|
+
byteLength: number().int().nonnegative(),
|
|
9321
|
+
nodeId: string(),
|
|
9322
|
+
slotCount: number().int().positive()
|
|
9323
|
+
});
|
|
9324
|
+
/**
|
|
9325
|
+
* Wire schema for a decoded audio chunk (Phase 5 / D9). Mirrors the
|
|
9326
|
+
* `DecodedAudioChunk` TS interface in `interfaces/stream-broker.ts`: PCM
|
|
9327
|
+
* sample bytes plus the track parameters a consumer needs to interpret them.
|
|
9328
|
+
*
|
|
9329
|
+
* Audio chunks are tiny (a ~500ms AudioCodecSession window is a few KB of
|
|
9330
|
+
* Float32 PCM), so unlike video frames they ship their bytes INLINE over
|
|
9331
|
+
* tRPC / Moleculer — no shared-memory plane. `data` is typed `Uint8Array`
|
|
9332
|
+
* (the wire-serialisable supertype of `Buffer`); a `Buffer` is assignable to
|
|
9333
|
+
* it.
|
|
9334
|
+
*/
|
|
9335
|
+
var AudioChunkFormatSchema = _enum(AUDIO_CHUNK_FORMATS);
|
|
9336
|
+
var DecodedAudioChunkSchema = object({
|
|
9337
|
+
data: _instanceof(Uint8Array),
|
|
9338
|
+
sampleRate: number().int().positive(),
|
|
9339
|
+
channels: number().int().positive(),
|
|
9340
|
+
timestamp: number(),
|
|
9341
|
+
/**
|
|
9342
|
+
* Byte format of `data`. ABSENT MEANS `f32le` — today's bytes, byte for
|
|
9343
|
+
* byte, for any peer that never heard of this field. A coded window
|
|
9344
|
+
* (`pcmu` / `pcma`, one byte per sample) is only ever emitted to a
|
|
9345
|
+
* subscription that DECLARED it accepts one, so absence can never mean
|
|
9346
|
+
* "coded bytes a consumer will read as floats" (D455).
|
|
9347
|
+
*/
|
|
9348
|
+
format: AudioChunkFormatSchema.optional()
|
|
9349
|
+
});
|
|
9350
|
+
/**
|
|
9351
|
+
* Input for `stream-broker.subscribeAudioChunks` (Phase 5 / D9). Audio ships
|
|
9352
|
+
* its bytes inline: a consumer asks the broker for the decoded audio-chunk
|
|
9353
|
+
* stream of one broker; the broker keeps a per-subscription bounded FIFO queue
|
|
9354
|
+
* the consumer drains via `pullAudioChunks`.
|
|
9355
|
+
*/
|
|
9356
|
+
var SubscribeAudioChunksInputSchema = object({
|
|
9357
|
+
brokerId: string(),
|
|
9358
|
+
/** Short caller-identity tag (`audio-analyzer`, …) for `listClients`. */
|
|
9359
|
+
tag: string().optional(),
|
|
9360
|
+
/**
|
|
9361
|
+
* Byte formats this subscriber can READ, best first. The broker serves the
|
|
9362
|
+
* chunk's own format when it is in this list and expands to `f32le`
|
|
9363
|
+
* otherwise, so a subscriber is never handed bytes it cannot interpret.
|
|
9364
|
+
*
|
|
9365
|
+
* Absent (or without the source format) means `f32le` — the behaviour every
|
|
9366
|
+
* subscriber had before D455, unchanged. This is the negotiation half of
|
|
9367
|
+
* the source-bytes lever: it is what lets the broker and its consumers
|
|
9368
|
+
* deploy one at a time across three nodes.
|
|
9369
|
+
*/
|
|
9370
|
+
accept: array(AudioChunkFormatSchema).readonly().optional()
|
|
9371
|
+
});
|
|
9372
|
+
/** Result of `stream-broker.subscribeAudioChunks`. */
|
|
9373
|
+
var SubscribeAudioChunksResultSchema = object({
|
|
9374
|
+
/** Opaque id passed to `pullAudioChunks` / `unsubscribeAudioChunks`. */
|
|
9375
|
+
subscriptionId: string() });
|
|
9376
|
+
var BrokerStatsSchema = object({
|
|
9377
|
+
status: _enum([
|
|
9378
|
+
"idle",
|
|
9379
|
+
"connecting",
|
|
9380
|
+
"streaming",
|
|
9381
|
+
"error",
|
|
9382
|
+
"stopped"
|
|
9383
|
+
]),
|
|
9384
|
+
inputFps: number(),
|
|
9385
|
+
encodedSubscribers: number(),
|
|
9386
|
+
uptimeMs: number(),
|
|
9387
|
+
bitrateKbps: number(),
|
|
9388
|
+
idrIntervalMs: number(),
|
|
9389
|
+
codec: string().optional(),
|
|
9390
|
+
totalBytes: number(),
|
|
9391
|
+
packetCount: number(),
|
|
9392
|
+
rtspClients: number(),
|
|
9393
|
+
pipeClients: number(),
|
|
9394
|
+
preBufferSec: number(),
|
|
9395
|
+
preBufferMs: number(),
|
|
9396
|
+
preBufferPackets: number(),
|
|
9397
|
+
/**
|
|
9398
|
+
* Detected audio track parameters from the RTSP DESCRIBE / SDP. `null`
|
|
9399
|
+
* when the stream has no audio track or the broker is in cold start.
|
|
9400
|
+
* `supported = false` means the codec was detected but the local
|
|
9401
|
+
* decoder pipeline cannot produce PCM chunks (e.g. AAC without the
|
|
9402
|
+
* AAC pipeline wired). Surfaced in the UI device-overview so operators
|
|
9403
|
+
* can pre-pick the audio-analysis model that matches the codec.
|
|
9404
|
+
*/
|
|
9405
|
+
audio: object({
|
|
9406
|
+
codec: string(),
|
|
9407
|
+
sampleRate: number(),
|
|
9408
|
+
channels: number(),
|
|
9409
|
+
supported: boolean()
|
|
9410
|
+
}).nullable().optional(),
|
|
9411
|
+
/**
|
|
9412
|
+
* BROKER-SIDE AUDIO MUTE (D83). `true` = this broker is deliberately
|
|
9413
|
+
* distributing none of the device's audio, on live or recording.
|
|
9414
|
+
*
|
|
9415
|
+
* Present so a silent camera can be told apart from a broken one on the
|
|
9416
|
+
* stream panel itself, without cross-referencing the switch group: a
|
|
9417
|
+
* broker holding an `audio` track descriptor while `audioMuted` is true is
|
|
9418
|
+
* working exactly as asked. `audioMutedDropped` counts the audio units
|
|
9419
|
+
* thrown away since the current dial — it is how you confirm from stats
|
|
9420
|
+
* alone that the mute is on the packet path and not merely persisted.
|
|
9421
|
+
*/
|
|
9422
|
+
audioMuted: boolean().optional(),
|
|
9423
|
+
audioMutedDropped: number().optional()
|
|
9424
|
+
});
|
|
9425
|
+
/**
|
|
9426
|
+
* Exporter-facing "profile restream" entry. Returned by
|
|
9427
|
+
* `cameraStreams.getProfileRtspEntries` — one per ASSIGNED profile slot
|
|
9428
|
+
* (high/mid/low). `brokerId` is the PROFILE-keyed broker id
|
|
9429
|
+
* (`${deviceId}/${profile}`, e.g. `15/high`); its `url` is a broker
|
|
9430
|
+
* RTSP restream that aliases the profile's assigned source broker, so
|
|
9431
|
+
* every consumer dialling a profile converges on the same single pull.
|
|
9432
|
+
* `codec`/`resolution` describe the assigned SOURCE camStream (for the
|
|
9433
|
+
* `auto` resolution-closest pick). Distinct from `RtspRestreamEntry`
|
|
9434
|
+
* (raw per-camStream, live-view only).
|
|
9435
|
+
*/
|
|
9436
|
+
var ProfileRtspEntrySchema = object({
|
|
9437
|
+
profile: CamProfileSchema,
|
|
9438
|
+
/** Profile-keyed broker id, format `${deviceId}/${profile}` (e.g. `"15/high"`). */
|
|
9439
|
+
brokerId: string(),
|
|
9440
|
+
url: string(),
|
|
9441
|
+
mutedUrl: string(),
|
|
9442
|
+
enabled: boolean(),
|
|
9443
|
+
codec: string().optional(),
|
|
9444
|
+
resolution: CamStreamResolutionSchema.optional()
|
|
9445
|
+
});
|
|
9446
|
+
/**
|
|
9447
|
+
* The model weight formats a catalog entry can ship. Schema-free on purpose:
|
|
9448
|
+
* `types/models.ts` builds Zod schemas from it, but a runner-closure consumer
|
|
9449
|
+
* (the model downloader in `@camstack/server/system`) needs only the list and must
|
|
9450
|
+
* reach it through `@camstack/types/addon` without building the cap schema
|
|
9451
|
+
* graph (D28).
|
|
9452
|
+
*/
|
|
9453
|
+
var MODEL_FORMATS = [
|
|
9454
|
+
"onnx",
|
|
9455
|
+
"coreml",
|
|
9456
|
+
"openvino",
|
|
9457
|
+
"tflite",
|
|
9458
|
+
"pt",
|
|
9459
|
+
"gguf"
|
|
9460
|
+
];
|
|
8947
9461
|
/**
|
|
8948
9462
|
* Per-call node pinning for `ctx.api` capability calls.
|
|
8949
9463
|
*
|
|
@@ -9267,6 +9781,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9267
9781
|
"mesh-network",
|
|
9268
9782
|
"meter",
|
|
9269
9783
|
"metrics-provider",
|
|
9784
|
+
"migrations",
|
|
9270
9785
|
"model-convert",
|
|
9271
9786
|
"model-distributor",
|
|
9272
9787
|
"motion",
|
|
@@ -9299,6 +9814,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9299
9814
|
"plate-gallery",
|
|
9300
9815
|
"platform-probe",
|
|
9301
9816
|
"power-meter",
|
|
9817
|
+
"power-source",
|
|
9302
9818
|
"presence",
|
|
9303
9819
|
"pressure-sensor",
|
|
9304
9820
|
"privacy-mask",
|
|
@@ -10650,6 +11166,13 @@ Object.freeze({
|
|
|
10650
11166
|
"valueType": "number"
|
|
10651
11167
|
}
|
|
10652
11168
|
],
|
|
11169
|
+
"power-source": [{
|
|
11170
|
+
"path": "switchOn",
|
|
11171
|
+
"valueType": "boolean"
|
|
11172
|
+
}, {
|
|
11173
|
+
"path": "offSeconds",
|
|
11174
|
+
"valueType": "number"
|
|
11175
|
+
}],
|
|
10653
11176
|
"presence": [
|
|
10654
11177
|
{
|
|
10655
11178
|
"path": "state",
|
|
@@ -11163,7 +11686,7 @@ Object.freeze({
|
|
|
11163
11686
|
* can answer "may a rule actuate this?" without importing the schema barrel
|
|
11164
11687
|
* (~144MB RSS per runner, D28).
|
|
11165
11688
|
*
|
|
11166
|
-
* Coverage:
|
|
11689
|
+
* Coverage: 98 device-scoped capabilities.
|
|
11167
11690
|
*/
|
|
11168
11691
|
var DEVICE_SCOPED_CAPS = new Set([
|
|
11169
11692
|
"accessories",
|
|
@@ -11232,6 +11755,7 @@ var DEVICE_SCOPED_CAPS = new Set([
|
|
|
11232
11755
|
"pet-fountain",
|
|
11233
11756
|
"pipeline-analytics",
|
|
11234
11757
|
"power-meter",
|
|
11758
|
+
"power-source",
|
|
11235
11759
|
"presence",
|
|
11236
11760
|
"pressure-sensor",
|
|
11237
11761
|
"privacy-mask",
|
|
@@ -11308,379 +11832,7 @@ function sleep(ms) {
|
|
|
11308
11832
|
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
11309
11833
|
}
|
|
11310
11834
|
//#endregion
|
|
11311
|
-
//#region ../types/dist/
|
|
11312
|
-
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
11313
|
-
DeviceType["Camera"] = "camera";
|
|
11314
|
-
DeviceType["Hub"] = "hub";
|
|
11315
|
-
DeviceType["Light"] = "light";
|
|
11316
|
-
DeviceType["Siren"] = "siren";
|
|
11317
|
-
DeviceType["Switch"] = "switch";
|
|
11318
|
-
DeviceType["Sensor"] = "sensor";
|
|
11319
|
-
DeviceType["Thermostat"] = "thermostat";
|
|
11320
|
-
/** Air-conditioner / heat-pump climate device (HVAC) — shares the
|
|
11321
|
-
* `climate-control` cap surface with `Thermostat` but renders a
|
|
11322
|
-
* dedicated AC-appropriate control UI (mode chips, fan speed,
|
|
11323
|
-
* independent vertical/horizontal swing). Sources: native Gree, and
|
|
11324
|
-
* reusable by other AC integrations. */
|
|
11325
|
-
DeviceType["Climate"] = "climate";
|
|
11326
|
-
DeviceType["Button"] = "button";
|
|
11327
|
-
/** Generic stateless event emitter — carries a device's EXACT declared
|
|
11328
|
-
* event vocabulary verbatim (no normalization). Installed with the
|
|
11329
|
-
* `event-emitter` cap. Sources: HA `event.*` entities (structured) and
|
|
11330
|
-
* HA bus events (e.g. `zha_event`, generic). */
|
|
11331
|
-
DeviceType["EventEmitter"] = "event-emitter";
|
|
11332
|
-
/** Firmware/software update entity — current vs available version,
|
|
11333
|
-
* updatable flag, update state, and an install action. Installed with
|
|
11334
|
-
* the `update` cap. Sources: Homematic firmware-update channels (and
|
|
11335
|
-
* reusable by other providers, e.g. HA `update.*` entities). */
|
|
11336
|
-
DeviceType["Update"] = "update";
|
|
11337
|
-
DeviceType["Generic"] = "generic";
|
|
11338
|
-
/** Generic notification delivery target (HA `notify.<service>`, future
|
|
11339
|
-
* Telegram / Discord / ntfy / SMTP, …). One device per delivery
|
|
11340
|
-
* endpoint; the `notifier` cap defines the send surface. */
|
|
11341
|
-
DeviceType["Notifier"] = "notifier";
|
|
11342
|
-
/** Pre-recorded action sequence with optional parameters
|
|
11343
|
-
* (HA `script.*`). Runnable via `script-runner` cap. */
|
|
11344
|
-
DeviceType["Script"] = "script";
|
|
11345
|
-
/** Automation rule (HA `automation.*`) — enable/disable + manual
|
|
11346
|
-
* trigger surface exposed via `automation-control` cap. */
|
|
11347
|
-
DeviceType["Automation"] = "automation";
|
|
11348
|
-
/** Door / smart lock device (HA `lock.*`). `lock-control` cap. */
|
|
11349
|
-
DeviceType["Lock"] = "lock";
|
|
11350
|
-
/** Window covering, blinds, garage door, valve, etc. (HA `cover.*`,
|
|
11351
|
-
* `valve.*`). `cover` cap with sub-roles for variant. */
|
|
11352
|
-
DeviceType["Cover"] = "cover";
|
|
11353
|
-
/** Pipe / water / gas valve with open/close/stop and optional
|
|
11354
|
-
* position (HA `valve.*`). `valve` cap — a cover-sibling actuator
|
|
11355
|
-
* modelled on the same open/closed lifecycle. */
|
|
11356
|
-
DeviceType["Valve"] = "valve";
|
|
11357
|
-
/** Humidifier / dehumidifier with on/off + target humidity + mode
|
|
11358
|
-
* (HA `humidifier.*`). `humidifier` cap — a climate-family actuator
|
|
11359
|
-
* modelled on the same target / mode lifecycle. */
|
|
11360
|
-
DeviceType["Humidifier"] = "humidifier";
|
|
11361
|
-
/** Water heater / boiler with target temperature + operation mode +
|
|
11362
|
-
* away mode (HA `water_heater.*`). `water-heater` cap — a
|
|
11363
|
-
* climate-family actuator. */
|
|
11364
|
-
DeviceType["WaterHeater"] = "water-heater";
|
|
11365
|
-
/** Ceiling / standing / exhaust fan (HA `fan.*`). `fan-control` cap. */
|
|
11366
|
-
DeviceType["Fan"] = "fan";
|
|
11367
|
-
/** Audio / video playback endpoint (HA `media_player.*`). Disjoint from
|
|
11368
|
-
* the camera surface — those use `Camera`. `media-player` cap. */
|
|
11369
|
-
DeviceType["MediaPlayer"] = "media-player";
|
|
11370
|
-
/** Security panel / alarm system (HA `alarm_control_panel.*`).
|
|
11371
|
-
* `alarm-panel` cap. */
|
|
11372
|
-
DeviceType["AlarmPanel"] = "alarm-panel";
|
|
11373
|
-
/** Generic user-settable input (HA `number` / `input_number` / `select`
|
|
11374
|
-
* / `input_select` / `text` / `input_text` / `input_datetime`).
|
|
11375
|
-
* Sub-type via `DeviceRole`: NumericControl / SelectControl /
|
|
11376
|
-
* TextControl / DateTimeControl. */
|
|
11377
|
-
DeviceType["Control"] = "control";
|
|
11378
|
-
/** Person / device-tracker presence (HA `person.*`, `device_tracker.*`).
|
|
11379
|
-
* `presence` cap. */
|
|
11380
|
-
DeviceType["Presence"] = "presence";
|
|
11381
|
-
/** Weather provider (HA `weather.*`). Tier-3, low MVP priority.
|
|
11382
|
-
* `weather` cap. */
|
|
11383
|
-
DeviceType["Weather"] = "weather";
|
|
11384
|
-
/** Robot vacuum (HA `vacuum.*`). Tier-3. `vacuum-control` cap. */
|
|
11385
|
-
DeviceType["Vacuum"] = "vacuum";
|
|
11386
|
-
/** Robotic lawn mower (HA `lawn_mower.*`). Tier-3.
|
|
11387
|
-
* `lawn-mower-control` cap. */
|
|
11388
|
-
DeviceType["LawnMower"] = "lawn-mower";
|
|
11389
|
-
/** Physical HA device group — parent container for entity-children
|
|
11390
|
-
* adopted from a single HA device entry. Not renderable as a
|
|
11391
|
-
* standalone device; exists only to anchor child entities. */
|
|
11392
|
-
DeviceType["Container"] = "container";
|
|
11393
|
-
/** Single still-image entity (HA `image.*`). Read-only display of an
|
|
11394
|
-
* `entity_picture` signed URL the browser loads directly. `image` cap. */
|
|
11395
|
-
DeviceType["Image"] = "image";
|
|
11396
|
-
/** Smart pet feeder — cloud-connected food dispenser with a bowl food
|
|
11397
|
-
* level, battery, desiccant life, feeding state and manual-feed /
|
|
11398
|
-
* call-pet / maintenance actions. Installed with the `pet-feeder` cap;
|
|
11399
|
-
* dual-hopper models (D4S/D4SH) expose per-hopper portions. Sources:
|
|
11400
|
-
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
11401
|
-
* integrations sharing the same food/desiccant/hopper surface. */
|
|
11402
|
-
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11403
|
-
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
11404
|
-
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
11405
|
-
* of a container and is BUILT as a composed device (D967). */
|
|
11406
|
-
DeviceType["PetFountain"] = "pet-fountain";
|
|
11407
|
-
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
11408
|
-
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
11409
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
11410
|
-
* A plug-built dishwasher carries running-state and power instead. */
|
|
11411
|
-
DeviceType["Dishwasher"] = "dishwasher";
|
|
11412
|
-
/** Washing machine. A plug-built one is running while its power stays
|
|
11413
|
-
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
11414
|
-
DeviceType["Washer"] = "washer";
|
|
11415
|
-
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
11416
|
-
DeviceType["Dryer"] = "dryer";
|
|
11417
|
-
/** The physical bridge box of a vendor ecosystem (Velux KLF-200, and later
|
|
11418
|
-
* other radio-to-IP bridges). It carries the box's own facts (firmware,
|
|
11419
|
-
* address, connection state) and the actions the box really supports
|
|
11420
|
-
* (`reboot`, `device-admin-link`). Products are NOT its children — they are
|
|
11421
|
-
* adopted beside it — and its connection settings stay on the integration. */
|
|
11422
|
-
DeviceType["Gateway"] = "gateway";
|
|
11423
|
-
return DeviceType;
|
|
11424
|
-
}({});
|
|
11425
|
-
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
11426
|
-
DeviceFeature["BatteryOperated"] = "battery-operated";
|
|
11427
|
-
DeviceFeature["Rebootable"] = "rebootable";
|
|
11428
|
-
/**
|
|
11429
|
-
* Device supports an on-demand re-sync of its derived spec with its
|
|
11430
|
-
* upstream source — drives the generic Re-sync button. The owning
|
|
11431
|
-
* provider implements the action via the `device-adoption.resync` cap.
|
|
11432
|
-
*/
|
|
11433
|
-
DeviceFeature["Resyncable"] = "resyncable";
|
|
11434
|
-
DeviceFeature["NativeSnapshot"] = "native-snapshot";
|
|
11435
|
-
DeviceFeature["DoorbellButton"] = "doorbell-button";
|
|
11436
|
-
DeviceFeature["TwoWayAudio"] = "two-way-audio";
|
|
11437
|
-
DeviceFeature["PanTiltZoom"] = "pan-tilt-zoom";
|
|
11438
|
-
/**
|
|
11439
|
-
* Camera supports the on-firmware autotrack subsystem (subject-
|
|
11440
|
-
* following). Distinct from `PanTiltZoom` because not every PTZ
|
|
11441
|
-
* camera ships autotrack — the admin UI uses this flag to gate
|
|
11442
|
-
* the autotrack toggle / settings card without re-deriving from
|
|
11443
|
-
* the cap registry. Mirrors `ptz-autotrack` cap registration:
|
|
11444
|
-
* driver sets this feature when probe confirms the firmware
|
|
11445
|
-
* surface, and registers the cap in the same code path.
|
|
11446
|
-
*/
|
|
11447
|
-
DeviceFeature["PtzAutotrack"] = "ptz-autotrack";
|
|
11448
|
-
/**
|
|
11449
|
-
* Accessory exposes a "trigger on motion" toggle — the parent camera's
|
|
11450
|
-
* motion detection automatically activates this device. Mirrors
|
|
11451
|
-
* `motion-trigger` cap registration: drivers set this feature in the
|
|
11452
|
-
* same code path that calls `ctx.registerNativeCap(motionTriggerCapability, ...)`.
|
|
11453
|
-
*
|
|
11454
|
-
* Used by admin UI (gate the in-hero `MotionTriggerToggle` against a
|
|
11455
|
-
* fast scalar without binding fetch), notifier rules, and `listAll`
|
|
11456
|
-
* filters that want "all devices with on-motion behaviour".
|
|
11457
|
-
*/
|
|
11458
|
-
DeviceFeature["MotionTrigger"] = "motion-trigger";
|
|
11459
|
-
/** Light supports rgb-triplet color via `color` cap. */
|
|
11460
|
-
DeviceFeature["LightColorRgb"] = "light-color-rgb";
|
|
11461
|
-
/** Light supports HSV color via `color` cap. */
|
|
11462
|
-
DeviceFeature["LightColorHsv"] = "light-color-hsv";
|
|
11463
|
-
/** Light supports color-temperature (mired) via `color` cap. */
|
|
11464
|
-
DeviceFeature["LightColorMired"] = "light-color-mired";
|
|
11465
|
-
/** Thermostat supports a `heat_cool` dual setpoint (targetLow +
|
|
11466
|
-
* targetHigh). Gates the range slider UI. */
|
|
11467
|
-
DeviceFeature["ClimateDualSetpoint"] = "climate-dual-setpoint";
|
|
11468
|
-
/** Thermostat exposes target humidity and/or current humidity
|
|
11469
|
-
* readings. Gates the humidity controls. */
|
|
11470
|
-
DeviceFeature["ClimateHumidity"] = "climate-humidity";
|
|
11471
|
-
/** Thermostat exposes a fan-mode selector. */
|
|
11472
|
-
DeviceFeature["ClimateFanMode"] = "climate-fan-mode";
|
|
11473
|
-
/** Thermostat exposes preset modes (eco / away / sleep / vendor). */
|
|
11474
|
-
DeviceFeature["ClimatePreset"] = "climate-preset";
|
|
11475
|
-
/** Thermostat exposes a vertical louver swing toggle. Gates the
|
|
11476
|
-
* vertical-swing switch in the climate UI. Independent of horizontal. */
|
|
11477
|
-
DeviceFeature["ClimateSwingVertical"] = "climate-swing-vertical";
|
|
11478
|
-
/** Thermostat exposes a horizontal louver swing toggle. Gates the
|
|
11479
|
-
* horizontal-swing switch in the climate UI. Independent of vertical. */
|
|
11480
|
-
DeviceFeature["ClimateSwingHorizontal"] = "climate-swing-horizontal";
|
|
11481
|
-
/** Cover exposes intermediate position control (0..100). Gates the
|
|
11482
|
-
* position slider UI. */
|
|
11483
|
-
DeviceFeature["CoverPositionable"] = "cover-positionable";
|
|
11484
|
-
/** Cover exposes slat-tilt control. Gates the tilt slider UI. */
|
|
11485
|
-
DeviceFeature["CoverTilt"] = "cover-tilt";
|
|
11486
|
-
/** Valve exposes intermediate position control (0..100). Gates the
|
|
11487
|
-
* position slider / drag surface UI. */
|
|
11488
|
-
DeviceFeature["ValvePositionable"] = "valve-positionable";
|
|
11489
|
-
/** Fan exposes a speed-percentage setter. Gates the speed slider UI. */
|
|
11490
|
-
DeviceFeature["FanSpeed"] = "fan-speed";
|
|
11491
|
-
/** Fan exposes a preset mode selector. */
|
|
11492
|
-
DeviceFeature["FanPreset"] = "fan-preset";
|
|
11493
|
-
/** Fan exposes blade direction (forward/reverse) — typical of
|
|
11494
|
-
* ceiling fans. */
|
|
11495
|
-
DeviceFeature["FanDirection"] = "fan-direction";
|
|
11496
|
-
/** Fan exposes an oscillation toggle. */
|
|
11497
|
-
DeviceFeature["FanOscillating"] = "fan-oscillating";
|
|
11498
|
-
/** Lock requires a PIN code on lock/unlock. Gates the code-entry
|
|
11499
|
-
* field on the UI lock-controls panel. */
|
|
11500
|
-
DeviceFeature["LockPinRequired"] = "lock-pin-required";
|
|
11501
|
-
/** Lock supports a latch-release ("open door") action distinct from
|
|
11502
|
-
* unlock. Mirrors HA `LockEntityFeature.OPEN` (bit 1) in
|
|
11503
|
-
* `supported_features`. Gates the Open Door button in the UI. */
|
|
11504
|
-
DeviceFeature["LockOpen"] = "lock-open";
|
|
11505
|
-
/** Media player exposes a seek-to-position surface. */
|
|
11506
|
-
DeviceFeature["MediaPlayerSeek"] = "media-player-seek";
|
|
11507
|
-
/** Media player exposes a volume-level setter. */
|
|
11508
|
-
DeviceFeature["MediaPlayerVolume"] = "media-player-volume";
|
|
11509
|
-
/** Media player exposes a mute toggle distinct from volume=0. */
|
|
11510
|
-
DeviceFeature["MediaPlayerMute"] = "media-player-mute";
|
|
11511
|
-
/** Media player exposes a shuffle toggle. */
|
|
11512
|
-
DeviceFeature["MediaPlayerShuffle"] = "media-player-shuffle";
|
|
11513
|
-
/** Media player exposes a repeat mode (off / all / one). */
|
|
11514
|
-
DeviceFeature["MediaPlayerRepeat"] = "media-player-repeat";
|
|
11515
|
-
/** Media player exposes a source / input selector. */
|
|
11516
|
-
DeviceFeature["MediaPlayerSelectSource"] = "media-player-select-source";
|
|
11517
|
-
/** Media player exposes a play-arbitrary-media surface (URL / id). */
|
|
11518
|
-
DeviceFeature["MediaPlayerPlayMedia"] = "media-player-play-media";
|
|
11519
|
-
/** Media player exposes next-track. */
|
|
11520
|
-
DeviceFeature["MediaPlayerNext"] = "media-player-next";
|
|
11521
|
-
/** Media player exposes previous-track. */
|
|
11522
|
-
DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
|
|
11523
|
-
/** Media player exposes stop distinct from pause. */
|
|
11524
|
-
DeviceFeature["MediaPlayerStop"] = "media-player-stop";
|
|
11525
|
-
/** Alarm panel requires a PIN code on arm/disarm. */
|
|
11526
|
-
DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
|
|
11527
|
-
/** Presence device carries GPS coordinates (lat/lng/accuracy) in
|
|
11528
|
-
* addition to a textual location. */
|
|
11529
|
-
DeviceFeature["PresenceGps"] = "presence-gps";
|
|
11530
|
-
/** Notifier accepts an inline / URL image attachment. */
|
|
11531
|
-
DeviceFeature["NotifierImage"] = "notifier-image";
|
|
11532
|
-
/** Notifier accepts a priority hint (high/normal/low). */
|
|
11533
|
-
DeviceFeature["NotifierPriority"] = "notifier-priority";
|
|
11534
|
-
/** Notifier accepts a free-form `data` payload for platform-specific
|
|
11535
|
-
* fields. */
|
|
11536
|
-
DeviceFeature["NotifierData"] = "notifier-data";
|
|
11537
|
-
/** Notifier supports interactive action buttons / callbacks. */
|
|
11538
|
-
DeviceFeature["NotifierActions"] = "notifier-actions";
|
|
11539
|
-
/** Notifier supports per-call recipient targeting (multi-user). */
|
|
11540
|
-
DeviceFeature["NotifierRecipients"] = "notifier-recipients";
|
|
11541
|
-
/** Script runner accepts a variables map on each run invocation. */
|
|
11542
|
-
DeviceFeature["ScriptVariables"] = "script-variables";
|
|
11543
|
-
/** Automation `trigger` accepts a skipCondition flag — fires the
|
|
11544
|
-
* automation's actions while bypassing its condition block. */
|
|
11545
|
-
DeviceFeature["AutomationSkipCondition"] = "automation-skip-condition";
|
|
11546
|
-
/** Robot vacuum exposes a live cleaning map (image child). Gates the
|
|
11547
|
-
* map tile in the vacuum UI. */
|
|
11548
|
-
DeviceFeature["VacuumHasMap"] = "vacuum-has-map";
|
|
11549
|
-
/** Robot vacuum exposes AI obstacle-detection toggles. Gates the AI
|
|
11550
|
-
* switches group. */
|
|
11551
|
-
DeviceFeature["VacuumHasAi"] = "vacuum-has-ai";
|
|
11552
|
-
/** Robot mower exposes a live mowing map (SVG image child). Gates the
|
|
11553
|
-
* mower map tile. */
|
|
11554
|
-
DeviceFeature["MowerHasMap"] = "mower-has-map";
|
|
11555
|
-
/** Robot mower exposes targeted mowing (all-area / zones / edges /
|
|
11556
|
-
* spots) — gates the Mow action + map selectors. */
|
|
11557
|
-
DeviceFeature["MowerHasTargetedMowing"] = "mower-has-targeted-mowing";
|
|
11558
|
-
return DeviceFeature;
|
|
11559
|
-
}({});
|
|
11560
|
-
/**
|
|
11561
|
-
* Semantic role a device plays within its parent. Populated by driver
|
|
11562
|
-
* addons when creating accessory devices (Reolink siren/floodlight/
|
|
11563
|
-
* PIR/chime/autotrack/doorbell, ONVIF relay outputs, …). Used by the
|
|
11564
|
-
* admin UI to pick icons, labels, and widgets — a `Switch` with
|
|
11565
|
-
* `role: Floodlight` renders as a bulb with a brightness slider,
|
|
11566
|
-
* whereas a `Switch` with `role: Siren` renders as a klaxon.
|
|
11567
|
-
*
|
|
11568
|
-
* Undefined for top-level devices (cameras, NVRs, hubs). Persisted in
|
|
11569
|
-
* sqlite as a nullable TEXT column — old rows keep working unchanged.
|
|
11570
|
-
*/
|
|
11571
|
-
var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
11572
|
-
DeviceRole["Siren"] = "siren";
|
|
11573
|
-
DeviceRole["Floodlight"] = "floodlight";
|
|
11574
|
-
DeviceRole["Spotlight"] = "spotlight";
|
|
11575
|
-
DeviceRole["PirSensor"] = "pir-sensor";
|
|
11576
|
-
DeviceRole["Chime"] = "chime";
|
|
11577
|
-
DeviceRole["Autotrack"] = "autotrack";
|
|
11578
|
-
DeviceRole["Nightvision"] = "nightvision";
|
|
11579
|
-
DeviceRole["PrivacyMask"] = "privacy-mask";
|
|
11580
|
-
DeviceRole["Doorbell"] = "doorbell";
|
|
11581
|
-
/** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
|
|
11582
|
-
DeviceRole["CoverBlind"] = "cover-blind";
|
|
11583
|
-
/** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
|
|
11584
|
-
DeviceRole["CoverShutter"] = "cover-shutter";
|
|
11585
|
-
/** Exterior awning. HA `device_class: awning`. */
|
|
11586
|
-
DeviceRole["CoverAwning"] = "cover-awning";
|
|
11587
|
-
/** Curtain / drape. HA `device_class: curtain`. */
|
|
11588
|
-
DeviceRole["CoverCurtain"] = "cover-curtain";
|
|
11589
|
-
/** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
|
|
11590
|
-
DeviceRole["CoverGarage"] = "cover-garage";
|
|
11591
|
-
/** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
|
|
11592
|
-
DeviceRole["CoverGate"] = "cover-gate";
|
|
11593
|
-
/** Door. HA `device_class: door`. A security actuator: exports gate it. */
|
|
11594
|
-
DeviceRole["CoverDoor"] = "cover-door";
|
|
11595
|
-
/** Window. HA `device_class: window`. */
|
|
11596
|
-
DeviceRole["CoverWindow"] = "cover-window";
|
|
11597
|
-
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
11598
|
-
* real Switch device for UI rendering / export adapters. */
|
|
11599
|
-
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
11600
|
-
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
11601
|
-
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
11602
|
-
DeviceRole["Outlet"] = "outlet";
|
|
11603
|
-
/** Generic motion / occupancy / moving event source. Distinct from
|
|
11604
|
-
* the camera accessory PirSensor role: that one is a camera child;
|
|
11605
|
-
* this is a standalone HA / 3rd-party motion sensor. */
|
|
11606
|
-
DeviceRole["MotionSensor"] = "motion-sensor";
|
|
11607
|
-
DeviceRole["ContactSensor"] = "contact-sensor";
|
|
11608
|
-
DeviceRole["LeakSensor"] = "leak-sensor";
|
|
11609
|
-
DeviceRole["SmokeSensor"] = "smoke-sensor";
|
|
11610
|
-
DeviceRole["COSensor"] = "co-sensor";
|
|
11611
|
-
DeviceRole["GasSensor"] = "gas-sensor";
|
|
11612
|
-
DeviceRole["TamperSensor"] = "tamper-sensor";
|
|
11613
|
-
DeviceRole["VibrationSensor"] = "vibration-sensor";
|
|
11614
|
-
DeviceRole["ConnectivitySensor"] = "connectivity-sensor";
|
|
11615
|
-
DeviceRole["SoundSensor"] = "sound-sensor";
|
|
11616
|
-
/** Fallback for `binary_sensor` without a known `device_class`. */
|
|
11617
|
-
DeviceRole["BinarySensor"] = "binary-sensor";
|
|
11618
|
-
DeviceRole["TemperatureSensor"] = "temperature-sensor";
|
|
11619
|
-
DeviceRole["HumiditySensor"] = "humidity-sensor";
|
|
11620
|
-
DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
|
|
11621
|
-
DeviceRole["PressureSensor"] = "pressure-sensor";
|
|
11622
|
-
/** Wind speed or direction (weather-station `wind-sensor` cap). */
|
|
11623
|
-
DeviceRole["WindSensor"] = "wind-sensor";
|
|
11624
|
-
/** Rain accumulation or rate (weather-station `rain-sensor` cap). */
|
|
11625
|
-
DeviceRole["RainSensor"] = "rain-sensor";
|
|
11626
|
-
/** UV index (weather-station `uv-sensor` cap). */
|
|
11627
|
-
DeviceRole["UvSensor"] = "uv-sensor";
|
|
11628
|
-
/** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
|
|
11629
|
-
* Distinct from AmbientLightSensor (lux). */
|
|
11630
|
-
DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
|
|
11631
|
-
/** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
|
|
11632
|
-
DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
|
|
11633
|
-
DeviceRole["PowerSensor"] = "power-sensor";
|
|
11634
|
-
DeviceRole["EnergySensor"] = "energy-sensor";
|
|
11635
|
-
DeviceRole["VoltageSensor"] = "voltage-sensor";
|
|
11636
|
-
DeviceRole["CurrentSensor"] = "current-sensor";
|
|
11637
|
-
DeviceRole["AirQualitySensor"] = "air-quality-sensor";
|
|
11638
|
-
/** Battery level (numeric % via `sensor` OR low-bool via
|
|
11639
|
-
* `binary_sensor` — the cap distinguishes via the value type). */
|
|
11640
|
-
DeviceRole["BatterySensor"] = "battery-sensor";
|
|
11641
|
-
/** Fallback for `sensor` numeric without a known `device_class`. */
|
|
11642
|
-
DeviceRole["NumericSensor"] = "numeric-sensor";
|
|
11643
|
-
/** String / enum state (HA `sensor` with `state_class: enum` or
|
|
11644
|
-
* `attributes.options`). */
|
|
11645
|
-
DeviceRole["EnumSensor"] = "enum-sensor";
|
|
11646
|
-
/** Date / timestamp state (HA `sensor` with `device_class: timestamp`
|
|
11647
|
-
* or `date`). The slice carries the raw ISO string verbatim (hosted on
|
|
11648
|
-
* the `enum-sensor` cap); the UI renders it locale-formatted. */
|
|
11649
|
-
DeviceRole["DateTimeSensor"] = "datetime-sensor";
|
|
11650
|
-
/** Last-resort fallback when nothing else matches. */
|
|
11651
|
-
DeviceRole["GenericSensor"] = "generic-sensor";
|
|
11652
|
-
DeviceRole["NumericControl"] = "numeric-control";
|
|
11653
|
-
DeviceRole["SelectControl"] = "select-control";
|
|
11654
|
-
DeviceRole["TextControl"] = "text-control";
|
|
11655
|
-
DeviceRole["DateTimeControl"] = "datetime-control";
|
|
11656
|
-
/** Mobile push notifier (HA `notify.mobile_app_*`) — supports
|
|
11657
|
-
* rich features (image, priority, channel routing). */
|
|
11658
|
-
DeviceRole["MobilePushNotifier"] = "mobile-push-notifier";
|
|
11659
|
-
/** Chat / messaging service (HA `notify.telegram_*`,
|
|
11660
|
-
* `notify.discord_*`, etc.). */
|
|
11661
|
-
DeviceRole["MessagingNotifier"] = "messaging-notifier";
|
|
11662
|
-
/** Email-based delivery (HA `notify.smtp`, etc.). */
|
|
11663
|
-
DeviceRole["EmailNotifier"] = "email-notifier";
|
|
11664
|
-
/** Fallback when the notifier service name doesn't match a known
|
|
11665
|
-
* pattern. */
|
|
11666
|
-
DeviceRole["GenericNotifier"] = "generic-notifier";
|
|
11667
|
-
/** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
|
|
11668
|
-
* cap. A `DeviceType.Generic` device. */
|
|
11669
|
-
DeviceRole["IrTransmitter"] = "ir-transmitter";
|
|
11670
|
-
return DeviceRole;
|
|
11671
|
-
}({});
|
|
11672
|
-
/**
|
|
11673
|
-
import { errMsg } from '@camstack/types'
|
|
11674
|
-
* Extract a human-readable message from an unknown error value.
|
|
11675
|
-
* Replaces the ubiquitous `errMsg(err)` pattern.
|
|
11676
|
-
*/
|
|
11677
|
-
function errMsg(err) {
|
|
11678
|
-
if (err instanceof Error) return err.message;
|
|
11679
|
-
if (typeof err === "string") return err;
|
|
11680
|
-
return String(err);
|
|
11681
|
-
}
|
|
11682
|
-
//#endregion
|
|
11683
|
-
//#region ../types/dist/composition-C7WdThmP.mjs
|
|
11835
|
+
//#region ../types/dist/composition-BBzVf2xd.mjs
|
|
11684
11836
|
/**
|
|
11685
11837
|
* Deterministic SHA-256 hash of an arbitrary serialisable value. The
|
|
11686
11838
|
* canonical form sorts object keys alphabetically at every depth so two
|
|
@@ -13074,6 +13226,90 @@ var EVENT_OWNER_TYPE_SET = new Set(EVENT_OWNER_TYPES);
|
|
|
13074
13226
|
function isEventOwnerType(ownerType) {
|
|
13075
13227
|
return EVENT_OWNER_TYPE_SET.has(ownerType);
|
|
13076
13228
|
}
|
|
13229
|
+
/**
|
|
13230
|
+
* What a published package needs from the rest of the install (D989).
|
|
13231
|
+
*
|
|
13232
|
+
* One published framework package (`@camstack/server`) carries the kernel, the
|
|
13233
|
+
* builtins and the capability contracts, so "which addon runs on which
|
|
13234
|
+
* framework" is a question of version, and the answer is DECLARED by the
|
|
13235
|
+
* package that knows it:
|
|
13236
|
+
*
|
|
13237
|
+
* - an addon says the oldest server it runs on (`requires.server: ">=X"`);
|
|
13238
|
+
* - the server says the oldest addon it works with
|
|
13239
|
+
* (`requires.addons: { "@camstack/addon-x": ">=Y" }`) and the oldest shell
|
|
13240
|
+
* around it (`requires.wrapper: { desktop, image }`);
|
|
13241
|
+
* - a wrapper (the desktop app, the container starter) says which server
|
|
13242
|
+
* range it can host, and reports its own kind and version.
|
|
13243
|
+
*
|
|
13244
|
+
* The publish workflow STAMPS these after the version bump
|
|
13245
|
+
* (`scripts/ci/stamp-requires.mjs`); nobody types a number by hand.
|
|
13246
|
+
*
|
|
13247
|
+
* A requirement that cannot be checked is NOT met: a shell that reports no
|
|
13248
|
+
* version counts as below the minimum, and an unreadable running version is
|
|
13249
|
+
* named in the result (a failed read is never a pass).
|
|
13250
|
+
*/
|
|
13251
|
+
/** `>=MAJOR.MINOR.PATCH[-prerelease]` — the only range shape a requirement uses. */
|
|
13252
|
+
var MinVersionSchema = string().regex(/^>=\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/, "a minimum is written \">=X.Y.Z\"");
|
|
13253
|
+
object({
|
|
13254
|
+
/** The oldest `@camstack/server` this package runs on. */
|
|
13255
|
+
server: MinVersionSchema.optional(),
|
|
13256
|
+
/** The oldest installed version of each named addon package. */
|
|
13257
|
+
addons: record(string(), MinVersionSchema).optional(),
|
|
13258
|
+
/** The oldest shell around the server, per shell kind. */
|
|
13259
|
+
wrapper: object({
|
|
13260
|
+
desktop: MinVersionSchema.optional(),
|
|
13261
|
+
image: MinVersionSchema.optional()
|
|
13262
|
+
}).optional()
|
|
13263
|
+
});
|
|
13264
|
+
/** One unmet requirement; each names the versions on both sides. */
|
|
13265
|
+
var UnmetRequirementSchema = discriminatedUnion("kind", [
|
|
13266
|
+
object({
|
|
13267
|
+
kind: literal("server-too-old"),
|
|
13268
|
+
required: string(),
|
|
13269
|
+
/** `null` — the running server version could not be read. */
|
|
13270
|
+
running: string().nullable()
|
|
13271
|
+
}),
|
|
13272
|
+
object({
|
|
13273
|
+
kind: literal("addon-too-old"),
|
|
13274
|
+
packageName: string(),
|
|
13275
|
+
required: string(),
|
|
13276
|
+
/** `null` — the addon is not installed (or its version is unreadable). */
|
|
13277
|
+
running: string().nullable()
|
|
13278
|
+
}),
|
|
13279
|
+
object({
|
|
13280
|
+
kind: literal("wrapper-too-old"),
|
|
13281
|
+
wrapper: _enum(["desktop", "image"]),
|
|
13282
|
+
required: string(),
|
|
13283
|
+
/** `null` — the wrapper reported no version. */
|
|
13284
|
+
running: string().nullable()
|
|
13285
|
+
})
|
|
13286
|
+
]);
|
|
13287
|
+
var RequiredAddonUpdateSchema = object({
|
|
13288
|
+
packageName: string(),
|
|
13289
|
+
/** The minimum the target server declares. */
|
|
13290
|
+
required: string(),
|
|
13291
|
+
/** What this node has; `null` when the addon is not installed. */
|
|
13292
|
+
installed: string().nullable()
|
|
13293
|
+
});
|
|
13294
|
+
/**
|
|
13295
|
+
* Which integration instance a settings form is for. An addon that serves several instances
|
|
13296
|
+
* (`instanceMode: multiple`) can show a different form per instance — an NVR integration
|
|
13297
|
+
* needs its connection, the default integration needs the addon's own sections.
|
|
13298
|
+
*
|
|
13299
|
+
* - `integrationId` is `null` in the create wizard: nothing exists yet, the operator is
|
|
13300
|
+
* setting up a NEW instance.
|
|
13301
|
+
* - `mode` is the wizard mode of the integration type (`getAvailableTypes`).
|
|
13302
|
+
* - `candidateStableId` is the discovery candidate a wizard was seeded from, if any.
|
|
13303
|
+
*/
|
|
13304
|
+
var IntegrationInstanceRefSchema = object({
|
|
13305
|
+
integrationId: string().nullable(),
|
|
13306
|
+
mode: _enum([
|
|
13307
|
+
"standalone",
|
|
13308
|
+
"account",
|
|
13309
|
+
"broker"
|
|
13310
|
+
]),
|
|
13311
|
+
candidateStableId: string().optional()
|
|
13312
|
+
});
|
|
13077
13313
|
var EncodeProfileSchema = object({
|
|
13078
13314
|
video: object({
|
|
13079
13315
|
codec: _enum([
|
|
@@ -13641,6 +13877,613 @@ var CameraSwitchGroupSchema = object({
|
|
|
13641
13877
|
*/
|
|
13642
13878
|
var DETECTION_PIPELINE_CAP_NAME = "detection-pipeline";
|
|
13643
13879
|
/**
|
|
13880
|
+
* Query filter for settings-store collections.
|
|
13881
|
+
*/
|
|
13882
|
+
var QueryFilterSchema = object({
|
|
13883
|
+
where: record(string(), unknown()).optional(),
|
|
13884
|
+
whereIn: record(string(), array(unknown())).optional(),
|
|
13885
|
+
whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
|
|
13886
|
+
/** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
|
|
13887
|
+
whereNot: record(string(), unknown()).optional(),
|
|
13888
|
+
/** NULL-safe exclusion of a SET — `whereNot` for more than one value. An
|
|
13889
|
+
* empty list excludes nothing. See `QueryFilter.whereNotIn`. */
|
|
13890
|
+
whereNotIn: record(string(), array(unknown())).optional(),
|
|
13891
|
+
orderBy: object({
|
|
13892
|
+
field: string(),
|
|
13893
|
+
direction: _enum(["asc", "desc"])
|
|
13894
|
+
}).optional(),
|
|
13895
|
+
limit: number().optional(),
|
|
13896
|
+
offset: number().optional()
|
|
13897
|
+
});
|
|
13898
|
+
/**
|
|
13899
|
+
* The predicate half of a filter, for BULK MUTATIONS.
|
|
13900
|
+
*
|
|
13901
|
+
* Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
|
|
13902
|
+
* meaning for a statement that rewrites a set, and accepting them would invite
|
|
13903
|
+
* a caller to believe `limit` bounds the damage. Every field is optional here
|
|
13904
|
+
* only so the shape stays composable — the implementation REJECTS a filter
|
|
13905
|
+
* that compiles to no predicate, because that is the whole collection.
|
|
13906
|
+
*/
|
|
13907
|
+
var MutationFilterSchema = object({
|
|
13908
|
+
where: record(string(), unknown()).optional(),
|
|
13909
|
+
whereIn: record(string(), array(unknown())).optional(),
|
|
13910
|
+
whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
|
|
13911
|
+
whereNot: record(string(), unknown()).optional(),
|
|
13912
|
+
whereNotIn: record(string(), array(unknown())).optional()
|
|
13913
|
+
});
|
|
13914
|
+
/**
|
|
13915
|
+
* One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
|
|
13916
|
+
*
|
|
13917
|
+
* `as` names the slot in the result, so the SAME column may be asked twice with
|
|
13918
|
+
* two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
|
|
13919
|
+
* a `Record<column, op>` shape could not express.
|
|
13920
|
+
*/
|
|
13921
|
+
var AggregateFieldSchema = object({
|
|
13922
|
+
/** Result key. */
|
|
13923
|
+
as: string().min(1),
|
|
13924
|
+
/** Column to aggregate. Must be a real column of a declared collection. */
|
|
13925
|
+
field: string().min(1),
|
|
13926
|
+
op: _enum([
|
|
13927
|
+
"sum",
|
|
13928
|
+
"min",
|
|
13929
|
+
"max"
|
|
13930
|
+
])
|
|
13931
|
+
});
|
|
13932
|
+
/**
|
|
13933
|
+
* `COUNT(*)` plus one number per requested field.
|
|
13934
|
+
*
|
|
13935
|
+
* `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
|
|
13936
|
+
* that really is 0 are different facts, and an accounting caller that renders
|
|
13937
|
+
* "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
|
|
13938
|
+
*/
|
|
13939
|
+
var AggregateResultSchema = object({
|
|
13940
|
+
count: number().int(),
|
|
13941
|
+
values: record(string(), number().nullable())
|
|
13942
|
+
});
|
|
13943
|
+
/** A single stored record: `{ id, data }`. */
|
|
13944
|
+
var SettingsRecordSchema = object({
|
|
13945
|
+
id: string(),
|
|
13946
|
+
data: record(string(), unknown())
|
|
13947
|
+
});
|
|
13948
|
+
/**
|
|
13949
|
+
* One record of a BULK insert — {@link SettingsRecordSchema} with the id made
|
|
13950
|
+
* optional.
|
|
13951
|
+
*
|
|
13952
|
+
* A separate schema rather than loosening the shared one: every other method
|
|
13953
|
+
* on this cap addresses a row BY its id, and making that field optional
|
|
13954
|
+
* everywhere would turn a forgotten key into a silently generated one on
|
|
13955
|
+
* `update` and `delete` as well.
|
|
13956
|
+
*/
|
|
13957
|
+
var BulkRecordSchema = object({
|
|
13958
|
+
id: string().optional(),
|
|
13959
|
+
data: record(string(), unknown())
|
|
13960
|
+
});
|
|
13961
|
+
/**
|
|
13962
|
+
* The database FILES one `sqlite-settings` engine process owns (D851).
|
|
13963
|
+
* Closed on purpose: a file is a thing the engine opens, backs up and gives a
|
|
13964
|
+
* serving thread, so a new one is a code change, never a string a caller
|
|
13965
|
+
* invents. `settings` is `camstack.db` and the default for every collection
|
|
13966
|
+
* that names no file.
|
|
13967
|
+
*/
|
|
13968
|
+
var DataStoreDatabaseSchema = _enum([
|
|
13969
|
+
"settings",
|
|
13970
|
+
"events",
|
|
13971
|
+
"history"
|
|
13972
|
+
]);
|
|
13973
|
+
DataStoreDatabaseSchema.options;
|
|
13974
|
+
/**
|
|
13975
|
+
* One write inside a {@link settingsStoreCapability.methods.transact} call.
|
|
13976
|
+
* The three that a "replace this set, bump that revision" write needs, plus
|
|
13977
|
+
* the batched upsert a rollup writer needs.
|
|
13978
|
+
*/
|
|
13979
|
+
var TransactOpSchema = discriminatedUnion("op", [
|
|
13980
|
+
object({
|
|
13981
|
+
op: literal("deleteWhere"),
|
|
13982
|
+
collection: string(),
|
|
13983
|
+
filter: MutationFilterSchema
|
|
13984
|
+
}),
|
|
13985
|
+
object({
|
|
13986
|
+
op: literal("insertMany"),
|
|
13987
|
+
collection: string(),
|
|
13988
|
+
records: array(BulkRecordSchema).readonly()
|
|
13989
|
+
}),
|
|
13990
|
+
object({
|
|
13991
|
+
op: literal("update"),
|
|
13992
|
+
collection: string(),
|
|
13993
|
+
id: string(),
|
|
13994
|
+
data: record(string(), unknown())
|
|
13995
|
+
}),
|
|
13996
|
+
object({
|
|
13997
|
+
op: literal("upsertMany"),
|
|
13998
|
+
collection: string(),
|
|
13999
|
+
conflict: array(string()).readonly(),
|
|
14000
|
+
records: array(BulkRecordSchema).readonly()
|
|
14001
|
+
})
|
|
14002
|
+
]);
|
|
14003
|
+
/**
|
|
14004
|
+
* The precondition of a transaction: the row `key` of `collection` must hold
|
|
14005
|
+
* `equals` in `column`, read INSIDE the transaction.
|
|
14006
|
+
*/
|
|
14007
|
+
var TransactGuardSchema = object({
|
|
14008
|
+
collection: string(),
|
|
14009
|
+
key: string(),
|
|
14010
|
+
column: string(),
|
|
14011
|
+
equals: unknown()
|
|
14012
|
+
});
|
|
14013
|
+
/**
|
|
14014
|
+
* Column declaration for a structured (SQL-backed) collection.
|
|
14015
|
+
*
|
|
14016
|
+
* Logical types — the backend translates each to the matching SQLite
|
|
14017
|
+
* storage class and handles per-type marshaling:
|
|
14018
|
+
* - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
|
|
14019
|
+
* - `JSON` — TEXT under the hood; serialised on write, parsed on read
|
|
14020
|
+
* - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
|
|
14021
|
+
*/
|
|
14022
|
+
var CollectionColumnSchema = object({
|
|
14023
|
+
name: string(),
|
|
14024
|
+
type: _enum([
|
|
14025
|
+
"TEXT",
|
|
14026
|
+
"INTEGER",
|
|
14027
|
+
"REAL",
|
|
14028
|
+
"JSON",
|
|
14029
|
+
"BOOLEAN"
|
|
14030
|
+
]),
|
|
14031
|
+
primaryKey: boolean().optional(),
|
|
14032
|
+
notNull: boolean().optional(),
|
|
14033
|
+
unique: boolean().optional(),
|
|
14034
|
+
/**
|
|
14035
|
+
* Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
|
|
14036
|
+
* columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
|
|
14037
|
+
* collection surface simply cannot express their existing tables — which is
|
|
14038
|
+
* why they were still on the uncapped `table*` API.
|
|
14039
|
+
*/
|
|
14040
|
+
defaultValue: union([
|
|
14041
|
+
string(),
|
|
14042
|
+
number(),
|
|
14043
|
+
boolean()
|
|
14044
|
+
]).optional()
|
|
14045
|
+
});
|
|
14046
|
+
var CollectionIndexSchema = object({
|
|
14047
|
+
name: string(),
|
|
14048
|
+
columns: array(string()).readonly(),
|
|
14049
|
+
unique: boolean().optional()
|
|
14050
|
+
});
|
|
14051
|
+
/**
|
|
14052
|
+
* The input of `declareCollection` — ONE schema for the door and for the
|
|
14053
|
+
* engine behind it, so the two surfaces cannot drift (the dispatcher forwards
|
|
14054
|
+
* the payload untouched).
|
|
14055
|
+
*
|
|
14056
|
+
* - `database` — the file the collection lives in (D851). Absent means
|
|
14057
|
+
* `settings`. A declaration naming a file other than the one the table is
|
|
14058
|
+
* already in is REFUSED by the engine, never moved.
|
|
14059
|
+
* - `primaryKey` — a COMPOSITE key, as column names. A single name is the same
|
|
14060
|
+
* as `primaryKey: true` on that column. A composite-keyed collection has no
|
|
14061
|
+
* `id`: it is written with `insertMany` / `upsertMany` / `transact` and read
|
|
14062
|
+
* with `query` / `count` / `aggregate` / `deleteWhere`; the calls that
|
|
14063
|
+
* address one row by id are refused.
|
|
14064
|
+
* - `withoutRowid` — emit `WITHOUT ROWID`. Requires a primary key.
|
|
14065
|
+
*/
|
|
14066
|
+
var DeclareCollectionInputSchema = object({
|
|
14067
|
+
namespace: string().optional(),
|
|
14068
|
+
collection: string(),
|
|
14069
|
+
columns: array(CollectionColumnSchema).readonly(),
|
|
14070
|
+
indexes: array(CollectionIndexSchema).readonly().optional(),
|
|
14071
|
+
database: DataStoreDatabaseSchema.optional(),
|
|
14072
|
+
primaryKey: array(string()).readonly().optional(),
|
|
14073
|
+
withoutRowid: boolean().optional()
|
|
14074
|
+
});
|
|
14075
|
+
method(object({
|
|
14076
|
+
namespace: string().optional(),
|
|
14077
|
+
collection: string(),
|
|
14078
|
+
key: string()
|
|
14079
|
+
}), unknown(), { auth: "admin" }), method(object({
|
|
14080
|
+
namespace: string().optional(),
|
|
14081
|
+
collection: string(),
|
|
14082
|
+
key: string(),
|
|
14083
|
+
value: unknown()
|
|
14084
|
+
}), _void(), {
|
|
14085
|
+
kind: "mutation",
|
|
14086
|
+
auth: "admin"
|
|
14087
|
+
}), method(object({
|
|
14088
|
+
namespace: string().optional(),
|
|
14089
|
+
collection: string(),
|
|
14090
|
+
filter: QueryFilterSchema.optional(),
|
|
14091
|
+
columns: array(string()).readonly().optional()
|
|
14092
|
+
}), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
|
|
14093
|
+
namespace: string().optional(),
|
|
14094
|
+
collection: string(),
|
|
14095
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
14096
|
+
* index on the collection. Never empty. */
|
|
14097
|
+
conflict: array(string()).readonly(),
|
|
14098
|
+
record: BulkRecordSchema
|
|
14099
|
+
}), object({
|
|
14100
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
14101
|
+
* row's own id on an update. */
|
|
14102
|
+
id: union([string(), number()]) }), {
|
|
14103
|
+
kind: "mutation",
|
|
14104
|
+
auth: "admin"
|
|
14105
|
+
}), method(object({
|
|
14106
|
+
namespace: string().optional(),
|
|
14107
|
+
collection: string(),
|
|
14108
|
+
conflict: array(string()).readonly(),
|
|
14109
|
+
records: array(BulkRecordSchema).readonly()
|
|
14110
|
+
}), object({ upserted: number().int() }), {
|
|
14111
|
+
kind: "mutation",
|
|
14112
|
+
auth: "admin"
|
|
14113
|
+
}), method(object({
|
|
14114
|
+
namespace: string().optional(),
|
|
14115
|
+
collection: string(),
|
|
14116
|
+
record: object({
|
|
14117
|
+
id: string().optional(),
|
|
14118
|
+
data: record(string(), unknown())
|
|
14119
|
+
})
|
|
14120
|
+
}), object({
|
|
14121
|
+
/**
|
|
14122
|
+
* The id the row ACTUALLY got (D473): the one supplied, the UUID minted
|
|
14123
|
+
* for an absent one, or the ROWID SQLite assigned on an `INTEGER`
|
|
14124
|
+
* primary key — which is the only place an auto key is knowable.
|
|
14125
|
+
*/
|
|
14126
|
+
id: union([string(), number()]) }), {
|
|
14127
|
+
kind: "mutation",
|
|
14128
|
+
auth: "admin"
|
|
14129
|
+
}), method(object({
|
|
14130
|
+
namespace: string().optional(),
|
|
14131
|
+
collection: string(),
|
|
14132
|
+
records: array(BulkRecordSchema).readonly()
|
|
14133
|
+
}), object({ inserted: number().int() }), {
|
|
14134
|
+
kind: "mutation",
|
|
14135
|
+
auth: "admin"
|
|
14136
|
+
}), method(object({
|
|
14137
|
+
namespace: string().optional(),
|
|
14138
|
+
guard: TransactGuardSchema.optional(),
|
|
14139
|
+
ops: array(TransactOpSchema).readonly()
|
|
14140
|
+
}), object({
|
|
14141
|
+
applied: boolean(),
|
|
14142
|
+
current: unknown().optional()
|
|
14143
|
+
}), {
|
|
14144
|
+
kind: "mutation",
|
|
14145
|
+
auth: "admin"
|
|
14146
|
+
}), method(object({
|
|
14147
|
+
namespace: string().optional(),
|
|
14148
|
+
collection: string(),
|
|
14149
|
+
id: string(),
|
|
14150
|
+
data: record(string(), unknown())
|
|
14151
|
+
}), _void(), {
|
|
14152
|
+
kind: "mutation",
|
|
14153
|
+
auth: "admin"
|
|
14154
|
+
}), method(object({
|
|
14155
|
+
namespace: string().optional(),
|
|
14156
|
+
collection: string(),
|
|
14157
|
+
key: string()
|
|
14158
|
+
}), _void(), {
|
|
14159
|
+
kind: "mutation",
|
|
14160
|
+
auth: "admin"
|
|
14161
|
+
}), method(object({
|
|
14162
|
+
namespace: string().optional(),
|
|
14163
|
+
collection: string(),
|
|
14164
|
+
filter: MutationFilterSchema
|
|
14165
|
+
}), object({ deleted: number().int() }), {
|
|
14166
|
+
kind: "mutation",
|
|
14167
|
+
auth: "admin"
|
|
14168
|
+
}), method(object({
|
|
14169
|
+
namespace: string().optional(),
|
|
14170
|
+
collection: string(),
|
|
14171
|
+
filter: MutationFilterSchema,
|
|
14172
|
+
data: record(string(), unknown())
|
|
14173
|
+
}), object({ updated: number().int() }), {
|
|
14174
|
+
kind: "mutation",
|
|
14175
|
+
auth: "admin"
|
|
14176
|
+
}), method(object({
|
|
14177
|
+
namespace: string().optional(),
|
|
14178
|
+
collection: string(),
|
|
14179
|
+
filter: QueryFilterSchema.optional()
|
|
14180
|
+
}), number(), { auth: "admin" }), method(object({
|
|
14181
|
+
namespace: string().optional(),
|
|
14182
|
+
collection: string(),
|
|
14183
|
+
fields: array(AggregateFieldSchema).readonly(),
|
|
14184
|
+
filter: QueryFilterSchema.optional()
|
|
14185
|
+
}), AggregateResultSchema, { auth: "admin" }), method(object({
|
|
14186
|
+
namespace: string().optional(),
|
|
14187
|
+
collection: string(),
|
|
14188
|
+
field: string(),
|
|
14189
|
+
bucketSize: number().int().positive(),
|
|
14190
|
+
origin: number().int(),
|
|
14191
|
+
filter: QueryFilterSchema.optional()
|
|
14192
|
+
}), array(object({
|
|
14193
|
+
bucket: number().int(),
|
|
14194
|
+
count: number().int()
|
|
14195
|
+
})).readonly(), { auth: "admin" }), method(object({
|
|
14196
|
+
namespace: string().optional(),
|
|
14197
|
+
collection: string()
|
|
14198
|
+
}), boolean(), { auth: "admin" }), method(DeclareCollectionInputSchema, _void(), {
|
|
14199
|
+
kind: "mutation",
|
|
14200
|
+
auth: "admin"
|
|
14201
|
+
});
|
|
14202
|
+
var MigrationIdSchema = string().regex(/^[a-z0-9-]+\/\d{4}-\d{2}-\d{2}-[a-z0-9-]+$/, "a migration id is \"<owner>/<yyyy-mm-dd>-<slug>\"");
|
|
14203
|
+
var MigrationLevelSchema = _enum([
|
|
14204
|
+
"hub-store",
|
|
14205
|
+
"addon-state",
|
|
14206
|
+
"node-config",
|
|
14207
|
+
"viewer",
|
|
14208
|
+
"addon-internal"
|
|
14209
|
+
]);
|
|
14210
|
+
var MigrationStoreSchema = _enum([
|
|
14211
|
+
"settings",
|
|
14212
|
+
"events",
|
|
14213
|
+
"history",
|
|
14214
|
+
"node-local",
|
|
14215
|
+
"addon-files"
|
|
14216
|
+
]);
|
|
14217
|
+
var MigrationScopeSchema = _enum(["cluster", "per-node"]);
|
|
14218
|
+
/** What depends on a migration while it is pending: `block-owner` is the default. */
|
|
14219
|
+
var MigrationOnFailureSchema = _enum(["block-owner", "tolerate"]);
|
|
14220
|
+
/**
|
|
14221
|
+
* `sql` is a hub-only body over the owner's connection. `plan` returns edits the
|
|
14222
|
+
* engine applies inside the migration's own transaction (hub-owned: computed in
|
|
14223
|
+
* that transaction; addon-owned: computed by the owner and shipped to the engine).
|
|
14224
|
+
* `procedure` is addon-owned work that is not SQL (keychain, integration registry,
|
|
14225
|
+
* device tombstones); the ledger records its outcome and it must be idempotent.
|
|
14226
|
+
*/
|
|
14227
|
+
var MigrationBodyKindSchema = _enum([
|
|
14228
|
+
"sql",
|
|
14229
|
+
"plan",
|
|
14230
|
+
"procedure"
|
|
14231
|
+
]);
|
|
14232
|
+
var MigrationMetaSchema = object({
|
|
14233
|
+
id: MigrationIdSchema,
|
|
14234
|
+
/** `hub`, an addon id, `node` or `viewer`. */
|
|
14235
|
+
owner: string().regex(/^[a-z0-9-]+$/),
|
|
14236
|
+
level: MigrationLevelSchema,
|
|
14237
|
+
/** Strictly increasing per owner: the order within an owner. */
|
|
14238
|
+
seq: number().int().positive(),
|
|
14239
|
+
/** Ids of any owner: the order across owners. */
|
|
14240
|
+
dependsOn: array(MigrationIdSchema),
|
|
14241
|
+
store: MigrationStoreSchema,
|
|
14242
|
+
scope: MigrationScopeSchema,
|
|
14243
|
+
onFailure: MigrationOnFailureSchema,
|
|
14244
|
+
bodyKind: MigrationBodyKindSchema,
|
|
14245
|
+
description: string().min(1),
|
|
14246
|
+
/** The marked field the migration's spec must assert survived. */
|
|
14247
|
+
fixtureMark: string().min(1)
|
|
14248
|
+
}).refine((m) => m.id.startsWith(`${m.owner}/`), {
|
|
14249
|
+
message: "the id must start with \"<owner>/\"",
|
|
14250
|
+
path: ["id"]
|
|
14251
|
+
});
|
|
14252
|
+
/** A cycle in the dependency graph, named by the ids on it. */
|
|
14253
|
+
var MigrationCycleError = class extends Error {
|
|
14254
|
+
ids;
|
|
14255
|
+
constructor(ids) {
|
|
14256
|
+
super(`migration dependsOn cycle: ${ids.join(" -> ")}`);
|
|
14257
|
+
this.ids = ids;
|
|
14258
|
+
this.name = "MigrationCycleError";
|
|
14259
|
+
}
|
|
14260
|
+
};
|
|
14261
|
+
/**
|
|
14262
|
+
* Topological order over `dependsOn` plus the implicit edge "a lower `seq` of an
|
|
14263
|
+
* owner runs first". Ties are broken by `(owner, seq)`. Throws
|
|
14264
|
+
* {@link MigrationCycleError} on a cycle. A `dependsOn` id that is not in the list
|
|
14265
|
+
* is ignored here — the catalogue schema is what refuses it.
|
|
14266
|
+
*/
|
|
14267
|
+
function orderMigrations(items) {
|
|
14268
|
+
const byId = new Map(items.map((item) => [item.id, item]));
|
|
14269
|
+
const deps = /* @__PURE__ */ new Map();
|
|
14270
|
+
const ownerSorted = /* @__PURE__ */ new Map();
|
|
14271
|
+
for (const item of items) {
|
|
14272
|
+
const list = ownerSorted.get(item.owner) ?? [];
|
|
14273
|
+
list.push(item);
|
|
14274
|
+
ownerSorted.set(item.owner, list);
|
|
14275
|
+
}
|
|
14276
|
+
for (const item of items) deps.set(item.id, new Set(item.dependsOn.filter((id) => byId.has(id))));
|
|
14277
|
+
for (const list of ownerSorted.values()) {
|
|
14278
|
+
list.sort((a, b) => a.seq - b.seq);
|
|
14279
|
+
for (let i = 1; i < list.length; i++) {
|
|
14280
|
+
const previous = list[i - 1];
|
|
14281
|
+
const current = list[i];
|
|
14282
|
+
if (previous !== void 0 && current !== void 0) deps.get(current.id)?.add(previous.id);
|
|
14283
|
+
}
|
|
14284
|
+
}
|
|
14285
|
+
const tie = (a, b) => a.owner < b.owner ? -1 : a.owner > b.owner ? 1 : a.seq - b.seq;
|
|
14286
|
+
const done = /* @__PURE__ */ new Set();
|
|
14287
|
+
const ordered = [];
|
|
14288
|
+
let remaining = [...items];
|
|
14289
|
+
while (remaining.length > 0) {
|
|
14290
|
+
const ready = remaining.filter((item) => [...deps.get(item.id) ?? []].every((dep) => done.has(dep)));
|
|
14291
|
+
if (ready.length === 0) throw new MigrationCycleError(remaining.map((item) => item.id).sort());
|
|
14292
|
+
ready.sort(tie);
|
|
14293
|
+
const next = ready[0];
|
|
14294
|
+
if (next === void 0) break;
|
|
14295
|
+
ordered.push(next);
|
|
14296
|
+
done.add(next.id);
|
|
14297
|
+
remaining = remaining.filter((item) => item.id !== next.id);
|
|
14298
|
+
}
|
|
14299
|
+
return ordered;
|
|
14300
|
+
}
|
|
14301
|
+
/** Every way a list of migrations (in declaration order) is not a catalogue. */
|
|
14302
|
+
function catalogueIssues(items) {
|
|
14303
|
+
const issues = [];
|
|
14304
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14305
|
+
const known = new Set(items.map((item) => item.id));
|
|
14306
|
+
const lastSeq = /* @__PURE__ */ new Map();
|
|
14307
|
+
const seqUsed = /* @__PURE__ */ new Map();
|
|
14308
|
+
for (const item of items) {
|
|
14309
|
+
if (seen.has(item.id)) issues.push({
|
|
14310
|
+
code: "duplicate-id",
|
|
14311
|
+
ids: [item.id],
|
|
14312
|
+
message: `duplicate id ${item.id}`
|
|
14313
|
+
});
|
|
14314
|
+
seen.add(item.id);
|
|
14315
|
+
const used = seqUsed.get(item.owner) ?? /* @__PURE__ */ new Set();
|
|
14316
|
+
if (used.has(item.seq)) issues.push({
|
|
14317
|
+
code: "duplicate-seq",
|
|
14318
|
+
ids: [item.id],
|
|
14319
|
+
message: `owner ${item.owner} has two migrations with seq ${item.seq}`
|
|
14320
|
+
});
|
|
14321
|
+
else if (item.seq < (lastSeq.get(item.owner) ?? 0)) issues.push({
|
|
14322
|
+
code: "seq-order",
|
|
14323
|
+
ids: [item.id],
|
|
14324
|
+
message: `seq ${item.seq} of ${item.id} does not increase in declaration order (owner ${item.owner})`
|
|
14325
|
+
});
|
|
14326
|
+
used.add(item.seq);
|
|
14327
|
+
seqUsed.set(item.owner, used);
|
|
14328
|
+
lastSeq.set(item.owner, Math.max(item.seq, lastSeq.get(item.owner) ?? 0));
|
|
14329
|
+
for (const dep of item.dependsOn) if (!known.has(dep)) issues.push({
|
|
14330
|
+
code: "unknown-dependency",
|
|
14331
|
+
ids: [item.id, dep],
|
|
14332
|
+
message: `${item.id} dependsOn unknown id ${dep}`
|
|
14333
|
+
});
|
|
14334
|
+
}
|
|
14335
|
+
try {
|
|
14336
|
+
orderMigrations(items);
|
|
14337
|
+
} catch (err) {
|
|
14338
|
+
if (err instanceof MigrationCycleError) issues.push({
|
|
14339
|
+
code: "cycle",
|
|
14340
|
+
ids: err.ids,
|
|
14341
|
+
message: err.message
|
|
14342
|
+
});
|
|
14343
|
+
else throw err;
|
|
14344
|
+
}
|
|
14345
|
+
return issues;
|
|
14346
|
+
}
|
|
14347
|
+
array(MigrationMetaSchema).superRefine((items, ctx) => {
|
|
14348
|
+
for (const issue of catalogueIssues(items)) ctx.addIssue({
|
|
14349
|
+
code: "custom",
|
|
14350
|
+
message: `${issue.code}: ${issue.message}`
|
|
14351
|
+
});
|
|
14352
|
+
});
|
|
14353
|
+
/**
|
|
14354
|
+
* The canonical JSON (`preconditionOf`) of the value a plan read; the apply step
|
|
14355
|
+
* re-reads, and a plan whose read no longer matches is refused (the migration is
|
|
14356
|
+
* `failed`, nothing it edited is kept).
|
|
14357
|
+
*/
|
|
14358
|
+
var PreconditionSchema = string().min(1).optional();
|
|
14359
|
+
var MigrationPlanSchema = object({ edits: array(discriminatedUnion("op", [
|
|
14360
|
+
object({
|
|
14361
|
+
op: literal("setKeys"),
|
|
14362
|
+
scope: string().min(1),
|
|
14363
|
+
values: record(string(), unknown()),
|
|
14364
|
+
precondition: PreconditionSchema
|
|
14365
|
+
}),
|
|
14366
|
+
object({
|
|
14367
|
+
op: literal("deleteKeys"),
|
|
14368
|
+
scope: string().min(1),
|
|
14369
|
+
keys: array(string().min(1)).min(1),
|
|
14370
|
+
precondition: PreconditionSchema
|
|
14371
|
+
}),
|
|
14372
|
+
object({
|
|
14373
|
+
op: literal("putRow"),
|
|
14374
|
+
table: string().min(1),
|
|
14375
|
+
key: record(string(), unknown()),
|
|
14376
|
+
row: record(string(), unknown()),
|
|
14377
|
+
precondition: PreconditionSchema
|
|
14378
|
+
}),
|
|
14379
|
+
object({
|
|
14380
|
+
op: literal("deleteRow"),
|
|
14381
|
+
table: string().min(1),
|
|
14382
|
+
key: record(string(), unknown()),
|
|
14383
|
+
precondition: PreconditionSchema
|
|
14384
|
+
}),
|
|
14385
|
+
object({
|
|
14386
|
+
op: literal("upsertRecord"),
|
|
14387
|
+
kind: string().min(1),
|
|
14388
|
+
recordKey: string().min(1),
|
|
14389
|
+
value: unknown(),
|
|
14390
|
+
precondition: PreconditionSchema
|
|
14391
|
+
}),
|
|
14392
|
+
object({
|
|
14393
|
+
op: literal("deleteRecord"),
|
|
14394
|
+
kind: string().min(1),
|
|
14395
|
+
recordKey: string().min(1),
|
|
14396
|
+
precondition: PreconditionSchema
|
|
14397
|
+
})
|
|
14398
|
+
])) });
|
|
14399
|
+
/**
|
|
14400
|
+
* What a `procedure` body reports. `already-done` means the rerun observed the
|
|
14401
|
+
* work finished (a crash between the work and the ledger row, or a manual fix)
|
|
14402
|
+
* and did none of it again; the ledger records `applied` either way.
|
|
14403
|
+
*/
|
|
14404
|
+
var MigrationProcedureResultSchema = object({
|
|
14405
|
+
outcome: _enum(["done", "already-done"]),
|
|
14406
|
+
summary: record(string(), unknown())
|
|
14407
|
+
});
|
|
14408
|
+
/** What an owner hands the engine when one of its migrations ran. */
|
|
14409
|
+
var MigrationOwnerResultSchema = discriminatedUnion("kind", [
|
|
14410
|
+
object({
|
|
14411
|
+
kind: literal("plan"),
|
|
14412
|
+
plan: MigrationPlanSchema
|
|
14413
|
+
}),
|
|
14414
|
+
object({
|
|
14415
|
+
kind: literal("procedure"),
|
|
14416
|
+
result: MigrationProcedureResultSchema
|
|
14417
|
+
}),
|
|
14418
|
+
object({
|
|
14419
|
+
kind: literal("failed"),
|
|
14420
|
+
error: string().min(1)
|
|
14421
|
+
})
|
|
14422
|
+
]);
|
|
14423
|
+
/**
|
|
14424
|
+
* `held`: a restore of a pre-migration snapshot undid this id; it does not rerun
|
|
14425
|
+
* until the operator retries or a new code version ships.
|
|
14426
|
+
* `skipped-newer`: the database knows an id this code does not.
|
|
14427
|
+
*/
|
|
14428
|
+
var MigrationStatusSchema = _enum([
|
|
14429
|
+
"applied",
|
|
14430
|
+
"failed",
|
|
14431
|
+
"blocked",
|
|
14432
|
+
"running",
|
|
14433
|
+
"held",
|
|
14434
|
+
"skipped-newer"
|
|
14435
|
+
]);
|
|
14436
|
+
var MigrationLedgerEntrySchema = object({
|
|
14437
|
+
id: string(),
|
|
14438
|
+
database: DataStoreDatabaseSchema,
|
|
14439
|
+
owner: string(),
|
|
14440
|
+
level: MigrationLevelSchema,
|
|
14441
|
+
seq: number().int().nonnegative(),
|
|
14442
|
+
status: MigrationStatusSchema,
|
|
14443
|
+
attempts: number().int().nonnegative(),
|
|
14444
|
+
appliedAt: number().nullable(),
|
|
14445
|
+
codeVersion: string().nullable(),
|
|
14446
|
+
/** What the apply changed: rows per table, as the engine counted them. */
|
|
14447
|
+
planSummary: record(string(), unknown()).nullable(),
|
|
14448
|
+
progress: record(string(), unknown()).nullable(),
|
|
14449
|
+
error: string().nullable(),
|
|
14450
|
+
/** Why it is `blocked` or `held` (`dependency-failed`, `snapshot-refused`, …). */
|
|
14451
|
+
reason: string().nullable(),
|
|
14452
|
+
nodeId: string().nullable(),
|
|
14453
|
+
bootId: string().nullable()
|
|
14454
|
+
});
|
|
14455
|
+
/** A catalogued migration that is not applied, with where it stands. */
|
|
14456
|
+
var MigrationPendingEntrySchema = object({
|
|
14457
|
+
meta: MigrationMetaSchema,
|
|
14458
|
+
database: DataStoreDatabaseSchema,
|
|
14459
|
+
state: _enum([
|
|
14460
|
+
"pending",
|
|
14461
|
+
"failed",
|
|
14462
|
+
"blocked",
|
|
14463
|
+
"held"
|
|
14464
|
+
]),
|
|
14465
|
+
reason: string().nullable()
|
|
14466
|
+
});
|
|
14467
|
+
/** Rows per table before and after a dry run, and what it would have changed. */
|
|
14468
|
+
var MigrationDryRunResultSchema = object({
|
|
14469
|
+
id: string(),
|
|
14470
|
+
ok: boolean(),
|
|
14471
|
+
error: string().nullable(),
|
|
14472
|
+
rowsChanged: number().int().nonnegative(),
|
|
14473
|
+
tables: array(object({
|
|
14474
|
+
table: string(),
|
|
14475
|
+
before: number().int().nonnegative(),
|
|
14476
|
+
after: number().int().nonnegative()
|
|
14477
|
+
}))
|
|
14478
|
+
});
|
|
14479
|
+
/** One of an owner's migrations, as the engine tells the owner to treat it this boot. */
|
|
14480
|
+
var MigrationOwnerStepSchema = object({
|
|
14481
|
+
id: MigrationIdSchema,
|
|
14482
|
+
action: _enum(["run", "skip"]),
|
|
14483
|
+
/** The ledger state the engine found: `pending` has no row yet. */
|
|
14484
|
+
state: union([literal("pending"), MigrationStatusSchema])
|
|
14485
|
+
});
|
|
14486
|
+
/**
|
|
13644
14487
|
* The trainer contract — what the hub hands the cloud trainer and what it
|
|
13645
14488
|
* gets back (cloud training, D805+).
|
|
13646
14489
|
*
|
|
@@ -17676,6 +18519,41 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
17676
18519
|
icon: "droplets"
|
|
17677
18520
|
}]
|
|
17678
18521
|
},
|
|
18522
|
+
"power-source": {
|
|
18523
|
+
scope: "device",
|
|
18524
|
+
noun: t("Power source", "Alimentazione"),
|
|
18525
|
+
actions: [
|
|
18526
|
+
{
|
|
18527
|
+
id: "powerSource.on",
|
|
18528
|
+
method: "powerOn",
|
|
18529
|
+
label: t("Power on", "Dai corrente"),
|
|
18530
|
+
phrase: t("Power on {device}", "Dai corrente a {device}"),
|
|
18531
|
+
icon: "power"
|
|
18532
|
+
},
|
|
18533
|
+
{
|
|
18534
|
+
id: "powerSource.off",
|
|
18535
|
+
method: "powerOff",
|
|
18536
|
+
label: t("Power off", "Togli corrente"),
|
|
18537
|
+
phrase: t("Cut the power of {device}", "Togli la corrente a {device}"),
|
|
18538
|
+
icon: "power-off"
|
|
18539
|
+
},
|
|
18540
|
+
{
|
|
18541
|
+
id: "powerSource.forceRestart",
|
|
18542
|
+
method: "forceRestart",
|
|
18543
|
+
label: t("Force restart", "Riavvio forzato"),
|
|
18544
|
+
phrase: t("Force restart {device} by cutting its power", "Riavvia {device} togliendo la corrente"),
|
|
18545
|
+
icon: "refresh-cw"
|
|
18546
|
+
}
|
|
18547
|
+
],
|
|
18548
|
+
state: [{
|
|
18549
|
+
kind: "boolean",
|
|
18550
|
+
field: "switchOn",
|
|
18551
|
+
label: t("Power switch on", "Presa accesa"),
|
|
18552
|
+
whenTrue: t("When the power of {device} comes on", "Quando arriva la corrente a {device}"),
|
|
18553
|
+
whenFalse: t("When the power of {device} is cut", "Quando manca la corrente a {device}"),
|
|
18554
|
+
icon: "power"
|
|
18555
|
+
}]
|
|
18556
|
+
},
|
|
17679
18557
|
"lock-control": {
|
|
17680
18558
|
scope: "device",
|
|
17681
18559
|
noun: t("Lock", "Serratura"),
|
|
@@ -18151,7 +19029,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
18151
19029
|
method: "setDirection",
|
|
18152
19030
|
label: t("Spin forward", "Rotazione avanti"),
|
|
18153
19031
|
phrase: t("Spin {device} forward", "Fai girare {device} in avanti"),
|
|
18154
|
-
icon: "
|
|
19032
|
+
icon: "refresh-cw",
|
|
18155
19033
|
effect: {
|
|
18156
19034
|
field: "direction",
|
|
18157
19035
|
value: "forward"
|
|
@@ -21229,6 +22107,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
21229
22107
|
"login-method": system(IDENTITY),
|
|
21230
22108
|
"mesh-network": system(NETWORK),
|
|
21231
22109
|
"metrics-provider": system(CLUSTER),
|
|
22110
|
+
migrations: system(INTERNAL),
|
|
21232
22111
|
"model-convert": system(ML),
|
|
21233
22112
|
"model-distributor": system(ML),
|
|
21234
22113
|
"mqtt-broker": system(NETWORK),
|
|
@@ -43794,7 +44673,7 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
|
|
|
43794
44673
|
* rebuilds without manual reload.
|
|
43795
44674
|
*
|
|
43796
44675
|
* The hub-local builtin `addon-pages-aggregator` (see
|
|
43797
|
-
* `@camstack/system/builtins/addon-pages-aggregator`) registers the
|
|
44676
|
+
* `@camstack/server/system/builtins/addon-pages-aggregator`) registers the
|
|
43798
44677
|
* provider. Splitting the public aggregator from the raw collection
|
|
43799
44678
|
* keeps both ends in codegen — there's no hand-written
|
|
43800
44679
|
* `addon-pages.router.ts` wrapper anymore.
|
|
@@ -43920,6 +44799,10 @@ method(object({
|
|
|
43920
44799
|
}), method(object({
|
|
43921
44800
|
addonId: string(),
|
|
43922
44801
|
nodeId: string().optional()
|
|
44802
|
+
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
44803
|
+
addonId: string(),
|
|
44804
|
+
nodeId: string().optional(),
|
|
44805
|
+
instance: IntegrationInstanceRefSchema
|
|
43923
44806
|
}), SettingsSchemaWithValuesSchema.nullable()), method(object({
|
|
43924
44807
|
addonId: string(),
|
|
43925
44808
|
nodeId: string().optional()
|
|
@@ -44109,7 +44992,7 @@ listWidgets: method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "ad
|
|
|
44109
44992
|
* manual reload — same scheme used by `addon-pages`.
|
|
44110
44993
|
*
|
|
44111
44994
|
* The hub-local builtin `addon-widgets-aggregator` (see
|
|
44112
|
-
* `@camstack/system/builtins/addon-widgets-aggregator`) registers the
|
|
44995
|
+
* `@camstack/server/system/builtins/addon-widgets-aggregator`) registers the
|
|
44113
44996
|
* provider. Splitting the public aggregator from the raw collection
|
|
44114
44997
|
* keeps both ends in codegen — there's no hand-written wrapper.
|
|
44115
44998
|
*/
|
|
@@ -44470,329 +45353,6 @@ method(object({
|
|
|
44470
45353
|
password: string()
|
|
44471
45354
|
}), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
|
|
44472
45355
|
/**
|
|
44473
|
-
* Query filter for settings-store collections.
|
|
44474
|
-
*/
|
|
44475
|
-
var QueryFilterSchema = object({
|
|
44476
|
-
where: record(string(), unknown()).optional(),
|
|
44477
|
-
whereIn: record(string(), array(unknown())).optional(),
|
|
44478
|
-
whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
|
|
44479
|
-
/** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
|
|
44480
|
-
whereNot: record(string(), unknown()).optional(),
|
|
44481
|
-
/** NULL-safe exclusion of a SET — `whereNot` for more than one value. An
|
|
44482
|
-
* empty list excludes nothing. See `QueryFilter.whereNotIn`. */
|
|
44483
|
-
whereNotIn: record(string(), array(unknown())).optional(),
|
|
44484
|
-
orderBy: object({
|
|
44485
|
-
field: string(),
|
|
44486
|
-
direction: _enum(["asc", "desc"])
|
|
44487
|
-
}).optional(),
|
|
44488
|
-
limit: number().optional(),
|
|
44489
|
-
offset: number().optional()
|
|
44490
|
-
});
|
|
44491
|
-
/**
|
|
44492
|
-
* The predicate half of a filter, for BULK MUTATIONS.
|
|
44493
|
-
*
|
|
44494
|
-
* Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
|
|
44495
|
-
* meaning for a statement that rewrites a set, and accepting them would invite
|
|
44496
|
-
* a caller to believe `limit` bounds the damage. Every field is optional here
|
|
44497
|
-
* only so the shape stays composable — the implementation REJECTS a filter
|
|
44498
|
-
* that compiles to no predicate, because that is the whole collection.
|
|
44499
|
-
*/
|
|
44500
|
-
var MutationFilterSchema = object({
|
|
44501
|
-
where: record(string(), unknown()).optional(),
|
|
44502
|
-
whereIn: record(string(), array(unknown())).optional(),
|
|
44503
|
-
whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
|
|
44504
|
-
whereNot: record(string(), unknown()).optional(),
|
|
44505
|
-
whereNotIn: record(string(), array(unknown())).optional()
|
|
44506
|
-
});
|
|
44507
|
-
/**
|
|
44508
|
-
* One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
|
|
44509
|
-
*
|
|
44510
|
-
* `as` names the slot in the result, so the SAME column may be asked twice with
|
|
44511
|
-
* two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
|
|
44512
|
-
* a `Record<column, op>` shape could not express.
|
|
44513
|
-
*/
|
|
44514
|
-
var AggregateFieldSchema = object({
|
|
44515
|
-
/** Result key. */
|
|
44516
|
-
as: string().min(1),
|
|
44517
|
-
/** Column to aggregate. Must be a real column of a declared collection. */
|
|
44518
|
-
field: string().min(1),
|
|
44519
|
-
op: _enum([
|
|
44520
|
-
"sum",
|
|
44521
|
-
"min",
|
|
44522
|
-
"max"
|
|
44523
|
-
])
|
|
44524
|
-
});
|
|
44525
|
-
/**
|
|
44526
|
-
* `COUNT(*)` plus one number per requested field.
|
|
44527
|
-
*
|
|
44528
|
-
* `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
|
|
44529
|
-
* that really is 0 are different facts, and an accounting caller that renders
|
|
44530
|
-
* "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
|
|
44531
|
-
*/
|
|
44532
|
-
var AggregateResultSchema = object({
|
|
44533
|
-
count: number().int(),
|
|
44534
|
-
values: record(string(), number().nullable())
|
|
44535
|
-
});
|
|
44536
|
-
/** A single stored record: `{ id, data }`. */
|
|
44537
|
-
var SettingsRecordSchema = object({
|
|
44538
|
-
id: string(),
|
|
44539
|
-
data: record(string(), unknown())
|
|
44540
|
-
});
|
|
44541
|
-
/**
|
|
44542
|
-
* One record of a BULK insert — {@link SettingsRecordSchema} with the id made
|
|
44543
|
-
* optional.
|
|
44544
|
-
*
|
|
44545
|
-
* A separate schema rather than loosening the shared one: every other method
|
|
44546
|
-
* on this cap addresses a row BY its id, and making that field optional
|
|
44547
|
-
* everywhere would turn a forgotten key into a silently generated one on
|
|
44548
|
-
* `update` and `delete` as well.
|
|
44549
|
-
*/
|
|
44550
|
-
var BulkRecordSchema = object({
|
|
44551
|
-
id: string().optional(),
|
|
44552
|
-
data: record(string(), unknown())
|
|
44553
|
-
});
|
|
44554
|
-
/**
|
|
44555
|
-
* The database FILES one `sqlite-settings` engine process owns (D851).
|
|
44556
|
-
* Closed on purpose: a file is a thing the engine opens, backs up and gives a
|
|
44557
|
-
* serving thread, so a new one is a code change, never a string a caller
|
|
44558
|
-
* invents. `settings` is `camstack.db` and the default for every collection
|
|
44559
|
-
* that names no file.
|
|
44560
|
-
*/
|
|
44561
|
-
var DataStoreDatabaseSchema = _enum([
|
|
44562
|
-
"settings",
|
|
44563
|
-
"events",
|
|
44564
|
-
"history"
|
|
44565
|
-
]);
|
|
44566
|
-
DataStoreDatabaseSchema.options;
|
|
44567
|
-
/**
|
|
44568
|
-
* One write inside a {@link settingsStoreCapability.methods.transact} call.
|
|
44569
|
-
* The three that a "replace this set, bump that revision" write needs, plus
|
|
44570
|
-
* the batched upsert a rollup writer needs.
|
|
44571
|
-
*/
|
|
44572
|
-
var TransactOpSchema = discriminatedUnion("op", [
|
|
44573
|
-
object({
|
|
44574
|
-
op: literal("deleteWhere"),
|
|
44575
|
-
collection: string(),
|
|
44576
|
-
filter: MutationFilterSchema
|
|
44577
|
-
}),
|
|
44578
|
-
object({
|
|
44579
|
-
op: literal("insertMany"),
|
|
44580
|
-
collection: string(),
|
|
44581
|
-
records: array(BulkRecordSchema).readonly()
|
|
44582
|
-
}),
|
|
44583
|
-
object({
|
|
44584
|
-
op: literal("update"),
|
|
44585
|
-
collection: string(),
|
|
44586
|
-
id: string(),
|
|
44587
|
-
data: record(string(), unknown())
|
|
44588
|
-
}),
|
|
44589
|
-
object({
|
|
44590
|
-
op: literal("upsertMany"),
|
|
44591
|
-
collection: string(),
|
|
44592
|
-
conflict: array(string()).readonly(),
|
|
44593
|
-
records: array(BulkRecordSchema).readonly()
|
|
44594
|
-
})
|
|
44595
|
-
]);
|
|
44596
|
-
/**
|
|
44597
|
-
* The precondition of a transaction: the row `key` of `collection` must hold
|
|
44598
|
-
* `equals` in `column`, read INSIDE the transaction.
|
|
44599
|
-
*/
|
|
44600
|
-
var TransactGuardSchema = object({
|
|
44601
|
-
collection: string(),
|
|
44602
|
-
key: string(),
|
|
44603
|
-
column: string(),
|
|
44604
|
-
equals: unknown()
|
|
44605
|
-
});
|
|
44606
|
-
/**
|
|
44607
|
-
* Column declaration for a structured (SQL-backed) collection.
|
|
44608
|
-
*
|
|
44609
|
-
* Logical types — the backend translates each to the matching SQLite
|
|
44610
|
-
* storage class and handles per-type marshaling:
|
|
44611
|
-
* - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
|
|
44612
|
-
* - `JSON` — TEXT under the hood; serialised on write, parsed on read
|
|
44613
|
-
* - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
|
|
44614
|
-
*/
|
|
44615
|
-
var CollectionColumnSchema = object({
|
|
44616
|
-
name: string(),
|
|
44617
|
-
type: _enum([
|
|
44618
|
-
"TEXT",
|
|
44619
|
-
"INTEGER",
|
|
44620
|
-
"REAL",
|
|
44621
|
-
"JSON",
|
|
44622
|
-
"BOOLEAN"
|
|
44623
|
-
]),
|
|
44624
|
-
primaryKey: boolean().optional(),
|
|
44625
|
-
notNull: boolean().optional(),
|
|
44626
|
-
unique: boolean().optional(),
|
|
44627
|
-
/**
|
|
44628
|
-
* Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
|
|
44629
|
-
* columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
|
|
44630
|
-
* collection surface simply cannot express their existing tables — which is
|
|
44631
|
-
* why they were still on the uncapped `table*` API.
|
|
44632
|
-
*/
|
|
44633
|
-
defaultValue: union([
|
|
44634
|
-
string(),
|
|
44635
|
-
number(),
|
|
44636
|
-
boolean()
|
|
44637
|
-
]).optional()
|
|
44638
|
-
});
|
|
44639
|
-
var CollectionIndexSchema = object({
|
|
44640
|
-
name: string(),
|
|
44641
|
-
columns: array(string()).readonly(),
|
|
44642
|
-
unique: boolean().optional()
|
|
44643
|
-
});
|
|
44644
|
-
/**
|
|
44645
|
-
* The input of `declareCollection` — ONE schema for the door and for the
|
|
44646
|
-
* engine behind it, so the two surfaces cannot drift (the dispatcher forwards
|
|
44647
|
-
* the payload untouched).
|
|
44648
|
-
*
|
|
44649
|
-
* - `database` — the file the collection lives in (D851). Absent means
|
|
44650
|
-
* `settings`. A declaration naming a file other than the one the table is
|
|
44651
|
-
* already in is REFUSED by the engine, never moved.
|
|
44652
|
-
* - `primaryKey` — a COMPOSITE key, as column names. A single name is the same
|
|
44653
|
-
* as `primaryKey: true` on that column. A composite-keyed collection has no
|
|
44654
|
-
* `id`: it is written with `insertMany` / `upsertMany` / `transact` and read
|
|
44655
|
-
* with `query` / `count` / `aggregate` / `deleteWhere`; the calls that
|
|
44656
|
-
* address one row by id are refused.
|
|
44657
|
-
* - `withoutRowid` — emit `WITHOUT ROWID`. Requires a primary key.
|
|
44658
|
-
*/
|
|
44659
|
-
var DeclareCollectionInputSchema = object({
|
|
44660
|
-
namespace: string().optional(),
|
|
44661
|
-
collection: string(),
|
|
44662
|
-
columns: array(CollectionColumnSchema).readonly(),
|
|
44663
|
-
indexes: array(CollectionIndexSchema).readonly().optional(),
|
|
44664
|
-
database: DataStoreDatabaseSchema.optional(),
|
|
44665
|
-
primaryKey: array(string()).readonly().optional(),
|
|
44666
|
-
withoutRowid: boolean().optional()
|
|
44667
|
-
});
|
|
44668
|
-
method(object({
|
|
44669
|
-
namespace: string().optional(),
|
|
44670
|
-
collection: string(),
|
|
44671
|
-
key: string()
|
|
44672
|
-
}), unknown(), { auth: "admin" }), method(object({
|
|
44673
|
-
namespace: string().optional(),
|
|
44674
|
-
collection: string(),
|
|
44675
|
-
key: string(),
|
|
44676
|
-
value: unknown()
|
|
44677
|
-
}), _void(), {
|
|
44678
|
-
kind: "mutation",
|
|
44679
|
-
auth: "admin"
|
|
44680
|
-
}), method(object({
|
|
44681
|
-
namespace: string().optional(),
|
|
44682
|
-
collection: string(),
|
|
44683
|
-
filter: QueryFilterSchema.optional(),
|
|
44684
|
-
columns: array(string()).readonly().optional()
|
|
44685
|
-
}), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
|
|
44686
|
-
namespace: string().optional(),
|
|
44687
|
-
collection: string(),
|
|
44688
|
-
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
44689
|
-
* index on the collection. Never empty. */
|
|
44690
|
-
conflict: array(string()).readonly(),
|
|
44691
|
-
record: BulkRecordSchema
|
|
44692
|
-
}), object({
|
|
44693
|
-
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
44694
|
-
* row's own id on an update. */
|
|
44695
|
-
id: union([string(), number()]) }), {
|
|
44696
|
-
kind: "mutation",
|
|
44697
|
-
auth: "admin"
|
|
44698
|
-
}), method(object({
|
|
44699
|
-
namespace: string().optional(),
|
|
44700
|
-
collection: string(),
|
|
44701
|
-
conflict: array(string()).readonly(),
|
|
44702
|
-
records: array(BulkRecordSchema).readonly()
|
|
44703
|
-
}), object({ upserted: number().int() }), {
|
|
44704
|
-
kind: "mutation",
|
|
44705
|
-
auth: "admin"
|
|
44706
|
-
}), method(object({
|
|
44707
|
-
namespace: string().optional(),
|
|
44708
|
-
collection: string(),
|
|
44709
|
-
record: object({
|
|
44710
|
-
id: string().optional(),
|
|
44711
|
-
data: record(string(), unknown())
|
|
44712
|
-
})
|
|
44713
|
-
}), object({
|
|
44714
|
-
/**
|
|
44715
|
-
* The id the row ACTUALLY got (D473): the one supplied, the UUID minted
|
|
44716
|
-
* for an absent one, or the ROWID SQLite assigned on an `INTEGER`
|
|
44717
|
-
* primary key — which is the only place an auto key is knowable.
|
|
44718
|
-
*/
|
|
44719
|
-
id: union([string(), number()]) }), {
|
|
44720
|
-
kind: "mutation",
|
|
44721
|
-
auth: "admin"
|
|
44722
|
-
}), method(object({
|
|
44723
|
-
namespace: string().optional(),
|
|
44724
|
-
collection: string(),
|
|
44725
|
-
records: array(BulkRecordSchema).readonly()
|
|
44726
|
-
}), object({ inserted: number().int() }), {
|
|
44727
|
-
kind: "mutation",
|
|
44728
|
-
auth: "admin"
|
|
44729
|
-
}), method(object({
|
|
44730
|
-
namespace: string().optional(),
|
|
44731
|
-
guard: TransactGuardSchema.optional(),
|
|
44732
|
-
ops: array(TransactOpSchema).readonly()
|
|
44733
|
-
}), object({
|
|
44734
|
-
applied: boolean(),
|
|
44735
|
-
current: unknown().optional()
|
|
44736
|
-
}), {
|
|
44737
|
-
kind: "mutation",
|
|
44738
|
-
auth: "admin"
|
|
44739
|
-
}), method(object({
|
|
44740
|
-
namespace: string().optional(),
|
|
44741
|
-
collection: string(),
|
|
44742
|
-
id: string(),
|
|
44743
|
-
data: record(string(), unknown())
|
|
44744
|
-
}), _void(), {
|
|
44745
|
-
kind: "mutation",
|
|
44746
|
-
auth: "admin"
|
|
44747
|
-
}), method(object({
|
|
44748
|
-
namespace: string().optional(),
|
|
44749
|
-
collection: string(),
|
|
44750
|
-
key: string()
|
|
44751
|
-
}), _void(), {
|
|
44752
|
-
kind: "mutation",
|
|
44753
|
-
auth: "admin"
|
|
44754
|
-
}), method(object({
|
|
44755
|
-
namespace: string().optional(),
|
|
44756
|
-
collection: string(),
|
|
44757
|
-
filter: MutationFilterSchema
|
|
44758
|
-
}), object({ deleted: number().int() }), {
|
|
44759
|
-
kind: "mutation",
|
|
44760
|
-
auth: "admin"
|
|
44761
|
-
}), method(object({
|
|
44762
|
-
namespace: string().optional(),
|
|
44763
|
-
collection: string(),
|
|
44764
|
-
filter: MutationFilterSchema,
|
|
44765
|
-
data: record(string(), unknown())
|
|
44766
|
-
}), object({ updated: number().int() }), {
|
|
44767
|
-
kind: "mutation",
|
|
44768
|
-
auth: "admin"
|
|
44769
|
-
}), method(object({
|
|
44770
|
-
namespace: string().optional(),
|
|
44771
|
-
collection: string(),
|
|
44772
|
-
filter: QueryFilterSchema.optional()
|
|
44773
|
-
}), number(), { auth: "admin" }), method(object({
|
|
44774
|
-
namespace: string().optional(),
|
|
44775
|
-
collection: string(),
|
|
44776
|
-
fields: array(AggregateFieldSchema).readonly(),
|
|
44777
|
-
filter: QueryFilterSchema.optional()
|
|
44778
|
-
}), AggregateResultSchema, { auth: "admin" }), method(object({
|
|
44779
|
-
namespace: string().optional(),
|
|
44780
|
-
collection: string(),
|
|
44781
|
-
field: string(),
|
|
44782
|
-
bucketSize: number().int().positive(),
|
|
44783
|
-
origin: number().int(),
|
|
44784
|
-
filter: QueryFilterSchema.optional()
|
|
44785
|
-
}), array(object({
|
|
44786
|
-
bucket: number().int(),
|
|
44787
|
-
count: number().int()
|
|
44788
|
-
})).readonly(), { auth: "admin" }), method(object({
|
|
44789
|
-
namespace: string().optional(),
|
|
44790
|
-
collection: string()
|
|
44791
|
-
}), boolean(), { auth: "admin" }), method(DeclareCollectionInputSchema, _void(), {
|
|
44792
|
-
kind: "mutation",
|
|
44793
|
-
auth: "admin"
|
|
44794
|
-
});
|
|
44795
|
-
/**
|
|
44796
45356
|
* How long one snapshot may take end to end: the pinned copy of the whole
|
|
44797
45357
|
* database plus `PRAGMA integrity_check` over the copy, on the hub's slowest
|
|
44798
45358
|
* disk. ~800 MB at a pessimistic 10 MB/s is under 3 minutes; the bound is
|
|
@@ -46710,7 +47270,7 @@ method(object({
|
|
|
46710
47270
|
kind: "mutation",
|
|
46711
47271
|
auth: "admin"
|
|
46712
47272
|
}), method(object({ blockIds: array(string()) }), object({ states: array(CompositionBlockStateSchema) }), { auth: "admin" });
|
|
46713
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Lock, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
47273
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Lock, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.PetFountain, DeviceType.Fan, DeviceType.Humidifier, DeviceType.Climate, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
46714
47274
|
var NUMBER = {
|
|
46715
47275
|
kind: "fixed",
|
|
46716
47276
|
result: ["number"]
|
|
@@ -47728,6 +48288,57 @@ id: union([string(), number()]) }), {
|
|
|
47728
48288
|
kind: "mutation",
|
|
47729
48289
|
auth: "admin"
|
|
47730
48290
|
});
|
|
48291
|
+
method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { auth: "admin" }), method(object({ owner: string().optional() }), object({ pending: array(MigrationPendingEntrySchema) }), { auth: "admin" }), method(object({ id: string().min(1) }), MigrationDryRunResultSchema, { auth: "admin" }), method(object({
|
|
48292
|
+
id: string().min(1),
|
|
48293
|
+
error: string().min(1)
|
|
48294
|
+
}), MigrationLedgerEntrySchema, {
|
|
48295
|
+
kind: "mutation",
|
|
48296
|
+
auth: "admin"
|
|
48297
|
+
}), method(object({ id: string().min(1) }), object({ entries: array(MigrationLedgerEntrySchema) }), {
|
|
48298
|
+
kind: "mutation",
|
|
48299
|
+
auth: "admin"
|
|
48300
|
+
}), method(object({
|
|
48301
|
+
database: DataStoreDatabaseSchema,
|
|
48302
|
+
snapshotId: string().min(1)
|
|
48303
|
+
}), object({
|
|
48304
|
+
scheduled: boolean(),
|
|
48305
|
+
held: array(string()),
|
|
48306
|
+
restartRequired: boolean()
|
|
48307
|
+
}), {
|
|
48308
|
+
kind: "mutation",
|
|
48309
|
+
auth: "admin"
|
|
48310
|
+
}), method(object({
|
|
48311
|
+
owner: string().min(1),
|
|
48312
|
+
metas: array(MigrationMetaSchema)
|
|
48313
|
+
}), object({
|
|
48314
|
+
bootId: string(),
|
|
48315
|
+
snapshot: _enum([
|
|
48316
|
+
"none",
|
|
48317
|
+
"written",
|
|
48318
|
+
"refused"
|
|
48319
|
+
]),
|
|
48320
|
+
steps: array(MigrationOwnerStepSchema)
|
|
48321
|
+
}), {
|
|
48322
|
+
kind: "mutation",
|
|
48323
|
+
auth: "admin"
|
|
48324
|
+
}), method(object({ id: string().min(1) }), object({
|
|
48325
|
+
proceed: boolean(),
|
|
48326
|
+
state: union([literal("pending"), MigrationStatusSchema]),
|
|
48327
|
+
reason: string().nullable()
|
|
48328
|
+
}), {
|
|
48329
|
+
kind: "mutation",
|
|
48330
|
+
auth: "admin"
|
|
48331
|
+
}), method(object({
|
|
48332
|
+
id: string().min(1),
|
|
48333
|
+
result: MigrationOwnerResultSchema
|
|
48334
|
+
}), object({
|
|
48335
|
+
status: MigrationStatusSchema,
|
|
48336
|
+
error: string().nullable(),
|
|
48337
|
+
rowsChanged: number().int().nonnegative()
|
|
48338
|
+
}), {
|
|
48339
|
+
kind: "mutation",
|
|
48340
|
+
auth: "admin"
|
|
48341
|
+
});
|
|
47731
48342
|
/**
|
|
47732
48343
|
* records - an addon's own facts and documents (D881): ledgers, audit rows,
|
|
47733
48344
|
* config documents, mirrors. The third storage API next to `ctx.settings`
|
|
@@ -64394,7 +65005,18 @@ var ServerUpdateActionResultSchema = object({
|
|
|
64394
65005
|
* store (D877), present when the pre-flight refused the update
|
|
64395
65006
|
* (`reason: 'addon-would-refuse'`). Optional for version skew.
|
|
64396
65007
|
*/
|
|
64397
|
-
blockers: array(UpdateBlockerSchema).optional()
|
|
65008
|
+
blockers: array(UpdateBlockerSchema).optional(),
|
|
65009
|
+
/**
|
|
65010
|
+
* The minimums the target server declares and this node does not meet
|
|
65011
|
+
* (D989), present when the update was refused with
|
|
65012
|
+
* `reason: 'requirements-unmet'`. Each names the versions on both sides.
|
|
65013
|
+
*/
|
|
65014
|
+
unmet: array(UnmetRequirementSchema).optional(),
|
|
65015
|
+
/**
|
|
65016
|
+
* The addons this node has below the minimum the staged server declares —
|
|
65017
|
+
* the ones to update WITH the server. Present on an accepted update.
|
|
65018
|
+
*/
|
|
65019
|
+
requiredAddonUpdates: array(RequiredAddonUpdateSchema).optional()
|
|
64398
65020
|
});
|
|
64399
65021
|
var LaunchOverridesSchema = object({
|
|
64400
65022
|
/** The persisted heap ceiling in MB, or `null` when none is set. */
|
|
@@ -66972,7 +67594,9 @@ var PackageUpdateSchema = object({
|
|
|
66972
67594
|
latestVersion: string(),
|
|
66973
67595
|
category: _enum(["addon", "core"]),
|
|
66974
67596
|
requiresRestart: boolean(),
|
|
66975
|
-
isSystem: boolean()
|
|
67597
|
+
isSystem: boolean(),
|
|
67598
|
+
/** Held: what the newer version needs and this node does not meet (D989). */
|
|
67599
|
+
blockedBy: array(UnmetRequirementSchema).readonly().optional()
|
|
66976
67600
|
});
|
|
66977
67601
|
var PackageVersionInfoSchema = object({
|
|
66978
67602
|
version: string(),
|
|
@@ -68428,19 +69052,19 @@ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status:
|
|
|
68428
69052
|
reason: _enum(["unknown-template", "not-a-media-player"]),
|
|
68429
69053
|
detail: string()
|
|
68430
69054
|
})]);
|
|
68431
|
-
var deviceInput = object({ deviceId: number().int().nonnegative() });
|
|
69055
|
+
var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
|
|
68432
69056
|
DeviceType.MediaPlayer;
|
|
68433
|
-
method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
|
|
69057
|
+
method(deviceInput$1, RemoteConfigSchema, { auth: "admin" }), method(deviceInput$1.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
|
|
68434
69058
|
kind: "mutation",
|
|
68435
69059
|
auth: "admin"
|
|
68436
|
-
}), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
|
|
69060
|
+
}), method(deviceInput$1, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput$1.extend({
|
|
68437
69061
|
role: RemoteRoleSchema,
|
|
68438
69062
|
/** Sends in a row (volume steps). */
|
|
68439
69063
|
repeat: number().int().min(1).max(50).default(1)
|
|
68440
69064
|
}), RemoteSendResultSchema, {
|
|
68441
69065
|
kind: "mutation",
|
|
68442
69066
|
auth: "protected"
|
|
68443
|
-
}), method(deviceInput.extend({
|
|
69067
|
+
}), method(deviceInput$1.extend({
|
|
68444
69068
|
command: RemoteMediaCommandSchema,
|
|
68445
69069
|
muted: boolean().optional(),
|
|
68446
69070
|
source: string().optional(),
|
|
@@ -72358,7 +72982,7 @@ var lawnMowerControlCapability = {
|
|
|
72358
72982
|
* clients — they reverse-connect to the hub. Exposing their interfaces
|
|
72359
72983
|
* via the same surface would leak internal topology with no upside.
|
|
72360
72984
|
*
|
|
72361
|
-
* Implementation in `@camstack/system/builtins/local-network/`.
|
|
72985
|
+
* Implementation in `@camstack/server/system/builtins/local-network/`.
|
|
72362
72986
|
*/
|
|
72363
72987
|
/** Coarse classification derived from the interface name + IP range. */
|
|
72364
72988
|
var InterfaceKindEnum = _enum([
|
|
@@ -72885,6 +73509,117 @@ var lockControlCapability = {
|
|
|
72885
73509
|
* whether persisting is worth a SQLite commit. */
|
|
72886
73510
|
volatileStateFields: ["lastChangedAt"]
|
|
72887
73511
|
};
|
|
73512
|
+
var PowerSourceRefusalReasonSchema = _enum([
|
|
73513
|
+
"no-power-source",
|
|
73514
|
+
"switch-missing",
|
|
73515
|
+
"switch-offline",
|
|
73516
|
+
"switch-unknown",
|
|
73517
|
+
"restart-in-progress",
|
|
73518
|
+
"switch-call-failed"
|
|
73519
|
+
]);
|
|
73520
|
+
var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
|
|
73521
|
+
accepted: literal(false),
|
|
73522
|
+
reason: PowerSourceRefusalReasonSchema,
|
|
73523
|
+
/** One line for the operator, naming the switch. */
|
|
73524
|
+
message: string()
|
|
73525
|
+
})]);
|
|
73526
|
+
var PowerSourceInfoSchema = object({
|
|
73527
|
+
/** False when the device has no power source linked; the rest is then empty. */
|
|
73528
|
+
linked: boolean(),
|
|
73529
|
+
switchDeviceId: number().nullable(),
|
|
73530
|
+
switchName: string().nullable(),
|
|
73531
|
+
/** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
|
|
73532
|
+
switchOn: boolean().nullable(),
|
|
73533
|
+
switchOnline: boolean().nullable(),
|
|
73534
|
+
restartInProgress: boolean(),
|
|
73535
|
+
offSeconds: number().int()
|
|
73536
|
+
});
|
|
73537
|
+
/** The composed slice: the switch state the link mirrors, plus the stored off time. */
|
|
73538
|
+
var PowerSourceStateSchema = object({
|
|
73539
|
+
/** Null while the switch has not reported: unknown is never `false` (D393). */
|
|
73540
|
+
switchOn: boolean().nullable(),
|
|
73541
|
+
offSeconds: number().int(),
|
|
73542
|
+
lastFetchedAt: number()
|
|
73543
|
+
});
|
|
73544
|
+
var POWER_SOURCE_DEVICE_TYPES = [
|
|
73545
|
+
DeviceType.Gateway,
|
|
73546
|
+
DeviceType.Hub,
|
|
73547
|
+
DeviceType.Camera,
|
|
73548
|
+
DeviceType.Sensor,
|
|
73549
|
+
DeviceType.MediaPlayer,
|
|
73550
|
+
DeviceType.Vacuum,
|
|
73551
|
+
DeviceType.Generic,
|
|
73552
|
+
DeviceType.Washer,
|
|
73553
|
+
DeviceType.Dryer,
|
|
73554
|
+
DeviceType.Dishwasher,
|
|
73555
|
+
DeviceType.PetFountain,
|
|
73556
|
+
DeviceType.Fan,
|
|
73557
|
+
DeviceType.Humidifier,
|
|
73558
|
+
DeviceType.Climate,
|
|
73559
|
+
DeviceType.WaterHeater
|
|
73560
|
+
];
|
|
73561
|
+
var powerSourceCustomize = {
|
|
73562
|
+
version: 1,
|
|
73563
|
+
targets: [{
|
|
73564
|
+
id: "switch",
|
|
73565
|
+
cardinality: "scalar",
|
|
73566
|
+
vocabulary: {
|
|
73567
|
+
cap: "power-source",
|
|
73568
|
+
stateField: "switchOn"
|
|
73569
|
+
},
|
|
73570
|
+
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
73571
|
+
apply: "add",
|
|
73572
|
+
path: "switchOn",
|
|
73573
|
+
sources: [{
|
|
73574
|
+
kind: "switch",
|
|
73575
|
+
transforms: [{ kind: "identity" }]
|
|
73576
|
+
}],
|
|
73577
|
+
companions: [{
|
|
73578
|
+
kind: "constant",
|
|
73579
|
+
path: "offSeconds",
|
|
73580
|
+
value: 10,
|
|
73581
|
+
when: "add"
|
|
73582
|
+
}, {
|
|
73583
|
+
kind: "clock",
|
|
73584
|
+
path: "lastFetchedAt",
|
|
73585
|
+
when: "always"
|
|
73586
|
+
}],
|
|
73587
|
+
sourceReport: { status: "assignment-status" }
|
|
73588
|
+
}]
|
|
73589
|
+
};
|
|
73590
|
+
var deviceInput = object({ deviceId: number().int().nonnegative() });
|
|
73591
|
+
var powerSourceCapability = {
|
|
73592
|
+
name: "power-source",
|
|
73593
|
+
scope: "device",
|
|
73594
|
+
mode: "singleton",
|
|
73595
|
+
deviceTypes: POWER_SOURCE_DEVICE_TYPES,
|
|
73596
|
+
methods: {
|
|
73597
|
+
getStatus: systemMethod(deviceInput, PowerSourceInfoSchema, { auth: "admin" }),
|
|
73598
|
+
powerOn: systemMethod(deviceInput, PowerSourceActionResultSchema, {
|
|
73599
|
+
kind: "mutation",
|
|
73600
|
+
auth: "admin"
|
|
73601
|
+
}),
|
|
73602
|
+
powerOff: systemMethod(deviceInput, PowerSourceActionResultSchema, {
|
|
73603
|
+
kind: "mutation",
|
|
73604
|
+
auth: "admin"
|
|
73605
|
+
}),
|
|
73606
|
+
forceRestart: systemMethod(deviceInput, PowerSourceActionResultSchema, {
|
|
73607
|
+
kind: "mutation",
|
|
73608
|
+
auth: "admin"
|
|
73609
|
+
})
|
|
73610
|
+
},
|
|
73611
|
+
runtimeState: PowerSourceStateSchema,
|
|
73612
|
+
customize: powerSourceCustomize,
|
|
73613
|
+
/**
|
|
73614
|
+
* Runtime-state durability: **session** — mirrored from the linked switch on
|
|
73615
|
+
* its next report; a restored value would outlive the reading it names.
|
|
73616
|
+
*
|
|
73617
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
73618
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
73619
|
+
*/
|
|
73620
|
+
durability: "session",
|
|
73621
|
+
history: "none"
|
|
73622
|
+
};
|
|
72888
73623
|
/**
|
|
72889
73624
|
* A monotonic total between resets (D944). Energy uses `power-meter.energy`
|
|
72890
73625
|
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
@@ -74190,7 +74925,7 @@ onStatusChanged: { data: object({
|
|
|
74190
74925
|
* jitter, and observed/peak bandwidth per device + per client.
|
|
74191
74926
|
*
|
|
74192
74927
|
* Implementation lives in the server's `NetworkQualityService` (thin
|
|
74193
|
-
* wrapper over the shared `NetworkQualityTracker` from `@camstack/system`).
|
|
74928
|
+
* wrapper over the shared `NetworkQualityTracker` from `@camstack/server/system`).
|
|
74194
74929
|
* The provider is registered from `trpc.router.ts` against the existing
|
|
74195
74930
|
* service instance — no addon owns this state.
|
|
74196
74931
|
*
|
|
@@ -76376,7 +77111,7 @@ var ptzAutotrackCapability = {
|
|
|
76376
77111
|
* - **Native**: the camera's own firmware autotrack, registered per device by
|
|
76377
77112
|
* the driver when the probe says it exists (Reolink: yes; Hikvision:
|
|
76378
77113
|
* model-dependent).
|
|
76379
|
-
* - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
|
|
77114
|
+
* - **Wrapper**: the emulated implementation (`@camstack/server/system`'s `autotrack` builtin),
|
|
76380
77115
|
* which follows a subject with `ptz.move` pulses driven by the detection
|
|
76381
77116
|
* pipeline. `defaultActive: false` — the operator binds it per camera in
|
|
76382
77117
|
* the bindings UI.
|
|
@@ -81788,6 +82523,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
81788
82523
|
petFeeder: petFeederCapability,
|
|
81789
82524
|
petFountain: petFountainCapability,
|
|
81790
82525
|
powerMeter: powerMeterCapability,
|
|
82526
|
+
powerSource: powerSourceCapability,
|
|
81791
82527
|
presence: presenceCapability,
|
|
81792
82528
|
pressureSensor: pressureSensorCapability,
|
|
81793
82529
|
privacyMask: privacyMaskCapability,
|
|
@@ -82963,6 +83699,13 @@ Object.freeze({
|
|
|
82963
83699
|
access: "view",
|
|
82964
83700
|
role: "admin"
|
|
82965
83701
|
},
|
|
83702
|
+
"addonSettings.getIntegrationFormSchema": {
|
|
83703
|
+
capName: "addon-settings",
|
|
83704
|
+
capScope: "system",
|
|
83705
|
+
addonId: null,
|
|
83706
|
+
access: "view",
|
|
83707
|
+
role: "admin"
|
|
83708
|
+
},
|
|
82966
83709
|
"addonSettings.getIntegrationSettings": {
|
|
82967
83710
|
capName: "addon-settings",
|
|
82968
83711
|
capScope: "system",
|
|
@@ -87051,6 +87794,69 @@ Object.freeze({
|
|
|
87051
87794
|
access: "view",
|
|
87052
87795
|
role: "admin"
|
|
87053
87796
|
},
|
|
87797
|
+
"migrations.declareOwner": {
|
|
87798
|
+
capName: "migrations",
|
|
87799
|
+
capScope: "system",
|
|
87800
|
+
addonId: null,
|
|
87801
|
+
access: "create",
|
|
87802
|
+
role: "admin"
|
|
87803
|
+
},
|
|
87804
|
+
"migrations.dryRun": {
|
|
87805
|
+
capName: "migrations",
|
|
87806
|
+
capScope: "system",
|
|
87807
|
+
addonId: null,
|
|
87808
|
+
access: "view",
|
|
87809
|
+
role: "admin"
|
|
87810
|
+
},
|
|
87811
|
+
"migrations.finishMigration": {
|
|
87812
|
+
capName: "migrations",
|
|
87813
|
+
capScope: "system",
|
|
87814
|
+
addonId: null,
|
|
87815
|
+
access: "create",
|
|
87816
|
+
role: "admin"
|
|
87817
|
+
},
|
|
87818
|
+
"migrations.listLedger": {
|
|
87819
|
+
capName: "migrations",
|
|
87820
|
+
capScope: "system",
|
|
87821
|
+
addonId: null,
|
|
87822
|
+
access: "view",
|
|
87823
|
+
role: "admin"
|
|
87824
|
+
},
|
|
87825
|
+
"migrations.listPending": {
|
|
87826
|
+
capName: "migrations",
|
|
87827
|
+
capScope: "system",
|
|
87828
|
+
addonId: null,
|
|
87829
|
+
access: "view",
|
|
87830
|
+
role: "admin"
|
|
87831
|
+
},
|
|
87832
|
+
"migrations.markFailed": {
|
|
87833
|
+
capName: "migrations",
|
|
87834
|
+
capScope: "system",
|
|
87835
|
+
addonId: null,
|
|
87836
|
+
access: "create",
|
|
87837
|
+
role: "admin"
|
|
87838
|
+
},
|
|
87839
|
+
"migrations.restorePreMigration": {
|
|
87840
|
+
capName: "migrations",
|
|
87841
|
+
capScope: "system",
|
|
87842
|
+
addonId: null,
|
|
87843
|
+
access: "create",
|
|
87844
|
+
role: "admin"
|
|
87845
|
+
},
|
|
87846
|
+
"migrations.retry": {
|
|
87847
|
+
capName: "migrations",
|
|
87848
|
+
capScope: "system",
|
|
87849
|
+
addonId: null,
|
|
87850
|
+
access: "create",
|
|
87851
|
+
role: "admin"
|
|
87852
|
+
},
|
|
87853
|
+
"migrations.startMigration": {
|
|
87854
|
+
capName: "migrations",
|
|
87855
|
+
capScope: "system",
|
|
87856
|
+
addonId: null,
|
|
87857
|
+
access: "create",
|
|
87858
|
+
role: "admin"
|
|
87859
|
+
},
|
|
87054
87860
|
"modelConvert.convert": {
|
|
87055
87861
|
capName: "model-convert",
|
|
87056
87862
|
capScope: "system",
|
|
@@ -89683,6 +90489,34 @@ Object.freeze({
|
|
|
89683
90489
|
access: "view",
|
|
89684
90490
|
role: "viewer"
|
|
89685
90491
|
},
|
|
90492
|
+
"powerSource.forceRestart": {
|
|
90493
|
+
capName: "power-source",
|
|
90494
|
+
capScope: "device",
|
|
90495
|
+
addonId: null,
|
|
90496
|
+
access: "create",
|
|
90497
|
+
role: "admin"
|
|
90498
|
+
},
|
|
90499
|
+
"powerSource.getStatus": {
|
|
90500
|
+
capName: "power-source",
|
|
90501
|
+
capScope: "device",
|
|
90502
|
+
addonId: null,
|
|
90503
|
+
access: "view",
|
|
90504
|
+
role: "admin"
|
|
90505
|
+
},
|
|
90506
|
+
"powerSource.powerOff": {
|
|
90507
|
+
capName: "power-source",
|
|
90508
|
+
capScope: "device",
|
|
90509
|
+
addonId: null,
|
|
90510
|
+
access: "create",
|
|
90511
|
+
role: "admin"
|
|
90512
|
+
},
|
|
90513
|
+
"powerSource.powerOn": {
|
|
90514
|
+
capName: "power-source",
|
|
90515
|
+
capScope: "device",
|
|
90516
|
+
addonId: null,
|
|
90517
|
+
access: "create",
|
|
90518
|
+
role: "admin"
|
|
90519
|
+
},
|
|
89686
90520
|
"presence.getStatus": {
|
|
89687
90521
|
capName: "presence",
|
|
89688
90522
|
capScope: "device",
|
|
@@ -94831,6 +95665,26 @@ Object.freeze({
|
|
|
94831
95665
|
form: "single",
|
|
94832
95666
|
optional: false
|
|
94833
95667
|
}],
|
|
95668
|
+
"powerSource.forceRestart": [{
|
|
95669
|
+
name: "deviceId",
|
|
95670
|
+
form: "single",
|
|
95671
|
+
optional: false
|
|
95672
|
+
}],
|
|
95673
|
+
"powerSource.getStatus": [{
|
|
95674
|
+
name: "deviceId",
|
|
95675
|
+
form: "single",
|
|
95676
|
+
optional: false
|
|
95677
|
+
}],
|
|
95678
|
+
"powerSource.powerOff": [{
|
|
95679
|
+
name: "deviceId",
|
|
95680
|
+
form: "single",
|
|
95681
|
+
optional: false
|
|
95682
|
+
}],
|
|
95683
|
+
"powerSource.powerOn": [{
|
|
95684
|
+
name: "deviceId",
|
|
95685
|
+
form: "single",
|
|
95686
|
+
optional: false
|
|
95687
|
+
}],
|
|
94834
95688
|
"presence.getStatus": [{
|
|
94835
95689
|
name: "deviceId",
|
|
94836
95690
|
form: "single",
|
|
@@ -100864,4 +101718,4 @@ function buildClipModelRegistry(entries) {
|
|
|
100864
101718
|
/** The built-in catalog's registry. */
|
|
100865
101719
|
var BUILTIN_CLIP_MODELS = buildClipModelRegistry(CLIP_IMAGE_MODELS);
|
|
100866
101720
|
//#endregion
|
|
100867
|
-
export { MAX_TRACK_RELATIONS as $, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as $i, bundledCamstack as $n, normalizeNcAction as $r, NcTemplateVarDescriptorSchema as $t, DETECTION_MACRO_CLASSES as A,
|
|
101721
|
+
export { MAX_TRACK_RELATIONS as $, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as $i, bundledCamstack as $n, normalizeNcAction as $r, NcTemplateVarDescriptorSchema as $t, DETECTION_MACRO_CLASSES as A, string as Aa, sceneMonitorCapability as Ai, TrackPuritySchema as An, isAlertEpisodeOpen as Ar, NcAlarmConfigSchema as At, EXPORT_DENSE_MAX_RANGES as B, sunTimes as Bi, alertEpisodeKind as Bn, isLabelSupplyStepId as Br, NcRuleSchema as Bt, COCO_TO_MACRO as C, literal as Ca, retrainRevisionConflictMessage as Ci, SetTrackRelationInputSchema as Cn, eventKindLabel as Cr, NC_GROUPING_MIN_SEC as Ct, DEFAULT_DETAIL_CROP_CONVENTION as D, partialRecord as Da, ruleDeviceCompatCapQueries as Di, TimelapseRulePatchSchema as Dn, gifDeriveSpeed as Dr, NC_SYSTEM_EVENT_KIND_GROUP_SPECS as Dt, CoverStateSchema as E, object as Ea, ruleBelongsToAlarm as Ei, TimelapseRuleInputSchema as En, failureContributionCapability as Er, NC_STATE_SUMMARY_SECTION_IDS as Et, EMBEDDING_REQUIREMENTS_FAILED as F, DeviceType as Fa, storageOccupancyCapability as Fi, activateAlarmProfile as Fn, isDetectionMacroClass as Fr, NcConditionDescriptorSchema as Ft, LabelAttributionSchema as G, systemEventSummaryScheduleOf as Gi, applySecureOnArmEdit as Gn, isSystemDelivery as Gr, NcSnoozeInputSchema as Gt, FULL_IMAGE_BBOX as H, systemEventDeliveryProblems as Hi, applyBlockingEdit as Hn, isRetiredClearKey as Hr, NcRuleUpdateInputSchema as Ht, EMBEDDING_REQUIREMENTS_UNAVAILABLE as I, errMsg as Ia, subKindsOf as Ii, addonWidgetsSourceCapability as In, isDrawableSubjectPath as Ir, NcConditionsSchema as It, LockStateSchema as J, templateVarsFor as Ji, audioMetricsCapability as Jn, kebabToCamel as Jr, NcStateSummarySectionIdSchema as Jt, ListTrackRelationsInputSchema as K, systemEventSummarySplitOf as Ki, armRemovalReconcile as Kn, isSystemEventSummaryRule as Kr, NcSnoozeSchema as Kt, EVENT_DENSITY_BATCH_MAX as L, EventCategory as La, subjectPathSampleFromBox as Li, alarmDeviceSecureOnArm as Ln, isEventKindLabelKey as Lr, NcRuleActionSchema as Lt, DeclaredDevices as M, tuple as Ma, sensorRaisedOf as Mi, TrackRelationSchema as Mn, isAppLinkBase as Mr, NcAlarmSensorsInputSchema as Mt, DetectionSourceSchema as N, union as Na, servedTemplateVars as Ni, TrackSideSchema as Nn, isAudioClassName as Nr, NcAlarmSensorsSchema as Nt, DEFAULT_EVENT_COLOR as O, record as Oa, ruleGroupingApplies as Oi, TimelapseRuleSchema as On, gifFromMp4Args as Or, NC_TAXONOMY as Ot, EMBEDDING_MODEL_FAILED as P, unknown as Pa, startMoverUnderClearance as Pi, TrackSourceSchema as Pn, isDefaultAlarmProfileId as Pr, NcAlarmSettingsPatchSchema as Pt, MAX_TRACK_PURITIES as Q, zoneAnalyticsCapability as Qi, buildViewerLink as Qn, ncMediaPolicyError as Qr, NcTemplatePreviewSchema as Qt, EVENT_KIND_BY_CAP as R, subjectPathSvgPoints as Ri, alarmPanelCapability as Rn, isEventOwnerType as Rr, NcRuleInputSchema as Rt, BucketAccumulator as S, discriminatedUnion as Sa, resolvePoolMemoryPolicy as Si, SetTrackPurityResultSchema as Sn, ensureAlarmProfiles as Sr, NC_GROUPING_MAX_SEC as St, ClearTrackRelationResultSchema as T, number as Ta, ruleAutoTriggersAlarm as Ti, TRACK_RELATIONS_DEFAULT_LIMIT as Tn, faceGalleryCapability as Tr, NC_SNOOZE_MAX_MINUTES as Tt, FailureCounters as U, systemEventFamilyProblems as Ui, applyModeDelaysEdits as Un, isRootSuppliableStepId as Ur, NcScheduleSchema as Ut, FIRST_LEVEL_MACRO_CLASSES as V, syncActiveAlarmProfileSettings as Vi, alertEpisodePayload as Vn, isMediaOwnerType as Vr, NcRuleTargetSchema as Vt, LABEL_SUPPLY_MACRO as W, systemEventFilterApplies as Wi, applyNonBlockingEdit as Wn, isScheduleActive as Wr, NcSharedSequenceSchema as Wt, MAX_BIRTH_DECISION_RECORDS as X, viewerLinkBaseOf as Xi, buildEventKindDescriptor as Xn, mayWriteToLocation as Xr, NcTaxonomySchema as Xt, MAX_ARCHIVED_DEBUG_NOTES as Y, vectorDimFromBase64 as Yi, audioModeOf as Yn, linkedStepOf as Yr, NcSystemEventKindSchema as Yt, MAX_BIRTH_LATENCY_PROXY_MS as Z, withSystemEventClasses as Zi, buildSubjectPath as Zn, memoizePinnedFfmpeg as Zr, NcTemplatePreviewInputSchema as Zt, AlarmArmModeSchema as _, sleep as _a, resolveDeliveryParams as _i, SCENE_DEFAULT_UNCOVERED_POLICY as _n, embeddingModelFailedError as _r, NC_CONFIRM_DEFAULT_TIMEOUT_MS as _t, CLIP_EMBEDDING_STEP_ID as a, CamProfileSchema as aa, paletteResultSchema as ai, RECORDING_SOURCE_CAMSTACK_ADDON as an, coreBlockIdFromAddonId as ar, NC_ALARM_DELAY_FIELDS as at, BaseDevice as b, array as ba, resolveModeNotifyPolicy as bi, SceneMonitorSchema as bn, embeddingRequirementsUnavailableError as br, NC_DEFAULT_SNOOZE_MINUTES as bt, readClusterModelPinStrict as c, RECORD_QUERY_MAX as ca, pickFaceRescoreIntervalMinutes as ci, RetrainOriginSchema as cn, deleteAlarmProfile as cr, NC_ALARM_SYSTEM_EVENT_KINDS as ct, APPEARANCE_BIN_COUNT as d, defineCustomActions as da, projectSubjectPath as di, SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX as dn, deriveRecordingMode as dr, NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT as dt, canonicalHash as ea, normalizeNcCapTarget as ei, OPS_LOG_DEFAULT_LIMIT as en, calendarEventLocalSpan as er, MOTION_CLOSE_AFTER_MS as et, APPEARANCE_BLOCKS as f, defineRecordKinds as fa, readDeviceStateFrom as fi, SCENE_CONFIRM_DEFAULT_TIMEOUT_MS as fn, describeSystemEventDeliveryProblem as fr, NC_CLIP_POST_ROLL_DEFAULT_SEC as ft, ActionTargetResolver as g, normalizeNodeId as ga, resolveClipSearchMinScore as gi, SCENE_DEFAULT_QUIET_SECONDS as gn, embeddingEncoderCapability as gr, NC_CONFIRM_DEFAULT_MAX_IMAGE_PX as gt, AUDIO_MACRO_LABELS as h, nodePin as ha, renameAlarmProfile as hi, SCENE_DEFAULT_OBSERVATION_SPACING_SEC as hn, deviceRemovalHookCapability as hr, NC_CONDITION_CATALOG as ht, CLIP_TEXT_MODELS as i, CAP_ADVANCE_FIELDS as ia, paintHex as ii, RECORDING_EXPORT_MAX_READ_BYTES as in, consumableLowPercentOf as ir, NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC as it, DETECTION_PIPELINE_CAP_NAME as j, templateLiteral as ja, secureActuationFor as ji, TrackRelationKindSchema as jn, isAlertEpisodeSeverity as jr, NcAlarmPostTriggeredActionSchema as jt, DEFAULT_TIMELAPSE_PREVIEW_TEXT as k, strictObject as ka, ruleKindOf as ki, TrackPlacementSchema as kn, isAlarmControllableCap as kr, NC_TEMPLATE_VARS as kt, resolveClusterModelPin as l, createEvent as la, pipelineAnalyticsCapability as li, RetrainStatusSchema as ln, deriveDetailCropRect as lr, NC_ALARM_TRIGGERED_MAX_SEC as lt, ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT as m, isDeviceScopedCap as ma, readTimelapseGeneratedAt as mi, SCENE_DEFAULT_CHECK_INTERVAL_SEC as mn, deviceAttentionKind as mr, NC_CLIP_RETENTION_MAX_SEC as mt, DEFAULT_CLIP_MODEL as n, isSourceCap as na, notificationRulesCapability as ni, PackageLlmVerdictSchema as nn, cloneAlarmSettings as nr, MotionTriggeredBySchema as nt, CLUSTER_MODEL_OWNER_ADDON_ID as o, InvalidRecordError as oa, parseAlertEpisodePayload as oi, RebuildObjectEmbeddingsRefusalSchema as on, cosineSimilarity as or, NC_ALARM_DELAY_MAX_SEC as ot, APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT as p, hydrateSchema as pa, readMotionTriggeredBy as pi, SCENE_DEFAULT_ANCHOR_THRESHOLD as pn, describeSystemEventFamilyProblem as pr, NC_CLIP_PRE_ROLL_DEFAULT_SEC as pt, ListTrackRelationsResultSchema as q, templateCarriesSummary as qi, assertTimelapseCadences as qn, isVectorIndexDimConflict as qr, NcSnoozeSuppressedSchema as qt, CLIP_IMAGE_MODELS as r, BaseAddon as ra, occupancyScope as ri, PoolMemoryWatchdog as rn, consumableFormOf as rr, NC_ALARM_DEFAULT_PROFILE_ID as rt, FACE_EMBEDDING_STEP_ID as s, RECORD_MAX_DATA_BYTES as sa, parseProcStatus as si, RetrainDismissedSchema as sn, createAlarmProfile as sr, NC_ALARM_NOTIFY_FIELDS as st, BUILTIN_CLIP_MODELS as t, evaluateSensorEdge as ta, normalizeNcMediaPolicy as ti, OpsLogEntrySchema as tn, classifyRetrainReview as tr, MediaFileKindEnum as tt, ACTION_TARGET_INVALIDATION_EVENTS as u, customAction as ua, plateGalleryCapability as ui, RetrainVerdictSubjectSchema as un, derivePostTriggeredAction as ur, NC_AUDIO_CONFIRM_HITS_DEFAULT as ut, ArchivedDebugNoteSchema as v, ZodObject as va, resolveLocationMode as vi, SCENE_DIVERGED as vn, embeddingRefusalOf as vr, NC_CONSUMABLE_LOW_PERCENT_DEFAULT as vt, ClearTrackRelationInputSchema as w, looseObject as wa, rootSupplyServes as wi, TIMELAPSE_DENSE_FLOOR_SEC as wn, evictionPolicyOfLocation as wr, NC_SENSOR_TRANSITION_KINDS as wt, BirthDecisionRecordSchema as x, boolean as xa, resolveNcMediaImage as xi, SetTrackPurityInputSchema as xn, encodeVectorBase64 as xr, NC_GROUPING_DEFAULT_SEC as xt, BIRTH_DECISION_DEFAULT_LIMIT as y, _enum as ya, resolveModeDelays as yi, SCENE_RESET_RECAPTURES as yn, embeddingRequirementsFailedError as yr, NC_CONSUMABLE_SYSTEM_EVENT_KINDS as yt, EVENT_OWNER_TYPES as z, summarizeReview as zi, alertEpisodeId as zn, isKnownTemplateVar as zr, NcRulePatchSchema as zt };
|