@smarthome.exchange/integrations 1.0.0 → 3.0.0

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.
Files changed (529) hide show
  1. package/changelog.md +84 -0
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/core/classes.configstore.d.ts +2 -0
  4. package/dist_ts/core/classes.configstore.js +84 -27
  5. package/dist_ts/core/classes.nativehomeadmission.d.ts +19 -0
  6. package/dist_ts/core/classes.nativehomeadmission.js +84 -0
  7. package/dist_ts/core/classes.nativeintegrationowner.d.ts +81 -0
  8. package/dist_ts/core/classes.nativeintegrationowner.js +273 -0
  9. package/dist_ts/core/classes.runtimemanager.d.ts +2 -0
  10. package/dist_ts/core/classes.runtimemanager.js +11 -3
  11. package/dist_ts/core/index.d.ts +2 -0
  12. package/dist_ts/core/index.js +3 -1
  13. package/dist_ts/core/types.d.ts +16 -0
  14. package/dist_ts/integrations/braviatv/braviatv.classes.client.d.ts +23 -72
  15. package/dist_ts/integrations/braviatv/braviatv.classes.client.js +265 -625
  16. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.d.ts +7 -7
  17. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.js +51 -68
  18. package/dist_ts/integrations/braviatv/braviatv.classes.integration.d.ts +8 -11
  19. package/dist_ts/integrations/braviatv/braviatv.classes.integration.js +186 -135
  20. package/dist_ts/integrations/braviatv/braviatv.discovery.js +12 -11
  21. package/dist_ts/integrations/braviatv/braviatv.mapper.d.ts +6 -14
  22. package/dist_ts/integrations/braviatv/braviatv.mapper.js +37 -131
  23. package/dist_ts/integrations/braviatv/braviatv.types.d.ts +55 -133
  24. package/dist_ts/integrations/braviatv/braviatv.validation.d.ts +7 -0
  25. package/dist_ts/integrations/braviatv/braviatv.validation.js +72 -0
  26. package/dist_ts/integrations/broadlink/broadlink.actions.d.ts +2 -0
  27. package/dist_ts/integrations/broadlink/broadlink.actions.js +36 -0
  28. package/dist_ts/integrations/broadlink/broadlink.classes.client.d.ts +21 -19
  29. package/dist_ts/integrations/broadlink/broadlink.classes.client.js +185 -124
  30. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.d.ts +5 -4
  31. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.js +64 -83
  32. package/dist_ts/integrations/broadlink/broadlink.classes.integration.d.ts +16 -19
  33. package/dist_ts/integrations/broadlink/broadlink.classes.integration.js +114 -59
  34. package/dist_ts/integrations/broadlink/broadlink.mapper.d.ts +3 -2
  35. package/dist_ts/integrations/broadlink/broadlink.mapper.js +2 -1
  36. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.d.ts +10 -0
  37. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.js +41 -0
  38. package/dist_ts/integrations/broadlink/broadlink.types.d.ts +43 -7
  39. package/dist_ts/integrations/broadlink/broadlink.validation.d.ts +7 -0
  40. package/dist_ts/integrations/broadlink/broadlink.validation.js +63 -0
  41. package/dist_ts/integrations/daikin/daikin.classes.client.d.ts +10 -52
  42. package/dist_ts/integrations/daikin/daikin.classes.client.js +55 -614
  43. package/dist_ts/integrations/daikin/daikin.classes.configflow.d.ts +8 -12
  44. package/dist_ts/integrations/daikin/daikin.classes.configflow.js +77 -138
  45. package/dist_ts/integrations/daikin/daikin.classes.integration.d.ts +7 -24
  46. package/dist_ts/integrations/daikin/daikin.classes.integration.js +175 -67
  47. package/dist_ts/integrations/daikin/daikin.discovery.d.ts +11 -24
  48. package/dist_ts/integrations/daikin/daikin.discovery.js +98 -305
  49. package/dist_ts/integrations/daikin/daikin.mapper.d.ts +6 -7
  50. package/dist_ts/integrations/daikin/daikin.mapper.js +95 -155
  51. package/dist_ts/integrations/daikin/daikin.types.d.ts +24 -44
  52. package/dist_ts/integrations/daikin/daikin.types.js +1 -1
  53. package/dist_ts/integrations/daikin/daikin.validation.d.ts +5 -0
  54. package/dist_ts/integrations/daikin/daikin.validation.js +53 -0
  55. package/dist_ts/integrations/deconz/deconz.classes.client.d.ts +37 -29
  56. package/dist_ts/integrations/deconz/deconz.classes.client.js +521 -294
  57. package/dist_ts/integrations/deconz/deconz.classes.configflow.d.ts +6 -1
  58. package/dist_ts/integrations/deconz/deconz.classes.configflow.js +63 -33
  59. package/dist_ts/integrations/deconz/deconz.classes.integration.d.ts +4 -3
  60. package/dist_ts/integrations/deconz/deconz.classes.integration.js +85 -40
  61. package/dist_ts/integrations/deconz/deconz.mapper.d.ts +1 -0
  62. package/dist_ts/integrations/deconz/deconz.mapper.js +24 -6
  63. package/dist_ts/integrations/deconz/deconz.types.d.ts +43 -6
  64. package/dist_ts/integrations/deconz/deconz.validation.d.ts +7 -1
  65. package/dist_ts/integrations/deconz/deconz.validation.js +215 -4
  66. package/dist_ts/integrations/denonavr/denonavr.classes.client.d.ts +31 -40
  67. package/dist_ts/integrations/denonavr/denonavr.classes.client.js +149 -404
  68. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.d.ts +7 -2
  69. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.js +44 -36
  70. package/dist_ts/integrations/denonavr/denonavr.classes.integration.d.ts +6 -11
  71. package/dist_ts/integrations/denonavr/denonavr.classes.integration.js +192 -113
  72. package/dist_ts/integrations/denonavr/denonavr.discovery.d.ts +10 -18
  73. package/dist_ts/integrations/denonavr/denonavr.discovery.js +71 -193
  74. package/dist_ts/integrations/denonavr/denonavr.mapper.d.ts +5 -13
  75. package/dist_ts/integrations/denonavr/denonavr.mapper.js +35 -159
  76. package/dist_ts/integrations/denonavr/denonavr.types.d.ts +55 -90
  77. package/dist_ts/integrations/denonavr/denonavr.validation.d.ts +10 -0
  78. package/dist_ts/integrations/denonavr/denonavr.validation.js +86 -0
  79. package/dist_ts/integrations/esphome/esphome.classes.client.d.ts +19 -7
  80. package/dist_ts/integrations/esphome/esphome.classes.client.js +183 -89
  81. package/dist_ts/integrations/esphome/esphome.classes.configflow.d.ts +5 -2
  82. package/dist_ts/integrations/esphome/esphome.classes.configflow.js +43 -33
  83. package/dist_ts/integrations/esphome/esphome.classes.integration.d.ts +8 -6
  84. package/dist_ts/integrations/esphome/esphome.classes.integration.js +71 -43
  85. package/dist_ts/integrations/esphome/esphome.discovery.js +4 -12
  86. package/dist_ts/integrations/esphome/esphome.mapper.d.ts +2 -2
  87. package/dist_ts/integrations/esphome/esphome.mapper.js +6 -4
  88. package/dist_ts/integrations/esphome/esphome.types.d.ts +31 -6
  89. package/dist_ts/integrations/esphome/esphome.types.js +1 -1
  90. package/dist_ts/integrations/esphome/esphome.validation.d.ts +7 -0
  91. package/dist_ts/integrations/esphome/esphome.validation.js +66 -0
  92. package/dist_ts/integrations/homeassistant/homeassistant.classes.client.d.ts +32 -4
  93. package/dist_ts/integrations/homeassistant/homeassistant.classes.client.js +345 -116
  94. package/dist_ts/integrations/homeassistant/homeassistant.classes.integration.d.ts +8 -5
  95. package/dist_ts/integrations/homeassistant/homeassistant.classes.integration.js +34 -8
  96. package/dist_ts/integrations/homeassistant/homeassistant.classes.runtime.d.ts +7 -4
  97. package/dist_ts/integrations/homeassistant/homeassistant.classes.runtime.js +44 -56
  98. package/dist_ts/integrations/homeassistant/homeassistant.types.d.ts +12 -1
  99. package/dist_ts/integrations/hue/hue.classes.client.d.ts +6 -1
  100. package/dist_ts/integrations/hue/hue.classes.client.js +120 -45
  101. package/dist_ts/integrations/hue/hue.classes.configflow.js +16 -7
  102. package/dist_ts/integrations/hue/hue.classes.integration.d.ts +2 -0
  103. package/dist_ts/integrations/hue/hue.classes.integration.js +103 -30
  104. package/dist_ts/integrations/hue/hue.validation.d.ts +1 -0
  105. package/dist_ts/integrations/hue/hue.validation.js +14 -4
  106. package/dist_ts/integrations/kodi/kodi.classes.client.d.ts +11 -45
  107. package/dist_ts/integrations/kodi/kodi.classes.client.js +84 -310
  108. package/dist_ts/integrations/kodi/kodi.classes.configflow.d.ts +9 -8
  109. package/dist_ts/integrations/kodi/kodi.classes.configflow.js +53 -48
  110. package/dist_ts/integrations/kodi/kodi.classes.integration.d.ts +11 -11
  111. package/dist_ts/integrations/kodi/kodi.classes.integration.js +114 -171
  112. package/dist_ts/integrations/kodi/kodi.discovery.js +53 -29
  113. package/dist_ts/integrations/kodi/kodi.mapper.d.ts +7 -2
  114. package/dist_ts/integrations/kodi/kodi.mapper.js +48 -10
  115. package/dist_ts/integrations/kodi/kodi.types.d.ts +32 -28
  116. package/dist_ts/integrations/kodi/kodi.validation.d.ts +9 -0
  117. package/dist_ts/integrations/kodi/kodi.validation.js +62 -0
  118. package/dist_ts/integrations/modbus/modbus.classes.client.d.ts +15 -61
  119. package/dist_ts/integrations/modbus/modbus.classes.client.js +117 -776
  120. package/dist_ts/integrations/modbus/modbus.classes.configflow.d.ts +9 -5
  121. package/dist_ts/integrations/modbus/modbus.classes.configflow.js +70 -38
  122. package/dist_ts/integrations/modbus/modbus.classes.integration.d.ts +6 -17
  123. package/dist_ts/integrations/modbus/modbus.classes.integration.js +133 -57
  124. package/dist_ts/integrations/modbus/modbus.discovery.d.ts +5 -8
  125. package/dist_ts/integrations/modbus/modbus.discovery.js +38 -93
  126. package/dist_ts/integrations/modbus/modbus.mapper.d.ts +8 -32
  127. package/dist_ts/integrations/modbus/modbus.mapper.js +71 -431
  128. package/dist_ts/integrations/modbus/modbus.types.d.ts +82 -332
  129. package/dist_ts/integrations/modbus/modbus.validation.d.ts +10 -0
  130. package/dist_ts/integrations/modbus/modbus.validation.js +128 -0
  131. package/dist_ts/integrations/mqtt/mqtt.classes.client.d.ts +15 -2
  132. package/dist_ts/integrations/mqtt/mqtt.classes.client.js +173 -23
  133. package/dist_ts/integrations/mqtt/mqtt.classes.configflow.d.ts +5 -1
  134. package/dist_ts/integrations/mqtt/mqtt.classes.configflow.js +53 -33
  135. package/dist_ts/integrations/mqtt/mqtt.classes.integration.d.ts +4 -1
  136. package/dist_ts/integrations/mqtt/mqtt.classes.integration.js +127 -56
  137. package/dist_ts/integrations/mqtt/mqtt.classes.session.d.ts +13 -0
  138. package/dist_ts/integrations/mqtt/mqtt.classes.session.js +130 -0
  139. package/dist_ts/integrations/mqtt/mqtt.mapper.d.ts +3 -0
  140. package/dist_ts/integrations/mqtt/mqtt.mapper.js +44 -1
  141. package/dist_ts/integrations/mqtt/mqtt.types.d.ts +46 -0
  142. package/dist_ts/integrations/mqtt/mqtt.validation.d.ts +7 -0
  143. package/dist_ts/integrations/mqtt/mqtt.validation.js +180 -0
  144. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.d.ts +12 -34
  145. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.js +143 -231
  146. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.d.ts +6 -1
  147. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.js +105 -18
  148. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.d.ts +8 -8
  149. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.js +141 -155
  150. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.d.ts +9 -0
  151. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.js +35 -0
  152. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.d.ts +6 -18
  153. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.js +45 -220
  154. package/dist_ts/integrations/nanoleaf/nanoleaf.types.d.ts +33 -147
  155. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.d.ts +6 -0
  156. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.js +82 -0
  157. package/dist_ts/integrations/onkyo/onkyo.classes.client.d.ts +15 -20
  158. package/dist_ts/integrations/onkyo/onkyo.classes.client.js +161 -404
  159. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.d.ts +9 -4
  160. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.js +51 -6
  161. package/dist_ts/integrations/onkyo/onkyo.classes.integration.d.ts +22 -6
  162. package/dist_ts/integrations/onkyo/onkyo.classes.integration.js +144 -11
  163. package/dist_ts/integrations/onkyo/onkyo.discovery.d.ts +6 -1
  164. package/dist_ts/integrations/onkyo/onkyo.discovery.js +40 -4
  165. package/dist_ts/integrations/onkyo/onkyo.mapper.d.ts +7 -8
  166. package/dist_ts/integrations/onkyo/onkyo.mapper.js +45 -12
  167. package/dist_ts/integrations/onkyo/onkyo.types.d.ts +58 -8
  168. package/dist_ts/integrations/onkyo/onkyo.types.js +13 -102
  169. package/dist_ts/integrations/onkyo/onkyo.validation.d.ts +16 -0
  170. package/dist_ts/integrations/onkyo/onkyo.validation.js +77 -0
  171. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.d.ts +25 -25
  172. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.js +116 -360
  173. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.d.ts +11 -3
  174. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.js +76 -6
  175. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.d.ts +26 -4
  176. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.js +142 -9
  177. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.d.ts +2 -1
  178. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.js +31 -4
  179. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.d.ts +9 -9
  180. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.js +31 -149
  181. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.d.ts +51 -11
  182. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.js +22 -87
  183. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.d.ts +6 -0
  184. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.js +56 -0
  185. package/dist_ts/integrations/pioneer/pioneer.classes.client.d.ts +31 -16
  186. package/dist_ts/integrations/pioneer/pioneer.classes.client.js +167 -409
  187. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.d.ts +10 -3
  188. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.js +66 -6
  189. package/dist_ts/integrations/pioneer/pioneer.classes.integration.d.ts +13 -5
  190. package/dist_ts/integrations/pioneer/pioneer.classes.integration.js +239 -11
  191. package/dist_ts/integrations/pioneer/pioneer.discovery.d.ts +14 -1
  192. package/dist_ts/integrations/pioneer/pioneer.discovery.js +51 -4
  193. package/dist_ts/integrations/pioneer/pioneer.mapper.d.ts +14 -8
  194. package/dist_ts/integrations/pioneer/pioneer.mapper.js +54 -12
  195. package/dist_ts/integrations/pioneer/pioneer.types.d.ts +79 -12
  196. package/dist_ts/integrations/pioneer/pioneer.types.js +12 -76
  197. package/dist_ts/integrations/pioneer/pioneer.validation.d.ts +10 -0
  198. package/dist_ts/integrations/pioneer/pioneer.validation.js +85 -0
  199. package/dist_ts/integrations/samsungtv/samsungtv.classes.client.d.ts +4 -2
  200. package/dist_ts/integrations/samsungtv/samsungtv.classes.client.js +41 -16
  201. package/dist_ts/integrations/samsungtv/samsungtv.classes.configflow.d.ts +5 -0
  202. package/dist_ts/integrations/samsungtv/samsungtv.classes.configflow.js +20 -7
  203. package/dist_ts/integrations/samsungtv/samsungtv.classes.integration.d.ts +1 -0
  204. package/dist_ts/integrations/samsungtv/samsungtv.classes.integration.js +53 -50
  205. package/dist_ts/integrations/samsungtv/samsungtv.types.d.ts +4 -1
  206. package/dist_ts/integrations/shelly/shelly.classes.client.d.ts +26 -30
  207. package/dist_ts/integrations/shelly/shelly.classes.client.js +504 -276
  208. package/dist_ts/integrations/shelly/shelly.classes.configflow.d.ts +8 -3
  209. package/dist_ts/integrations/shelly/shelly.classes.configflow.js +43 -38
  210. package/dist_ts/integrations/shelly/shelly.classes.integration.d.ts +6 -6
  211. package/dist_ts/integrations/shelly/shelly.classes.integration.js +103 -101
  212. package/dist_ts/integrations/shelly/shelly.classes.subscription.d.ts +4 -0
  213. package/dist_ts/integrations/shelly/shelly.classes.subscription.js +24 -2
  214. package/dist_ts/integrations/shelly/shelly.mapper.d.ts +1 -2
  215. package/dist_ts/integrations/shelly/shelly.mapper.js +21 -20
  216. package/dist_ts/integrations/shelly/shelly.rpc.js +4 -1
  217. package/dist_ts/integrations/shelly/shelly.types.d.ts +42 -2
  218. package/dist_ts/integrations/shelly/shelly.types.js +11 -2
  219. package/dist_ts/integrations/shelly/shelly.validation.d.ts +7 -0
  220. package/dist_ts/integrations/shelly/shelly.validation.js +79 -0
  221. package/dist_ts/integrations/sonos/sonos.classes.client.d.ts +79 -22
  222. package/dist_ts/integrations/sonos/sonos.classes.client.js +427 -139
  223. package/dist_ts/integrations/sonos/sonos.classes.configflow.d.ts +9 -2
  224. package/dist_ts/integrations/sonos/sonos.classes.configflow.js +26 -28
  225. package/dist_ts/integrations/sonos/sonos.classes.integration.d.ts +7 -6
  226. package/dist_ts/integrations/sonos/sonos.classes.integration.js +289 -224
  227. package/dist_ts/integrations/sonos/sonos.config.d.ts +6 -1
  228. package/dist_ts/integrations/sonos/sonos.config.js +23 -2
  229. package/dist_ts/integrations/sonos/sonos.mapper.d.ts +1 -1
  230. package/dist_ts/integrations/sonos/sonos.mapper.js +14 -9
  231. package/dist_ts/integrations/sonos/sonos.matchers.js +3 -3
  232. package/dist_ts/integrations/sonos/sonos.types.d.ts +26 -1
  233. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.d.ts +13 -36
  234. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.js +179 -502
  235. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.d.ts +6 -1
  236. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.js +50 -40
  237. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.d.ts +14 -15
  238. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.js +108 -128
  239. package/dist_ts/integrations/soundtouch/soundtouch.discovery.d.ts +2 -20
  240. package/dist_ts/integrations/soundtouch/soundtouch.discovery.js +23 -113
  241. package/dist_ts/integrations/soundtouch/soundtouch.mapper.d.ts +3 -12
  242. package/dist_ts/integrations/soundtouch/soundtouch.mapper.js +35 -189
  243. package/dist_ts/integrations/soundtouch/soundtouch.types.d.ts +57 -142
  244. package/dist_ts/integrations/soundtouch/soundtouch.types.js +18 -3
  245. package/dist_ts/integrations/soundtouch/soundtouch.validation.d.ts +22 -0
  246. package/dist_ts/integrations/soundtouch/soundtouch.validation.js +65 -0
  247. package/dist_ts/integrations/tasmota/tasmota.classes.integration.d.ts +5 -0
  248. package/dist_ts/integrations/tasmota/tasmota.classes.integration.js +23 -7
  249. package/dist_ts/integrations/tasmota/tasmota.classes.runtime.d.ts +19 -5
  250. package/dist_ts/integrations/tasmota/tasmota.classes.runtime.js +115 -41
  251. package/dist_ts/integrations/tasmota/tasmota.config.js +23 -1
  252. package/dist_ts/integrations/tasmota/tasmota.credentials.d.ts +11 -0
  253. package/dist_ts/integrations/tasmota/tasmota.credentials.js +97 -0
  254. package/dist_ts/integrations/tasmota/tasmota.discovery.d.ts +7 -1
  255. package/dist_ts/integrations/tasmota/tasmota.discovery.js +108 -30
  256. package/dist_ts/integrations/tasmota/tasmota.mapper.d.ts +2 -2
  257. package/dist_ts/integrations/tasmota/tasmota.mapper.js +7 -7
  258. package/dist_ts/integrations/tasmota/tasmota.types.d.ts +41 -2
  259. package/dist_ts/integrations/tuya/tuya.classes.integration.d.ts +4 -1
  260. package/dist_ts/integrations/tuya/tuya.classes.integration.js +79 -110
  261. package/dist_ts/integrations/tuya/tuya.classes.runtime.d.ts +5 -2
  262. package/dist_ts/integrations/tuya/tuya.classes.runtime.js +73 -26
  263. package/dist_ts/integrations/tuya/tuya.mapper.js +2 -2
  264. package/dist_ts/integrations/tuya/tuya.types.d.ts +3 -0
  265. package/dist_ts/integrations/tuya/tuya.validation.d.ts +2 -2
  266. package/dist_ts/integrations/tuya/tuya.validation.js +6 -11
  267. package/dist_ts/integrations/webostv/webostv.classes.client.d.ts +6 -5
  268. package/dist_ts/integrations/webostv/webostv.classes.client.js +147 -76
  269. package/dist_ts/integrations/webostv/webostv.classes.configflow.d.ts +7 -2
  270. package/dist_ts/integrations/webostv/webostv.classes.configflow.js +36 -20
  271. package/dist_ts/integrations/webostv/webostv.classes.integration.d.ts +4 -4
  272. package/dist_ts/integrations/webostv/webostv.classes.integration.js +46 -54
  273. package/dist_ts/integrations/webostv/webostv.mapper.js +5 -5
  274. package/dist_ts/integrations/webostv/webostv.types.d.ts +16 -3
  275. package/dist_ts/integrations/webostv/webostv.types.js +1 -1
  276. package/dist_ts/integrations/webostv/webostv.validation.d.ts +3 -1
  277. package/dist_ts/integrations/webostv/webostv.validation.js +23 -1
  278. package/dist_ts/integrations/wiz/index.d.ts +1 -0
  279. package/dist_ts/integrations/wiz/index.js +2 -1
  280. package/dist_ts/integrations/wiz/wiz.classes.client.d.ts +14 -28
  281. package/dist_ts/integrations/wiz/wiz.classes.client.js +93 -229
  282. package/dist_ts/integrations/wiz/wiz.classes.configflow.d.ts +6 -4
  283. package/dist_ts/integrations/wiz/wiz.classes.configflow.js +38 -67
  284. package/dist_ts/integrations/wiz/wiz.classes.integration.d.ts +10 -21
  285. package/dist_ts/integrations/wiz/wiz.classes.integration.js +204 -44
  286. package/dist_ts/integrations/wiz/wiz.discovery.d.ts +10 -31
  287. package/dist_ts/integrations/wiz/wiz.discovery.js +48 -249
  288. package/dist_ts/integrations/wiz/wiz.mapper.d.ts +7 -51
  289. package/dist_ts/integrations/wiz/wiz.mapper.js +82 -668
  290. package/dist_ts/integrations/wiz/wiz.types.d.ts +34 -208
  291. package/dist_ts/integrations/wiz/wiz.validation.d.ts +8 -0
  292. package/dist_ts/integrations/wiz/wiz.validation.js +72 -0
  293. package/dist_ts/integrations/yamaha/index.d.ts +1 -0
  294. package/dist_ts/integrations/yamaha/index.js +2 -1
  295. package/dist_ts/integrations/yamaha/yamaha.classes.client.d.ts +30 -4
  296. package/dist_ts/integrations/yamaha/yamaha.classes.client.js +162 -6
  297. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.d.ts +10 -3
  298. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.js +106 -6
  299. package/dist_ts/integrations/yamaha/yamaha.classes.integration.d.ts +22 -4
  300. package/dist_ts/integrations/yamaha/yamaha.classes.integration.js +243 -8
  301. package/dist_ts/integrations/yamaha/yamaha.discovery.d.ts +13 -1
  302. package/dist_ts/integrations/yamaha/yamaha.discovery.js +57 -4
  303. package/dist_ts/integrations/yamaha/yamaha.mapper.d.ts +16 -8
  304. package/dist_ts/integrations/yamaha/yamaha.mapper.js +58 -12
  305. package/dist_ts/integrations/yamaha/yamaha.types.d.ts +73 -6
  306. package/dist_ts/integrations/yamaha/yamaha.types.js +8 -94
  307. package/dist_ts/integrations/yamaha/yamaha.validation.d.ts +12 -0
  308. package/dist_ts/integrations/yamaha/yamaha.validation.js +89 -0
  309. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.d.ts +6 -1
  310. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.js +18 -8
  311. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.d.ts +4 -1
  312. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.js +54 -6
  313. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.d.ts +12 -6
  314. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.js +73 -59
  315. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.d.ts +3 -2
  316. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.js +17 -12
  317. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.types.d.ts +31 -2
  318. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.d.ts +9 -1
  319. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.js +57 -7
  320. package/dist_ts/integrations/zwave_js/zwave_js.classes.client.d.ts +10 -4
  321. package/dist_ts/integrations/zwave_js/zwave_js.classes.client.js +167 -31
  322. package/dist_ts/integrations/zwave_js/zwave_js.classes.configflow.d.ts +6 -1
  323. package/dist_ts/integrations/zwave_js/zwave_js.classes.configflow.js +57 -35
  324. package/dist_ts/integrations/zwave_js/zwave_js.classes.integration.d.ts +3 -1
  325. package/dist_ts/integrations/zwave_js/zwave_js.classes.integration.js +59 -37
  326. package/dist_ts/integrations/zwave_js/zwave_js.discovery.js +3 -3
  327. package/dist_ts/integrations/zwave_js/zwave_js.mapper.js +41 -24
  328. package/dist_ts/integrations/zwave_js/zwave_js.types.d.ts +25 -3
  329. package/dist_ts/integrations/zwave_js/zwave_js.validation.d.ts +6 -2
  330. package/dist_ts/integrations/zwave_js/zwave_js.validation.js +52 -17
  331. package/dist_ts/plugins.d.ts +2 -1
  332. package/dist_ts/plugins.js +3 -2
  333. package/package.json +9 -9
  334. package/readme.md +539 -8
  335. package/ts/00_commitinfo_data.ts +1 -1
  336. package/ts/core/classes.configstore.ts +84 -27
  337. package/ts/core/classes.nativehomeadmission.ts +96 -0
  338. package/ts/core/classes.nativeintegrationowner.ts +302 -0
  339. package/ts/core/classes.runtimemanager.ts +11 -2
  340. package/ts/core/index.ts +2 -0
  341. package/ts/core/types.ts +18 -0
  342. package/ts/integrations/braviatv/braviatv.classes.client.ts +245 -709
  343. package/ts/integrations/braviatv/braviatv.classes.configflow.ts +47 -76
  344. package/ts/integrations/braviatv/braviatv.classes.integration.ts +167 -147
  345. package/ts/integrations/braviatv/braviatv.discovery.ts +11 -10
  346. package/ts/integrations/braviatv/braviatv.mapper.ts +39 -142
  347. package/ts/integrations/braviatv/braviatv.types.ts +53 -173
  348. package/ts/integrations/braviatv/braviatv.validation.ts +68 -0
  349. package/ts/integrations/broadlink/broadlink.actions.ts +31 -0
  350. package/ts/integrations/broadlink/broadlink.classes.client.ts +170 -144
  351. package/ts/integrations/broadlink/broadlink.classes.configflow.ts +59 -89
  352. package/ts/integrations/broadlink/broadlink.classes.integration.ts +110 -64
  353. package/ts/integrations/broadlink/broadlink.mapper.ts +5 -4
  354. package/ts/integrations/broadlink/broadlink.selected.mapper.ts +46 -0
  355. package/ts/integrations/broadlink/broadlink.types.ts +48 -8
  356. package/ts/integrations/broadlink/broadlink.validation.ts +66 -0
  357. package/ts/integrations/daikin/daikin.classes.client.ts +52 -661
  358. package/ts/integrations/daikin/daikin.classes.configflow.ts +72 -152
  359. package/ts/integrations/daikin/daikin.classes.integration.ts +166 -71
  360. package/ts/integrations/daikin/daikin.discovery.ts +94 -346
  361. package/ts/integrations/daikin/daikin.mapper.ts +83 -166
  362. package/ts/integrations/daikin/daikin.types.ts +27 -48
  363. package/ts/integrations/daikin/daikin.validation.ts +51 -0
  364. package/ts/integrations/daikin/readme.md +83 -0
  365. package/ts/integrations/deconz/deconz.classes.client.ts +348 -252
  366. package/ts/integrations/deconz/deconz.classes.configflow.ts +57 -29
  367. package/ts/integrations/deconz/deconz.classes.integration.ts +69 -37
  368. package/ts/integrations/deconz/deconz.mapper.ts +22 -5
  369. package/ts/integrations/deconz/deconz.types.ts +49 -6
  370. package/ts/integrations/deconz/deconz.validation.ts +177 -4
  371. package/ts/integrations/deconz/readme.md +15 -1
  372. package/ts/integrations/denonavr/denonavr.classes.client.ts +132 -421
  373. package/ts/integrations/denonavr/denonavr.classes.configflow.ts +44 -37
  374. package/ts/integrations/denonavr/denonavr.classes.integration.ts +171 -117
  375. package/ts/integrations/denonavr/denonavr.discovery.ts +67 -220
  376. package/ts/integrations/denonavr/denonavr.mapper.ts +36 -182
  377. package/ts/integrations/denonavr/denonavr.types.ts +48 -111
  378. package/ts/integrations/denonavr/denonavr.validation.ts +87 -0
  379. package/ts/integrations/esphome/esphome.classes.client.ts +179 -94
  380. package/ts/integrations/esphome/esphome.classes.configflow.ts +40 -33
  381. package/ts/integrations/esphome/esphome.classes.integration.ts +63 -36
  382. package/ts/integrations/esphome/esphome.discovery.ts +3 -12
  383. package/ts/integrations/esphome/esphome.mapper.ts +9 -7
  384. package/ts/integrations/esphome/esphome.types.ts +35 -6
  385. package/ts/integrations/esphome/esphome.validation.ts +66 -0
  386. package/ts/integrations/esphome/readme.md +20 -6
  387. package/ts/integrations/homeassistant/homeassistant.classes.client.ts +353 -125
  388. package/ts/integrations/homeassistant/homeassistant.classes.integration.ts +35 -18
  389. package/ts/integrations/homeassistant/homeassistant.classes.runtime.ts +50 -63
  390. package/ts/integrations/homeassistant/homeassistant.types.ts +17 -1
  391. package/ts/integrations/homeassistant/readme.md +22 -6
  392. package/ts/integrations/hue/hue.classes.client.ts +110 -41
  393. package/ts/integrations/hue/hue.classes.configflow.ts +12 -6
  394. package/ts/integrations/hue/hue.classes.integration.ts +92 -26
  395. package/ts/integrations/hue/hue.validation.ts +13 -3
  396. package/ts/integrations/hue/readme.md +3 -3
  397. package/ts/integrations/kodi/kodi.classes.client.ts +72 -352
  398. package/ts/integrations/kodi/kodi.classes.configflow.ts +52 -55
  399. package/ts/integrations/kodi/kodi.classes.integration.ts +97 -178
  400. package/ts/integrations/kodi/kodi.discovery.ts +49 -28
  401. package/ts/integrations/kodi/kodi.mapper.ts +52 -10
  402. package/ts/integrations/kodi/kodi.types.ts +33 -58
  403. package/ts/integrations/kodi/kodi.validation.ts +60 -0
  404. package/ts/integrations/modbus/modbus.classes.client.ts +100 -842
  405. package/ts/integrations/modbus/modbus.classes.configflow.ts +70 -41
  406. package/ts/integrations/modbus/modbus.classes.integration.ts +115 -60
  407. package/ts/integrations/modbus/modbus.discovery.ts +38 -106
  408. package/ts/integrations/modbus/modbus.mapper.ts +64 -467
  409. package/ts/integrations/modbus/modbus.types.ts +64 -381
  410. package/ts/integrations/modbus/modbus.validation.ts +119 -0
  411. package/ts/integrations/mqtt/mqtt.classes.client.ts +136 -19
  412. package/ts/integrations/mqtt/mqtt.classes.configflow.ts +45 -32
  413. package/ts/integrations/mqtt/mqtt.classes.integration.ts +99 -38
  414. package/ts/integrations/mqtt/mqtt.classes.session.ts +118 -0
  415. package/ts/integrations/mqtt/mqtt.mapper.ts +43 -1
  416. package/ts/integrations/mqtt/mqtt.types.ts +52 -0
  417. package/ts/integrations/mqtt/mqtt.validation.ts +157 -0
  418. package/ts/integrations/mqtt/readme.md +12 -3
  419. package/ts/integrations/nanoleaf/nanoleaf.classes.client.ts +115 -249
  420. package/ts/integrations/nanoleaf/nanoleaf.classes.configflow.ts +90 -19
  421. package/ts/integrations/nanoleaf/nanoleaf.classes.integration.ts +130 -181
  422. package/ts/integrations/nanoleaf/nanoleaf.credentials.ts +39 -0
  423. package/ts/integrations/nanoleaf/nanoleaf.mapper.ts +47 -260
  424. package/ts/integrations/nanoleaf/nanoleaf.types.ts +29 -147
  425. package/ts/integrations/nanoleaf/nanoleaf.validation.ts +77 -0
  426. package/ts/integrations/onkyo/onkyo.classes.client.ts +148 -457
  427. package/ts/integrations/onkyo/onkyo.classes.configflow.ts +52 -6
  428. package/ts/integrations/onkyo/onkyo.classes.integration.ts +121 -12
  429. package/ts/integrations/onkyo/onkyo.discovery.ts +41 -3
  430. package/ts/integrations/onkyo/onkyo.mapper.ts +46 -19
  431. package/ts/integrations/onkyo/onkyo.types.ts +55 -110
  432. package/ts/integrations/onkyo/onkyo.validation.ts +85 -0
  433. package/ts/integrations/onkyo/readme.md +126 -0
  434. package/ts/integrations/panasonic_viera/panasonic_viera.classes.client.ts +101 -398
  435. package/ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.ts +69 -5
  436. package/ts/integrations/panasonic_viera/panasonic_viera.classes.integration.ts +141 -9
  437. package/ts/integrations/panasonic_viera/panasonic_viera.discovery.ts +32 -3
  438. package/ts/integrations/panasonic_viera/panasonic_viera.mapper.ts +34 -161
  439. package/ts/integrations/panasonic_viera/panasonic_viera.types.ts +52 -96
  440. package/ts/integrations/panasonic_viera/panasonic_viera.validation.ts +56 -0
  441. package/ts/integrations/pioneer/pioneer.classes.client.ts +132 -428
  442. package/ts/integrations/pioneer/pioneer.classes.configflow.ts +67 -5
  443. package/ts/integrations/pioneer/pioneer.classes.integration.ts +225 -11
  444. package/ts/integrations/pioneer/pioneer.discovery.ts +45 -3
  445. package/ts/integrations/pioneer/pioneer.mapper.ts +57 -13
  446. package/ts/integrations/pioneer/pioneer.types.ts +87 -85
  447. package/ts/integrations/pioneer/pioneer.validation.ts +84 -0
  448. package/ts/integrations/samsungtv/readme.md +11 -5
  449. package/ts/integrations/samsungtv/samsungtv.classes.client.ts +40 -15
  450. package/ts/integrations/samsungtv/samsungtv.classes.configflow.ts +21 -6
  451. package/ts/integrations/samsungtv/samsungtv.classes.integration.ts +53 -38
  452. package/ts/integrations/samsungtv/samsungtv.types.ts +4 -1
  453. package/ts/integrations/shelly/readme.md +22 -7
  454. package/ts/integrations/shelly/shelly.classes.client.ts +386 -269
  455. package/ts/integrations/shelly/shelly.classes.configflow.ts +43 -38
  456. package/ts/integrations/shelly/shelly.classes.integration.ts +92 -111
  457. package/ts/integrations/shelly/shelly.classes.subscription.ts +24 -1
  458. package/ts/integrations/shelly/shelly.mapper.ts +19 -20
  459. package/ts/integrations/shelly/shelly.rpc.ts +2 -0
  460. package/ts/integrations/shelly/shelly.types.ts +50 -2
  461. package/ts/integrations/shelly/shelly.validation.ts +76 -0
  462. package/ts/integrations/sonos/readme.md +117 -38
  463. package/ts/integrations/sonos/sonos.classes.client.ts +392 -123
  464. package/ts/integrations/sonos/sonos.classes.configflow.ts +25 -28
  465. package/ts/integrations/sonos/sonos.classes.integration.ts +211 -186
  466. package/ts/integrations/sonos/sonos.config.ts +24 -2
  467. package/ts/integrations/sonos/sonos.mapper.ts +13 -8
  468. package/ts/integrations/sonos/sonos.matchers.ts +2 -2
  469. package/ts/integrations/sonos/sonos.types.ts +30 -1
  470. package/ts/integrations/soundtouch/soundtouch.classes.client.ts +152 -571
  471. package/ts/integrations/soundtouch/soundtouch.classes.configflow.ts +47 -42
  472. package/ts/integrations/soundtouch/soundtouch.classes.integration.ts +95 -150
  473. package/ts/integrations/soundtouch/soundtouch.discovery.ts +21 -133
  474. package/ts/integrations/soundtouch/soundtouch.mapper.ts +36 -207
  475. package/ts/integrations/soundtouch/soundtouch.types.ts +50 -195
  476. package/ts/integrations/soundtouch/soundtouch.validation.ts +60 -0
  477. package/ts/integrations/tasmota/readme.md +16 -5
  478. package/ts/integrations/tasmota/tasmota.classes.integration.ts +24 -6
  479. package/ts/integrations/tasmota/tasmota.classes.runtime.ts +112 -43
  480. package/ts/integrations/tasmota/tasmota.config.ts +17 -0
  481. package/ts/integrations/tasmota/tasmota.credentials.ts +92 -0
  482. package/ts/integrations/tasmota/tasmota.discovery.ts +87 -24
  483. package/ts/integrations/tasmota/tasmota.mapper.ts +6 -6
  484. package/ts/integrations/tasmota/tasmota.types.ts +43 -2
  485. package/ts/integrations/tuya/readme.md +52 -10
  486. package/ts/integrations/tuya/tuya.classes.integration.ts +69 -98
  487. package/ts/integrations/tuya/tuya.classes.runtime.ts +70 -24
  488. package/ts/integrations/tuya/tuya.mapper.ts +1 -1
  489. package/ts/integrations/tuya/tuya.types.ts +4 -0
  490. package/ts/integrations/tuya/tuya.validation.ts +5 -8
  491. package/ts/integrations/webostv/readme.md +115 -22
  492. package/ts/integrations/webostv/webostv.classes.client.ts +123 -50
  493. package/ts/integrations/webostv/webostv.classes.configflow.ts +35 -15
  494. package/ts/integrations/webostv/webostv.classes.integration.ts +44 -37
  495. package/ts/integrations/webostv/webostv.mapper.ts +4 -4
  496. package/ts/integrations/webostv/webostv.types.ts +18 -3
  497. package/ts/integrations/webostv/webostv.validation.ts +22 -1
  498. package/ts/integrations/wiz/index.ts +1 -0
  499. package/ts/integrations/wiz/wiz.classes.client.ts +84 -254
  500. package/ts/integrations/wiz/wiz.classes.configflow.ts +39 -70
  501. package/ts/integrations/wiz/wiz.classes.integration.ts +189 -45
  502. package/ts/integrations/wiz/wiz.discovery.ts +48 -291
  503. package/ts/integrations/wiz/wiz.mapper.ts +81 -754
  504. package/ts/integrations/wiz/wiz.types.ts +24 -224
  505. package/ts/integrations/wiz/wiz.validation.ts +73 -0
  506. package/ts/integrations/yamaha/index.ts +1 -0
  507. package/ts/integrations/yamaha/yamaha.classes.client.ts +150 -6
  508. package/ts/integrations/yamaha/yamaha.classes.configflow.ts +100 -5
  509. package/ts/integrations/yamaha/yamaha.classes.integration.ts +236 -8
  510. package/ts/integrations/yamaha/yamaha.discovery.ts +52 -3
  511. package/ts/integrations/yamaha/yamaha.mapper.ts +65 -13
  512. package/ts/integrations/yamaha/yamaha.types.ts +77 -97
  513. package/ts/integrations/yamaha/yamaha.validation.ts +86 -0
  514. package/ts/integrations/zigbee2mqtt/readme.md +22 -27
  515. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.ts +16 -7
  516. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.ts +53 -6
  517. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.ts +62 -49
  518. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.ts +17 -11
  519. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.types.ts +35 -2
  520. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.ts +53 -7
  521. package/ts/integrations/zwave_js/readme.md +42 -9
  522. package/ts/integrations/zwave_js/zwave_js.classes.client.ts +155 -31
  523. package/ts/integrations/zwave_js/zwave_js.classes.configflow.ts +55 -31
  524. package/ts/integrations/zwave_js/zwave_js.classes.integration.ts +57 -35
  525. package/ts/integrations/zwave_js/zwave_js.discovery.ts +2 -2
  526. package/ts/integrations/zwave_js/zwave_js.mapper.ts +37 -23
  527. package/ts/integrations/zwave_js/zwave_js.types.ts +26 -3
  528. package/ts/integrations/zwave_js/zwave_js.validation.ts +52 -18
  529. package/ts/plugins.ts +2 -1
@@ -1,280 +1,146 @@
1
- import type {
2
- INanoleafAuthTokenResult,
3
- INanoleafConfig,
4
- INanoleafControllerInfo,
5
- INanoleafEffects,
6
- INanoleafEffectsCommand,
7
- INanoleafPanelLayout,
8
- INanoleafRhythmInfo,
9
- INanoleafSnapshot,
10
- INanoleafState,
11
- INanoleafStateCommand,
12
- } from './nanoleaf.types.js';
13
-
14
- const DEFAULT_NANOLEAF_PORT = 16021;
1
+ import * as plugins from '../../plugins.js';
2
+ import { NoSqlConfigStore } from '../../core/classes.configstore.js';
3
+ import { createNanoleafCredentialStore, nanoleafCredentialKey, readNanoleafCredential } from './nanoleaf.credentials.js';
4
+ import type { INanoleafConfig, INanoleafIntegrationOptions, INanoleafSnapshot, INanoleafWriteResult } from './nanoleaf.types.js';
5
+ import { normalizeNanoleafConfig } from './nanoleaf.validation.js';
15
6
 
16
7
  export class NanoleafClient {
17
- constructor(private readonly config: INanoleafConfig) {}
18
-
19
- public async getSnapshot(): Promise<INanoleafSnapshot> {
20
- if (this.config.snapshot) {
21
- return this.normalizeSnapshot(this.config.snapshot);
22
- }
23
-
24
- if (this.canRequest()) {
25
- const controllerInfo = await this.requestJson<INanoleafControllerInfo>(this.authenticatedPath(''));
26
- return this.normalizeSnapshot({
27
- controllerInfo,
28
- state: controllerInfo.state ?? {},
29
- effects: controllerInfo.effects ?? {},
30
- panelLayout: controllerInfo.panelLayout,
31
- rhythm: controllerInfo.rhythm,
32
- });
33
- }
34
-
35
- return this.normalizeSnapshot({
36
- controllerInfo: this.config.controllerInfo ?? this.defaultControllerInfo(),
37
- state: this.config.state ?? this.config.controllerInfo?.state ?? {},
38
- effects: this.config.effects ?? this.config.controllerInfo?.effects ?? {},
39
- panelLayout: this.config.panelLayout ?? this.config.controllerInfo?.panelLayout,
40
- rhythm: this.config.rhythm ?? this.config.controllerInfo?.rhythm,
41
- });
42
- }
43
-
44
- public async getControllerInfo(): Promise<INanoleafControllerInfo> {
45
- return (await this.getSnapshot()).controllerInfo;
46
- }
47
-
48
- public async getState(): Promise<INanoleafState> {
49
- if (this.config.snapshot || this.config.state || this.config.controllerInfo?.state || !this.canRequest()) {
50
- return (await this.getSnapshot()).state;
51
- }
52
- return this.requestJson<INanoleafState>(this.authenticatedPath('/state'));
53
- }
54
-
55
- public async getEffects(): Promise<INanoleafEffects> {
56
- if (this.config.snapshot || this.config.effects || this.config.controllerInfo?.effects || !this.canRequest()) {
57
- return (await this.getSnapshot()).effects;
58
- }
59
- return this.requestJson<INanoleafEffects>(this.authenticatedPath('/effects'));
60
- }
61
-
62
- public async getPanelLayout(): Promise<INanoleafPanelLayout | undefined> {
63
- return (await this.getSnapshot()).panelLayout;
64
- }
65
-
66
- public async getRhythm(): Promise<INanoleafRhythmInfo | undefined> {
67
- return (await this.getSnapshot()).rhythm;
68
- }
69
-
70
- public async turnOn(): Promise<void> {
71
- await this.setState({ on: { value: true } });
72
- }
73
-
74
- public async turnOff(transitionArg?: number): Promise<void> {
75
- if (transitionArg === undefined) {
76
- await this.setState({ on: { value: false } });
77
- return;
78
- }
79
- await this.setState({ on: { value: false }, brightness: { value: 0, duration: transitionArg } });
80
- }
81
-
82
- public async setBrightness(percentArg: number, transitionArg?: number): Promise<void> {
83
- await this.setState({
84
- brightness: {
85
- value: this.clamp(Math.round(percentArg), 0, 100),
86
- duration: transitionArg,
8
+ readonly #config: Readonly<INanoleafConfig>;
9
+ readonly #protocol: plugins.ecobridgeDeviceManager.NanoleafProtocol;
10
+ readonly #ownsStore: boolean;
11
+ readonly #lifetime = new AbortController();
12
+ readonly #operations = new Set<Promise<unknown>>();
13
+ #store?: NoSqlConfigStore;
14
+ #healthy = false;
15
+ #closed = false;
16
+ #closePromise?: Promise<void>;
17
+ #retryPromise?: Promise<void>;
18
+ #protocolClosed = false;
19
+ #removeParentAbort: () => void = () => undefined;
20
+
21
+ constructor(configArg: INanoleafConfig, ownerArg?: INanoleafIntegrationOptions | NoSqlConfigStore, signalArg?: AbortSignal, homeIdArg?: string) {
22
+ this.#config = normalizeNanoleafConfig(configArg);
23
+ if (signalArg !== undefined && !(signalArg instanceof AbortSignal)) throw new TypeError('Nanoleaf lifetime signal must be an AbortSignal.');
24
+ if (homeIdArg === undefined) throw new TypeError('Nanoleaf client requires the admitted host home.');
25
+ const store = createNanoleafCredentialStore(this.#config, homeIdArg, ownerArg);
26
+ this.#store = store.store;
27
+ this.#ownsStore = store.owned;
28
+ this.#protocol = new plugins.ecobridgeDeviceManager.NanoleafProtocol({
29
+ origin: this.#config.origin, expectedSerialNumber: this.#config.expectedSerialNumber,
30
+ expectedModel: this.#config.expectedModel, allowUnencryptedHttp: this.#config.allowUnencryptedHttp,
31
+ ca: this.#config.certificateAuthority, timeoutMs: this.#config.timeoutMs,
32
+ maxResponseBytes: this.#config.maxResponseBytes, maxPendingOperations: this.#config.maxPendingOperations,
33
+ getAuthToken: async (signal) => {
34
+ signal.throwIfAborted();
35
+ const currentStore = this.#store;
36
+ if (!currentStore) throw new Error('Nanoleaf client is destroyed.');
37
+ await currentStore.initialize({ signal });
38
+ signal.throwIfAborted();
39
+ const credential: unknown = await currentStore.get(nanoleafCredentialKey(this.#config));
40
+ signal.throwIfAborted();
41
+ return readNanoleafCredential(this.#config, credential);
87
42
  },
88
43
  });
89
- }
90
-
91
- public async setHue(hueArg: number): Promise<void> {
92
- await this.setState({ hue: { value: this.clamp(Math.round(hueArg), 0, 360) } });
93
- }
94
-
95
- public async setSaturation(saturationArg: number): Promise<void> {
96
- await this.setState({ sat: { value: this.clamp(Math.round(saturationArg), 0, 100) } });
97
- }
98
-
99
- public async setColorTemperature(kelvinArg: number): Promise<void> {
100
- await this.setState({ ct: { value: Math.round(kelvinArg) } });
101
- }
102
-
103
- public async setState(stateArg: INanoleafStateCommand): Promise<void> {
104
- this.applyStatePatch(stateArg);
105
- if (this.canRequest()) {
106
- await this.requestJson<void>(this.authenticatedPath('/state'), {
107
- method: 'PUT',
108
- body: stateArg,
109
- });
110
- return;
111
- }
112
- this.assertFixtureMode();
113
- }
114
-
115
- public async setEffect(effectArg: string): Promise<void> {
116
- this.applyEffectsPatch({ select: effectArg });
117
- if (this.canRequest()) {
118
- await this.requestJson<void>(this.authenticatedPath('/effects'), {
119
- method: 'PUT',
120
- body: { select: effectArg },
121
- });
122
- return;
123
- }
124
- this.assertFixtureMode();
125
- }
126
-
127
- public async writeEffectsCommand(commandArg: INanoleafEffectsCommand): Promise<void> {
128
- if (this.canRequest()) {
129
- await this.requestJson<void>(this.authenticatedPath('/effects'), {
130
- method: 'PUT',
131
- body: { write: commandArg },
132
- });
133
- return;
134
- }
135
- this.assertFixtureMode();
136
- }
137
-
138
- public async identify(): Promise<void> {
139
- if (this.canRequest()) {
140
- await this.requestJson<void>(this.authenticatedPath('/identify'), { method: 'PUT' });
141
- return;
44
+ if (signalArg) {
45
+ const aborted = (): void => { void this.destroy(); };
46
+ signalArg.addEventListener('abort', aborted, { once: true });
47
+ this.#removeParentAbort = () => signalArg.removeEventListener('abort', aborted);
48
+ if (signalArg.aborted) aborted();
142
49
  }
143
- this.assertFixtureMode();
144
- }
145
-
146
- public async createAuthToken(): Promise<INanoleafAuthTokenResult> {
147
- return {
148
- success: false,
149
- error: 'Nanoleaf pairing/token generation is not implemented. Put the controller in pairing mode and provide an existing authToken.',
150
- };
151
50
  }
152
51
 
153
- public async destroy(): Promise<void> {}
52
+ public isHealthy(): boolean { return this.#healthy && !this.#closed; }
154
53
 
155
- private normalizeSnapshot(snapshotArg: INanoleafSnapshot): INanoleafSnapshot {
156
- const controllerInfo = snapshotArg.controllerInfo;
157
- const state = snapshotArg.state ?? controllerInfo.state ?? {};
158
- const effects = snapshotArg.effects ?? controllerInfo.effects ?? {};
159
- const panelLayout = snapshotArg.panelLayout ?? controllerInfo.panelLayout;
160
- const rhythm = snapshotArg.rhythm ?? controllerInfo.rhythm;
161
- controllerInfo.state = state;
162
- controllerInfo.effects = effects;
163
- controllerInfo.panelLayout = panelLayout;
164
- controllerInfo.rhythm = rhythm;
165
- return { controllerInfo, state, effects, panelLayout, rhythm };
166
- }
167
-
168
- private applyStatePatch(stateArg: INanoleafStateCommand): void {
169
- const state = this.ensureMutableState();
170
- if (stateArg.on) {
171
- state.on = { ...state.on, ...stateArg.on };
172
- }
173
- if (stateArg.brightness) {
174
- state.brightness = { ...state.brightness, ...stateArg.brightness };
175
- }
176
- if (stateArg.hue) {
177
- state.hue = { ...state.hue, ...stateArg.hue };
178
- }
179
- if (stateArg.sat) {
180
- state.sat = { ...state.sat, ...stateArg.sat };
181
- }
182
- if (stateArg.ct) {
183
- state.ct = { ...state.ct, ...stateArg.ct };
184
- }
54
+ public getSnapshot(signalArg?: AbortSignal): Promise<INanoleafSnapshot> {
55
+ return this.#run(async (signal) => this.#snapshot(await this.#protocol.readSnapshot({ signal })), signalArg);
185
56
  }
186
57
 
187
- private applyEffectsPatch(effectsArg: Partial<INanoleafEffects>): void {
188
- const effects = this.ensureMutableEffects();
189
- Object.assign(effects, effectsArg);
58
+ public setPower(powerArg: boolean, signalArg?: AbortSignal): Promise<INanoleafWriteResult> {
59
+ return this.#setState({ power: powerArg }, signalArg);
190
60
  }
191
61
 
192
- private ensureMutableState(): INanoleafState {
193
- if (this.config.snapshot) {
194
- this.config.snapshot.state ||= {};
195
- this.config.snapshot.controllerInfo.state = this.config.snapshot.state;
196
- return this.config.snapshot.state;
197
- }
198
- this.config.state ||= this.config.controllerInfo?.state ?? {};
199
- if (this.config.controllerInfo) {
200
- this.config.controllerInfo.state = this.config.state;
201
- }
202
- return this.config.state;
62
+ public setBrightness(brightnessArg: number, signalArg?: AbortSignal): Promise<INanoleafWriteResult> {
63
+ return this.#setState({ brightness: brightnessArg }, signalArg);
203
64
  }
204
65
 
205
- private ensureMutableEffects(): INanoleafEffects {
206
- if (this.config.snapshot) {
207
- this.config.snapshot.effects ||= {};
208
- this.config.snapshot.controllerInfo.effects = this.config.snapshot.effects;
209
- return this.config.snapshot.effects;
210
- }
211
- this.config.effects ||= this.config.controllerInfo?.effects ?? {};
212
- if (this.config.controllerInfo) {
213
- this.config.controllerInfo.effects = this.config.effects;
214
- }
215
- return this.config.effects;
66
+ public setColorTemperature(kelvinArg: number, signalArg?: AbortSignal): Promise<INanoleafWriteResult> {
67
+ return this.#setState({ colorTemperatureKelvin: kelvinArg }, signalArg);
216
68
  }
217
69
 
218
- private assertFixtureMode(): void {
219
- if (!this.hasFixtureData()) {
220
- throw new Error('Nanoleaf host and authToken are required when snapshot/manual config data is not provided.');
221
- }
70
+ #setState(commandArg: plugins.ecobridgeDeviceManager.INanoleafStateCommand, signalArg?: AbortSignal): Promise<INanoleafWriteResult> {
71
+ return this.#run(async (signal) => {
72
+ const result = await this.#protocol.setState(commandArg, { signal });
73
+ return Object.freeze({ acceptance: result.acceptance, snapshot: this.#snapshot(result.snapshot) });
74
+ }, signalArg);
222
75
  }
223
76
 
224
- private hasFixtureData(): boolean {
225
- return Boolean(this.config.snapshot || this.config.controllerInfo || this.config.state || this.config.effects || this.config.panelLayout || this.config.rhythm);
77
+ public selectEffect(effectArg: string, signalArg?: AbortSignal): Promise<INanoleafWriteResult> {
78
+ return this.#run(async (signal) => {
79
+ const result = await this.#protocol.selectEffect(effectArg, { signal });
80
+ return Object.freeze({ acceptance: result.acceptance, snapshot: this.#snapshot(result.snapshot) });
81
+ }, signalArg);
226
82
  }
227
83
 
228
- private canRequest(): boolean {
229
- return Boolean(this.config.host && this.authToken());
84
+ public destroy(): Promise<void> {
85
+ if (this.#closePromise) return this.#closePromise;
86
+ this.#closed = true;
87
+ this.#healthy = false;
88
+ this.#removeParentAbort();
89
+ this.#closePromise = Promise.resolve().then(() => this.#drainCleanup());
90
+ this.#lifetime.abort();
91
+ return this.#closePromise;
230
92
  }
231
93
 
232
- private authToken(): string | undefined {
233
- return this.config.authToken || this.config.token;
94
+ /** Explicitly retries retained cleanup; no device operation is replayed. */
95
+ public retryCleanup(): Promise<void> {
96
+ if (!this.#closePromise) return this.destroy();
97
+ if (this.#retryPromise) return this.#retryPromise;
98
+ const retry = this.#closePromise.then(() => undefined, () => this.#drainCleanup(true));
99
+ this.#retryPromise = retry;
100
+ void retry.finally(() => { if (this.#retryPromise === retry) this.#retryPromise = undefined; }).catch(() => undefined);
101
+ return retry;
234
102
  }
235
103
 
236
- private authenticatedPath(pathArg: string): string {
237
- const token = this.authToken();
238
- if (!token) {
239
- throw new Error('Nanoleaf authToken is required for local HTTP requests.');
240
- }
241
- return `/api/v1/${encodeURIComponent(token)}${pathArg}`;
104
+ async #drainCleanup(retryArg = false): Promise<void> {
105
+ const results = await Promise.allSettled([
106
+ Promise.resolve().then(async () => {
107
+ if (!this.#protocolClosed) {
108
+ await this.#protocol.close();
109
+ this.#protocolClosed = true;
110
+ }
111
+ }),
112
+ Promise.allSettled([...this.#operations]),
113
+ ]);
114
+ if (this.#ownsStore && this.#store) {
115
+ results.push(...await Promise.allSettled([Promise.resolve().then(async () => {
116
+ if (retryArg) await this.#store?.retryCleanup();
117
+ else await this.#store?.close();
118
+ this.#store = undefined;
119
+ })]));
120
+ } else if (this.#protocolClosed) this.#store = undefined;
121
+ const failures = results.flatMap((resultArg) => resultArg.status === 'rejected' ? [resultArg.reason as unknown] : []);
122
+ if (failures.length) throw new AggregateError(failures, 'Nanoleaf client cleanup failed.');
242
123
  }
243
124
 
244
- private async requestJson<TResult>(pathArg: string, optionsArg: { method?: string; body?: unknown } = {}): Promise<TResult> {
245
- const response = await globalThis.fetch(`${this.baseUrl()}${pathArg}`, {
246
- method: optionsArg.method ?? (optionsArg.body === undefined ? 'GET' : 'POST'),
247
- headers: optionsArg.body === undefined ? undefined : { 'content-type': 'application/json' },
248
- body: optionsArg.body === undefined ? undefined : JSON.stringify(optionsArg.body),
249
- });
250
- const text = await response.text();
251
- if (!response.ok) {
252
- throw new Error(`Nanoleaf request ${pathArg} failed with HTTP ${response.status}: ${text}`);
253
- }
254
- if (!text) {
255
- return undefined as TResult;
256
- }
257
- return JSON.parse(text) as TResult;
125
+ #snapshot(snapshotArg: plugins.ecobridgeDeviceManager.INanoleafSnapshot): INanoleafSnapshot {
126
+ return Object.freeze({ ...snapshotArg, homeId: this.#config.homeId, origin: this.#config.origin });
258
127
  }
259
128
 
260
- private baseUrl(): string {
261
- if (!this.config.host) {
262
- throw new Error('Nanoleaf host is required for local HTTP requests.');
129
+ #run<TResult>(workArg: (signalArg: AbortSignal) => Promise<TResult>, signalArg?: AbortSignal): Promise<TResult> {
130
+ if (this.#closed) return Promise.reject(new plugins.ecobridgeDeviceManager.NanoleafProtocolError('CLOSED', 'Nanoleaf client is destroyed.'));
131
+ if (this.#operations.size >= (this.#config.maxPendingOperations ?? 32)) {
132
+ return Promise.reject(new plugins.ecobridgeDeviceManager.NanoleafProtocolError('BUSY', 'Nanoleaf client operation capacity is exhausted.'));
263
133
  }
264
- const protocol = this.config.protocol ?? 'http';
265
- const port = this.config.port ?? DEFAULT_NANOLEAF_PORT;
266
- return `${protocol}://${this.config.host}:${port}`;
267
- }
268
-
269
- private defaultControllerInfo(): INanoleafControllerInfo {
270
- return {
271
- name: 'Nanoleaf',
272
- manufacturer: 'Nanoleaf',
273
- model: 'Nanoleaf Controller',
274
- };
275
- }
276
-
277
- private clamp(valueArg: number, minArg: number, maxArg: number): number {
278
- return Math.max(minArg, Math.min(maxArg, valueArg));
134
+ if (signalArg !== undefined && !(signalArg instanceof AbortSignal)) return Promise.reject(new TypeError('Nanoleaf operation signal must be an AbortSignal.'));
135
+ const signal = signalArg ? AbortSignal.any([this.#lifetime.signal, signalArg]) : this.#lifetime.signal;
136
+ const operation = Promise.resolve().then(async () => {
137
+ if (signal.aborted) throw new plugins.ecobridgeDeviceManager.NanoleafProtocolError('ABORTED', 'Nanoleaf operation was cancelled before admission.');
138
+ return workArg(signal);
139
+ }).then((resultArg) => { this.#healthy = !this.#closed && !signal.aborted; return resultArg; }, (errorArg: unknown) => {
140
+ this.#healthy = false;
141
+ throw errorArg;
142
+ }).finally(() => this.#operations.delete(operation));
143
+ this.#operations.add(operation);
144
+ return operation;
279
145
  }
280
146
  }
@@ -1,29 +1,100 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { NativeIntegrationOwner, type NativeIntegrationScope } from '../../core/classes.nativeintegrationowner.js';
3
+ import type { INativeAdmissionContext } from '../../core/classes.nativehomeadmission.js';
1
4
  import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
2
- import type { INanoleafConfig } from './nanoleaf.types.js';
3
-
4
- const DEFAULT_NANOLEAF_PORT = 16021;
5
+ import { createNanoleafCredentialStore, nanoleafCredential, nanoleafCredentialKey } from './nanoleaf.credentials.js';
6
+ import type { INanoleafConfig, INanoleafIntegrationOptions } from './nanoleaf.types.js';
7
+ import { nanoleafKeys, nanoleafRecord, normalizeNanoleafConfig } from './nanoleaf.validation.js';
5
8
 
6
9
  export class NanoleafConfigFlow implements IConfigFlow<INanoleafConfig> {
10
+ readonly #scope: NativeIntegrationScope;
11
+ readonly #credentials?: INanoleafIntegrationOptions;
12
+
13
+ constructor(ownerArg?: INanoleafIntegrationOptions, scopeArg?: NativeIntegrationScope) {
14
+ this.#credentials = ownerArg && Object.freeze({ db: ownerArg.db, keyProvider: ownerArg.keyProvider });
15
+ this.#scope = scopeArg ?? new NativeIntegrationOwner('nanoleaf', { homeId: ownerArg?.homeId }).createFlowScope();
16
+ }
17
+
18
+ public destroy(): Promise<void> { return this.#scope.close(); }
19
+ public retryCleanup(): Promise<void> { return this.#scope.retryCleanup(); }
20
+
7
21
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<INanoleafConfig>> {
8
- void contextArg;
22
+ if (candidateArg.integrationDomain !== undefined && candidateArg.integrationDomain !== 'nanoleaf') {
23
+ return { kind: 'error', error: 'Nanoleaf config flow requires a Nanoleaf candidate.' };
24
+ }
25
+ let context: INativeAdmissionContext;
26
+ try { context = this.#scope.admit(contextArg); }
27
+ catch { return { kind: 'error', error: 'Nanoleaf config flow requires an open instance and the explicit matching host home.' }; }
9
28
  return {
10
- kind: 'form',
11
- title: 'Connect Nanoleaf',
12
- description: 'Configure the local Nanoleaf HTTP endpoint with an existing auth token from the controller.',
29
+ kind: 'form', title: 'Connect selected Nanoleaf controller',
30
+ description: 'Provide the selected local IPv4 origin, serial and documented model. An existing token is validated and stored encrypted for the host-selected home; plaintext vendor HTTP requires explicit consent.',
13
31
  fields: [
14
- { name: 'host', label: 'Host', type: 'text', required: true },
15
- { name: 'port', label: 'Port', type: 'number', required: true },
16
- { name: 'authToken', label: 'Auth token', type: 'password', required: true },
32
+ { name: 'origin', label: 'Selected HTTP(S) IPv4 origin', type: 'text', required: true },
33
+ { name: 'expectedSerialNumber', label: 'Expected serial number', type: 'text', required: true },
34
+ { name: 'expectedModel', label: 'Expected documented controller model', type: 'text', required: true },
35
+ { name: 'credentialKey', label: 'New encrypted credential reference', type: 'text', required: true },
36
+ { name: 'authToken', label: 'Existing controller token', type: 'password', required: true },
37
+ { name: 'allowUnencryptedHttp', label: 'Consent to plaintext local HTTP', type: 'boolean' },
38
+ { name: 'certificateAuthority', label: 'Trusted HTTPS controller PEM certificate', type: 'text' },
17
39
  ],
18
- submit: async (valuesArg) => ({
19
- kind: 'done',
20
- title: 'Nanoleaf configured',
21
- config: {
22
- host: String(valuesArg.host || candidateArg.host || ''),
23
- port: typeof valuesArg.port === 'number' ? valuesArg.port : candidateArg.port || DEFAULT_NANOLEAF_PORT,
24
- authToken: String(valuesArg.authToken || ''),
25
- },
26
- }),
40
+ submit: (valuesArg) => this.#submit(valuesArg, context),
27
41
  };
28
42
  }
43
+
44
+ async #submit(valuesArg: Record<string, unknown>, contextArg: INativeAdmissionContext): Promise<IConfigFlowStep<INanoleafConfig>> {
45
+ let config: Readonly<INanoleafConfig>;
46
+ let credential: ReturnType<typeof nanoleafCredential>;
47
+ try {
48
+ const values = nanoleafRecord(valuesArg, 'config flow values');
49
+ nanoleafKeys(values, ['homeId', 'origin', 'expectedSerialNumber', 'expectedModel', 'credentialKey', 'authToken',
50
+ 'allowUnencryptedHttp', 'certificateAuthority', 'timeoutMs', 'maxResponseBytes', 'maxPendingOperations']);
51
+ if (values.homeId !== undefined && values.homeId !== contextArg.homeId) throw new TypeError('Nanoleaf form home conflicts with the host home.');
52
+ const { authToken, ...configuration } = values;
53
+ config = normalizeNanoleafConfig({ ...configuration, homeId: contextArg.homeId });
54
+ credential = nanoleafCredential(config, authToken);
55
+ this.#scope.admit(contextArg, config.homeId);
56
+ } catch { return { kind: 'error', error: 'Nanoleaf config flow values or host home are invalid, cancelled or closed.' }; }
57
+ return this.#scope.run(contextArg, config.homeId, async (leaseArg): Promise<IConfigFlowStep<INanoleafConfig>> => {
58
+ try {
59
+ const handle = createNanoleafCredentialStore(config, leaseArg.context.homeId, leaseArg.context.configStore ?? this.#credentials);
60
+ let protocol: plugins.ecobridgeDeviceManager.NanoleafProtocol | undefined;
61
+ let protocolClosed = false;
62
+ let storeClosed = !handle.owned;
63
+ let firstStoreCleanup = true;
64
+ // One admitted credential-validation operation owns its protocol and optional store.
65
+ leaseArg.own(async () => {
66
+ const results = await Promise.allSettled([
67
+ Promise.resolve().then(async () => {
68
+ if (protocol && !protocolClosed) { await protocol.close(); protocolClosed = true; }
69
+ }),
70
+ Promise.resolve().then(async () => {
71
+ if (!storeClosed) {
72
+ // Failed lease callbacks run again only on explicit owner cleanup retry.
73
+ if (firstStoreCleanup) { firstStoreCleanup = false; await handle.store.close(); }
74
+ else await handle.store.retryCleanup();
75
+ storeClosed = true;
76
+ }
77
+ }),
78
+ ]);
79
+ const failures = results.flatMap((resultArg) => resultArg.status === 'rejected' ? [resultArg.reason as unknown] : []);
80
+ if (failures.length) throw new AggregateError(failures, 'Nanoleaf flow resource cleanup failed.');
81
+ });
82
+ await handle.store.initialize({ signal: leaseArg.signal });
83
+ leaseArg.assertOpen();
84
+ protocol = new plugins.ecobridgeDeviceManager.NanoleafProtocol({ origin: config.origin,
85
+ expectedSerialNumber: config.expectedSerialNumber, expectedModel: config.expectedModel,
86
+ getAuthToken: () => credential.authToken, allowUnencryptedHttp: config.allowUnencryptedHttp,
87
+ ca: config.certificateAuthority, timeoutMs: config.timeoutMs, maxResponseBytes: config.maxResponseBytes,
88
+ maxPendingOperations: config.maxPendingOperations });
89
+ await protocol.readSnapshot({ signal: leaseArg.signal });
90
+ leaseArg.assertOpen();
91
+ await handle.store.create(nanoleafCredentialKey(config), credential);
92
+ leaseArg.assertOpen();
93
+ return { kind: 'done', title: 'Nanoleaf identity verified and token stored encrypted', config };
94
+ } catch { return { kind: 'error', error: 'Nanoleaf controller validation or encrypted credential persistence failed.' }; }
95
+ }).catch((errorArg: unknown): IConfigFlowStep<INanoleafConfig> => {
96
+ if (errorArg instanceof AggregateError) throw errorArg;
97
+ return { kind: 'error', error: 'Nanoleaf config flow was cancelled or closed.' };
98
+ });
99
+ }
29
100
  }