@camstack/addon-provider-homeassistant 1.2.643 → 1.2.644
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 +6 -0
- package/dist/addon.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/{ha-broker-source-DxSvfCed.mjs → ha-broker-source-DmHRCdW2.mjs} +1412 -803
- package/dist/{ha-broker-source-zbaephU5.js → ha-broker-source-tDtT7Zi-.js} +1411 -802
- package/dist/ha-export/ha-export.addon.js +2 -2
- package/dist/ha-export/ha-export.addon.mjs +2 -2
- package/package.json +4 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region ../types/dist/event-category-
|
|
1
|
+
//#region ../types/dist/event-category-CaURIwQA.mjs
|
|
2
2
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
3
3
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4
4
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -714,6 +714,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
714
714
|
EventCategory["NotificationRuleBroken"] = "notification.rule-broken";
|
|
715
715
|
/** The clear of {@link NotificationRuleBroken}: the rule loads and names nothing deleted. */
|
|
716
716
|
EventCategory["NotificationRuleRepaired"] = "notification.rule-repaired";
|
|
717
|
+
/** A migration failed or was blocked; the Alert Center re-reads the ledger. */
|
|
718
|
+
EventCategory["MigrationFailed"] = "migration.failed";
|
|
719
|
+
/** A migration applied or a failure cleared; the Alert Center re-reads the ledger. */
|
|
720
|
+
EventCategory["MigrationApplied"] = "migration.applied";
|
|
717
721
|
EventCategory["DeviceUpdated"] = "device.updated";
|
|
718
722
|
/**
|
|
719
723
|
* Transport-level connectivity. Emitted by the device driver when
|
|
@@ -776,6 +780,378 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
776
780
|
return EventCategory;
|
|
777
781
|
}({});
|
|
778
782
|
//#endregion
|
|
783
|
+
//#region ../types/dist/device-type-CEqjmUnR.mjs
|
|
784
|
+
/**
|
|
785
|
+
import { errMsg } from '@camstack/types'
|
|
786
|
+
* Extract a human-readable message from an unknown error value.
|
|
787
|
+
* Replaces the ubiquitous `errMsg(err)` pattern.
|
|
788
|
+
*/
|
|
789
|
+
function errMsg(err) {
|
|
790
|
+
if (err instanceof Error) return err.message;
|
|
791
|
+
if (typeof err === "string") return err;
|
|
792
|
+
return String(err);
|
|
793
|
+
}
|
|
794
|
+
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
795
|
+
DeviceType["Camera"] = "camera";
|
|
796
|
+
DeviceType["Hub"] = "hub";
|
|
797
|
+
DeviceType["Light"] = "light";
|
|
798
|
+
DeviceType["Siren"] = "siren";
|
|
799
|
+
DeviceType["Switch"] = "switch";
|
|
800
|
+
DeviceType["Sensor"] = "sensor";
|
|
801
|
+
DeviceType["Thermostat"] = "thermostat";
|
|
802
|
+
/** Air-conditioner / heat-pump climate device (HVAC) — shares the
|
|
803
|
+
* `climate-control` cap surface with `Thermostat` but renders a
|
|
804
|
+
* dedicated AC-appropriate control UI (mode chips, fan speed,
|
|
805
|
+
* independent vertical/horizontal swing). Sources: native Gree, and
|
|
806
|
+
* reusable by other AC integrations. */
|
|
807
|
+
DeviceType["Climate"] = "climate";
|
|
808
|
+
DeviceType["Button"] = "button";
|
|
809
|
+
/** Generic stateless event emitter — carries a device's EXACT declared
|
|
810
|
+
* event vocabulary verbatim (no normalization). Installed with the
|
|
811
|
+
* `event-emitter` cap. Sources: HA `event.*` entities (structured) and
|
|
812
|
+
* HA bus events (e.g. `zha_event`, generic). */
|
|
813
|
+
DeviceType["EventEmitter"] = "event-emitter";
|
|
814
|
+
/** Firmware/software update entity — current vs available version,
|
|
815
|
+
* updatable flag, update state, and an install action. Installed with
|
|
816
|
+
* the `update` cap. Sources: Homematic firmware-update channels (and
|
|
817
|
+
* reusable by other providers, e.g. HA `update.*` entities). */
|
|
818
|
+
DeviceType["Update"] = "update";
|
|
819
|
+
DeviceType["Generic"] = "generic";
|
|
820
|
+
/** Generic notification delivery target (HA `notify.<service>`, future
|
|
821
|
+
* Telegram / Discord / ntfy / SMTP, …). One device per delivery
|
|
822
|
+
* endpoint; the `notifier` cap defines the send surface. */
|
|
823
|
+
DeviceType["Notifier"] = "notifier";
|
|
824
|
+
/** Pre-recorded action sequence with optional parameters
|
|
825
|
+
* (HA `script.*`). Runnable via `script-runner` cap. */
|
|
826
|
+
DeviceType["Script"] = "script";
|
|
827
|
+
/** Automation rule (HA `automation.*`) — enable/disable + manual
|
|
828
|
+
* trigger surface exposed via `automation-control` cap. */
|
|
829
|
+
DeviceType["Automation"] = "automation";
|
|
830
|
+
/** Door / smart lock device (HA `lock.*`). `lock-control` cap. */
|
|
831
|
+
DeviceType["Lock"] = "lock";
|
|
832
|
+
/** Window covering, blinds, garage door, valve, etc. (HA `cover.*`,
|
|
833
|
+
* `valve.*`). `cover` cap with sub-roles for variant. */
|
|
834
|
+
DeviceType["Cover"] = "cover";
|
|
835
|
+
/** Pipe / water / gas valve with open/close/stop and optional
|
|
836
|
+
* position (HA `valve.*`). `valve` cap — a cover-sibling actuator
|
|
837
|
+
* modelled on the same open/closed lifecycle. */
|
|
838
|
+
DeviceType["Valve"] = "valve";
|
|
839
|
+
/** Humidifier / dehumidifier with on/off + target humidity + mode
|
|
840
|
+
* (HA `humidifier.*`). `humidifier` cap — a climate-family actuator
|
|
841
|
+
* modelled on the same target / mode lifecycle. */
|
|
842
|
+
DeviceType["Humidifier"] = "humidifier";
|
|
843
|
+
/** Water heater / boiler with target temperature + operation mode +
|
|
844
|
+
* away mode (HA `water_heater.*`). `water-heater` cap — a
|
|
845
|
+
* climate-family actuator. */
|
|
846
|
+
DeviceType["WaterHeater"] = "water-heater";
|
|
847
|
+
/** Ceiling / standing / exhaust fan (HA `fan.*`). `fan-control` cap. */
|
|
848
|
+
DeviceType["Fan"] = "fan";
|
|
849
|
+
/** Audio / video playback endpoint (HA `media_player.*`). Disjoint from
|
|
850
|
+
* the camera surface — those use `Camera`. `media-player` cap. */
|
|
851
|
+
DeviceType["MediaPlayer"] = "media-player";
|
|
852
|
+
/** Security panel / alarm system (HA `alarm_control_panel.*`).
|
|
853
|
+
* `alarm-panel` cap. */
|
|
854
|
+
DeviceType["AlarmPanel"] = "alarm-panel";
|
|
855
|
+
/** Generic user-settable input (HA `number` / `input_number` / `select`
|
|
856
|
+
* / `input_select` / `text` / `input_text` / `input_datetime`).
|
|
857
|
+
* Sub-type via `DeviceRole`: NumericControl / SelectControl /
|
|
858
|
+
* TextControl / DateTimeControl. */
|
|
859
|
+
DeviceType["Control"] = "control";
|
|
860
|
+
/** Person / device-tracker presence (HA `person.*`, `device_tracker.*`).
|
|
861
|
+
* `presence` cap. */
|
|
862
|
+
DeviceType["Presence"] = "presence";
|
|
863
|
+
/** Weather provider (HA `weather.*`). Tier-3, low MVP priority.
|
|
864
|
+
* `weather` cap. */
|
|
865
|
+
DeviceType["Weather"] = "weather";
|
|
866
|
+
/** Robot vacuum (HA `vacuum.*`). Tier-3. `vacuum-control` cap. */
|
|
867
|
+
DeviceType["Vacuum"] = "vacuum";
|
|
868
|
+
/** Robotic lawn mower (HA `lawn_mower.*`). Tier-3.
|
|
869
|
+
* `lawn-mower-control` cap. */
|
|
870
|
+
DeviceType["LawnMower"] = "lawn-mower";
|
|
871
|
+
/** Physical HA device group — parent container for entity-children
|
|
872
|
+
* adopted from a single HA device entry. Not renderable as a
|
|
873
|
+
* standalone device; exists only to anchor child entities. */
|
|
874
|
+
DeviceType["Container"] = "container";
|
|
875
|
+
/** Single still-image entity (HA `image.*`). Read-only display of an
|
|
876
|
+
* `entity_picture` signed URL the browser loads directly. `image` cap. */
|
|
877
|
+
DeviceType["Image"] = "image";
|
|
878
|
+
/** Smart pet feeder — cloud-connected food dispenser with a bowl food
|
|
879
|
+
* level, battery, desiccant life, feeding state and manual-feed /
|
|
880
|
+
* call-pet / maintenance actions. Installed with the `pet-feeder` cap;
|
|
881
|
+
* dual-hopper models (D4S/D4SH) expose per-hopper portions. Sources:
|
|
882
|
+
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
883
|
+
* integrations sharing the same food/desiccant/hopper surface. */
|
|
884
|
+
DeviceType["PetFeeder"] = "pet-feeder";
|
|
885
|
+
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
886
|
+
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
887
|
+
* of a container and is BUILT as a composed device (D967). */
|
|
888
|
+
DeviceType["PetFountain"] = "pet-fountain";
|
|
889
|
+
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
890
|
+
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
891
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
892
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
893
|
+
DeviceType["Dishwasher"] = "dishwasher";
|
|
894
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
895
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
896
|
+
DeviceType["Washer"] = "washer";
|
|
897
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
898
|
+
DeviceType["Dryer"] = "dryer";
|
|
899
|
+
/** The physical bridge box of a vendor ecosystem (Velux KLF-200, and later
|
|
900
|
+
* other radio-to-IP bridges). It carries the box's own facts (firmware,
|
|
901
|
+
* address, connection state) and the actions the box really supports
|
|
902
|
+
* (`reboot`, `device-admin-link`). Products are NOT its children — they are
|
|
903
|
+
* adopted beside it — and its connection settings stay on the integration. */
|
|
904
|
+
DeviceType["Gateway"] = "gateway";
|
|
905
|
+
return DeviceType;
|
|
906
|
+
}({});
|
|
907
|
+
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
908
|
+
DeviceFeature["BatteryOperated"] = "battery-operated";
|
|
909
|
+
DeviceFeature["Rebootable"] = "rebootable";
|
|
910
|
+
/**
|
|
911
|
+
* Device supports an on-demand re-sync of its derived spec with its
|
|
912
|
+
* upstream source — drives the generic Re-sync button. The owning
|
|
913
|
+
* provider implements the action via the `device-adoption.resync` cap.
|
|
914
|
+
*/
|
|
915
|
+
DeviceFeature["Resyncable"] = "resyncable";
|
|
916
|
+
DeviceFeature["NativeSnapshot"] = "native-snapshot";
|
|
917
|
+
DeviceFeature["DoorbellButton"] = "doorbell-button";
|
|
918
|
+
DeviceFeature["TwoWayAudio"] = "two-way-audio";
|
|
919
|
+
DeviceFeature["PanTiltZoom"] = "pan-tilt-zoom";
|
|
920
|
+
/**
|
|
921
|
+
* Camera supports the on-firmware autotrack subsystem (subject-
|
|
922
|
+
* following). Distinct from `PanTiltZoom` because not every PTZ
|
|
923
|
+
* camera ships autotrack — the admin UI uses this flag to gate
|
|
924
|
+
* the autotrack toggle / settings card without re-deriving from
|
|
925
|
+
* the cap registry. Mirrors `ptz-autotrack` cap registration:
|
|
926
|
+
* driver sets this feature when probe confirms the firmware
|
|
927
|
+
* surface, and registers the cap in the same code path.
|
|
928
|
+
*/
|
|
929
|
+
DeviceFeature["PtzAutotrack"] = "ptz-autotrack";
|
|
930
|
+
/**
|
|
931
|
+
* Accessory exposes a "trigger on motion" toggle — the parent camera's
|
|
932
|
+
* motion detection automatically activates this device. Mirrors
|
|
933
|
+
* `motion-trigger` cap registration: drivers set this feature in the
|
|
934
|
+
* same code path that calls `ctx.registerNativeCap(motionTriggerCapability, ...)`.
|
|
935
|
+
*
|
|
936
|
+
* Used by admin UI (gate the in-hero `MotionTriggerToggle` against a
|
|
937
|
+
* fast scalar without binding fetch), notifier rules, and `listAll`
|
|
938
|
+
* filters that want "all devices with on-motion behaviour".
|
|
939
|
+
*/
|
|
940
|
+
DeviceFeature["MotionTrigger"] = "motion-trigger";
|
|
941
|
+
/** Light supports rgb-triplet color via `color` cap. */
|
|
942
|
+
DeviceFeature["LightColorRgb"] = "light-color-rgb";
|
|
943
|
+
/** Light supports HSV color via `color` cap. */
|
|
944
|
+
DeviceFeature["LightColorHsv"] = "light-color-hsv";
|
|
945
|
+
/** Light supports color-temperature (mired) via `color` cap. */
|
|
946
|
+
DeviceFeature["LightColorMired"] = "light-color-mired";
|
|
947
|
+
/** Thermostat supports a `heat_cool` dual setpoint (targetLow +
|
|
948
|
+
* targetHigh). Gates the range slider UI. */
|
|
949
|
+
DeviceFeature["ClimateDualSetpoint"] = "climate-dual-setpoint";
|
|
950
|
+
/** Thermostat exposes target humidity and/or current humidity
|
|
951
|
+
* readings. Gates the humidity controls. */
|
|
952
|
+
DeviceFeature["ClimateHumidity"] = "climate-humidity";
|
|
953
|
+
/** Thermostat exposes a fan-mode selector. */
|
|
954
|
+
DeviceFeature["ClimateFanMode"] = "climate-fan-mode";
|
|
955
|
+
/** Thermostat exposes preset modes (eco / away / sleep / vendor). */
|
|
956
|
+
DeviceFeature["ClimatePreset"] = "climate-preset";
|
|
957
|
+
/** Thermostat exposes a vertical louver swing toggle. Gates the
|
|
958
|
+
* vertical-swing switch in the climate UI. Independent of horizontal. */
|
|
959
|
+
DeviceFeature["ClimateSwingVertical"] = "climate-swing-vertical";
|
|
960
|
+
/** Thermostat exposes a horizontal louver swing toggle. Gates the
|
|
961
|
+
* horizontal-swing switch in the climate UI. Independent of vertical. */
|
|
962
|
+
DeviceFeature["ClimateSwingHorizontal"] = "climate-swing-horizontal";
|
|
963
|
+
/** Cover exposes intermediate position control (0..100). Gates the
|
|
964
|
+
* position slider UI. */
|
|
965
|
+
DeviceFeature["CoverPositionable"] = "cover-positionable";
|
|
966
|
+
/** Cover exposes slat-tilt control. Gates the tilt slider UI. */
|
|
967
|
+
DeviceFeature["CoverTilt"] = "cover-tilt";
|
|
968
|
+
/** Valve exposes intermediate position control (0..100). Gates the
|
|
969
|
+
* position slider / drag surface UI. */
|
|
970
|
+
DeviceFeature["ValvePositionable"] = "valve-positionable";
|
|
971
|
+
/** Fan exposes a speed-percentage setter. Gates the speed slider UI. */
|
|
972
|
+
DeviceFeature["FanSpeed"] = "fan-speed";
|
|
973
|
+
/** Fan exposes a preset mode selector. */
|
|
974
|
+
DeviceFeature["FanPreset"] = "fan-preset";
|
|
975
|
+
/** Fan exposes blade direction (forward/reverse) — typical of
|
|
976
|
+
* ceiling fans. */
|
|
977
|
+
DeviceFeature["FanDirection"] = "fan-direction";
|
|
978
|
+
/** Fan exposes an oscillation toggle. */
|
|
979
|
+
DeviceFeature["FanOscillating"] = "fan-oscillating";
|
|
980
|
+
/** Lock requires a PIN code on lock/unlock. Gates the code-entry
|
|
981
|
+
* field on the UI lock-controls panel. */
|
|
982
|
+
DeviceFeature["LockPinRequired"] = "lock-pin-required";
|
|
983
|
+
/** Lock supports a latch-release ("open door") action distinct from
|
|
984
|
+
* unlock. Mirrors HA `LockEntityFeature.OPEN` (bit 1) in
|
|
985
|
+
* `supported_features`. Gates the Open Door button in the UI. */
|
|
986
|
+
DeviceFeature["LockOpen"] = "lock-open";
|
|
987
|
+
/** Media player exposes a seek-to-position surface. */
|
|
988
|
+
DeviceFeature["MediaPlayerSeek"] = "media-player-seek";
|
|
989
|
+
/** Media player exposes a volume-level setter. */
|
|
990
|
+
DeviceFeature["MediaPlayerVolume"] = "media-player-volume";
|
|
991
|
+
/** Media player exposes a mute toggle distinct from volume=0. */
|
|
992
|
+
DeviceFeature["MediaPlayerMute"] = "media-player-mute";
|
|
993
|
+
/** Media player exposes a shuffle toggle. */
|
|
994
|
+
DeviceFeature["MediaPlayerShuffle"] = "media-player-shuffle";
|
|
995
|
+
/** Media player exposes a repeat mode (off / all / one). */
|
|
996
|
+
DeviceFeature["MediaPlayerRepeat"] = "media-player-repeat";
|
|
997
|
+
/** Media player exposes a source / input selector. */
|
|
998
|
+
DeviceFeature["MediaPlayerSelectSource"] = "media-player-select-source";
|
|
999
|
+
/** Media player exposes a play-arbitrary-media surface (URL / id). */
|
|
1000
|
+
DeviceFeature["MediaPlayerPlayMedia"] = "media-player-play-media";
|
|
1001
|
+
/** Media player exposes next-track. */
|
|
1002
|
+
DeviceFeature["MediaPlayerNext"] = "media-player-next";
|
|
1003
|
+
/** Media player exposes previous-track. */
|
|
1004
|
+
DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
|
|
1005
|
+
/** Media player exposes stop distinct from pause. */
|
|
1006
|
+
DeviceFeature["MediaPlayerStop"] = "media-player-stop";
|
|
1007
|
+
/** Alarm panel requires a PIN code on arm/disarm. */
|
|
1008
|
+
DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
|
|
1009
|
+
/** Presence device carries GPS coordinates (lat/lng/accuracy) in
|
|
1010
|
+
* addition to a textual location. */
|
|
1011
|
+
DeviceFeature["PresenceGps"] = "presence-gps";
|
|
1012
|
+
/** Notifier accepts an inline / URL image attachment. */
|
|
1013
|
+
DeviceFeature["NotifierImage"] = "notifier-image";
|
|
1014
|
+
/** Notifier accepts a priority hint (high/normal/low). */
|
|
1015
|
+
DeviceFeature["NotifierPriority"] = "notifier-priority";
|
|
1016
|
+
/** Notifier accepts a free-form `data` payload for platform-specific
|
|
1017
|
+
* fields. */
|
|
1018
|
+
DeviceFeature["NotifierData"] = "notifier-data";
|
|
1019
|
+
/** Notifier supports interactive action buttons / callbacks. */
|
|
1020
|
+
DeviceFeature["NotifierActions"] = "notifier-actions";
|
|
1021
|
+
/** Notifier supports per-call recipient targeting (multi-user). */
|
|
1022
|
+
DeviceFeature["NotifierRecipients"] = "notifier-recipients";
|
|
1023
|
+
/** Script runner accepts a variables map on each run invocation. */
|
|
1024
|
+
DeviceFeature["ScriptVariables"] = "script-variables";
|
|
1025
|
+
/** Automation `trigger` accepts a skipCondition flag — fires the
|
|
1026
|
+
* automation's actions while bypassing its condition block. */
|
|
1027
|
+
DeviceFeature["AutomationSkipCondition"] = "automation-skip-condition";
|
|
1028
|
+
/** Robot vacuum exposes a live cleaning map (image child). Gates the
|
|
1029
|
+
* map tile in the vacuum UI. */
|
|
1030
|
+
DeviceFeature["VacuumHasMap"] = "vacuum-has-map";
|
|
1031
|
+
/** Robot vacuum exposes AI obstacle-detection toggles. Gates the AI
|
|
1032
|
+
* switches group. */
|
|
1033
|
+
DeviceFeature["VacuumHasAi"] = "vacuum-has-ai";
|
|
1034
|
+
/** Robot mower exposes a live mowing map (SVG image child). Gates the
|
|
1035
|
+
* mower map tile. */
|
|
1036
|
+
DeviceFeature["MowerHasMap"] = "mower-has-map";
|
|
1037
|
+
/** Robot mower exposes targeted mowing (all-area / zones / edges /
|
|
1038
|
+
* spots) — gates the Mow action + map selectors. */
|
|
1039
|
+
DeviceFeature["MowerHasTargetedMowing"] = "mower-has-targeted-mowing";
|
|
1040
|
+
return DeviceFeature;
|
|
1041
|
+
}({});
|
|
1042
|
+
/**
|
|
1043
|
+
* Semantic role a device plays within its parent. Populated by driver
|
|
1044
|
+
* addons when creating accessory devices (Reolink siren/floodlight/
|
|
1045
|
+
* PIR/chime/autotrack/doorbell, ONVIF relay outputs, …). Used by the
|
|
1046
|
+
* admin UI to pick icons, labels, and widgets — a `Switch` with
|
|
1047
|
+
* `role: Floodlight` renders as a bulb with a brightness slider,
|
|
1048
|
+
* whereas a `Switch` with `role: Siren` renders as a klaxon.
|
|
1049
|
+
*
|
|
1050
|
+
* Undefined for top-level devices (cameras, NVRs, hubs). Persisted in
|
|
1051
|
+
* sqlite as a nullable TEXT column — old rows keep working unchanged.
|
|
1052
|
+
*/
|
|
1053
|
+
var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
1054
|
+
DeviceRole["Siren"] = "siren";
|
|
1055
|
+
DeviceRole["Floodlight"] = "floodlight";
|
|
1056
|
+
DeviceRole["Spotlight"] = "spotlight";
|
|
1057
|
+
DeviceRole["PirSensor"] = "pir-sensor";
|
|
1058
|
+
DeviceRole["Chime"] = "chime";
|
|
1059
|
+
DeviceRole["Autotrack"] = "autotrack";
|
|
1060
|
+
DeviceRole["Nightvision"] = "nightvision";
|
|
1061
|
+
DeviceRole["PrivacyMask"] = "privacy-mask";
|
|
1062
|
+
DeviceRole["Doorbell"] = "doorbell";
|
|
1063
|
+
/** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
|
|
1064
|
+
DeviceRole["CoverBlind"] = "cover-blind";
|
|
1065
|
+
/** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
|
|
1066
|
+
DeviceRole["CoverShutter"] = "cover-shutter";
|
|
1067
|
+
/** Exterior awning. HA `device_class: awning`. */
|
|
1068
|
+
DeviceRole["CoverAwning"] = "cover-awning";
|
|
1069
|
+
/** Curtain / drape. HA `device_class: curtain`. */
|
|
1070
|
+
DeviceRole["CoverCurtain"] = "cover-curtain";
|
|
1071
|
+
/** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
|
|
1072
|
+
DeviceRole["CoverGarage"] = "cover-garage";
|
|
1073
|
+
/** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
|
|
1074
|
+
DeviceRole["CoverGate"] = "cover-gate";
|
|
1075
|
+
/** Door. HA `device_class: door`. A security actuator: exports gate it. */
|
|
1076
|
+
DeviceRole["CoverDoor"] = "cover-door";
|
|
1077
|
+
/** Window. HA `device_class: window`. */
|
|
1078
|
+
DeviceRole["CoverWindow"] = "cover-window";
|
|
1079
|
+
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
1080
|
+
* real Switch device for UI rendering / export adapters. */
|
|
1081
|
+
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
1082
|
+
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
1083
|
+
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
1084
|
+
DeviceRole["Outlet"] = "outlet";
|
|
1085
|
+
/** Generic motion / occupancy / moving event source. Distinct from
|
|
1086
|
+
* the camera accessory PirSensor role: that one is a camera child;
|
|
1087
|
+
* this is a standalone HA / 3rd-party motion sensor. */
|
|
1088
|
+
DeviceRole["MotionSensor"] = "motion-sensor";
|
|
1089
|
+
DeviceRole["ContactSensor"] = "contact-sensor";
|
|
1090
|
+
DeviceRole["LeakSensor"] = "leak-sensor";
|
|
1091
|
+
DeviceRole["SmokeSensor"] = "smoke-sensor";
|
|
1092
|
+
DeviceRole["COSensor"] = "co-sensor";
|
|
1093
|
+
DeviceRole["GasSensor"] = "gas-sensor";
|
|
1094
|
+
DeviceRole["TamperSensor"] = "tamper-sensor";
|
|
1095
|
+
DeviceRole["VibrationSensor"] = "vibration-sensor";
|
|
1096
|
+
DeviceRole["ConnectivitySensor"] = "connectivity-sensor";
|
|
1097
|
+
DeviceRole["SoundSensor"] = "sound-sensor";
|
|
1098
|
+
/** Fallback for `binary_sensor` without a known `device_class`. */
|
|
1099
|
+
DeviceRole["BinarySensor"] = "binary-sensor";
|
|
1100
|
+
DeviceRole["TemperatureSensor"] = "temperature-sensor";
|
|
1101
|
+
DeviceRole["HumiditySensor"] = "humidity-sensor";
|
|
1102
|
+
DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
|
|
1103
|
+
DeviceRole["PressureSensor"] = "pressure-sensor";
|
|
1104
|
+
/** Wind speed or direction (weather-station `wind-sensor` cap). */
|
|
1105
|
+
DeviceRole["WindSensor"] = "wind-sensor";
|
|
1106
|
+
/** Rain accumulation or rate (weather-station `rain-sensor` cap). */
|
|
1107
|
+
DeviceRole["RainSensor"] = "rain-sensor";
|
|
1108
|
+
/** UV index (weather-station `uv-sensor` cap). */
|
|
1109
|
+
DeviceRole["UvSensor"] = "uv-sensor";
|
|
1110
|
+
/** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
|
|
1111
|
+
* Distinct from AmbientLightSensor (lux). */
|
|
1112
|
+
DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
|
|
1113
|
+
/** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
|
|
1114
|
+
DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
|
|
1115
|
+
DeviceRole["PowerSensor"] = "power-sensor";
|
|
1116
|
+
DeviceRole["EnergySensor"] = "energy-sensor";
|
|
1117
|
+
DeviceRole["VoltageSensor"] = "voltage-sensor";
|
|
1118
|
+
DeviceRole["CurrentSensor"] = "current-sensor";
|
|
1119
|
+
DeviceRole["AirQualitySensor"] = "air-quality-sensor";
|
|
1120
|
+
/** Battery level (numeric % via `sensor` OR low-bool via
|
|
1121
|
+
* `binary_sensor` — the cap distinguishes via the value type). */
|
|
1122
|
+
DeviceRole["BatterySensor"] = "battery-sensor";
|
|
1123
|
+
/** Fallback for `sensor` numeric without a known `device_class`. */
|
|
1124
|
+
DeviceRole["NumericSensor"] = "numeric-sensor";
|
|
1125
|
+
/** String / enum state (HA `sensor` with `state_class: enum` or
|
|
1126
|
+
* `attributes.options`). */
|
|
1127
|
+
DeviceRole["EnumSensor"] = "enum-sensor";
|
|
1128
|
+
/** Date / timestamp state (HA `sensor` with `device_class: timestamp`
|
|
1129
|
+
* or `date`). The slice carries the raw ISO string verbatim (hosted on
|
|
1130
|
+
* the `enum-sensor` cap); the UI renders it locale-formatted. */
|
|
1131
|
+
DeviceRole["DateTimeSensor"] = "datetime-sensor";
|
|
1132
|
+
/** Last-resort fallback when nothing else matches. */
|
|
1133
|
+
DeviceRole["GenericSensor"] = "generic-sensor";
|
|
1134
|
+
DeviceRole["NumericControl"] = "numeric-control";
|
|
1135
|
+
DeviceRole["SelectControl"] = "select-control";
|
|
1136
|
+
DeviceRole["TextControl"] = "text-control";
|
|
1137
|
+
DeviceRole["DateTimeControl"] = "datetime-control";
|
|
1138
|
+
/** Mobile push notifier (HA `notify.mobile_app_*`) — supports
|
|
1139
|
+
* rich features (image, priority, channel routing). */
|
|
1140
|
+
DeviceRole["MobilePushNotifier"] = "mobile-push-notifier";
|
|
1141
|
+
/** Chat / messaging service (HA `notify.telegram_*`,
|
|
1142
|
+
* `notify.discord_*`, etc.). */
|
|
1143
|
+
DeviceRole["MessagingNotifier"] = "messaging-notifier";
|
|
1144
|
+
/** Email-based delivery (HA `notify.smtp`, etc.). */
|
|
1145
|
+
DeviceRole["EmailNotifier"] = "email-notifier";
|
|
1146
|
+
/** Fallback when the notifier service name doesn't match a known
|
|
1147
|
+
* pattern. */
|
|
1148
|
+
DeviceRole["GenericNotifier"] = "generic-notifier";
|
|
1149
|
+
/** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
|
|
1150
|
+
* cap. A `DeviceType.Generic` device. */
|
|
1151
|
+
DeviceRole["IrTransmitter"] = "ir-transmitter";
|
|
1152
|
+
return DeviceRole;
|
|
1153
|
+
}({});
|
|
1154
|
+
//#endregion
|
|
779
1155
|
//#region ../../node_modules/zod/v4/core/core.js
|
|
780
1156
|
var _a$1;
|
|
781
1157
|
function $constructor(name, initializer, params) {
|
|
@@ -5587,7 +5963,7 @@ var ZodIssueCode = {
|
|
|
5587
5963
|
var ZodFirstPartyTypeKind;
|
|
5588
5964
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5589
5965
|
//#endregion
|
|
5590
|
-
//#region ../types/dist/sleep-
|
|
5966
|
+
//#region ../types/dist/sleep-CSYuxssh.mjs
|
|
5591
5967
|
/**
|
|
5592
5968
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5593
5969
|
* window to float samples (D455).
|
|
@@ -6103,6 +6479,102 @@ function emitReadiness(bus, params) {
|
|
|
6103
6479
|
ts
|
|
6104
6480
|
}));
|
|
6105
6481
|
}
|
|
6482
|
+
var NOT_RUN = {
|
|
6483
|
+
declared: false,
|
|
6484
|
+
snapshot: null,
|
|
6485
|
+
applied: [],
|
|
6486
|
+
failed: [],
|
|
6487
|
+
blocked: [],
|
|
6488
|
+
skipped: [],
|
|
6489
|
+
blockOwner: []
|
|
6490
|
+
};
|
|
6491
|
+
/**
|
|
6492
|
+
* Offer `migrations` to the engine and run what it says to run, in its order. Never
|
|
6493
|
+
* throws: an unreachable or refusing engine is logged and reported `declared: false`,
|
|
6494
|
+
* because the hub (and this addon's boot) must not hang on a migration.
|
|
6495
|
+
*/
|
|
6496
|
+
async function runAddonMigrations(host, migrations, logger) {
|
|
6497
|
+
const first = migrations[0];
|
|
6498
|
+
if (first === void 0) return NOT_RUN;
|
|
6499
|
+
const owner = first.meta.owner;
|
|
6500
|
+
const log = logger.withTags({ migrationOwner: owner });
|
|
6501
|
+
const byId = new Map(migrations.map((m) => [m.meta.id, m]));
|
|
6502
|
+
let declaration;
|
|
6503
|
+
try {
|
|
6504
|
+
declaration = await host.declareOwner({
|
|
6505
|
+
owner,
|
|
6506
|
+
metas: migrations.map((m) => m.meta)
|
|
6507
|
+
});
|
|
6508
|
+
} catch (err) {
|
|
6509
|
+
log.error("the migration engine refused or could not take this addon catalogue — none ran", { meta: { error: errMsg(err) } });
|
|
6510
|
+
return {
|
|
6511
|
+
...NOT_RUN,
|
|
6512
|
+
blockOwner: migrations.filter((m) => m.meta.onFailure === "block-owner").map((m) => m.meta.id)
|
|
6513
|
+
};
|
|
6514
|
+
}
|
|
6515
|
+
const applied = [];
|
|
6516
|
+
const failed = [];
|
|
6517
|
+
const blocked = [];
|
|
6518
|
+
const skipped = [];
|
|
6519
|
+
const settle = (id, status) => {
|
|
6520
|
+
if (status === "applied") applied.push(id);
|
|
6521
|
+
else if (status === "failed") failed.push(id);
|
|
6522
|
+
else if (status === "blocked") blocked.push(id);
|
|
6523
|
+
else skipped.push(id);
|
|
6524
|
+
};
|
|
6525
|
+
for (const step of declaration.steps) {
|
|
6526
|
+
const bound = byId.get(step.id);
|
|
6527
|
+
if (bound === void 0 || step.action === "skip") {
|
|
6528
|
+
skipped.push(step.id);
|
|
6529
|
+
continue;
|
|
6530
|
+
}
|
|
6531
|
+
const tags = { migrationId: step.id };
|
|
6532
|
+
try {
|
|
6533
|
+
const gate = await host.startMigration({ id: step.id });
|
|
6534
|
+
if (!gate.proceed) {
|
|
6535
|
+
log.warn("migration not run", {
|
|
6536
|
+
tags,
|
|
6537
|
+
meta: {
|
|
6538
|
+
state: gate.state,
|
|
6539
|
+
reason: gate.reason
|
|
6540
|
+
}
|
|
6541
|
+
});
|
|
6542
|
+
settle(step.id, gate.state === "pending" ? "blocked" : gate.state);
|
|
6543
|
+
continue;
|
|
6544
|
+
}
|
|
6545
|
+
const result = await bound.execute();
|
|
6546
|
+
const outcome = await host.finishMigration({
|
|
6547
|
+
id: step.id,
|
|
6548
|
+
result
|
|
6549
|
+
});
|
|
6550
|
+
if (outcome.status === "applied") log.info("migration applied", {
|
|
6551
|
+
tags,
|
|
6552
|
+
meta: { rowsChanged: outcome.rowsChanged }
|
|
6553
|
+
});
|
|
6554
|
+
else log.error("migration failed", {
|
|
6555
|
+
tags,
|
|
6556
|
+
meta: { error: outcome.error }
|
|
6557
|
+
});
|
|
6558
|
+
settle(step.id, outcome.status);
|
|
6559
|
+
} catch (err) {
|
|
6560
|
+
log.error("migration could not be completed with the engine", {
|
|
6561
|
+
tags,
|
|
6562
|
+
meta: { error: errMsg(err) }
|
|
6563
|
+
});
|
|
6564
|
+
failed.push(step.id);
|
|
6565
|
+
}
|
|
6566
|
+
}
|
|
6567
|
+
const blockOwner = [...failed, ...blocked].filter((id) => byId.get(id)?.meta.onFailure === "block-owner");
|
|
6568
|
+
return {
|
|
6569
|
+
declared: true,
|
|
6570
|
+
snapshot: declaration.snapshot,
|
|
6571
|
+
applied,
|
|
6572
|
+
failed,
|
|
6573
|
+
blocked,
|
|
6574
|
+
skipped,
|
|
6575
|
+
blockOwner
|
|
6576
|
+
};
|
|
6577
|
+
}
|
|
6106
6578
|
/**
|
|
6107
6579
|
* Build a {@link DurableState} over a single store key. Transport-agnostic:
|
|
6108
6580
|
* `read`/`write` are the addon-store or device-store accessors. The whole
|
|
@@ -7158,6 +7630,28 @@ var BaseAddon = class {
|
|
|
7158
7630
|
return normalized;
|
|
7159
7631
|
}
|
|
7160
7632
|
/**
|
|
7633
|
+
* Run this addon's migration catalogue (D987 M3) through the hub's `migrations`
|
|
7634
|
+
* engine. Call it at the point of the boot where the data must already have the new
|
|
7635
|
+
* shape — `onInitialize`, or `onRestoreDevices` for a migration that needs the
|
|
7636
|
+
* restored devices — with the catalogue bound to the addon's ports
|
|
7637
|
+
* (`defineAddonMigrations(ADDON_MIGRATIONS, ports)`).
|
|
7638
|
+
*
|
|
7639
|
+
* An engine that cannot be reached or refuses the catalogue is logged and runs
|
|
7640
|
+
* nothing; the boot continues. A migration that FAILED (or was blocked by one)
|
|
7641
|
+
* and declares `onFailure: 'block-owner'` makes this throw, so the addon does not
|
|
7642
|
+
* serve data whose shape it cannot trust; `tolerate` migrations never do.
|
|
7643
|
+
*/
|
|
7644
|
+
async runMigrations(migrations) {
|
|
7645
|
+
const api = this.ctx.api.migrations;
|
|
7646
|
+
const report = await runAddonMigrations({
|
|
7647
|
+
declareOwner: (input) => api.declareOwner.mutate(input),
|
|
7648
|
+
startMigration: (input) => api.startMigration.mutate(input),
|
|
7649
|
+
finishMigration: (input) => api.finishMigration.mutate(input)
|
|
7650
|
+
}, migrations, this.ctx.logger);
|
|
7651
|
+
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`);
|
|
7652
|
+
return report;
|
|
7653
|
+
}
|
|
7654
|
+
/**
|
|
7161
7655
|
* Called by the isolated-process runner AFTER `broker.start()`.
|
|
7162
7656
|
* In-process addons never need this because the hub broker is already
|
|
7163
7657
|
* running when `initialize()` fires. For forked children the broker
|
|
@@ -8455,6 +8949,98 @@ function defineEntryKind(name, spec) {
|
|
|
8455
8949
|
if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
|
|
8456
8950
|
return defined;
|
|
8457
8951
|
}
|
|
8952
|
+
object({
|
|
8953
|
+
field: string().min(1),
|
|
8954
|
+
on: literal("advance")
|
|
8955
|
+
});
|
|
8956
|
+
/**
|
|
8957
|
+
* Output schema shared by the contribution + live methods.
|
|
8958
|
+
*
|
|
8959
|
+
* Mirrors the `ConfigUISchemaWithValues` shape (sections[] + optional
|
|
8960
|
+
* tabs[]) without importing from `../interfaces/config-ui.js` — a
|
|
8961
|
+
* concrete-but-lenient Zod object keeps tRPC output inference happy
|
|
8962
|
+
* (using `z.unknown()` here collapses unrelated router branches to
|
|
8963
|
+
* `unknown` when the generator re-inlines the huge AppRouter type).
|
|
8964
|
+
*
|
|
8965
|
+
* `.passthrough()` on sections/fields accepts whatever FormBuilder
|
|
8966
|
+
* extensions the caller adds (showWhen, displayScale, …) without
|
|
8967
|
+
* rebuilding every time a new field kind is introduced.
|
|
8968
|
+
*/
|
|
8969
|
+
var ContributionSectionSchema = object({
|
|
8970
|
+
id: string(),
|
|
8971
|
+
title: string(),
|
|
8972
|
+
description: string().optional(),
|
|
8973
|
+
style: _enum(["card", "accordion"]).optional(),
|
|
8974
|
+
defaultCollapsed: boolean().optional(),
|
|
8975
|
+
columns: union([
|
|
8976
|
+
literal(1),
|
|
8977
|
+
literal(2),
|
|
8978
|
+
literal(3),
|
|
8979
|
+
literal(4)
|
|
8980
|
+
]).optional(),
|
|
8981
|
+
tab: string().optional(),
|
|
8982
|
+
location: _enum([
|
|
8983
|
+
"settings",
|
|
8984
|
+
"top-tab",
|
|
8985
|
+
"hero"
|
|
8986
|
+
]).optional(),
|
|
8987
|
+
order: number().optional(),
|
|
8988
|
+
fields: array(any())
|
|
8989
|
+
});
|
|
8990
|
+
object({
|
|
8991
|
+
tabs: array(object({
|
|
8992
|
+
id: string(),
|
|
8993
|
+
label: string(),
|
|
8994
|
+
icon: string(),
|
|
8995
|
+
order: number().optional()
|
|
8996
|
+
})).optional(),
|
|
8997
|
+
sections: array(ContributionSectionSchema)
|
|
8998
|
+
}).nullable();
|
|
8999
|
+
object({ deviceId: number() }), object({ deviceId: number() }), object({
|
|
9000
|
+
deviceId: number(),
|
|
9001
|
+
patch: record(string(), unknown())
|
|
9002
|
+
}), object({ success: literal(true) });
|
|
9003
|
+
object({ deviceId: number() }), unknown().nullable();
|
|
9004
|
+
function method(input, output, options) {
|
|
9005
|
+
return {
|
|
9006
|
+
input,
|
|
9007
|
+
output,
|
|
9008
|
+
kind: options?.kind ?? "query",
|
|
9009
|
+
...options?.auth !== void 0 ? { auth: options.auth } : {},
|
|
9010
|
+
...options?.access !== void 0 ? { access: options.access } : {},
|
|
9011
|
+
...options?.role !== void 0 ? { role: options.role } : {},
|
|
9012
|
+
...options?.caller !== void 0 ? { caller: options.caller } : {},
|
|
9013
|
+
timeoutMs: options?.timeoutMs
|
|
9014
|
+
};
|
|
9015
|
+
}
|
|
9016
|
+
/**
|
|
9017
|
+
* A wrapper/system-only method: served exclusively by the cap's system-level
|
|
9018
|
+
* provider (`InferProvider`), and OPTIONAL on `InferNativeProvider` so per-device
|
|
9019
|
+
* driver natives don't stub out a wrapper concern (e.g. a cross-device cache
|
|
9020
|
+
* overview). The `systemOnly: true` literal is what `InferNativeProvider` keys on.
|
|
9021
|
+
*/
|
|
9022
|
+
function systemMethod(input, output, options) {
|
|
9023
|
+
return {
|
|
9024
|
+
...method(input, output, options),
|
|
9025
|
+
systemOnly: true
|
|
9026
|
+
};
|
|
9027
|
+
}
|
|
9028
|
+
/**
|
|
9029
|
+
* A method a SOURCE of a collection cap may legitimately not serve — OPTIONAL
|
|
9030
|
+
* on `InferProvider`. The `providerOptional: true` literal is what
|
|
9031
|
+
* `InferProvider` keys on; see {@link CapabilityMethodSchema.providerOptional}
|
|
9032
|
+
* for when this is the honest answer and when it is a soft stub.
|
|
9033
|
+
*/
|
|
9034
|
+
function optionalMethod(input, output, options) {
|
|
9035
|
+
return {
|
|
9036
|
+
...method(input, output, options),
|
|
9037
|
+
providerOptional: true
|
|
9038
|
+
};
|
|
9039
|
+
}
|
|
9040
|
+
/** Shorthand to define an event schema */
|
|
9041
|
+
function event(data) {
|
|
9042
|
+
return { data };
|
|
9043
|
+
}
|
|
8458
9044
|
var READING_QUANTITIES = [
|
|
8459
9045
|
"temperature",
|
|
8460
9046
|
"pressure",
|
|
@@ -8847,7 +9433,7 @@ var ProfileRtspEntrySchema = object({
|
|
|
8847
9433
|
/**
|
|
8848
9434
|
* The model weight formats a catalog entry can ship. Schema-free on purpose:
|
|
8849
9435
|
* `types/models.ts` builds Zod schemas from it, but a runner-closure consumer
|
|
8850
|
-
* (the model downloader in `@camstack/system`) needs only the list and must
|
|
9436
|
+
* (the model downloader in `@camstack/server/system`) needs only the list and must
|
|
8851
9437
|
* reach it through `@camstack/types/addon` without building the cap schema
|
|
8852
9438
|
* graph (D28).
|
|
8853
9439
|
*/
|
|
@@ -8859,98 +9445,6 @@ var MODEL_FORMATS = [
|
|
|
8859
9445
|
"pt",
|
|
8860
9446
|
"gguf"
|
|
8861
9447
|
];
|
|
8862
|
-
object({
|
|
8863
|
-
field: string().min(1),
|
|
8864
|
-
on: literal("advance")
|
|
8865
|
-
});
|
|
8866
|
-
/**
|
|
8867
|
-
* Output schema shared by the contribution + live methods.
|
|
8868
|
-
*
|
|
8869
|
-
* Mirrors the `ConfigUISchemaWithValues` shape (sections[] + optional
|
|
8870
|
-
* tabs[]) without importing from `../interfaces/config-ui.js` — a
|
|
8871
|
-
* concrete-but-lenient Zod object keeps tRPC output inference happy
|
|
8872
|
-
* (using `z.unknown()` here collapses unrelated router branches to
|
|
8873
|
-
* `unknown` when the generator re-inlines the huge AppRouter type).
|
|
8874
|
-
*
|
|
8875
|
-
* `.passthrough()` on sections/fields accepts whatever FormBuilder
|
|
8876
|
-
* extensions the caller adds (showWhen, displayScale, …) without
|
|
8877
|
-
* rebuilding every time a new field kind is introduced.
|
|
8878
|
-
*/
|
|
8879
|
-
var ContributionSectionSchema = object({
|
|
8880
|
-
id: string(),
|
|
8881
|
-
title: string(),
|
|
8882
|
-
description: string().optional(),
|
|
8883
|
-
style: _enum(["card", "accordion"]).optional(),
|
|
8884
|
-
defaultCollapsed: boolean().optional(),
|
|
8885
|
-
columns: union([
|
|
8886
|
-
literal(1),
|
|
8887
|
-
literal(2),
|
|
8888
|
-
literal(3),
|
|
8889
|
-
literal(4)
|
|
8890
|
-
]).optional(),
|
|
8891
|
-
tab: string().optional(),
|
|
8892
|
-
location: _enum([
|
|
8893
|
-
"settings",
|
|
8894
|
-
"top-tab",
|
|
8895
|
-
"hero"
|
|
8896
|
-
]).optional(),
|
|
8897
|
-
order: number().optional(),
|
|
8898
|
-
fields: array(any())
|
|
8899
|
-
});
|
|
8900
|
-
object({
|
|
8901
|
-
tabs: array(object({
|
|
8902
|
-
id: string(),
|
|
8903
|
-
label: string(),
|
|
8904
|
-
icon: string(),
|
|
8905
|
-
order: number().optional()
|
|
8906
|
-
})).optional(),
|
|
8907
|
-
sections: array(ContributionSectionSchema)
|
|
8908
|
-
}).nullable();
|
|
8909
|
-
object({ deviceId: number() }), object({ deviceId: number() }), object({
|
|
8910
|
-
deviceId: number(),
|
|
8911
|
-
patch: record(string(), unknown())
|
|
8912
|
-
}), object({ success: literal(true) });
|
|
8913
|
-
object({ deviceId: number() }), unknown().nullable();
|
|
8914
|
-
function method(input, output, options) {
|
|
8915
|
-
return {
|
|
8916
|
-
input,
|
|
8917
|
-
output,
|
|
8918
|
-
kind: options?.kind ?? "query",
|
|
8919
|
-
...options?.auth !== void 0 ? { auth: options.auth } : {},
|
|
8920
|
-
...options?.access !== void 0 ? { access: options.access } : {},
|
|
8921
|
-
...options?.role !== void 0 ? { role: options.role } : {},
|
|
8922
|
-
...options?.caller !== void 0 ? { caller: options.caller } : {},
|
|
8923
|
-
timeoutMs: options?.timeoutMs
|
|
8924
|
-
};
|
|
8925
|
-
}
|
|
8926
|
-
/**
|
|
8927
|
-
* A wrapper/system-only method: served exclusively by the cap's system-level
|
|
8928
|
-
* provider (`InferProvider`), and OPTIONAL on `InferNativeProvider` so per-device
|
|
8929
|
-
* driver natives don't stub out a wrapper concern (e.g. a cross-device cache
|
|
8930
|
-
* overview). The `systemOnly: true` literal is what `InferNativeProvider` keys on.
|
|
8931
|
-
*/
|
|
8932
|
-
function systemMethod(input, output, options) {
|
|
8933
|
-
return {
|
|
8934
|
-
...method(input, output, options),
|
|
8935
|
-
systemOnly: true
|
|
8936
|
-
};
|
|
8937
|
-
}
|
|
8938
|
-
/**
|
|
8939
|
-
* A method a SOURCE of a collection cap may legitimately not serve — OPTIONAL
|
|
8940
|
-
* on `InferProvider`. The `providerOptional: true` literal is what
|
|
8941
|
-
* `InferProvider` keys on; see {@link CapabilityMethodSchema.providerOptional}
|
|
8942
|
-
* for when this is the honest answer and when it is a soft stub.
|
|
8943
|
-
*/
|
|
8944
|
-
function optionalMethod(input, output, options) {
|
|
8945
|
-
return {
|
|
8946
|
-
...method(input, output, options),
|
|
8947
|
-
providerOptional: true
|
|
8948
|
-
};
|
|
8949
|
-
}
|
|
8950
|
-
/** Shorthand to define an event schema */
|
|
8951
|
-
function event(data) {
|
|
8952
|
-
return { data };
|
|
8953
|
-
}
|
|
8954
9448
|
/**
|
|
8955
9449
|
* Per-call node pinning for `ctx.api` capability calls.
|
|
8956
9450
|
*
|
|
@@ -9251,6 +9745,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9251
9745
|
"mesh-network",
|
|
9252
9746
|
"meter",
|
|
9253
9747
|
"metrics-provider",
|
|
9748
|
+
"migrations",
|
|
9254
9749
|
"model-convert",
|
|
9255
9750
|
"model-distributor",
|
|
9256
9751
|
"motion",
|
|
@@ -11153,379 +11648,7 @@ object({
|
|
|
11153
11648
|
params: record(string(), union([string(), number()])).optional()
|
|
11154
11649
|
});
|
|
11155
11650
|
//#endregion
|
|
11156
|
-
//#region ../types/dist/
|
|
11157
|
-
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
11158
|
-
DeviceType["Camera"] = "camera";
|
|
11159
|
-
DeviceType["Hub"] = "hub";
|
|
11160
|
-
DeviceType["Light"] = "light";
|
|
11161
|
-
DeviceType["Siren"] = "siren";
|
|
11162
|
-
DeviceType["Switch"] = "switch";
|
|
11163
|
-
DeviceType["Sensor"] = "sensor";
|
|
11164
|
-
DeviceType["Thermostat"] = "thermostat";
|
|
11165
|
-
/** Air-conditioner / heat-pump climate device (HVAC) — shares the
|
|
11166
|
-
* `climate-control` cap surface with `Thermostat` but renders a
|
|
11167
|
-
* dedicated AC-appropriate control UI (mode chips, fan speed,
|
|
11168
|
-
* independent vertical/horizontal swing). Sources: native Gree, and
|
|
11169
|
-
* reusable by other AC integrations. */
|
|
11170
|
-
DeviceType["Climate"] = "climate";
|
|
11171
|
-
DeviceType["Button"] = "button";
|
|
11172
|
-
/** Generic stateless event emitter — carries a device's EXACT declared
|
|
11173
|
-
* event vocabulary verbatim (no normalization). Installed with the
|
|
11174
|
-
* `event-emitter` cap. Sources: HA `event.*` entities (structured) and
|
|
11175
|
-
* HA bus events (e.g. `zha_event`, generic). */
|
|
11176
|
-
DeviceType["EventEmitter"] = "event-emitter";
|
|
11177
|
-
/** Firmware/software update entity — current vs available version,
|
|
11178
|
-
* updatable flag, update state, and an install action. Installed with
|
|
11179
|
-
* the `update` cap. Sources: Homematic firmware-update channels (and
|
|
11180
|
-
* reusable by other providers, e.g. HA `update.*` entities). */
|
|
11181
|
-
DeviceType["Update"] = "update";
|
|
11182
|
-
DeviceType["Generic"] = "generic";
|
|
11183
|
-
/** Generic notification delivery target (HA `notify.<service>`, future
|
|
11184
|
-
* Telegram / Discord / ntfy / SMTP, …). One device per delivery
|
|
11185
|
-
* endpoint; the `notifier` cap defines the send surface. */
|
|
11186
|
-
DeviceType["Notifier"] = "notifier";
|
|
11187
|
-
/** Pre-recorded action sequence with optional parameters
|
|
11188
|
-
* (HA `script.*`). Runnable via `script-runner` cap. */
|
|
11189
|
-
DeviceType["Script"] = "script";
|
|
11190
|
-
/** Automation rule (HA `automation.*`) — enable/disable + manual
|
|
11191
|
-
* trigger surface exposed via `automation-control` cap. */
|
|
11192
|
-
DeviceType["Automation"] = "automation";
|
|
11193
|
-
/** Door / smart lock device (HA `lock.*`). `lock-control` cap. */
|
|
11194
|
-
DeviceType["Lock"] = "lock";
|
|
11195
|
-
/** Window covering, blinds, garage door, valve, etc. (HA `cover.*`,
|
|
11196
|
-
* `valve.*`). `cover` cap with sub-roles for variant. */
|
|
11197
|
-
DeviceType["Cover"] = "cover";
|
|
11198
|
-
/** Pipe / water / gas valve with open/close/stop and optional
|
|
11199
|
-
* position (HA `valve.*`). `valve` cap — a cover-sibling actuator
|
|
11200
|
-
* modelled on the same open/closed lifecycle. */
|
|
11201
|
-
DeviceType["Valve"] = "valve";
|
|
11202
|
-
/** Humidifier / dehumidifier with on/off + target humidity + mode
|
|
11203
|
-
* (HA `humidifier.*`). `humidifier` cap — a climate-family actuator
|
|
11204
|
-
* modelled on the same target / mode lifecycle. */
|
|
11205
|
-
DeviceType["Humidifier"] = "humidifier";
|
|
11206
|
-
/** Water heater / boiler with target temperature + operation mode +
|
|
11207
|
-
* away mode (HA `water_heater.*`). `water-heater` cap — a
|
|
11208
|
-
* climate-family actuator. */
|
|
11209
|
-
DeviceType["WaterHeater"] = "water-heater";
|
|
11210
|
-
/** Ceiling / standing / exhaust fan (HA `fan.*`). `fan-control` cap. */
|
|
11211
|
-
DeviceType["Fan"] = "fan";
|
|
11212
|
-
/** Audio / video playback endpoint (HA `media_player.*`). Disjoint from
|
|
11213
|
-
* the camera surface — those use `Camera`. `media-player` cap. */
|
|
11214
|
-
DeviceType["MediaPlayer"] = "media-player";
|
|
11215
|
-
/** Security panel / alarm system (HA `alarm_control_panel.*`).
|
|
11216
|
-
* `alarm-panel` cap. */
|
|
11217
|
-
DeviceType["AlarmPanel"] = "alarm-panel";
|
|
11218
|
-
/** Generic user-settable input (HA `number` / `input_number` / `select`
|
|
11219
|
-
* / `input_select` / `text` / `input_text` / `input_datetime`).
|
|
11220
|
-
* Sub-type via `DeviceRole`: NumericControl / SelectControl /
|
|
11221
|
-
* TextControl / DateTimeControl. */
|
|
11222
|
-
DeviceType["Control"] = "control";
|
|
11223
|
-
/** Person / device-tracker presence (HA `person.*`, `device_tracker.*`).
|
|
11224
|
-
* `presence` cap. */
|
|
11225
|
-
DeviceType["Presence"] = "presence";
|
|
11226
|
-
/** Weather provider (HA `weather.*`). Tier-3, low MVP priority.
|
|
11227
|
-
* `weather` cap. */
|
|
11228
|
-
DeviceType["Weather"] = "weather";
|
|
11229
|
-
/** Robot vacuum (HA `vacuum.*`). Tier-3. `vacuum-control` cap. */
|
|
11230
|
-
DeviceType["Vacuum"] = "vacuum";
|
|
11231
|
-
/** Robotic lawn mower (HA `lawn_mower.*`). Tier-3.
|
|
11232
|
-
* `lawn-mower-control` cap. */
|
|
11233
|
-
DeviceType["LawnMower"] = "lawn-mower";
|
|
11234
|
-
/** Physical HA device group — parent container for entity-children
|
|
11235
|
-
* adopted from a single HA device entry. Not renderable as a
|
|
11236
|
-
* standalone device; exists only to anchor child entities. */
|
|
11237
|
-
DeviceType["Container"] = "container";
|
|
11238
|
-
/** Single still-image entity (HA `image.*`). Read-only display of an
|
|
11239
|
-
* `entity_picture` signed URL the browser loads directly. `image` cap. */
|
|
11240
|
-
DeviceType["Image"] = "image";
|
|
11241
|
-
/** Smart pet feeder — cloud-connected food dispenser with a bowl food
|
|
11242
|
-
* level, battery, desiccant life, feeding state and manual-feed /
|
|
11243
|
-
* call-pet / maintenance actions. Installed with the `pet-feeder` cap;
|
|
11244
|
-
* dual-hopper models (D4S/D4SH) expose per-hopper portions. Sources:
|
|
11245
|
-
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
11246
|
-
* integrations sharing the same food/desiccant/hopper surface. */
|
|
11247
|
-
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11248
|
-
/** Pet water fountain — tank level, water drunk, pump and its duty cycle.
|
|
11249
|
-
* Installed with the `pet-fountain` cap. Reaches CamStack as loose entities
|
|
11250
|
-
* of a container and is BUILT as a composed device (D967). */
|
|
11251
|
-
DeviceType["PetFountain"] = "pet-fountain";
|
|
11252
|
-
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
11253
|
-
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
11254
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
11255
|
-
* A plug-built dishwasher carries running-state and power instead. */
|
|
11256
|
-
DeviceType["Dishwasher"] = "dishwasher";
|
|
11257
|
-
/** Washing machine. A plug-built one is running while its power stays
|
|
11258
|
-
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
11259
|
-
DeviceType["Washer"] = "washer";
|
|
11260
|
-
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
11261
|
-
DeviceType["Dryer"] = "dryer";
|
|
11262
|
-
/** The physical bridge box of a vendor ecosystem (Velux KLF-200, and later
|
|
11263
|
-
* other radio-to-IP bridges). It carries the box's own facts (firmware,
|
|
11264
|
-
* address, connection state) and the actions the box really supports
|
|
11265
|
-
* (`reboot`, `device-admin-link`). Products are NOT its children — they are
|
|
11266
|
-
* adopted beside it — and its connection settings stay on the integration. */
|
|
11267
|
-
DeviceType["Gateway"] = "gateway";
|
|
11268
|
-
return DeviceType;
|
|
11269
|
-
}({});
|
|
11270
|
-
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
11271
|
-
DeviceFeature["BatteryOperated"] = "battery-operated";
|
|
11272
|
-
DeviceFeature["Rebootable"] = "rebootable";
|
|
11273
|
-
/**
|
|
11274
|
-
* Device supports an on-demand re-sync of its derived spec with its
|
|
11275
|
-
* upstream source — drives the generic Re-sync button. The owning
|
|
11276
|
-
* provider implements the action via the `device-adoption.resync` cap.
|
|
11277
|
-
*/
|
|
11278
|
-
DeviceFeature["Resyncable"] = "resyncable";
|
|
11279
|
-
DeviceFeature["NativeSnapshot"] = "native-snapshot";
|
|
11280
|
-
DeviceFeature["DoorbellButton"] = "doorbell-button";
|
|
11281
|
-
DeviceFeature["TwoWayAudio"] = "two-way-audio";
|
|
11282
|
-
DeviceFeature["PanTiltZoom"] = "pan-tilt-zoom";
|
|
11283
|
-
/**
|
|
11284
|
-
* Camera supports the on-firmware autotrack subsystem (subject-
|
|
11285
|
-
* following). Distinct from `PanTiltZoom` because not every PTZ
|
|
11286
|
-
* camera ships autotrack — the admin UI uses this flag to gate
|
|
11287
|
-
* the autotrack toggle / settings card without re-deriving from
|
|
11288
|
-
* the cap registry. Mirrors `ptz-autotrack` cap registration:
|
|
11289
|
-
* driver sets this feature when probe confirms the firmware
|
|
11290
|
-
* surface, and registers the cap in the same code path.
|
|
11291
|
-
*/
|
|
11292
|
-
DeviceFeature["PtzAutotrack"] = "ptz-autotrack";
|
|
11293
|
-
/**
|
|
11294
|
-
* Accessory exposes a "trigger on motion" toggle — the parent camera's
|
|
11295
|
-
* motion detection automatically activates this device. Mirrors
|
|
11296
|
-
* `motion-trigger` cap registration: drivers set this feature in the
|
|
11297
|
-
* same code path that calls `ctx.registerNativeCap(motionTriggerCapability, ...)`.
|
|
11298
|
-
*
|
|
11299
|
-
* Used by admin UI (gate the in-hero `MotionTriggerToggle` against a
|
|
11300
|
-
* fast scalar without binding fetch), notifier rules, and `listAll`
|
|
11301
|
-
* filters that want "all devices with on-motion behaviour".
|
|
11302
|
-
*/
|
|
11303
|
-
DeviceFeature["MotionTrigger"] = "motion-trigger";
|
|
11304
|
-
/** Light supports rgb-triplet color via `color` cap. */
|
|
11305
|
-
DeviceFeature["LightColorRgb"] = "light-color-rgb";
|
|
11306
|
-
/** Light supports HSV color via `color` cap. */
|
|
11307
|
-
DeviceFeature["LightColorHsv"] = "light-color-hsv";
|
|
11308
|
-
/** Light supports color-temperature (mired) via `color` cap. */
|
|
11309
|
-
DeviceFeature["LightColorMired"] = "light-color-mired";
|
|
11310
|
-
/** Thermostat supports a `heat_cool` dual setpoint (targetLow +
|
|
11311
|
-
* targetHigh). Gates the range slider UI. */
|
|
11312
|
-
DeviceFeature["ClimateDualSetpoint"] = "climate-dual-setpoint";
|
|
11313
|
-
/** Thermostat exposes target humidity and/or current humidity
|
|
11314
|
-
* readings. Gates the humidity controls. */
|
|
11315
|
-
DeviceFeature["ClimateHumidity"] = "climate-humidity";
|
|
11316
|
-
/** Thermostat exposes a fan-mode selector. */
|
|
11317
|
-
DeviceFeature["ClimateFanMode"] = "climate-fan-mode";
|
|
11318
|
-
/** Thermostat exposes preset modes (eco / away / sleep / vendor). */
|
|
11319
|
-
DeviceFeature["ClimatePreset"] = "climate-preset";
|
|
11320
|
-
/** Thermostat exposes a vertical louver swing toggle. Gates the
|
|
11321
|
-
* vertical-swing switch in the climate UI. Independent of horizontal. */
|
|
11322
|
-
DeviceFeature["ClimateSwingVertical"] = "climate-swing-vertical";
|
|
11323
|
-
/** Thermostat exposes a horizontal louver swing toggle. Gates the
|
|
11324
|
-
* horizontal-swing switch in the climate UI. Independent of vertical. */
|
|
11325
|
-
DeviceFeature["ClimateSwingHorizontal"] = "climate-swing-horizontal";
|
|
11326
|
-
/** Cover exposes intermediate position control (0..100). Gates the
|
|
11327
|
-
* position slider UI. */
|
|
11328
|
-
DeviceFeature["CoverPositionable"] = "cover-positionable";
|
|
11329
|
-
/** Cover exposes slat-tilt control. Gates the tilt slider UI. */
|
|
11330
|
-
DeviceFeature["CoverTilt"] = "cover-tilt";
|
|
11331
|
-
/** Valve exposes intermediate position control (0..100). Gates the
|
|
11332
|
-
* position slider / drag surface UI. */
|
|
11333
|
-
DeviceFeature["ValvePositionable"] = "valve-positionable";
|
|
11334
|
-
/** Fan exposes a speed-percentage setter. Gates the speed slider UI. */
|
|
11335
|
-
DeviceFeature["FanSpeed"] = "fan-speed";
|
|
11336
|
-
/** Fan exposes a preset mode selector. */
|
|
11337
|
-
DeviceFeature["FanPreset"] = "fan-preset";
|
|
11338
|
-
/** Fan exposes blade direction (forward/reverse) — typical of
|
|
11339
|
-
* ceiling fans. */
|
|
11340
|
-
DeviceFeature["FanDirection"] = "fan-direction";
|
|
11341
|
-
/** Fan exposes an oscillation toggle. */
|
|
11342
|
-
DeviceFeature["FanOscillating"] = "fan-oscillating";
|
|
11343
|
-
/** Lock requires a PIN code on lock/unlock. Gates the code-entry
|
|
11344
|
-
* field on the UI lock-controls panel. */
|
|
11345
|
-
DeviceFeature["LockPinRequired"] = "lock-pin-required";
|
|
11346
|
-
/** Lock supports a latch-release ("open door") action distinct from
|
|
11347
|
-
* unlock. Mirrors HA `LockEntityFeature.OPEN` (bit 1) in
|
|
11348
|
-
* `supported_features`. Gates the Open Door button in the UI. */
|
|
11349
|
-
DeviceFeature["LockOpen"] = "lock-open";
|
|
11350
|
-
/** Media player exposes a seek-to-position surface. */
|
|
11351
|
-
DeviceFeature["MediaPlayerSeek"] = "media-player-seek";
|
|
11352
|
-
/** Media player exposes a volume-level setter. */
|
|
11353
|
-
DeviceFeature["MediaPlayerVolume"] = "media-player-volume";
|
|
11354
|
-
/** Media player exposes a mute toggle distinct from volume=0. */
|
|
11355
|
-
DeviceFeature["MediaPlayerMute"] = "media-player-mute";
|
|
11356
|
-
/** Media player exposes a shuffle toggle. */
|
|
11357
|
-
DeviceFeature["MediaPlayerShuffle"] = "media-player-shuffle";
|
|
11358
|
-
/** Media player exposes a repeat mode (off / all / one). */
|
|
11359
|
-
DeviceFeature["MediaPlayerRepeat"] = "media-player-repeat";
|
|
11360
|
-
/** Media player exposes a source / input selector. */
|
|
11361
|
-
DeviceFeature["MediaPlayerSelectSource"] = "media-player-select-source";
|
|
11362
|
-
/** Media player exposes a play-arbitrary-media surface (URL / id). */
|
|
11363
|
-
DeviceFeature["MediaPlayerPlayMedia"] = "media-player-play-media";
|
|
11364
|
-
/** Media player exposes next-track. */
|
|
11365
|
-
DeviceFeature["MediaPlayerNext"] = "media-player-next";
|
|
11366
|
-
/** Media player exposes previous-track. */
|
|
11367
|
-
DeviceFeature["MediaPlayerPrevious"] = "media-player-previous";
|
|
11368
|
-
/** Media player exposes stop distinct from pause. */
|
|
11369
|
-
DeviceFeature["MediaPlayerStop"] = "media-player-stop";
|
|
11370
|
-
/** Alarm panel requires a PIN code on arm/disarm. */
|
|
11371
|
-
DeviceFeature["AlarmPinRequired"] = "alarm-pin-required";
|
|
11372
|
-
/** Presence device carries GPS coordinates (lat/lng/accuracy) in
|
|
11373
|
-
* addition to a textual location. */
|
|
11374
|
-
DeviceFeature["PresenceGps"] = "presence-gps";
|
|
11375
|
-
/** Notifier accepts an inline / URL image attachment. */
|
|
11376
|
-
DeviceFeature["NotifierImage"] = "notifier-image";
|
|
11377
|
-
/** Notifier accepts a priority hint (high/normal/low). */
|
|
11378
|
-
DeviceFeature["NotifierPriority"] = "notifier-priority";
|
|
11379
|
-
/** Notifier accepts a free-form `data` payload for platform-specific
|
|
11380
|
-
* fields. */
|
|
11381
|
-
DeviceFeature["NotifierData"] = "notifier-data";
|
|
11382
|
-
/** Notifier supports interactive action buttons / callbacks. */
|
|
11383
|
-
DeviceFeature["NotifierActions"] = "notifier-actions";
|
|
11384
|
-
/** Notifier supports per-call recipient targeting (multi-user). */
|
|
11385
|
-
DeviceFeature["NotifierRecipients"] = "notifier-recipients";
|
|
11386
|
-
/** Script runner accepts a variables map on each run invocation. */
|
|
11387
|
-
DeviceFeature["ScriptVariables"] = "script-variables";
|
|
11388
|
-
/** Automation `trigger` accepts a skipCondition flag — fires the
|
|
11389
|
-
* automation's actions while bypassing its condition block. */
|
|
11390
|
-
DeviceFeature["AutomationSkipCondition"] = "automation-skip-condition";
|
|
11391
|
-
/** Robot vacuum exposes a live cleaning map (image child). Gates the
|
|
11392
|
-
* map tile in the vacuum UI. */
|
|
11393
|
-
DeviceFeature["VacuumHasMap"] = "vacuum-has-map";
|
|
11394
|
-
/** Robot vacuum exposes AI obstacle-detection toggles. Gates the AI
|
|
11395
|
-
* switches group. */
|
|
11396
|
-
DeviceFeature["VacuumHasAi"] = "vacuum-has-ai";
|
|
11397
|
-
/** Robot mower exposes a live mowing map (SVG image child). Gates the
|
|
11398
|
-
* mower map tile. */
|
|
11399
|
-
DeviceFeature["MowerHasMap"] = "mower-has-map";
|
|
11400
|
-
/** Robot mower exposes targeted mowing (all-area / zones / edges /
|
|
11401
|
-
* spots) — gates the Mow action + map selectors. */
|
|
11402
|
-
DeviceFeature["MowerHasTargetedMowing"] = "mower-has-targeted-mowing";
|
|
11403
|
-
return DeviceFeature;
|
|
11404
|
-
}({});
|
|
11405
|
-
/**
|
|
11406
|
-
* Semantic role a device plays within its parent. Populated by driver
|
|
11407
|
-
* addons when creating accessory devices (Reolink siren/floodlight/
|
|
11408
|
-
* PIR/chime/autotrack/doorbell, ONVIF relay outputs, …). Used by the
|
|
11409
|
-
* admin UI to pick icons, labels, and widgets — a `Switch` with
|
|
11410
|
-
* `role: Floodlight` renders as a bulb with a brightness slider,
|
|
11411
|
-
* whereas a `Switch` with `role: Siren` renders as a klaxon.
|
|
11412
|
-
*
|
|
11413
|
-
* Undefined for top-level devices (cameras, NVRs, hubs). Persisted in
|
|
11414
|
-
* sqlite as a nullable TEXT column — old rows keep working unchanged.
|
|
11415
|
-
*/
|
|
11416
|
-
var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
11417
|
-
DeviceRole["Siren"] = "siren";
|
|
11418
|
-
DeviceRole["Floodlight"] = "floodlight";
|
|
11419
|
-
DeviceRole["Spotlight"] = "spotlight";
|
|
11420
|
-
DeviceRole["PirSensor"] = "pir-sensor";
|
|
11421
|
-
DeviceRole["Chime"] = "chime";
|
|
11422
|
-
DeviceRole["Autotrack"] = "autotrack";
|
|
11423
|
-
DeviceRole["Nightvision"] = "nightvision";
|
|
11424
|
-
DeviceRole["PrivacyMask"] = "privacy-mask";
|
|
11425
|
-
DeviceRole["Doorbell"] = "doorbell";
|
|
11426
|
-
/** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
|
|
11427
|
-
DeviceRole["CoverBlind"] = "cover-blind";
|
|
11428
|
-
/** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
|
|
11429
|
-
DeviceRole["CoverShutter"] = "cover-shutter";
|
|
11430
|
-
/** Exterior awning. HA `device_class: awning`. */
|
|
11431
|
-
DeviceRole["CoverAwning"] = "cover-awning";
|
|
11432
|
-
/** Curtain / drape. HA `device_class: curtain`. */
|
|
11433
|
-
DeviceRole["CoverCurtain"] = "cover-curtain";
|
|
11434
|
-
/** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
|
|
11435
|
-
DeviceRole["CoverGarage"] = "cover-garage";
|
|
11436
|
-
/** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
|
|
11437
|
-
DeviceRole["CoverGate"] = "cover-gate";
|
|
11438
|
-
/** Door. HA `device_class: door`. A security actuator: exports gate it. */
|
|
11439
|
-
DeviceRole["CoverDoor"] = "cover-door";
|
|
11440
|
-
/** Window. HA `device_class: window`. */
|
|
11441
|
-
DeviceRole["CoverWindow"] = "cover-window";
|
|
11442
|
-
/** Virtual HA toggle (input_boolean.*) — distinguishable from a
|
|
11443
|
-
* real Switch device for UI rendering / export adapters. */
|
|
11444
|
-
DeviceRole["BinaryHelper"] = "binary-helper";
|
|
11445
|
-
/** A smart plug: a `switch` whose source says it is an outlet (HA
|
|
11446
|
-
* `device_class: outlet`). The Alexa export shows it as a SMARTPLUG. */
|
|
11447
|
-
DeviceRole["Outlet"] = "outlet";
|
|
11448
|
-
/** Generic motion / occupancy / moving event source. Distinct from
|
|
11449
|
-
* the camera accessory PirSensor role: that one is a camera child;
|
|
11450
|
-
* this is a standalone HA / 3rd-party motion sensor. */
|
|
11451
|
-
DeviceRole["MotionSensor"] = "motion-sensor";
|
|
11452
|
-
DeviceRole["ContactSensor"] = "contact-sensor";
|
|
11453
|
-
DeviceRole["LeakSensor"] = "leak-sensor";
|
|
11454
|
-
DeviceRole["SmokeSensor"] = "smoke-sensor";
|
|
11455
|
-
DeviceRole["COSensor"] = "co-sensor";
|
|
11456
|
-
DeviceRole["GasSensor"] = "gas-sensor";
|
|
11457
|
-
DeviceRole["TamperSensor"] = "tamper-sensor";
|
|
11458
|
-
DeviceRole["VibrationSensor"] = "vibration-sensor";
|
|
11459
|
-
DeviceRole["ConnectivitySensor"] = "connectivity-sensor";
|
|
11460
|
-
DeviceRole["SoundSensor"] = "sound-sensor";
|
|
11461
|
-
/** Fallback for `binary_sensor` without a known `device_class`. */
|
|
11462
|
-
DeviceRole["BinarySensor"] = "binary-sensor";
|
|
11463
|
-
DeviceRole["TemperatureSensor"] = "temperature-sensor";
|
|
11464
|
-
DeviceRole["HumiditySensor"] = "humidity-sensor";
|
|
11465
|
-
DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
|
|
11466
|
-
DeviceRole["PressureSensor"] = "pressure-sensor";
|
|
11467
|
-
/** Wind speed or direction (weather-station `wind-sensor` cap). */
|
|
11468
|
-
DeviceRole["WindSensor"] = "wind-sensor";
|
|
11469
|
-
/** Rain accumulation or rate (weather-station `rain-sensor` cap). */
|
|
11470
|
-
DeviceRole["RainSensor"] = "rain-sensor";
|
|
11471
|
-
/** UV index (weather-station `uv-sensor` cap). */
|
|
11472
|
-
DeviceRole["UvSensor"] = "uv-sensor";
|
|
11473
|
-
/** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
|
|
11474
|
-
* Distinct from AmbientLightSensor (lux). */
|
|
11475
|
-
DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
|
|
11476
|
-
/** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
|
|
11477
|
-
DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
|
|
11478
|
-
DeviceRole["PowerSensor"] = "power-sensor";
|
|
11479
|
-
DeviceRole["EnergySensor"] = "energy-sensor";
|
|
11480
|
-
DeviceRole["VoltageSensor"] = "voltage-sensor";
|
|
11481
|
-
DeviceRole["CurrentSensor"] = "current-sensor";
|
|
11482
|
-
DeviceRole["AirQualitySensor"] = "air-quality-sensor";
|
|
11483
|
-
/** Battery level (numeric % via `sensor` OR low-bool via
|
|
11484
|
-
* `binary_sensor` — the cap distinguishes via the value type). */
|
|
11485
|
-
DeviceRole["BatterySensor"] = "battery-sensor";
|
|
11486
|
-
/** Fallback for `sensor` numeric without a known `device_class`. */
|
|
11487
|
-
DeviceRole["NumericSensor"] = "numeric-sensor";
|
|
11488
|
-
/** String / enum state (HA `sensor` with `state_class: enum` or
|
|
11489
|
-
* `attributes.options`). */
|
|
11490
|
-
DeviceRole["EnumSensor"] = "enum-sensor";
|
|
11491
|
-
/** Date / timestamp state (HA `sensor` with `device_class: timestamp`
|
|
11492
|
-
* or `date`). The slice carries the raw ISO string verbatim (hosted on
|
|
11493
|
-
* the `enum-sensor` cap); the UI renders it locale-formatted. */
|
|
11494
|
-
DeviceRole["DateTimeSensor"] = "datetime-sensor";
|
|
11495
|
-
/** Last-resort fallback when nothing else matches. */
|
|
11496
|
-
DeviceRole["GenericSensor"] = "generic-sensor";
|
|
11497
|
-
DeviceRole["NumericControl"] = "numeric-control";
|
|
11498
|
-
DeviceRole["SelectControl"] = "select-control";
|
|
11499
|
-
DeviceRole["TextControl"] = "text-control";
|
|
11500
|
-
DeviceRole["DateTimeControl"] = "datetime-control";
|
|
11501
|
-
/** Mobile push notifier (HA `notify.mobile_app_*`) — supports
|
|
11502
|
-
* rich features (image, priority, channel routing). */
|
|
11503
|
-
DeviceRole["MobilePushNotifier"] = "mobile-push-notifier";
|
|
11504
|
-
/** Chat / messaging service (HA `notify.telegram_*`,
|
|
11505
|
-
* `notify.discord_*`, etc.). */
|
|
11506
|
-
DeviceRole["MessagingNotifier"] = "messaging-notifier";
|
|
11507
|
-
/** Email-based delivery (HA `notify.smtp`, etc.). */
|
|
11508
|
-
DeviceRole["EmailNotifier"] = "email-notifier";
|
|
11509
|
-
/** Fallback when the notifier service name doesn't match a known
|
|
11510
|
-
* pattern. */
|
|
11511
|
-
DeviceRole["GenericNotifier"] = "generic-notifier";
|
|
11512
|
-
/** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
|
|
11513
|
-
* cap. A `DeviceType.Generic` device. */
|
|
11514
|
-
DeviceRole["IrTransmitter"] = "ir-transmitter";
|
|
11515
|
-
return DeviceRole;
|
|
11516
|
-
}({});
|
|
11517
|
-
/**
|
|
11518
|
-
import { errMsg } from '@camstack/types'
|
|
11519
|
-
* Extract a human-readable message from an unknown error value.
|
|
11520
|
-
* Replaces the ubiquitous `errMsg(err)` pattern.
|
|
11521
|
-
*/
|
|
11522
|
-
function errMsg(err) {
|
|
11523
|
-
if (err instanceof Error) return err.message;
|
|
11524
|
-
if (typeof err === "string") return err;
|
|
11525
|
-
return String(err);
|
|
11526
|
-
}
|
|
11527
|
-
//#endregion
|
|
11528
|
-
//#region ../types/dist/composition-C7WdThmP.mjs
|
|
11651
|
+
//#region ../types/dist/composition-BBzVf2xd.mjs
|
|
11529
11652
|
/**
|
|
11530
11653
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11531
11654
|
*
|
|
@@ -12744,6 +12867,71 @@ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
|
12744
12867
|
var MediaPresenceOwnerKindSchema = _enum([...EVENT_OWNER_TYPES, "track"]);
|
|
12745
12868
|
new Set(EVENT_OWNER_TYPES);
|
|
12746
12869
|
/**
|
|
12870
|
+
* What a published package needs from the rest of the install (D989).
|
|
12871
|
+
*
|
|
12872
|
+
* One published framework package (`@camstack/server`) carries the kernel, the
|
|
12873
|
+
* builtins and the capability contracts, so "which addon runs on which
|
|
12874
|
+
* framework" is a question of version, and the answer is DECLARED by the
|
|
12875
|
+
* package that knows it:
|
|
12876
|
+
*
|
|
12877
|
+
* - an addon says the oldest server it runs on (`requires.server: ">=X"`);
|
|
12878
|
+
* - the server says the oldest addon it works with
|
|
12879
|
+
* (`requires.addons: { "@camstack/addon-x": ">=Y" }`) and the oldest shell
|
|
12880
|
+
* around it (`requires.wrapper: { desktop, image }`);
|
|
12881
|
+
* - a wrapper (the desktop app, the container starter) says which server
|
|
12882
|
+
* range it can host, and reports its own kind and version.
|
|
12883
|
+
*
|
|
12884
|
+
* The publish workflow STAMPS these after the version bump
|
|
12885
|
+
* (`scripts/ci/stamp-requires.mjs`); nobody types a number by hand.
|
|
12886
|
+
*
|
|
12887
|
+
* A requirement that cannot be checked is NOT met: a shell that reports no
|
|
12888
|
+
* version counts as below the minimum, and an unreadable running version is
|
|
12889
|
+
* named in the result (a failed read is never a pass).
|
|
12890
|
+
*/
|
|
12891
|
+
/** `>=MAJOR.MINOR.PATCH[-prerelease]` — the only range shape a requirement uses. */
|
|
12892
|
+
var MinVersionSchema = string().regex(/^>=\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/, "a minimum is written \">=X.Y.Z\"");
|
|
12893
|
+
object({
|
|
12894
|
+
/** The oldest `@camstack/server` this package runs on. */
|
|
12895
|
+
server: MinVersionSchema.optional(),
|
|
12896
|
+
/** The oldest installed version of each named addon package. */
|
|
12897
|
+
addons: record(string(), MinVersionSchema).optional(),
|
|
12898
|
+
/** The oldest shell around the server, per shell kind. */
|
|
12899
|
+
wrapper: object({
|
|
12900
|
+
desktop: MinVersionSchema.optional(),
|
|
12901
|
+
image: MinVersionSchema.optional()
|
|
12902
|
+
}).optional()
|
|
12903
|
+
});
|
|
12904
|
+
/** One unmet requirement; each names the versions on both sides. */
|
|
12905
|
+
var UnmetRequirementSchema = discriminatedUnion("kind", [
|
|
12906
|
+
object({
|
|
12907
|
+
kind: literal("server-too-old"),
|
|
12908
|
+
required: string(),
|
|
12909
|
+
/** `null` — the running server version could not be read. */
|
|
12910
|
+
running: string().nullable()
|
|
12911
|
+
}),
|
|
12912
|
+
object({
|
|
12913
|
+
kind: literal("addon-too-old"),
|
|
12914
|
+
packageName: string(),
|
|
12915
|
+
required: string(),
|
|
12916
|
+
/** `null` — the addon is not installed (or its version is unreadable). */
|
|
12917
|
+
running: string().nullable()
|
|
12918
|
+
}),
|
|
12919
|
+
object({
|
|
12920
|
+
kind: literal("wrapper-too-old"),
|
|
12921
|
+
wrapper: _enum(["desktop", "image"]),
|
|
12922
|
+
required: string(),
|
|
12923
|
+
/** `null` — the wrapper reported no version. */
|
|
12924
|
+
running: string().nullable()
|
|
12925
|
+
})
|
|
12926
|
+
]);
|
|
12927
|
+
var RequiredAddonUpdateSchema = object({
|
|
12928
|
+
packageName: string(),
|
|
12929
|
+
/** The minimum the target server declares. */
|
|
12930
|
+
required: string(),
|
|
12931
|
+
/** What this node has; `null` when the addon is not installed. */
|
|
12932
|
+
installed: string().nullable()
|
|
12933
|
+
});
|
|
12934
|
+
/**
|
|
12747
12935
|
* Which integration instance a settings form is for. An addon that serves several instances
|
|
12748
12936
|
* (`instanceMode: multiple`) can show a different form per instance — an NVR integration
|
|
12749
12937
|
* needs its connection, the default integration needs the addon's own sections.
|
|
@@ -13362,6 +13550,613 @@ var CameraSwitchGroupSchema = object({
|
|
|
13362
13550
|
fetchedAt: number()
|
|
13363
13551
|
});
|
|
13364
13552
|
/**
|
|
13553
|
+
* Query filter for settings-store collections.
|
|
13554
|
+
*/
|
|
13555
|
+
var QueryFilterSchema = object({
|
|
13556
|
+
where: record(string(), unknown()).optional(),
|
|
13557
|
+
whereIn: record(string(), array(unknown())).optional(),
|
|
13558
|
+
whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
|
|
13559
|
+
/** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
|
|
13560
|
+
whereNot: record(string(), unknown()).optional(),
|
|
13561
|
+
/** NULL-safe exclusion of a SET — `whereNot` for more than one value. An
|
|
13562
|
+
* empty list excludes nothing. See `QueryFilter.whereNotIn`. */
|
|
13563
|
+
whereNotIn: record(string(), array(unknown())).optional(),
|
|
13564
|
+
orderBy: object({
|
|
13565
|
+
field: string(),
|
|
13566
|
+
direction: _enum(["asc", "desc"])
|
|
13567
|
+
}).optional(),
|
|
13568
|
+
limit: number().optional(),
|
|
13569
|
+
offset: number().optional()
|
|
13570
|
+
});
|
|
13571
|
+
/**
|
|
13572
|
+
* The predicate half of a filter, for BULK MUTATIONS.
|
|
13573
|
+
*
|
|
13574
|
+
* Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
|
|
13575
|
+
* meaning for a statement that rewrites a set, and accepting them would invite
|
|
13576
|
+
* a caller to believe `limit` bounds the damage. Every field is optional here
|
|
13577
|
+
* only so the shape stays composable — the implementation REJECTS a filter
|
|
13578
|
+
* that compiles to no predicate, because that is the whole collection.
|
|
13579
|
+
*/
|
|
13580
|
+
var MutationFilterSchema = object({
|
|
13581
|
+
where: record(string(), unknown()).optional(),
|
|
13582
|
+
whereIn: record(string(), array(unknown())).optional(),
|
|
13583
|
+
whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
|
|
13584
|
+
whereNot: record(string(), unknown()).optional(),
|
|
13585
|
+
whereNotIn: record(string(), array(unknown())).optional()
|
|
13586
|
+
});
|
|
13587
|
+
/**
|
|
13588
|
+
* One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
|
|
13589
|
+
*
|
|
13590
|
+
* `as` names the slot in the result, so the SAME column may be asked twice with
|
|
13591
|
+
* two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
|
|
13592
|
+
* a `Record<column, op>` shape could not express.
|
|
13593
|
+
*/
|
|
13594
|
+
var AggregateFieldSchema = object({
|
|
13595
|
+
/** Result key. */
|
|
13596
|
+
as: string().min(1),
|
|
13597
|
+
/** Column to aggregate. Must be a real column of a declared collection. */
|
|
13598
|
+
field: string().min(1),
|
|
13599
|
+
op: _enum([
|
|
13600
|
+
"sum",
|
|
13601
|
+
"min",
|
|
13602
|
+
"max"
|
|
13603
|
+
])
|
|
13604
|
+
});
|
|
13605
|
+
/**
|
|
13606
|
+
* `COUNT(*)` plus one number per requested field.
|
|
13607
|
+
*
|
|
13608
|
+
* `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
|
|
13609
|
+
* that really is 0 are different facts, and an accounting caller that renders
|
|
13610
|
+
* "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
|
|
13611
|
+
*/
|
|
13612
|
+
var AggregateResultSchema = object({
|
|
13613
|
+
count: number().int(),
|
|
13614
|
+
values: record(string(), number().nullable())
|
|
13615
|
+
});
|
|
13616
|
+
/** A single stored record: `{ id, data }`. */
|
|
13617
|
+
var SettingsRecordSchema = object({
|
|
13618
|
+
id: string(),
|
|
13619
|
+
data: record(string(), unknown())
|
|
13620
|
+
});
|
|
13621
|
+
/**
|
|
13622
|
+
* One record of a BULK insert — {@link SettingsRecordSchema} with the id made
|
|
13623
|
+
* optional.
|
|
13624
|
+
*
|
|
13625
|
+
* A separate schema rather than loosening the shared one: every other method
|
|
13626
|
+
* on this cap addresses a row BY its id, and making that field optional
|
|
13627
|
+
* everywhere would turn a forgotten key into a silently generated one on
|
|
13628
|
+
* `update` and `delete` as well.
|
|
13629
|
+
*/
|
|
13630
|
+
var BulkRecordSchema = object({
|
|
13631
|
+
id: string().optional(),
|
|
13632
|
+
data: record(string(), unknown())
|
|
13633
|
+
});
|
|
13634
|
+
/**
|
|
13635
|
+
* The database FILES one `sqlite-settings` engine process owns (D851).
|
|
13636
|
+
* Closed on purpose: a file is a thing the engine opens, backs up and gives a
|
|
13637
|
+
* serving thread, so a new one is a code change, never a string a caller
|
|
13638
|
+
* invents. `settings` is `camstack.db` and the default for every collection
|
|
13639
|
+
* that names no file.
|
|
13640
|
+
*/
|
|
13641
|
+
var DataStoreDatabaseSchema = _enum([
|
|
13642
|
+
"settings",
|
|
13643
|
+
"events",
|
|
13644
|
+
"history"
|
|
13645
|
+
]);
|
|
13646
|
+
DataStoreDatabaseSchema.options;
|
|
13647
|
+
/**
|
|
13648
|
+
* One write inside a {@link settingsStoreCapability.methods.transact} call.
|
|
13649
|
+
* The three that a "replace this set, bump that revision" write needs, plus
|
|
13650
|
+
* the batched upsert a rollup writer needs.
|
|
13651
|
+
*/
|
|
13652
|
+
var TransactOpSchema = discriminatedUnion("op", [
|
|
13653
|
+
object({
|
|
13654
|
+
op: literal("deleteWhere"),
|
|
13655
|
+
collection: string(),
|
|
13656
|
+
filter: MutationFilterSchema
|
|
13657
|
+
}),
|
|
13658
|
+
object({
|
|
13659
|
+
op: literal("insertMany"),
|
|
13660
|
+
collection: string(),
|
|
13661
|
+
records: array(BulkRecordSchema).readonly()
|
|
13662
|
+
}),
|
|
13663
|
+
object({
|
|
13664
|
+
op: literal("update"),
|
|
13665
|
+
collection: string(),
|
|
13666
|
+
id: string(),
|
|
13667
|
+
data: record(string(), unknown())
|
|
13668
|
+
}),
|
|
13669
|
+
object({
|
|
13670
|
+
op: literal("upsertMany"),
|
|
13671
|
+
collection: string(),
|
|
13672
|
+
conflict: array(string()).readonly(),
|
|
13673
|
+
records: array(BulkRecordSchema).readonly()
|
|
13674
|
+
})
|
|
13675
|
+
]);
|
|
13676
|
+
/**
|
|
13677
|
+
* The precondition of a transaction: the row `key` of `collection` must hold
|
|
13678
|
+
* `equals` in `column`, read INSIDE the transaction.
|
|
13679
|
+
*/
|
|
13680
|
+
var TransactGuardSchema = object({
|
|
13681
|
+
collection: string(),
|
|
13682
|
+
key: string(),
|
|
13683
|
+
column: string(),
|
|
13684
|
+
equals: unknown()
|
|
13685
|
+
});
|
|
13686
|
+
/**
|
|
13687
|
+
* Column declaration for a structured (SQL-backed) collection.
|
|
13688
|
+
*
|
|
13689
|
+
* Logical types — the backend translates each to the matching SQLite
|
|
13690
|
+
* storage class and handles per-type marshaling:
|
|
13691
|
+
* - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
|
|
13692
|
+
* - `JSON` — TEXT under the hood; serialised on write, parsed on read
|
|
13693
|
+
* - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
|
|
13694
|
+
*/
|
|
13695
|
+
var CollectionColumnSchema = object({
|
|
13696
|
+
name: string(),
|
|
13697
|
+
type: _enum([
|
|
13698
|
+
"TEXT",
|
|
13699
|
+
"INTEGER",
|
|
13700
|
+
"REAL",
|
|
13701
|
+
"JSON",
|
|
13702
|
+
"BOOLEAN"
|
|
13703
|
+
]),
|
|
13704
|
+
primaryKey: boolean().optional(),
|
|
13705
|
+
notNull: boolean().optional(),
|
|
13706
|
+
unique: boolean().optional(),
|
|
13707
|
+
/**
|
|
13708
|
+
* Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
|
|
13709
|
+
* columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
|
|
13710
|
+
* collection surface simply cannot express their existing tables — which is
|
|
13711
|
+
* why they were still on the uncapped `table*` API.
|
|
13712
|
+
*/
|
|
13713
|
+
defaultValue: union([
|
|
13714
|
+
string(),
|
|
13715
|
+
number(),
|
|
13716
|
+
boolean()
|
|
13717
|
+
]).optional()
|
|
13718
|
+
});
|
|
13719
|
+
var CollectionIndexSchema = object({
|
|
13720
|
+
name: string(),
|
|
13721
|
+
columns: array(string()).readonly(),
|
|
13722
|
+
unique: boolean().optional()
|
|
13723
|
+
});
|
|
13724
|
+
/**
|
|
13725
|
+
* The input of `declareCollection` — ONE schema for the door and for the
|
|
13726
|
+
* engine behind it, so the two surfaces cannot drift (the dispatcher forwards
|
|
13727
|
+
* the payload untouched).
|
|
13728
|
+
*
|
|
13729
|
+
* - `database` — the file the collection lives in (D851). Absent means
|
|
13730
|
+
* `settings`. A declaration naming a file other than the one the table is
|
|
13731
|
+
* already in is REFUSED by the engine, never moved.
|
|
13732
|
+
* - `primaryKey` — a COMPOSITE key, as column names. A single name is the same
|
|
13733
|
+
* as `primaryKey: true` on that column. A composite-keyed collection has no
|
|
13734
|
+
* `id`: it is written with `insertMany` / `upsertMany` / `transact` and read
|
|
13735
|
+
* with `query` / `count` / `aggregate` / `deleteWhere`; the calls that
|
|
13736
|
+
* address one row by id are refused.
|
|
13737
|
+
* - `withoutRowid` — emit `WITHOUT ROWID`. Requires a primary key.
|
|
13738
|
+
*/
|
|
13739
|
+
var DeclareCollectionInputSchema = object({
|
|
13740
|
+
namespace: string().optional(),
|
|
13741
|
+
collection: string(),
|
|
13742
|
+
columns: array(CollectionColumnSchema).readonly(),
|
|
13743
|
+
indexes: array(CollectionIndexSchema).readonly().optional(),
|
|
13744
|
+
database: DataStoreDatabaseSchema.optional(),
|
|
13745
|
+
primaryKey: array(string()).readonly().optional(),
|
|
13746
|
+
withoutRowid: boolean().optional()
|
|
13747
|
+
});
|
|
13748
|
+
method(object({
|
|
13749
|
+
namespace: string().optional(),
|
|
13750
|
+
collection: string(),
|
|
13751
|
+
key: string()
|
|
13752
|
+
}), unknown(), { auth: "admin" }), method(object({
|
|
13753
|
+
namespace: string().optional(),
|
|
13754
|
+
collection: string(),
|
|
13755
|
+
key: string(),
|
|
13756
|
+
value: unknown()
|
|
13757
|
+
}), _void(), {
|
|
13758
|
+
kind: "mutation",
|
|
13759
|
+
auth: "admin"
|
|
13760
|
+
}), method(object({
|
|
13761
|
+
namespace: string().optional(),
|
|
13762
|
+
collection: string(),
|
|
13763
|
+
filter: QueryFilterSchema.optional(),
|
|
13764
|
+
columns: array(string()).readonly().optional()
|
|
13765
|
+
}), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
|
|
13766
|
+
namespace: string().optional(),
|
|
13767
|
+
collection: string(),
|
|
13768
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
13769
|
+
* index on the collection. Never empty. */
|
|
13770
|
+
conflict: array(string()).readonly(),
|
|
13771
|
+
record: BulkRecordSchema
|
|
13772
|
+
}), object({
|
|
13773
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
13774
|
+
* row's own id on an update. */
|
|
13775
|
+
id: union([string(), number()]) }), {
|
|
13776
|
+
kind: "mutation",
|
|
13777
|
+
auth: "admin"
|
|
13778
|
+
}), method(object({
|
|
13779
|
+
namespace: string().optional(),
|
|
13780
|
+
collection: string(),
|
|
13781
|
+
conflict: array(string()).readonly(),
|
|
13782
|
+
records: array(BulkRecordSchema).readonly()
|
|
13783
|
+
}), object({ upserted: number().int() }), {
|
|
13784
|
+
kind: "mutation",
|
|
13785
|
+
auth: "admin"
|
|
13786
|
+
}), method(object({
|
|
13787
|
+
namespace: string().optional(),
|
|
13788
|
+
collection: string(),
|
|
13789
|
+
record: object({
|
|
13790
|
+
id: string().optional(),
|
|
13791
|
+
data: record(string(), unknown())
|
|
13792
|
+
})
|
|
13793
|
+
}), object({
|
|
13794
|
+
/**
|
|
13795
|
+
* The id the row ACTUALLY got (D473): the one supplied, the UUID minted
|
|
13796
|
+
* for an absent one, or the ROWID SQLite assigned on an `INTEGER`
|
|
13797
|
+
* primary key — which is the only place an auto key is knowable.
|
|
13798
|
+
*/
|
|
13799
|
+
id: union([string(), number()]) }), {
|
|
13800
|
+
kind: "mutation",
|
|
13801
|
+
auth: "admin"
|
|
13802
|
+
}), method(object({
|
|
13803
|
+
namespace: string().optional(),
|
|
13804
|
+
collection: string(),
|
|
13805
|
+
records: array(BulkRecordSchema).readonly()
|
|
13806
|
+
}), object({ inserted: number().int() }), {
|
|
13807
|
+
kind: "mutation",
|
|
13808
|
+
auth: "admin"
|
|
13809
|
+
}), method(object({
|
|
13810
|
+
namespace: string().optional(),
|
|
13811
|
+
guard: TransactGuardSchema.optional(),
|
|
13812
|
+
ops: array(TransactOpSchema).readonly()
|
|
13813
|
+
}), object({
|
|
13814
|
+
applied: boolean(),
|
|
13815
|
+
current: unknown().optional()
|
|
13816
|
+
}), {
|
|
13817
|
+
kind: "mutation",
|
|
13818
|
+
auth: "admin"
|
|
13819
|
+
}), method(object({
|
|
13820
|
+
namespace: string().optional(),
|
|
13821
|
+
collection: string(),
|
|
13822
|
+
id: string(),
|
|
13823
|
+
data: record(string(), unknown())
|
|
13824
|
+
}), _void(), {
|
|
13825
|
+
kind: "mutation",
|
|
13826
|
+
auth: "admin"
|
|
13827
|
+
}), method(object({
|
|
13828
|
+
namespace: string().optional(),
|
|
13829
|
+
collection: string(),
|
|
13830
|
+
key: string()
|
|
13831
|
+
}), _void(), {
|
|
13832
|
+
kind: "mutation",
|
|
13833
|
+
auth: "admin"
|
|
13834
|
+
}), method(object({
|
|
13835
|
+
namespace: string().optional(),
|
|
13836
|
+
collection: string(),
|
|
13837
|
+
filter: MutationFilterSchema
|
|
13838
|
+
}), object({ deleted: number().int() }), {
|
|
13839
|
+
kind: "mutation",
|
|
13840
|
+
auth: "admin"
|
|
13841
|
+
}), method(object({
|
|
13842
|
+
namespace: string().optional(),
|
|
13843
|
+
collection: string(),
|
|
13844
|
+
filter: MutationFilterSchema,
|
|
13845
|
+
data: record(string(), unknown())
|
|
13846
|
+
}), object({ updated: number().int() }), {
|
|
13847
|
+
kind: "mutation",
|
|
13848
|
+
auth: "admin"
|
|
13849
|
+
}), method(object({
|
|
13850
|
+
namespace: string().optional(),
|
|
13851
|
+
collection: string(),
|
|
13852
|
+
filter: QueryFilterSchema.optional()
|
|
13853
|
+
}), number(), { auth: "admin" }), method(object({
|
|
13854
|
+
namespace: string().optional(),
|
|
13855
|
+
collection: string(),
|
|
13856
|
+
fields: array(AggregateFieldSchema).readonly(),
|
|
13857
|
+
filter: QueryFilterSchema.optional()
|
|
13858
|
+
}), AggregateResultSchema, { auth: "admin" }), method(object({
|
|
13859
|
+
namespace: string().optional(),
|
|
13860
|
+
collection: string(),
|
|
13861
|
+
field: string(),
|
|
13862
|
+
bucketSize: number().int().positive(),
|
|
13863
|
+
origin: number().int(),
|
|
13864
|
+
filter: QueryFilterSchema.optional()
|
|
13865
|
+
}), array(object({
|
|
13866
|
+
bucket: number().int(),
|
|
13867
|
+
count: number().int()
|
|
13868
|
+
})).readonly(), { auth: "admin" }), method(object({
|
|
13869
|
+
namespace: string().optional(),
|
|
13870
|
+
collection: string()
|
|
13871
|
+
}), boolean(), { auth: "admin" }), method(DeclareCollectionInputSchema, _void(), {
|
|
13872
|
+
kind: "mutation",
|
|
13873
|
+
auth: "admin"
|
|
13874
|
+
});
|
|
13875
|
+
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>\"");
|
|
13876
|
+
var MigrationLevelSchema = _enum([
|
|
13877
|
+
"hub-store",
|
|
13878
|
+
"addon-state",
|
|
13879
|
+
"node-config",
|
|
13880
|
+
"viewer",
|
|
13881
|
+
"addon-internal"
|
|
13882
|
+
]);
|
|
13883
|
+
var MigrationStoreSchema = _enum([
|
|
13884
|
+
"settings",
|
|
13885
|
+
"events",
|
|
13886
|
+
"history",
|
|
13887
|
+
"node-local",
|
|
13888
|
+
"addon-files"
|
|
13889
|
+
]);
|
|
13890
|
+
var MigrationScopeSchema = _enum(["cluster", "per-node"]);
|
|
13891
|
+
/** What depends on a migration while it is pending: `block-owner` is the default. */
|
|
13892
|
+
var MigrationOnFailureSchema = _enum(["block-owner", "tolerate"]);
|
|
13893
|
+
/**
|
|
13894
|
+
* `sql` is a hub-only body over the owner's connection. `plan` returns edits the
|
|
13895
|
+
* engine applies inside the migration's own transaction (hub-owned: computed in
|
|
13896
|
+
* that transaction; addon-owned: computed by the owner and shipped to the engine).
|
|
13897
|
+
* `procedure` is addon-owned work that is not SQL (keychain, integration registry,
|
|
13898
|
+
* device tombstones); the ledger records its outcome and it must be idempotent.
|
|
13899
|
+
*/
|
|
13900
|
+
var MigrationBodyKindSchema = _enum([
|
|
13901
|
+
"sql",
|
|
13902
|
+
"plan",
|
|
13903
|
+
"procedure"
|
|
13904
|
+
]);
|
|
13905
|
+
var MigrationMetaSchema = object({
|
|
13906
|
+
id: MigrationIdSchema,
|
|
13907
|
+
/** `hub`, an addon id, `node` or `viewer`. */
|
|
13908
|
+
owner: string().regex(/^[a-z0-9-]+$/),
|
|
13909
|
+
level: MigrationLevelSchema,
|
|
13910
|
+
/** Strictly increasing per owner: the order within an owner. */
|
|
13911
|
+
seq: number().int().positive(),
|
|
13912
|
+
/** Ids of any owner: the order across owners. */
|
|
13913
|
+
dependsOn: array(MigrationIdSchema),
|
|
13914
|
+
store: MigrationStoreSchema,
|
|
13915
|
+
scope: MigrationScopeSchema,
|
|
13916
|
+
onFailure: MigrationOnFailureSchema,
|
|
13917
|
+
bodyKind: MigrationBodyKindSchema,
|
|
13918
|
+
description: string().min(1),
|
|
13919
|
+
/** The marked field the migration's spec must assert survived. */
|
|
13920
|
+
fixtureMark: string().min(1)
|
|
13921
|
+
}).refine((m) => m.id.startsWith(`${m.owner}/`), {
|
|
13922
|
+
message: "the id must start with \"<owner>/\"",
|
|
13923
|
+
path: ["id"]
|
|
13924
|
+
});
|
|
13925
|
+
/** A cycle in the dependency graph, named by the ids on it. */
|
|
13926
|
+
var MigrationCycleError = class extends Error {
|
|
13927
|
+
ids;
|
|
13928
|
+
constructor(ids) {
|
|
13929
|
+
super(`migration dependsOn cycle: ${ids.join(" -> ")}`);
|
|
13930
|
+
this.ids = ids;
|
|
13931
|
+
this.name = "MigrationCycleError";
|
|
13932
|
+
}
|
|
13933
|
+
};
|
|
13934
|
+
/**
|
|
13935
|
+
* Topological order over `dependsOn` plus the implicit edge "a lower `seq` of an
|
|
13936
|
+
* owner runs first". Ties are broken by `(owner, seq)`. Throws
|
|
13937
|
+
* {@link MigrationCycleError} on a cycle. A `dependsOn` id that is not in the list
|
|
13938
|
+
* is ignored here — the catalogue schema is what refuses it.
|
|
13939
|
+
*/
|
|
13940
|
+
function orderMigrations(items) {
|
|
13941
|
+
const byId = new Map(items.map((item) => [item.id, item]));
|
|
13942
|
+
const deps = /* @__PURE__ */ new Map();
|
|
13943
|
+
const ownerSorted = /* @__PURE__ */ new Map();
|
|
13944
|
+
for (const item of items) {
|
|
13945
|
+
const list = ownerSorted.get(item.owner) ?? [];
|
|
13946
|
+
list.push(item);
|
|
13947
|
+
ownerSorted.set(item.owner, list);
|
|
13948
|
+
}
|
|
13949
|
+
for (const item of items) deps.set(item.id, new Set(item.dependsOn.filter((id) => byId.has(id))));
|
|
13950
|
+
for (const list of ownerSorted.values()) {
|
|
13951
|
+
list.sort((a, b) => a.seq - b.seq);
|
|
13952
|
+
for (let i = 1; i < list.length; i++) {
|
|
13953
|
+
const previous = list[i - 1];
|
|
13954
|
+
const current = list[i];
|
|
13955
|
+
if (previous !== void 0 && current !== void 0) deps.get(current.id)?.add(previous.id);
|
|
13956
|
+
}
|
|
13957
|
+
}
|
|
13958
|
+
const tie = (a, b) => a.owner < b.owner ? -1 : a.owner > b.owner ? 1 : a.seq - b.seq;
|
|
13959
|
+
const done = /* @__PURE__ */ new Set();
|
|
13960
|
+
const ordered = [];
|
|
13961
|
+
let remaining = [...items];
|
|
13962
|
+
while (remaining.length > 0) {
|
|
13963
|
+
const ready = remaining.filter((item) => [...deps.get(item.id) ?? []].every((dep) => done.has(dep)));
|
|
13964
|
+
if (ready.length === 0) throw new MigrationCycleError(remaining.map((item) => item.id).sort());
|
|
13965
|
+
ready.sort(tie);
|
|
13966
|
+
const next = ready[0];
|
|
13967
|
+
if (next === void 0) break;
|
|
13968
|
+
ordered.push(next);
|
|
13969
|
+
done.add(next.id);
|
|
13970
|
+
remaining = remaining.filter((item) => item.id !== next.id);
|
|
13971
|
+
}
|
|
13972
|
+
return ordered;
|
|
13973
|
+
}
|
|
13974
|
+
/** Every way a list of migrations (in declaration order) is not a catalogue. */
|
|
13975
|
+
function catalogueIssues(items) {
|
|
13976
|
+
const issues = [];
|
|
13977
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13978
|
+
const known = new Set(items.map((item) => item.id));
|
|
13979
|
+
const lastSeq = /* @__PURE__ */ new Map();
|
|
13980
|
+
const seqUsed = /* @__PURE__ */ new Map();
|
|
13981
|
+
for (const item of items) {
|
|
13982
|
+
if (seen.has(item.id)) issues.push({
|
|
13983
|
+
code: "duplicate-id",
|
|
13984
|
+
ids: [item.id],
|
|
13985
|
+
message: `duplicate id ${item.id}`
|
|
13986
|
+
});
|
|
13987
|
+
seen.add(item.id);
|
|
13988
|
+
const used = seqUsed.get(item.owner) ?? /* @__PURE__ */ new Set();
|
|
13989
|
+
if (used.has(item.seq)) issues.push({
|
|
13990
|
+
code: "duplicate-seq",
|
|
13991
|
+
ids: [item.id],
|
|
13992
|
+
message: `owner ${item.owner} has two migrations with seq ${item.seq}`
|
|
13993
|
+
});
|
|
13994
|
+
else if (item.seq < (lastSeq.get(item.owner) ?? 0)) issues.push({
|
|
13995
|
+
code: "seq-order",
|
|
13996
|
+
ids: [item.id],
|
|
13997
|
+
message: `seq ${item.seq} of ${item.id} does not increase in declaration order (owner ${item.owner})`
|
|
13998
|
+
});
|
|
13999
|
+
used.add(item.seq);
|
|
14000
|
+
seqUsed.set(item.owner, used);
|
|
14001
|
+
lastSeq.set(item.owner, Math.max(item.seq, lastSeq.get(item.owner) ?? 0));
|
|
14002
|
+
for (const dep of item.dependsOn) if (!known.has(dep)) issues.push({
|
|
14003
|
+
code: "unknown-dependency",
|
|
14004
|
+
ids: [item.id, dep],
|
|
14005
|
+
message: `${item.id} dependsOn unknown id ${dep}`
|
|
14006
|
+
});
|
|
14007
|
+
}
|
|
14008
|
+
try {
|
|
14009
|
+
orderMigrations(items);
|
|
14010
|
+
} catch (err) {
|
|
14011
|
+
if (err instanceof MigrationCycleError) issues.push({
|
|
14012
|
+
code: "cycle",
|
|
14013
|
+
ids: err.ids,
|
|
14014
|
+
message: err.message
|
|
14015
|
+
});
|
|
14016
|
+
else throw err;
|
|
14017
|
+
}
|
|
14018
|
+
return issues;
|
|
14019
|
+
}
|
|
14020
|
+
array(MigrationMetaSchema).superRefine((items, ctx) => {
|
|
14021
|
+
for (const issue of catalogueIssues(items)) ctx.addIssue({
|
|
14022
|
+
code: "custom",
|
|
14023
|
+
message: `${issue.code}: ${issue.message}`
|
|
14024
|
+
});
|
|
14025
|
+
});
|
|
14026
|
+
/**
|
|
14027
|
+
* The canonical JSON (`preconditionOf`) of the value a plan read; the apply step
|
|
14028
|
+
* re-reads, and a plan whose read no longer matches is refused (the migration is
|
|
14029
|
+
* `failed`, nothing it edited is kept).
|
|
14030
|
+
*/
|
|
14031
|
+
var PreconditionSchema = string().min(1).optional();
|
|
14032
|
+
var MigrationPlanSchema = object({ edits: array(discriminatedUnion("op", [
|
|
14033
|
+
object({
|
|
14034
|
+
op: literal("setKeys"),
|
|
14035
|
+
scope: string().min(1),
|
|
14036
|
+
values: record(string(), unknown()),
|
|
14037
|
+
precondition: PreconditionSchema
|
|
14038
|
+
}),
|
|
14039
|
+
object({
|
|
14040
|
+
op: literal("deleteKeys"),
|
|
14041
|
+
scope: string().min(1),
|
|
14042
|
+
keys: array(string().min(1)).min(1),
|
|
14043
|
+
precondition: PreconditionSchema
|
|
14044
|
+
}),
|
|
14045
|
+
object({
|
|
14046
|
+
op: literal("putRow"),
|
|
14047
|
+
table: string().min(1),
|
|
14048
|
+
key: record(string(), unknown()),
|
|
14049
|
+
row: record(string(), unknown()),
|
|
14050
|
+
precondition: PreconditionSchema
|
|
14051
|
+
}),
|
|
14052
|
+
object({
|
|
14053
|
+
op: literal("deleteRow"),
|
|
14054
|
+
table: string().min(1),
|
|
14055
|
+
key: record(string(), unknown()),
|
|
14056
|
+
precondition: PreconditionSchema
|
|
14057
|
+
}),
|
|
14058
|
+
object({
|
|
14059
|
+
op: literal("upsertRecord"),
|
|
14060
|
+
kind: string().min(1),
|
|
14061
|
+
recordKey: string().min(1),
|
|
14062
|
+
value: unknown(),
|
|
14063
|
+
precondition: PreconditionSchema
|
|
14064
|
+
}),
|
|
14065
|
+
object({
|
|
14066
|
+
op: literal("deleteRecord"),
|
|
14067
|
+
kind: string().min(1),
|
|
14068
|
+
recordKey: string().min(1),
|
|
14069
|
+
precondition: PreconditionSchema
|
|
14070
|
+
})
|
|
14071
|
+
])) });
|
|
14072
|
+
/**
|
|
14073
|
+
* What a `procedure` body reports. `already-done` means the rerun observed the
|
|
14074
|
+
* work finished (a crash between the work and the ledger row, or a manual fix)
|
|
14075
|
+
* and did none of it again; the ledger records `applied` either way.
|
|
14076
|
+
*/
|
|
14077
|
+
var MigrationProcedureResultSchema = object({
|
|
14078
|
+
outcome: _enum(["done", "already-done"]),
|
|
14079
|
+
summary: record(string(), unknown())
|
|
14080
|
+
});
|
|
14081
|
+
/** What an owner hands the engine when one of its migrations ran. */
|
|
14082
|
+
var MigrationOwnerResultSchema = discriminatedUnion("kind", [
|
|
14083
|
+
object({
|
|
14084
|
+
kind: literal("plan"),
|
|
14085
|
+
plan: MigrationPlanSchema
|
|
14086
|
+
}),
|
|
14087
|
+
object({
|
|
14088
|
+
kind: literal("procedure"),
|
|
14089
|
+
result: MigrationProcedureResultSchema
|
|
14090
|
+
}),
|
|
14091
|
+
object({
|
|
14092
|
+
kind: literal("failed"),
|
|
14093
|
+
error: string().min(1)
|
|
14094
|
+
})
|
|
14095
|
+
]);
|
|
14096
|
+
/**
|
|
14097
|
+
* `held`: a restore of a pre-migration snapshot undid this id; it does not rerun
|
|
14098
|
+
* until the operator retries or a new code version ships.
|
|
14099
|
+
* `skipped-newer`: the database knows an id this code does not.
|
|
14100
|
+
*/
|
|
14101
|
+
var MigrationStatusSchema = _enum([
|
|
14102
|
+
"applied",
|
|
14103
|
+
"failed",
|
|
14104
|
+
"blocked",
|
|
14105
|
+
"running",
|
|
14106
|
+
"held",
|
|
14107
|
+
"skipped-newer"
|
|
14108
|
+
]);
|
|
14109
|
+
var MigrationLedgerEntrySchema = object({
|
|
14110
|
+
id: string(),
|
|
14111
|
+
database: DataStoreDatabaseSchema,
|
|
14112
|
+
owner: string(),
|
|
14113
|
+
level: MigrationLevelSchema,
|
|
14114
|
+
seq: number().int().nonnegative(),
|
|
14115
|
+
status: MigrationStatusSchema,
|
|
14116
|
+
attempts: number().int().nonnegative(),
|
|
14117
|
+
appliedAt: number().nullable(),
|
|
14118
|
+
codeVersion: string().nullable(),
|
|
14119
|
+
/** What the apply changed: rows per table, as the engine counted them. */
|
|
14120
|
+
planSummary: record(string(), unknown()).nullable(),
|
|
14121
|
+
progress: record(string(), unknown()).nullable(),
|
|
14122
|
+
error: string().nullable(),
|
|
14123
|
+
/** Why it is `blocked` or `held` (`dependency-failed`, `snapshot-refused`, …). */
|
|
14124
|
+
reason: string().nullable(),
|
|
14125
|
+
nodeId: string().nullable(),
|
|
14126
|
+
bootId: string().nullable()
|
|
14127
|
+
});
|
|
14128
|
+
/** A catalogued migration that is not applied, with where it stands. */
|
|
14129
|
+
var MigrationPendingEntrySchema = object({
|
|
14130
|
+
meta: MigrationMetaSchema,
|
|
14131
|
+
database: DataStoreDatabaseSchema,
|
|
14132
|
+
state: _enum([
|
|
14133
|
+
"pending",
|
|
14134
|
+
"failed",
|
|
14135
|
+
"blocked",
|
|
14136
|
+
"held"
|
|
14137
|
+
]),
|
|
14138
|
+
reason: string().nullable()
|
|
14139
|
+
});
|
|
14140
|
+
/** Rows per table before and after a dry run, and what it would have changed. */
|
|
14141
|
+
var MigrationDryRunResultSchema = object({
|
|
14142
|
+
id: string(),
|
|
14143
|
+
ok: boolean(),
|
|
14144
|
+
error: string().nullable(),
|
|
14145
|
+
rowsChanged: number().int().nonnegative(),
|
|
14146
|
+
tables: array(object({
|
|
14147
|
+
table: string(),
|
|
14148
|
+
before: number().int().nonnegative(),
|
|
14149
|
+
after: number().int().nonnegative()
|
|
14150
|
+
}))
|
|
14151
|
+
});
|
|
14152
|
+
/** One of an owner's migrations, as the engine tells the owner to treat it this boot. */
|
|
14153
|
+
var MigrationOwnerStepSchema = object({
|
|
14154
|
+
id: MigrationIdSchema,
|
|
14155
|
+
action: _enum(["run", "skip"]),
|
|
14156
|
+
/** The ledger state the engine found: `pending` has no row yet. */
|
|
14157
|
+
state: union([literal("pending"), MigrationStatusSchema])
|
|
14158
|
+
});
|
|
14159
|
+
/**
|
|
13365
14160
|
* The trainer contract — what the hub hands the cloud trainer and what it
|
|
13366
14161
|
* gets back (cloud training, D805+).
|
|
13367
14162
|
*
|
|
@@ -20352,6 +21147,7 @@ var SYSTEM_CAP_VOCABULARY = {
|
|
|
20352
21147
|
"login-method": system(IDENTITY),
|
|
20353
21148
|
"mesh-network": system(NETWORK),
|
|
20354
21149
|
"metrics-provider": system(CLUSTER),
|
|
21150
|
+
migrations: system(INTERNAL),
|
|
20355
21151
|
"model-convert": system(ML),
|
|
20356
21152
|
"model-distributor": system(ML),
|
|
20357
21153
|
"mqtt-broker": system(NETWORK),
|
|
@@ -40554,7 +41350,8 @@ function normalizeUnit(raw) {
|
|
|
40554
41350
|
if (lower === "dbm") return "dBm";
|
|
40555
41351
|
if (lower === "dbfs") return "dBFS";
|
|
40556
41352
|
if (lower === "inhg") return "inHg";
|
|
40557
|
-
if (lower === "mm/h") return "mm/h";
|
|
41353
|
+
if (lower === "mm/h" || lower === "mm/hr") return "mm/h";
|
|
41354
|
+
if (lower === "in/h" || lower === "in/hr") return "in/h";
|
|
40558
41355
|
if (lower === "w/m²" || lower === "w/m2") return "W/m²";
|
|
40559
41356
|
if (lower === "°" || lower === "deg" || lower === "degree" || lower === "degrees") return "°";
|
|
40560
41357
|
if (lower === "kbps") return "kbps";
|
|
@@ -42948,7 +43745,7 @@ function pruneDeletedEntities(selection, live, log, exporter) {
|
|
|
42948
43745
|
* rebuilds without manual reload.
|
|
42949
43746
|
*
|
|
42950
43747
|
* The hub-local builtin `addon-pages-aggregator` (see
|
|
42951
|
-
* `@camstack/system/builtins/addon-pages-aggregator`) registers the
|
|
43748
|
+
* `@camstack/server/system/builtins/addon-pages-aggregator`) registers the
|
|
42952
43749
|
* provider. Splitting the public aggregator from the raw collection
|
|
42953
43750
|
* keeps both ends in codegen — there's no hand-written
|
|
42954
43751
|
* `addon-pages.router.ts` wrapper anymore.
|
|
@@ -43038,7 +43835,7 @@ var addonRoutesCapability = {
|
|
|
43038
43835
|
*/
|
|
43039
43836
|
invoke: method(InvokeRequestSchema, InvokeReplyEnvelopeSchema, { kind: "mutation" })
|
|
43040
43837
|
},
|
|
43041
|
-
/** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
|
|
43838
|
+
/** BIG PLAN 2: declarative mount hint — read by `@camstack/server/system` `buildCapRouters`. */
|
|
43042
43839
|
mount: { kind: "skip" }
|
|
43043
43840
|
};
|
|
43044
43841
|
var ConfigTabDeclarationSchema = object({
|
|
@@ -43267,7 +44064,7 @@ method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" });
|
|
|
43267
44064
|
* manual reload — same scheme used by `addon-pages`.
|
|
43268
44065
|
*
|
|
43269
44066
|
* The hub-local builtin `addon-widgets-aggregator` (see
|
|
43270
|
-
* `@camstack/system/builtins/addon-widgets-aggregator`) registers the
|
|
44067
|
+
* `@camstack/server/system/builtins/addon-widgets-aggregator`) registers the
|
|
43271
44068
|
* provider. Splitting the public aggregator from the raw collection
|
|
43272
44069
|
* keeps both ends in codegen — there's no hand-written wrapper.
|
|
43273
44070
|
*/
|
|
@@ -43628,329 +44425,6 @@ method(object({
|
|
|
43628
44425
|
password: string()
|
|
43629
44426
|
}), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
|
|
43630
44427
|
/**
|
|
43631
|
-
* Query filter for settings-store collections.
|
|
43632
|
-
*/
|
|
43633
|
-
var QueryFilterSchema = object({
|
|
43634
|
-
where: record(string(), unknown()).optional(),
|
|
43635
|
-
whereIn: record(string(), array(unknown())).optional(),
|
|
43636
|
-
whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
|
|
43637
|
-
/** NULL-safe exclusion: matches rows whose field is NULL OR != the value. */
|
|
43638
|
-
whereNot: record(string(), unknown()).optional(),
|
|
43639
|
-
/** NULL-safe exclusion of a SET — `whereNot` for more than one value. An
|
|
43640
|
-
* empty list excludes nothing. See `QueryFilter.whereNotIn`. */
|
|
43641
|
-
whereNotIn: record(string(), array(unknown())).optional(),
|
|
43642
|
-
orderBy: object({
|
|
43643
|
-
field: string(),
|
|
43644
|
-
direction: _enum(["asc", "desc"])
|
|
43645
|
-
}).optional(),
|
|
43646
|
-
limit: number().optional(),
|
|
43647
|
-
offset: number().optional()
|
|
43648
|
-
});
|
|
43649
|
-
/**
|
|
43650
|
-
* The predicate half of a filter, for BULK MUTATIONS.
|
|
43651
|
-
*
|
|
43652
|
-
* Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
|
|
43653
|
-
* meaning for a statement that rewrites a set, and accepting them would invite
|
|
43654
|
-
* a caller to believe `limit` bounds the damage. Every field is optional here
|
|
43655
|
-
* only so the shape stays composable — the implementation REJECTS a filter
|
|
43656
|
-
* that compiles to no predicate, because that is the whole collection.
|
|
43657
|
-
*/
|
|
43658
|
-
var MutationFilterSchema = object({
|
|
43659
|
-
where: record(string(), unknown()).optional(),
|
|
43660
|
-
whereIn: record(string(), array(unknown())).optional(),
|
|
43661
|
-
whereBetween: record(string(), tuple([unknown(), unknown()])).optional(),
|
|
43662
|
-
whereNot: record(string(), unknown()).optional(),
|
|
43663
|
-
whereNotIn: record(string(), array(unknown())).optional()
|
|
43664
|
-
});
|
|
43665
|
-
/**
|
|
43666
|
-
* One scalar an {@link settingsStoreCapability.methods.aggregate} call asks for.
|
|
43667
|
-
*
|
|
43668
|
-
* `as` names the slot in the result, so the SAME column may be asked twice with
|
|
43669
|
-
* two operations (`MIN(startMs)` and `MAX(startMs)` in one round trip) — which
|
|
43670
|
-
* a `Record<column, op>` shape could not express.
|
|
43671
|
-
*/
|
|
43672
|
-
var AggregateFieldSchema = object({
|
|
43673
|
-
/** Result key. */
|
|
43674
|
-
as: string().min(1),
|
|
43675
|
-
/** Column to aggregate. Must be a real column of a declared collection. */
|
|
43676
|
-
field: string().min(1),
|
|
43677
|
-
op: _enum([
|
|
43678
|
-
"sum",
|
|
43679
|
-
"min",
|
|
43680
|
-
"max"
|
|
43681
|
-
])
|
|
43682
|
-
});
|
|
43683
|
-
/**
|
|
43684
|
-
* `COUNT(*)` plus one number per requested field.
|
|
43685
|
-
*
|
|
43686
|
-
* `null` means NO ROW MATCHED, never zero: a `SUM` over an empty set and a sum
|
|
43687
|
-
* that really is 0 are different facts, and an accounting caller that renders
|
|
43688
|
-
* "0 bytes, oldest = 0" for "nothing here" reports a lie about a disk.
|
|
43689
|
-
*/
|
|
43690
|
-
var AggregateResultSchema = object({
|
|
43691
|
-
count: number().int(),
|
|
43692
|
-
values: record(string(), number().nullable())
|
|
43693
|
-
});
|
|
43694
|
-
/** A single stored record: `{ id, data }`. */
|
|
43695
|
-
var SettingsRecordSchema = object({
|
|
43696
|
-
id: string(),
|
|
43697
|
-
data: record(string(), unknown())
|
|
43698
|
-
});
|
|
43699
|
-
/**
|
|
43700
|
-
* One record of a BULK insert — {@link SettingsRecordSchema} with the id made
|
|
43701
|
-
* optional.
|
|
43702
|
-
*
|
|
43703
|
-
* A separate schema rather than loosening the shared one: every other method
|
|
43704
|
-
* on this cap addresses a row BY its id, and making that field optional
|
|
43705
|
-
* everywhere would turn a forgotten key into a silently generated one on
|
|
43706
|
-
* `update` and `delete` as well.
|
|
43707
|
-
*/
|
|
43708
|
-
var BulkRecordSchema = object({
|
|
43709
|
-
id: string().optional(),
|
|
43710
|
-
data: record(string(), unknown())
|
|
43711
|
-
});
|
|
43712
|
-
/**
|
|
43713
|
-
* The database FILES one `sqlite-settings` engine process owns (D851).
|
|
43714
|
-
* Closed on purpose: a file is a thing the engine opens, backs up and gives a
|
|
43715
|
-
* serving thread, so a new one is a code change, never a string a caller
|
|
43716
|
-
* invents. `settings` is `camstack.db` and the default for every collection
|
|
43717
|
-
* that names no file.
|
|
43718
|
-
*/
|
|
43719
|
-
var DataStoreDatabaseSchema = _enum([
|
|
43720
|
-
"settings",
|
|
43721
|
-
"events",
|
|
43722
|
-
"history"
|
|
43723
|
-
]);
|
|
43724
|
-
DataStoreDatabaseSchema.options;
|
|
43725
|
-
/**
|
|
43726
|
-
* One write inside a {@link settingsStoreCapability.methods.transact} call.
|
|
43727
|
-
* The three that a "replace this set, bump that revision" write needs, plus
|
|
43728
|
-
* the batched upsert a rollup writer needs.
|
|
43729
|
-
*/
|
|
43730
|
-
var TransactOpSchema = discriminatedUnion("op", [
|
|
43731
|
-
object({
|
|
43732
|
-
op: literal("deleteWhere"),
|
|
43733
|
-
collection: string(),
|
|
43734
|
-
filter: MutationFilterSchema
|
|
43735
|
-
}),
|
|
43736
|
-
object({
|
|
43737
|
-
op: literal("insertMany"),
|
|
43738
|
-
collection: string(),
|
|
43739
|
-
records: array(BulkRecordSchema).readonly()
|
|
43740
|
-
}),
|
|
43741
|
-
object({
|
|
43742
|
-
op: literal("update"),
|
|
43743
|
-
collection: string(),
|
|
43744
|
-
id: string(),
|
|
43745
|
-
data: record(string(), unknown())
|
|
43746
|
-
}),
|
|
43747
|
-
object({
|
|
43748
|
-
op: literal("upsertMany"),
|
|
43749
|
-
collection: string(),
|
|
43750
|
-
conflict: array(string()).readonly(),
|
|
43751
|
-
records: array(BulkRecordSchema).readonly()
|
|
43752
|
-
})
|
|
43753
|
-
]);
|
|
43754
|
-
/**
|
|
43755
|
-
* The precondition of a transaction: the row `key` of `collection` must hold
|
|
43756
|
-
* `equals` in `column`, read INSIDE the transaction.
|
|
43757
|
-
*/
|
|
43758
|
-
var TransactGuardSchema = object({
|
|
43759
|
-
collection: string(),
|
|
43760
|
-
key: string(),
|
|
43761
|
-
column: string(),
|
|
43762
|
-
equals: unknown()
|
|
43763
|
-
});
|
|
43764
|
-
/**
|
|
43765
|
-
* Column declaration for a structured (SQL-backed) collection.
|
|
43766
|
-
*
|
|
43767
|
-
* Logical types — the backend translates each to the matching SQLite
|
|
43768
|
-
* storage class and handles per-type marshaling:
|
|
43769
|
-
* - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
|
|
43770
|
-
* - `JSON` — TEXT under the hood; serialised on write, parsed on read
|
|
43771
|
-
* - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
|
|
43772
|
-
*/
|
|
43773
|
-
var CollectionColumnSchema = object({
|
|
43774
|
-
name: string(),
|
|
43775
|
-
type: _enum([
|
|
43776
|
-
"TEXT",
|
|
43777
|
-
"INTEGER",
|
|
43778
|
-
"REAL",
|
|
43779
|
-
"JSON",
|
|
43780
|
-
"BOOLEAN"
|
|
43781
|
-
]),
|
|
43782
|
-
primaryKey: boolean().optional(),
|
|
43783
|
-
notNull: boolean().optional(),
|
|
43784
|
-
unique: boolean().optional(),
|
|
43785
|
-
/**
|
|
43786
|
-
* Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
|
|
43787
|
-
* columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
|
|
43788
|
-
* collection surface simply cannot express their existing tables — which is
|
|
43789
|
-
* why they were still on the uncapped `table*` API.
|
|
43790
|
-
*/
|
|
43791
|
-
defaultValue: union([
|
|
43792
|
-
string(),
|
|
43793
|
-
number(),
|
|
43794
|
-
boolean()
|
|
43795
|
-
]).optional()
|
|
43796
|
-
});
|
|
43797
|
-
var CollectionIndexSchema = object({
|
|
43798
|
-
name: string(),
|
|
43799
|
-
columns: array(string()).readonly(),
|
|
43800
|
-
unique: boolean().optional()
|
|
43801
|
-
});
|
|
43802
|
-
/**
|
|
43803
|
-
* The input of `declareCollection` — ONE schema for the door and for the
|
|
43804
|
-
* engine behind it, so the two surfaces cannot drift (the dispatcher forwards
|
|
43805
|
-
* the payload untouched).
|
|
43806
|
-
*
|
|
43807
|
-
* - `database` — the file the collection lives in (D851). Absent means
|
|
43808
|
-
* `settings`. A declaration naming a file other than the one the table is
|
|
43809
|
-
* already in is REFUSED by the engine, never moved.
|
|
43810
|
-
* - `primaryKey` — a COMPOSITE key, as column names. A single name is the same
|
|
43811
|
-
* as `primaryKey: true` on that column. A composite-keyed collection has no
|
|
43812
|
-
* `id`: it is written with `insertMany` / `upsertMany` / `transact` and read
|
|
43813
|
-
* with `query` / `count` / `aggregate` / `deleteWhere`; the calls that
|
|
43814
|
-
* address one row by id are refused.
|
|
43815
|
-
* - `withoutRowid` — emit `WITHOUT ROWID`. Requires a primary key.
|
|
43816
|
-
*/
|
|
43817
|
-
var DeclareCollectionInputSchema = object({
|
|
43818
|
-
namespace: string().optional(),
|
|
43819
|
-
collection: string(),
|
|
43820
|
-
columns: array(CollectionColumnSchema).readonly(),
|
|
43821
|
-
indexes: array(CollectionIndexSchema).readonly().optional(),
|
|
43822
|
-
database: DataStoreDatabaseSchema.optional(),
|
|
43823
|
-
primaryKey: array(string()).readonly().optional(),
|
|
43824
|
-
withoutRowid: boolean().optional()
|
|
43825
|
-
});
|
|
43826
|
-
method(object({
|
|
43827
|
-
namespace: string().optional(),
|
|
43828
|
-
collection: string(),
|
|
43829
|
-
key: string()
|
|
43830
|
-
}), unknown(), { auth: "admin" }), method(object({
|
|
43831
|
-
namespace: string().optional(),
|
|
43832
|
-
collection: string(),
|
|
43833
|
-
key: string(),
|
|
43834
|
-
value: unknown()
|
|
43835
|
-
}), _void(), {
|
|
43836
|
-
kind: "mutation",
|
|
43837
|
-
auth: "admin"
|
|
43838
|
-
}), method(object({
|
|
43839
|
-
namespace: string().optional(),
|
|
43840
|
-
collection: string(),
|
|
43841
|
-
filter: QueryFilterSchema.optional(),
|
|
43842
|
-
columns: array(string()).readonly().optional()
|
|
43843
|
-
}), array(SettingsRecordSchema).readonly(), { auth: "admin" }), method(object({
|
|
43844
|
-
namespace: string().optional(),
|
|
43845
|
-
collection: string(),
|
|
43846
|
-
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
43847
|
-
* index on the collection. Never empty. */
|
|
43848
|
-
conflict: array(string()).readonly(),
|
|
43849
|
-
record: BulkRecordSchema
|
|
43850
|
-
}), object({
|
|
43851
|
-
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
43852
|
-
* row's own id on an update. */
|
|
43853
|
-
id: union([string(), number()]) }), {
|
|
43854
|
-
kind: "mutation",
|
|
43855
|
-
auth: "admin"
|
|
43856
|
-
}), method(object({
|
|
43857
|
-
namespace: string().optional(),
|
|
43858
|
-
collection: string(),
|
|
43859
|
-
conflict: array(string()).readonly(),
|
|
43860
|
-
records: array(BulkRecordSchema).readonly()
|
|
43861
|
-
}), object({ upserted: number().int() }), {
|
|
43862
|
-
kind: "mutation",
|
|
43863
|
-
auth: "admin"
|
|
43864
|
-
}), method(object({
|
|
43865
|
-
namespace: string().optional(),
|
|
43866
|
-
collection: string(),
|
|
43867
|
-
record: object({
|
|
43868
|
-
id: string().optional(),
|
|
43869
|
-
data: record(string(), unknown())
|
|
43870
|
-
})
|
|
43871
|
-
}), object({
|
|
43872
|
-
/**
|
|
43873
|
-
* The id the row ACTUALLY got (D473): the one supplied, the UUID minted
|
|
43874
|
-
* for an absent one, or the ROWID SQLite assigned on an `INTEGER`
|
|
43875
|
-
* primary key — which is the only place an auto key is knowable.
|
|
43876
|
-
*/
|
|
43877
|
-
id: union([string(), number()]) }), {
|
|
43878
|
-
kind: "mutation",
|
|
43879
|
-
auth: "admin"
|
|
43880
|
-
}), method(object({
|
|
43881
|
-
namespace: string().optional(),
|
|
43882
|
-
collection: string(),
|
|
43883
|
-
records: array(BulkRecordSchema).readonly()
|
|
43884
|
-
}), object({ inserted: number().int() }), {
|
|
43885
|
-
kind: "mutation",
|
|
43886
|
-
auth: "admin"
|
|
43887
|
-
}), method(object({
|
|
43888
|
-
namespace: string().optional(),
|
|
43889
|
-
guard: TransactGuardSchema.optional(),
|
|
43890
|
-
ops: array(TransactOpSchema).readonly()
|
|
43891
|
-
}), object({
|
|
43892
|
-
applied: boolean(),
|
|
43893
|
-
current: unknown().optional()
|
|
43894
|
-
}), {
|
|
43895
|
-
kind: "mutation",
|
|
43896
|
-
auth: "admin"
|
|
43897
|
-
}), method(object({
|
|
43898
|
-
namespace: string().optional(),
|
|
43899
|
-
collection: string(),
|
|
43900
|
-
id: string(),
|
|
43901
|
-
data: record(string(), unknown())
|
|
43902
|
-
}), _void(), {
|
|
43903
|
-
kind: "mutation",
|
|
43904
|
-
auth: "admin"
|
|
43905
|
-
}), method(object({
|
|
43906
|
-
namespace: string().optional(),
|
|
43907
|
-
collection: string(),
|
|
43908
|
-
key: string()
|
|
43909
|
-
}), _void(), {
|
|
43910
|
-
kind: "mutation",
|
|
43911
|
-
auth: "admin"
|
|
43912
|
-
}), method(object({
|
|
43913
|
-
namespace: string().optional(),
|
|
43914
|
-
collection: string(),
|
|
43915
|
-
filter: MutationFilterSchema
|
|
43916
|
-
}), object({ deleted: number().int() }), {
|
|
43917
|
-
kind: "mutation",
|
|
43918
|
-
auth: "admin"
|
|
43919
|
-
}), method(object({
|
|
43920
|
-
namespace: string().optional(),
|
|
43921
|
-
collection: string(),
|
|
43922
|
-
filter: MutationFilterSchema,
|
|
43923
|
-
data: record(string(), unknown())
|
|
43924
|
-
}), object({ updated: number().int() }), {
|
|
43925
|
-
kind: "mutation",
|
|
43926
|
-
auth: "admin"
|
|
43927
|
-
}), method(object({
|
|
43928
|
-
namespace: string().optional(),
|
|
43929
|
-
collection: string(),
|
|
43930
|
-
filter: QueryFilterSchema.optional()
|
|
43931
|
-
}), number(), { auth: "admin" }), method(object({
|
|
43932
|
-
namespace: string().optional(),
|
|
43933
|
-
collection: string(),
|
|
43934
|
-
fields: array(AggregateFieldSchema).readonly(),
|
|
43935
|
-
filter: QueryFilterSchema.optional()
|
|
43936
|
-
}), AggregateResultSchema, { auth: "admin" }), method(object({
|
|
43937
|
-
namespace: string().optional(),
|
|
43938
|
-
collection: string(),
|
|
43939
|
-
field: string(),
|
|
43940
|
-
bucketSize: number().int().positive(),
|
|
43941
|
-
origin: number().int(),
|
|
43942
|
-
filter: QueryFilterSchema.optional()
|
|
43943
|
-
}), array(object({
|
|
43944
|
-
bucket: number().int(),
|
|
43945
|
-
count: number().int()
|
|
43946
|
-
})).readonly(), { auth: "admin" }), method(object({
|
|
43947
|
-
namespace: string().optional(),
|
|
43948
|
-
collection: string()
|
|
43949
|
-
}), boolean(), { auth: "admin" }), method(DeclareCollectionInputSchema, _void(), {
|
|
43950
|
-
kind: "mutation",
|
|
43951
|
-
auth: "admin"
|
|
43952
|
-
});
|
|
43953
|
-
/**
|
|
43954
44428
|
* How long one snapshot may take end to end: the pinned copy of the whole
|
|
43955
44429
|
* database plus `PRAGMA integrity_check` over the copy, on the hub's slowest
|
|
43956
44430
|
* disk. ~800 MB at a pessimistic 10 MB/s is under 3 minutes; the bound is
|
|
@@ -45913,7 +46387,7 @@ method(object({
|
|
|
45913
46387
|
kind: "mutation",
|
|
45914
46388
|
auth: "admin"
|
|
45915
46389
|
}), method(object({ blockIds: array(string()) }), object({ states: array(CompositionBlockStateSchema) }), { auth: "admin" });
|
|
45916
|
-
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.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;
|
|
46390
|
+
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;
|
|
45917
46391
|
var NUMBER = {
|
|
45918
46392
|
kind: "fixed",
|
|
45919
46393
|
result: ["number"]
|
|
@@ -46924,6 +47398,57 @@ id: union([string(), number()]) }), {
|
|
|
46924
47398
|
kind: "mutation",
|
|
46925
47399
|
auth: "admin"
|
|
46926
47400
|
});
|
|
47401
|
+
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({
|
|
47402
|
+
id: string().min(1),
|
|
47403
|
+
error: string().min(1)
|
|
47404
|
+
}), MigrationLedgerEntrySchema, {
|
|
47405
|
+
kind: "mutation",
|
|
47406
|
+
auth: "admin"
|
|
47407
|
+
}), method(object({ id: string().min(1) }), object({ entries: array(MigrationLedgerEntrySchema) }), {
|
|
47408
|
+
kind: "mutation",
|
|
47409
|
+
auth: "admin"
|
|
47410
|
+
}), method(object({
|
|
47411
|
+
database: DataStoreDatabaseSchema,
|
|
47412
|
+
snapshotId: string().min(1)
|
|
47413
|
+
}), object({
|
|
47414
|
+
scheduled: boolean(),
|
|
47415
|
+
held: array(string()),
|
|
47416
|
+
restartRequired: boolean()
|
|
47417
|
+
}), {
|
|
47418
|
+
kind: "mutation",
|
|
47419
|
+
auth: "admin"
|
|
47420
|
+
}), method(object({
|
|
47421
|
+
owner: string().min(1),
|
|
47422
|
+
metas: array(MigrationMetaSchema)
|
|
47423
|
+
}), object({
|
|
47424
|
+
bootId: string(),
|
|
47425
|
+
snapshot: _enum([
|
|
47426
|
+
"none",
|
|
47427
|
+
"written",
|
|
47428
|
+
"refused"
|
|
47429
|
+
]),
|
|
47430
|
+
steps: array(MigrationOwnerStepSchema)
|
|
47431
|
+
}), {
|
|
47432
|
+
kind: "mutation",
|
|
47433
|
+
auth: "admin"
|
|
47434
|
+
}), method(object({ id: string().min(1) }), object({
|
|
47435
|
+
proceed: boolean(),
|
|
47436
|
+
state: union([literal("pending"), MigrationStatusSchema]),
|
|
47437
|
+
reason: string().nullable()
|
|
47438
|
+
}), {
|
|
47439
|
+
kind: "mutation",
|
|
47440
|
+
auth: "admin"
|
|
47441
|
+
}), method(object({
|
|
47442
|
+
id: string().min(1),
|
|
47443
|
+
result: MigrationOwnerResultSchema
|
|
47444
|
+
}), object({
|
|
47445
|
+
status: MigrationStatusSchema,
|
|
47446
|
+
error: string().nullable(),
|
|
47447
|
+
rowsChanged: number().int().nonnegative()
|
|
47448
|
+
}), {
|
|
47449
|
+
kind: "mutation",
|
|
47450
|
+
auth: "admin"
|
|
47451
|
+
});
|
|
46927
47452
|
/**
|
|
46928
47453
|
* records - an addon's own facts and documents (D881): ledgers, audit rows,
|
|
46929
47454
|
* config documents, mirrors. The third storage API next to `ctx.settings`
|
|
@@ -61867,7 +62392,18 @@ var ServerUpdateActionResultSchema = object({
|
|
|
61867
62392
|
* store (D877), present when the pre-flight refused the update
|
|
61868
62393
|
* (`reason: 'addon-would-refuse'`). Optional for version skew.
|
|
61869
62394
|
*/
|
|
61870
|
-
blockers: array(UpdateBlockerSchema).optional()
|
|
62395
|
+
blockers: array(UpdateBlockerSchema).optional(),
|
|
62396
|
+
/**
|
|
62397
|
+
* The minimums the target server declares and this node does not meet
|
|
62398
|
+
* (D989), present when the update was refused with
|
|
62399
|
+
* `reason: 'requirements-unmet'`. Each names the versions on both sides.
|
|
62400
|
+
*/
|
|
62401
|
+
unmet: array(UnmetRequirementSchema).optional(),
|
|
62402
|
+
/**
|
|
62403
|
+
* The addons this node has below the minimum the staged server declares —
|
|
62404
|
+
* the ones to update WITH the server. Present on an accepted update.
|
|
62405
|
+
*/
|
|
62406
|
+
requiredAddonUpdates: array(RequiredAddonUpdateSchema).optional()
|
|
61871
62407
|
});
|
|
61872
62408
|
var LaunchOverridesSchema = object({
|
|
61873
62409
|
/** The persisted heap ceiling in MB, or `null` when none is set. */
|
|
@@ -64483,7 +65019,9 @@ var PackageUpdateSchema = object({
|
|
|
64483
65019
|
latestVersion: string(),
|
|
64484
65020
|
category: _enum(["addon", "core"]),
|
|
64485
65021
|
requiresRestart: boolean(),
|
|
64486
|
-
isSystem: boolean()
|
|
65022
|
+
isSystem: boolean(),
|
|
65023
|
+
/** Held: what the newer version needs and this node does not meet (D989). */
|
|
65024
|
+
blockedBy: array(UnmetRequirementSchema).readonly().optional()
|
|
64487
65025
|
});
|
|
64488
65026
|
var PackageVersionInfoSchema = object({
|
|
64489
65027
|
version: string(),
|
|
@@ -69817,7 +70355,7 @@ var lawnMowerControlCapability = {
|
|
|
69817
70355
|
* clients — they reverse-connect to the hub. Exposing their interfaces
|
|
69818
70356
|
* via the same surface would leak internal topology with no upside.
|
|
69819
70357
|
*
|
|
69820
|
-
* Implementation in `@camstack/system/builtins/local-network/`.
|
|
70358
|
+
* Implementation in `@camstack/server/system/builtins/local-network/`.
|
|
69821
70359
|
*/
|
|
69822
70360
|
/** Coarse classification derived from the interface name + IP range. */
|
|
69823
70361
|
var InterfaceKindEnum = _enum([
|
|
@@ -70353,7 +70891,15 @@ var POWER_SOURCE_DEVICE_TYPES = [
|
|
|
70353
70891
|
DeviceType.Sensor,
|
|
70354
70892
|
DeviceType.MediaPlayer,
|
|
70355
70893
|
DeviceType.Vacuum,
|
|
70356
|
-
DeviceType.Generic
|
|
70894
|
+
DeviceType.Generic,
|
|
70895
|
+
DeviceType.Washer,
|
|
70896
|
+
DeviceType.Dryer,
|
|
70897
|
+
DeviceType.Dishwasher,
|
|
70898
|
+
DeviceType.PetFountain,
|
|
70899
|
+
DeviceType.Fan,
|
|
70900
|
+
DeviceType.Humidifier,
|
|
70901
|
+
DeviceType.Climate,
|
|
70902
|
+
DeviceType.WaterHeater
|
|
70357
70903
|
];
|
|
70358
70904
|
var powerSourceCustomize = {
|
|
70359
70905
|
version: 1,
|
|
@@ -71697,7 +72243,7 @@ onStatusChanged: { data: object({
|
|
|
71697
72243
|
* jitter, and observed/peak bandwidth per device + per client.
|
|
71698
72244
|
*
|
|
71699
72245
|
* Implementation lives in the server's `NetworkQualityService` (thin
|
|
71700
|
-
* wrapper over the shared `NetworkQualityTracker` from `@camstack/system`).
|
|
72246
|
+
* wrapper over the shared `NetworkQualityTracker` from `@camstack/server/system`).
|
|
71701
72247
|
* The provider is registered from `trpc.router.ts` against the existing
|
|
71702
72248
|
* service instance — no addon owns this state.
|
|
71703
72249
|
*
|
|
@@ -73848,7 +74394,7 @@ var ptzAutotrackCapability = {
|
|
|
73848
74394
|
* - **Native**: the camera's own firmware autotrack, registered per device by
|
|
73849
74395
|
* the driver when the probe says it exists (Reolink: yes; Hikvision:
|
|
73850
74396
|
* model-dependent).
|
|
73851
|
-
* - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
|
|
74397
|
+
* - **Wrapper**: the emulated implementation (`@camstack/server/system`'s `autotrack` builtin),
|
|
73852
74398
|
* which follows a subject with `ptz.move` pulses driven by the detection
|
|
73853
74399
|
* pipeline. `defaultActive: false` — the operator binds it per camera in
|
|
73854
74400
|
* the bindings UI.
|
|
@@ -84967,6 +85513,69 @@ Object.freeze({
|
|
|
84967
85513
|
access: "view",
|
|
84968
85514
|
role: "admin"
|
|
84969
85515
|
},
|
|
85516
|
+
"migrations.declareOwner": {
|
|
85517
|
+
capName: "migrations",
|
|
85518
|
+
capScope: "system",
|
|
85519
|
+
addonId: null,
|
|
85520
|
+
access: "create",
|
|
85521
|
+
role: "admin"
|
|
85522
|
+
},
|
|
85523
|
+
"migrations.dryRun": {
|
|
85524
|
+
capName: "migrations",
|
|
85525
|
+
capScope: "system",
|
|
85526
|
+
addonId: null,
|
|
85527
|
+
access: "view",
|
|
85528
|
+
role: "admin"
|
|
85529
|
+
},
|
|
85530
|
+
"migrations.finishMigration": {
|
|
85531
|
+
capName: "migrations",
|
|
85532
|
+
capScope: "system",
|
|
85533
|
+
addonId: null,
|
|
85534
|
+
access: "create",
|
|
85535
|
+
role: "admin"
|
|
85536
|
+
},
|
|
85537
|
+
"migrations.listLedger": {
|
|
85538
|
+
capName: "migrations",
|
|
85539
|
+
capScope: "system",
|
|
85540
|
+
addonId: null,
|
|
85541
|
+
access: "view",
|
|
85542
|
+
role: "admin"
|
|
85543
|
+
},
|
|
85544
|
+
"migrations.listPending": {
|
|
85545
|
+
capName: "migrations",
|
|
85546
|
+
capScope: "system",
|
|
85547
|
+
addonId: null,
|
|
85548
|
+
access: "view",
|
|
85549
|
+
role: "admin"
|
|
85550
|
+
},
|
|
85551
|
+
"migrations.markFailed": {
|
|
85552
|
+
capName: "migrations",
|
|
85553
|
+
capScope: "system",
|
|
85554
|
+
addonId: null,
|
|
85555
|
+
access: "create",
|
|
85556
|
+
role: "admin"
|
|
85557
|
+
},
|
|
85558
|
+
"migrations.restorePreMigration": {
|
|
85559
|
+
capName: "migrations",
|
|
85560
|
+
capScope: "system",
|
|
85561
|
+
addonId: null,
|
|
85562
|
+
access: "create",
|
|
85563
|
+
role: "admin"
|
|
85564
|
+
},
|
|
85565
|
+
"migrations.retry": {
|
|
85566
|
+
capName: "migrations",
|
|
85567
|
+
capScope: "system",
|
|
85568
|
+
addonId: null,
|
|
85569
|
+
access: "create",
|
|
85570
|
+
role: "admin"
|
|
85571
|
+
},
|
|
85572
|
+
"migrations.startMigration": {
|
|
85573
|
+
capName: "migrations",
|
|
85574
|
+
capScope: "system",
|
|
85575
|
+
addonId: null,
|
|
85576
|
+
access: "create",
|
|
85577
|
+
role: "admin"
|
|
85578
|
+
},
|
|
84970
85579
|
"modelConvert.convert": {
|
|
84971
85580
|
capName: "model-convert",
|
|
84972
85581
|
capScope: "system",
|
|
@@ -95452,4 +96061,4 @@ async function listHomeAssistantBrokers(query) {
|
|
|
95452
96061
|
return (await query({})).filter((broker) => broker.kind === HA_BROKER_KIND);
|
|
95453
96062
|
}
|
|
95454
96063
|
//#endregion
|
|
95455
|
-
export { humiditySensorCapability as $,
|
|
96064
|
+
export { humiditySensorCapability as $, number as $t, brokerCapability as A, temperatureSensorCapability as At, consumableKindOf as B, RecordSecretUnavailableError as Bt, alarmPanelCapability as C, runningFromVacuumState as Ct, bestLocationMatch as D, smokeCapability as Dt, batteryCapability as E, sendToExportedTarget as Et, carbonMonoxideCapability as F, valveCapability as Ft, deviceAdoptionCapability as G, entryBody as Gt, controlCapability as H, createEvent as Ht, climateControlCapability as I, vibrationCapability as It, eventEmitterCapability as J, _enum as Jt, deviceExportCapability as K, isReadingQuantity as Kt, colorCapability as L, waterHeaterCapability as Lt, buildDeviceAdminUrl as M, tryConvertUnit as Mt, buttonCapability as N, updateCapability as Nt, binaryCapability as O, switchCapability as Ot, calendarSourceCapability as P, vacuumControlCapability as Pt, humidifierCapability as Q, literal as Qt, connectivityCapability as R, weatherCapability as Rt, airQualitySensorCapability as S, runningFromMediaPlayer as St, automationControlCapability as T, scriptRunnerCapability as Tt, coverCapability as U, defineEntryKind as Ut, contactCapability as V, baseUnitOf as Vt, deviceAdminLinkCapability as W, defineRecordKinds as Wt, floodCapability as X, boolean as Xt, fanControlCapability as Y, array as Yt, gasCapability as Z, discriminatedUnion as Zt, PLUG_APPLIANCE_TYPES as _, publicEndpointReaderFrom as _t, BaseDevice as a, url as an, motionCapability as at, accessoriesCapability as b, runExportedAction as bt, COCO_TO_MACRO as c, DeviceType as cn, notifierCapability as ct, ConsumableItemSchema as d, parseAdminBase as dt, object as en, imageCapability as et, ConsumableStatusSchema as f, powerMeterCapability as ft, MediaPlayerRepeatSchema as g, pruneDeletedEntities as gt, HvacModeSchema as h, pressureSensorCapability as ht, AlarmArmModeSchema as i, unknown as in, mediaPlayerCapability as it, buildAddonRouteProvider as j, tryConvertDelta as jt, brightnessCapability as k, tamperCapability as kt, CameraSwitchIdSchema as l, errMsg as ln, numericSensorCapability as lt, FanDirectionSchema as m, presenceCapability as mt, HA_PROVIDER_ADDON_ID as n, string as nn, lawnMowerControlCapability as nt, BaseDeviceProvider as o, DeviceFeature as on, normalizeUnit as ot, EnumSensorDateTimeFormatSchema as p, prepareNotification as pt, enumSensorCapability as q, nodePin as qt, listHomeAssistantBrokers as r, union as rn, lockControlCapability as rt, CAMERA_SWITCH_ORDER as s, DeviceRole as sn, notificationOutputCapability as st, HA_BROKER_KIND as t, record as tn, ingestReading as tt, ConsumableFormSchema as u, EventCategory as un, oauthIntegrationCapability as ut, RUNNING_STATE_COLD as v, quantityFromUnit as vt, ambientLightSensorCapability as w, runningStateCapability as wt, addonRoutesCapability as x, runningFromLawnMower as xt, TargetSchema as y, resolveAttachmentUrls as yt, consumableFormOf as z, BaseAddon as zt };
|