@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,372 +1,92 @@
1
- import type {
2
- IKodiActivePlayer,
3
- IKodiApplicationProperties,
4
- IKodiConfig,
5
- IKodiDeviceInfo,
6
- IKodiJsonRpcRequest,
7
- IKodiJsonRpcResponse,
8
- IKodiMediaItem,
9
- IKodiPlayerProperties,
10
- IKodiSnapshot,
11
- IKodiTime,
12
- TKodiInputCommand,
13
- TKodiJsonRpcParams,
14
- TKodiMediaType,
15
- } from './kodi.types.js';
16
-
17
- const defaultPort = 8080;
18
- const defaultWsPort = 9090;
19
- const defaultTimeoutMs = 5000;
20
-
21
- const playerProperties = ['time', 'totaltime', 'speed', 'live', 'percentage', 'playlistid', 'position', 'repeat', 'shuffled'];
22
- const itemProperties = ['title', 'file', 'uniqueid', 'thumbnail', 'artist', 'albumartist', 'showtitle', 'album', 'season', 'episode', 'streamdetails'];
23
-
24
- export class KodiJsonRpcError extends Error {
25
- constructor(public readonly method: string, public readonly code: number | undefined, messageArg: string, public readonly data?: unknown) {
26
- super(`Kodi JSON-RPC ${method} failed${typeof code === 'number' ? ` (${code})` : ''}: ${messageArg}`);
27
- this.name = 'KodiJsonRpcError';
28
- }
29
- }
1
+ import * as plugins from '../../plugins.js';
2
+ import { NativeHomeAdmission, type INativeAdmissionContext } from '../../core/classes.nativehomeadmission.js';
3
+ import type { IKodiClientOptions, IKodiConfig, IKodiNativeSnapshot, IKodiSetupContext } from './kodi.types.js';
4
+ import { kodiKeys, kodiRecord, kodiSignal, normalizeKodiConfig } from './kodi.validation.js';
30
5
 
6
+ /** Consumer lifecycle and home projection; the foundation owns all protocol work. */
31
7
  export class KodiClient {
32
- private requestId = 1;
33
-
34
- constructor(private readonly config: IKodiConfig) {}
35
-
36
- public async getSnapshot(): Promise<IKodiSnapshot> {
37
- if (this.config.snapshot) {
38
- return this.normalizeSnapshot(this.cloneSnapshot(this.config.snapshot));
39
- }
40
- if (!this.config.host) {
41
- return this.normalizeSnapshot({
42
- deviceInfo: this.deviceInfoFromConfig(),
43
- players: [],
44
- online: false,
45
- updatedAt: new Date().toISOString(),
46
- });
47
- }
48
-
49
- const [application, players] = await Promise.all([
50
- this.getApplicationProperties().catch(() => undefined),
51
- this.getActivePlayers(),
52
- ]);
53
- const player = players[0];
54
- const [playerPropertiesResult, item] = player ? await Promise.all([
55
- this.getPlayerProperties(player.playerid).catch(() => undefined),
56
- this.getPlayerItem(player.playerid).catch(() => undefined),
57
- ]) : [undefined, undefined];
58
-
59
- return this.normalizeSnapshot({
60
- deviceInfo: {
61
- ...this.deviceInfoFromConfig(),
62
- name: this.config.name || this.config.deviceInfo?.name || application?.name || this.config.host,
63
- version: this.versionString(application),
64
- },
65
- application,
66
- players,
67
- player,
68
- playerProperties: playerPropertiesResult,
69
- item,
70
- online: true,
71
- updatedAt: new Date().toISOString(),
72
- });
73
- }
74
-
75
- public async ping(): Promise<boolean> {
76
- const result = await this.callMethod<string>('JSONRPC.Ping');
77
- return result === 'pong';
78
- }
79
-
80
- public async getApplicationProperties(): Promise<IKodiApplicationProperties> {
81
- return this.callMethod<IKodiApplicationProperties>('Application.GetProperties', {
82
- properties: ['name', 'version', 'volume', 'muted'],
83
- });
84
- }
85
-
86
- public async getActivePlayers(): Promise<IKodiActivePlayer[]> {
87
- return this.callMethod<IKodiActivePlayer[]>('Player.GetActivePlayers');
88
- }
89
-
90
- public async getPlayerProperties(playerIdArg: number): Promise<IKodiPlayerProperties> {
91
- return this.callMethod<IKodiPlayerProperties>('Player.GetProperties', {
92
- playerid: playerIdArg,
93
- properties: playerProperties,
8
+ readonly #config: Readonly<IKodiConfig>;
9
+ readonly #context: INativeAdmissionContext;
10
+ readonly #protocol: plugins.ecobridgeDeviceManager.KodiProtocol;
11
+ readonly #lifetime = new AbortController();
12
+ readonly #parentSignal?: AbortSignal;
13
+ readonly #onParentAbort: () => void;
14
+ readonly #operations = new Set<Promise<unknown>>();
15
+ #closed = false;
16
+ #healthy = false;
17
+ #closePromise?: Promise<void>;
18
+
19
+ public constructor(config: IKodiConfig, context: IKodiSetupContext, options: IKodiClientOptions = {}) {
20
+ this.#config = normalizeKodiConfig(config);
21
+ this.#context = new NativeHomeAdmission('kodi').admit(context, this.#config.homeId);
22
+ const value = kodiRecord(options, 'client options');
23
+ kodiKeys(value, ['getBasicCredentials']);
24
+ this.#parentSignal = this.#context.abortSignal;
25
+ if (value.getBasicCredentials !== undefined && typeof value.getBasicCredentials !== 'function') throw new TypeError('Kodi Basic provider must be a function.');
26
+ this.#parentSignal?.throwIfAborted();
27
+ this.#protocol = new plugins.ecobridgeDeviceManager.KodiProtocol({
28
+ origin: this.#config.origin, expectedApplicationName: this.#config.expectedApplicationName,
29
+ expectedApplicationMajor: this.#config.expectedApplicationMajor, allowUnencryptedHttp: true,
30
+ control: this.#config.control, timeoutMs: this.#config.timeoutMs,
31
+ maxQueuedOperations: this.#config.maxQueuedOperations, maxResponseBytes: this.#config.maxResponseBytes,
32
+ getBasicCredentials: value.getBasicCredentials as IKodiClientOptions['getBasicCredentials'],
94
33
  });
34
+ this.#onParentAbort = () => { void this.destroy().catch(() => {}); };
35
+ this.#parentSignal?.addEventListener('abort', this.#onParentAbort, { once: true });
36
+ if (this.#parentSignal?.aborted) this.#onParentAbort();
95
37
  }
96
38
 
97
- public async getPlayerItem(playerIdArg: number): Promise<IKodiMediaItem | undefined> {
98
- const result = await this.callMethod<{ item?: IKodiMediaItem }>('Player.GetItem', {
99
- playerid: playerIdArg,
100
- properties: itemProperties,
101
- });
102
- return result.item;
103
- }
104
-
105
- public async setVolumeLevel(volumeLevelArg: number): Promise<number> {
106
- return this.callMethod<number>('Application.SetVolume', {
107
- volume: Math.max(0, Math.min(100, Math.round(volumeLevelArg * 100))),
108
- });
109
- }
110
-
111
- public async stepVolume(directionArg: 'increment' | 'decrement'): Promise<number> {
112
- return this.callMethod<number>('Application.SetVolume', { volume: directionArg });
113
- }
114
-
115
- public async setMuted(mutedArg: boolean): Promise<boolean> {
116
- return this.callMethod<boolean>('Application.SetMute', { mute: mutedArg });
117
- }
118
-
119
- public async playPause(): Promise<unknown> {
120
- return this.playState('toggle');
121
- }
122
-
123
- public async play(): Promise<unknown> {
124
- return this.playState(true);
125
- }
126
-
127
- public async pause(): Promise<unknown> {
128
- return this.playState(false);
129
- }
130
-
131
- public async stop(): Promise<string> {
132
- return this.callMethod<string>('Player.Stop', { playerid: await this.activePlayerId() });
133
- }
134
-
135
- public async nextTrack(): Promise<string> {
136
- return this.callMethod<string>('Player.GoTo', { playerid: await this.activePlayerId(), to: 'next' });
137
- }
138
-
139
- public async previousTrack(): Promise<string> {
140
- return this.callMethod<string>('Player.GoTo', { playerid: await this.activePlayerId(), to: 'previous' });
141
- }
142
-
143
- public async seek(positionSecondsArg: number): Promise<unknown> {
144
- return this.callMethod('Player.Seek', {
145
- playerid: await this.activePlayerId(),
146
- value: { time: this.secondsToTime(positionSecondsArg) },
147
- });
148
- }
39
+ public isHealthy(): boolean { return this.#healthy && !this.#closed && !this.#protocol.isClosed; }
149
40
 
150
- public async playMedia(mediaTypeArg: TKodiMediaType, mediaIdArg: string | number): Promise<string> {
151
- return this.callMethod<string>('Player.Open', { item: this.mediaItem(mediaTypeArg, mediaIdArg) });
41
+ public getSnapshot(signal?: AbortSignal): Promise<IKodiNativeSnapshot> {
42
+ return this.run(async (signal) => this.project(await this.#protocol.readSnapshot({ signal })), signal);
152
43
  }
153
44
 
154
- public async clearPlaylist(playlistIdArg = 0): Promise<string> {
155
- return this.callMethod<string>('Playlist.Clear', { playlistid: playlistIdArg });
45
+ public setVolume(volume: number, signal?: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IKodiControlReceipt> {
46
+ return this.run((signal) => this.#protocol.setVolume(volume, { signal }), signal);
156
47
  }
157
48
 
158
- public async addToPlaylist(mediaTypeArg: TKodiMediaType, mediaIdArg: string | number, playlistIdArg = 0): Promise<string> {
159
- return this.callMethod<string>('Playlist.Add', {
160
- playlistid: playlistIdArg,
161
- item: this.playlistItem(mediaTypeArg, mediaIdArg),
162
- });
49
+ public setMuted(muted: boolean, signal?: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IKodiControlReceipt> {
50
+ return this.run((signal) => this.#protocol.setMuted(muted, { signal }), signal);
163
51
  }
164
52
 
165
- public async showNotification(titleArg: string, messageArg: string, iconArg = 'info', displayTimeMsArg = 10000): Promise<string> {
166
- return this.callMethod<string>('GUI.ShowNotification', {
167
- title: titleArg,
168
- message: messageArg,
169
- image: iconArg,
170
- displaytime: Math.max(1500, Math.round(displayTimeMsArg)),
53
+ public destroy(): Promise<void> {
54
+ if (this.#closePromise) return this.#closePromise;
55
+ this.#closed = true;
56
+ this.#healthy = false;
57
+ this.#closePromise = Promise.resolve().then(async () => {
58
+ const [protocolCleanup] = await Promise.allSettled([this.#protocol.close(), ...this.#operations]);
59
+ // Operation failures belong to their callers; this close still joins every projection.
60
+ if (protocolCleanup.status === 'rejected') throw protocolCleanup.reason;
171
61
  });
62
+ this.#parentSignal?.removeEventListener('abort', this.#onParentAbort);
63
+ this.#lifetime.abort(new Error('Kodi client is closed.'));
64
+ return this.#closePromise;
172
65
  }
173
66
 
174
- public async input(commandArg: TKodiInputCommand): Promise<string | unknown> {
175
- const method = this.inputMethod(commandArg);
176
- return this.callMethod(method);
67
+ private project(state: plugins.ecobridgeDeviceManager.IKodiSnapshot): IKodiNativeSnapshot {
68
+ return Object.freeze({ ...state, homeId: this.#context.homeId, name: this.#config.name ?? state.applicationName, online: true });
177
69
  }
178
70
 
179
- public async quit(): Promise<string> {
180
- return this.callMethod<string>('Application.Quit');
181
- }
182
-
183
- public async callMethod<T = unknown>(methodArg: string, paramsArg?: TKodiJsonRpcParams): Promise<T> {
184
- if (!this.config.host) {
185
- throw new Error('Kodi host is required when snapshot data is not provided.');
186
- }
187
-
188
- const request: IKodiJsonRpcRequest = {
189
- jsonrpc: '2.0',
190
- method: methodArg,
191
- id: this.requestId++,
192
- };
193
- if (paramsArg !== undefined) {
194
- request.params = paramsArg;
195
- }
196
-
197
- const abortController = new AbortController();
198
- const timeout = setTimeout(() => abortController.abort(), this.config.timeoutMs || defaultTimeoutMs);
71
+ private run<TResult>(work: (signal: AbortSignal) => Promise<TResult>, callerSignal?: AbortSignal): Promise<TResult> {
72
+ if (this.#closed || this.#protocol.isClosed) return Promise.reject(new plugins.ecobridgeDeviceManager.KodiProtocolError('closed', 'Kodi client is terminally closed.'));
73
+ let signal: AbortSignal;
199
74
  try {
200
- const response = await globalThis.fetch(this.jsonRpcUrl(), {
201
- method: 'POST',
202
- headers: this.headers(),
203
- body: JSON.stringify(request),
204
- signal: abortController.signal,
205
- });
206
- const text = await response.text();
207
- if (!response.ok) {
208
- throw new Error(`Kodi request ${methodArg} failed with HTTP ${response.status}: ${text}`);
209
- }
210
- const payload = JSON.parse(text) as IKodiJsonRpcResponse<T>;
211
- if (payload.error) {
212
- throw new KodiJsonRpcError(methodArg, payload.error.code, payload.error.message || 'Unknown JSON-RPC error', payload.error.data);
213
- }
214
- return payload.result as T;
215
- } finally {
216
- clearTimeout(timeout);
217
- }
218
- }
219
-
220
- public async destroy(): Promise<void> {}
221
-
222
- private async playState(playArg: boolean | 'toggle'): Promise<unknown> {
223
- return this.callMethod('Player.PlayPause', {
224
- playerid: await this.activePlayerId(),
225
- play: playArg,
226
- });
227
- }
228
-
229
- private async activePlayerId(): Promise<number> {
230
- const snapshot = await this.getSnapshot();
231
- const playerId = snapshot.player?.playerid ?? snapshot.players[0]?.playerid;
232
- if (typeof playerId !== 'number') {
233
- throw new Error('Kodi has no active player.');
234
- }
235
- return playerId;
236
- }
237
-
238
- private mediaItem(mediaTypeArg: TKodiMediaType, mediaIdArg: string | number): Record<string, unknown> {
239
- const type = mediaTypeArg.toLowerCase();
240
- if (type === 'playlist') {
241
- return { playlistid: Number(mediaIdArg) };
242
- }
243
- if (type === 'channel') {
244
- return { channelid: Number(mediaIdArg) };
245
- }
246
- if (type === 'directory') {
247
- return { path: String(mediaIdArg), recursive: true };
248
- }
249
- if (type === 'movie') {
250
- return { movieid: Number(mediaIdArg) };
251
- }
252
- if (type === 'episode') {
253
- return { episodeid: Number(mediaIdArg) };
254
- }
255
- if (type === 'season') {
256
- return { seasonid: Number(mediaIdArg) };
257
- }
258
- if (type === 'tvshow') {
259
- return { tvshowid: Number(mediaIdArg) };
260
- }
261
- if (type === 'album') {
262
- return { albumid: Number(mediaIdArg) };
263
- }
264
- if (type === 'artist') {
265
- return { artistid: Number(mediaIdArg) };
266
- }
267
- if (type === 'song' || type === 'track') {
268
- return { songid: Number(mediaIdArg) };
269
- }
270
- return { file: String(mediaIdArg) };
271
- }
272
-
273
- private playlistItem(mediaTypeArg: TKodiMediaType, mediaIdArg: string | number): Record<string, unknown> {
274
- const type = mediaTypeArg.toLowerCase();
275
- if (type === 'album') {
276
- return { albumid: Number(mediaIdArg) };
277
- }
278
- if (type === 'artist') {
279
- return { artistid: Number(mediaIdArg) };
280
- }
281
- if (type === 'song' || type === 'track') {
282
- return { songid: Number(mediaIdArg) };
283
- }
284
- return this.mediaItem(type, mediaIdArg);
285
- }
286
-
287
- private secondsToTime(secondsArg: number): IKodiTime {
288
- const safeSeconds = Math.max(0, Math.floor(secondsArg));
289
- return {
290
- hours: Math.floor(safeSeconds / 3600),
291
- minutes: Math.floor((safeSeconds % 3600) / 60),
292
- seconds: safeSeconds % 60,
293
- milliseconds: Math.max(0, Math.round((secondsArg - Math.floor(secondsArg)) * 1000)),
294
- };
295
- }
296
-
297
- private inputMethod(commandArg: string): string {
298
- const normalized = commandArg.replace(/[_\s-]+/g, '').toLowerCase();
299
- const methods: Record<string, string> = {
300
- up: 'Input.Up',
301
- down: 'Input.Down',
302
- left: 'Input.Left',
303
- right: 'Input.Right',
304
- select: 'Input.Select',
305
- ok: 'Input.Select',
306
- enter: 'Input.Select',
307
- back: 'Input.Back',
308
- home: 'Input.Home',
309
- info: 'Input.Info',
310
- contextmenu: 'Input.ContextMenu',
311
- };
312
- return methods[normalized] || (commandArg.includes('.') ? commandArg : `Input.${commandArg}`);
313
- }
314
-
315
- private normalizeSnapshot(snapshotArg: IKodiSnapshot): IKodiSnapshot {
316
- const deviceInfo = {
317
- ...this.deviceInfoFromConfig(),
318
- ...snapshotArg.deviceInfo,
319
- };
320
- if (!deviceInfo.name) {
321
- deviceInfo.name = snapshotArg.application?.name || this.config.name || this.config.host || 'Kodi';
322
- }
323
- if (!deviceInfo.version) {
324
- deviceInfo.version = this.versionString(snapshotArg.application);
325
- }
326
- return {
327
- ...snapshotArg,
328
- deviceInfo,
329
- players: snapshotArg.players || [],
330
- player: snapshotArg.player || snapshotArg.players?.[0],
331
- online: snapshotArg.online,
332
- };
333
- }
334
-
335
- private deviceInfoFromConfig(): IKodiDeviceInfo {
336
- return {
337
- ...this.config.deviceInfo,
338
- id: this.config.deviceInfo?.id || this.config.uniqueId,
339
- uuid: this.config.deviceInfo?.uuid || this.config.uniqueId,
340
- name: this.config.deviceInfo?.name || this.config.name,
341
- host: this.config.deviceInfo?.host || this.config.host,
342
- port: this.config.deviceInfo?.port || this.config.port || defaultPort,
343
- wsPort: this.config.deviceInfo?.wsPort || this.config.wsPort || defaultWsPort,
344
- manufacturer: this.config.deviceInfo?.manufacturer || 'Kodi',
345
- };
346
- }
347
-
348
- private versionString(applicationArg: IKodiApplicationProperties | undefined): string | undefined {
349
- const version = applicationArg?.version;
350
- if (!version || typeof version.major !== 'number') {
351
- return undefined;
352
- }
353
- return `${version.major}.${typeof version.minor === 'number' ? version.minor : 0}${version.revision ? `-${version.revision}` : ''}`;
354
- }
355
-
356
- private cloneSnapshot(snapshotArg: IKodiSnapshot): IKodiSnapshot {
357
- return JSON.parse(JSON.stringify(snapshotArg)) as IKodiSnapshot;
358
- }
359
-
360
- private jsonRpcUrl(): string {
361
- const protocol = this.config.ssl ? 'https' : 'http';
362
- return `${protocol}://${this.config.host}:${this.config.port || defaultPort}/jsonrpc`;
363
- }
364
-
365
- private headers(): Record<string, string> {
366
- const headers: Record<string, string> = { 'content-type': 'application/json' };
367
- if (this.config.username !== undefined && this.config.password !== undefined) {
368
- headers.authorization = `Basic ${globalThis.btoa(`${this.config.username}:${this.config.password}`)}`;
369
- }
370
- return headers;
75
+ kodiSignal(callerSignal);
76
+ if (callerSignal?.aborted) throw new plugins.ecobridgeDeviceManager.KodiProtocolError('cancelled', 'Kodi operation was cancelled before admission.');
77
+ signal = AbortSignal.any([this.#lifetime.signal, ...(callerSignal ? [callerSignal] : [])]);
78
+ } catch (error) { return Promise.reject(error); }
79
+ let operation: Promise<TResult>;
80
+ try { operation = work(signal).then((result) => {
81
+ this.#healthy = !this.#closed && !signal.aborted && !this.#protocol.isClosed;
82
+ return result;
83
+ }, (error: unknown) => {
84
+ this.#healthy = false;
85
+ throw error;
86
+ }); } catch (error) { return Promise.reject(error); }
87
+ this.#operations.add(operation);
88
+ const settled = (): void => { this.#operations.delete(operation); };
89
+ void operation.then(settled, settled);
90
+ return operation;
371
91
  }
372
92
  }
@@ -1,63 +1,60 @@
1
- import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
2
- import type { IKodiConfig } from './kodi.types.js';
3
-
4
- const defaultPort = 8080;
5
- const defaultWsPort = 9090;
6
- const defaultTimeoutMs = 5000;
1
+ import * as plugins from '../../plugins.js';
2
+ import type { IConfigFlow, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
3
+ import { NativeIntegrationOwner, type NativeIntegrationScope } from '../../core/classes.nativeintegrationowner.js';
4
+ import { KodiClient } from './kodi.classes.client.js';
5
+ import type { IKodiConfig, IKodiConfigFlowContext } from './kodi.types.js';
6
+ import { kodiInteger, kodiKeys, kodiRecord, kodiText, normalizeKodiConfig } from './kodi.validation.js';
7
7
 
8
+ /** Captures selected configuration. Setup separately owns live readiness admission. */
8
9
  export class KodiConfigFlow implements IConfigFlow<IKodiConfig> {
9
- public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IKodiConfig>> {
10
- void contextArg;
10
+ readonly #scope: NativeIntegrationScope;
11
+ public constructor(owner: NativeIntegrationOwner = new NativeIntegrationOwner('kodi')) {
12
+ this.#scope = owner.createFlowScope();
13
+ }
14
+
15
+ public destroy(): Promise<void> { return this.#scope.close(); }
16
+ public retryCleanup(): Promise<void> { return this.#scope.retryCleanup(); }
17
+
18
+ public async start(input: IDiscoveryCandidate, context: IKodiConfigFlowContext): Promise<IConfigFlowStep<IKodiConfig>> {
19
+ const candidate = kodiRecord(input, 'config candidate');
20
+ const host = kodiText(candidate.host, 'selected candidate host', 128);
21
+ const port = kodiInteger(candidate.port === undefined ? 8080 : candidate.port, 1, 65535, 'candidate port');
22
+ const origin = plugins.ecobridgeDeviceManager.validateKodiOrigin(`http://${host}:${port}`);
23
+ const captured = this.#scope.admit(context);
11
24
  return {
12
- kind: 'form',
13
- title: 'Connect Kodi',
14
- description: 'Configure the local Kodi JSON-RPC endpoint.',
25
+ kind: 'form', title: 'Connect selected Kodi application',
26
+ description: 'Specify the expected application name and major for the host-selected home. Accept plaintext HTTP explicitly. Controls default to disabled; enabling them requires endpoint trust and an integer volume ceiling. Live readiness is checked during setup.',
15
27
  fields: [
16
- { name: 'host', label: 'Host', type: 'text', required: true },
17
- { name: 'port', label: 'HTTP JSON-RPC port', type: 'number' },
18
- { name: 'ssl', label: 'Use HTTPS', type: 'boolean' },
19
- { name: 'wsPort', label: 'WebSocket port', type: 'number' },
20
- { name: 'username', label: 'Username', type: 'text' },
21
- { name: 'password', label: 'Password', type: 'password' },
22
- { name: 'name', label: 'Name', type: 'text' },
28
+ { name: 'expectedApplicationName', label: 'Exact application name', type: 'text', required: true },
29
+ { name: 'expectedApplicationMajor', label: 'Application major version', type: 'number', required: true },
30
+ { name: 'allowUnencryptedHttp', label: 'Accept plaintext HTTP', type: 'boolean', required: true },
31
+ { name: 'allowControls', label: 'Enable application volume and mute controls', type: 'boolean' },
32
+ { name: 'trustSelectedEndpoint', label: 'Trust this selected endpoint for controls', type: 'boolean' },
33
+ { name: 'maximumVolume', label: 'Maximum integer application volume (0–100)', type: 'number' },
34
+ { name: 'name', label: 'Display name', type: 'text' },
23
35
  ],
24
- submit: async (valuesArg) => ({
25
- kind: 'done',
26
- title: 'Kodi configured',
27
- config: {
28
- host: this.stringValue(valuesArg.host) || candidateArg.host || '',
29
- port: this.numberValue(valuesArg.port) || candidateArg.port || defaultPort,
30
- wsPort: this.numberValue(valuesArg.wsPort) || this.numberMetadata(candidateArg, 'wsPort') || defaultWsPort,
31
- ssl: this.booleanValue(valuesArg.ssl) ?? this.booleanMetadata(candidateArg, 'ssl') ?? false,
32
- username: this.stringValue(valuesArg.username),
33
- password: this.stringValue(valuesArg.password),
34
- name: this.stringValue(valuesArg.name) || candidateArg.name,
35
- uniqueId: candidateArg.id,
36
- timeoutMs: defaultTimeoutMs,
37
- },
38
- }),
36
+ submit: async (input) => {
37
+ try {
38
+ const values = kodiRecord(input, 'config-flow values');
39
+ return await this.#scope.run(captured, captured.homeId, async (lease): Promise<IConfigFlowStep<IKodiConfig>> => {
40
+ kodiKeys(values, ['homeId', 'expectedApplicationName', 'expectedApplicationMajor', 'allowUnencryptedHttp', 'allowControls', 'trustSelectedEndpoint', 'maximumVolume', 'name', 'timeoutMs', 'maxQueuedOperations', 'maxResponseBytes']);
41
+ if (values.homeId !== undefined && values.homeId !== lease.context.homeId) throw new TypeError('Kodi form home differs from the host-selected home.');
42
+ if (values.allowControls !== undefined && typeof values.allowControls !== 'boolean') throw new TypeError('Kodi controls require an explicit boolean opt-in.');
43
+ if (values.allowControls !== true && (values.trustSelectedEndpoint === true || values.maximumVolume !== undefined)) throw new TypeError('Kodi owner control policy requires an explicit controls opt-in.');
44
+ const config = normalizeKodiConfig({ homeId: lease.context.homeId, origin,
45
+ expectedApplicationName: values.expectedApplicationName, expectedApplicationMajor: values.expectedApplicationMajor,
46
+ allowUnencryptedHttp: values.allowUnencryptedHttp,
47
+ control: values.allowControls === true ? { trustSelectedEndpoint: values.trustSelectedEndpoint, maximumVolume: values.maximumVolume } : undefined,
48
+ name: values.name, timeoutMs: values.timeoutMs, maxQueuedOperations: values.maxQueuedOperations, maxResponseBytes: values.maxResponseBytes });
49
+ // Construction delegates endpoint validation without opening a connection.
50
+ const client = new KodiClient(config, { ...lease.context, abortSignal: lease.signal });
51
+ lease.own(() => client.destroy());
52
+ return { kind: 'done', title: 'Kodi configuration captured', config };
53
+ });
54
+ } catch (error) {
55
+ return { kind: 'error', error: error instanceof Error ? error.message : 'Kodi configuration was refused.' };
56
+ }
57
+ },
39
58
  };
40
59
  }
41
-
42
- private stringValue(valueArg: unknown): string | undefined {
43
- return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
44
- }
45
-
46
- private numberValue(valueArg: unknown): number | undefined {
47
- return typeof valueArg === 'number' && Number.isFinite(valueArg) ? valueArg : undefined;
48
- }
49
-
50
- private booleanValue(valueArg: unknown): boolean | undefined {
51
- return typeof valueArg === 'boolean' ? valueArg : undefined;
52
- }
53
-
54
- private numberMetadata(candidateArg: IDiscoveryCandidate, keyArg: string): number | undefined {
55
- const value = candidateArg.metadata?.[keyArg];
56
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
57
- }
58
-
59
- private booleanMetadata(candidateArg: IDiscoveryCandidate, keyArg: string): boolean | undefined {
60
- const value = candidateArg.metadata?.[keyArg];
61
- return typeof value === 'boolean' ? value : undefined;
62
- }
63
60
  }