@smarthome.exchange/integrations 1.0.0 → 2.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 (294) hide show
  1. package/changelog.md +49 -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 +79 -0
  8. package/dist_ts/core/classes.nativeintegrationowner.js +269 -0
  9. package/dist_ts/core/index.d.ts +2 -0
  10. package/dist_ts/core/index.js +3 -1
  11. package/dist_ts/core/types.d.ts +14 -0
  12. package/dist_ts/integrations/braviatv/braviatv.classes.client.d.ts +23 -72
  13. package/dist_ts/integrations/braviatv/braviatv.classes.client.js +265 -625
  14. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.d.ts +7 -7
  15. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.js +51 -68
  16. package/dist_ts/integrations/braviatv/braviatv.classes.integration.d.ts +8 -11
  17. package/dist_ts/integrations/braviatv/braviatv.classes.integration.js +186 -135
  18. package/dist_ts/integrations/braviatv/braviatv.discovery.js +12 -11
  19. package/dist_ts/integrations/braviatv/braviatv.mapper.d.ts +6 -14
  20. package/dist_ts/integrations/braviatv/braviatv.mapper.js +37 -131
  21. package/dist_ts/integrations/braviatv/braviatv.types.d.ts +55 -133
  22. package/dist_ts/integrations/braviatv/braviatv.validation.d.ts +7 -0
  23. package/dist_ts/integrations/braviatv/braviatv.validation.js +72 -0
  24. package/dist_ts/integrations/broadlink/broadlink.actions.d.ts +2 -0
  25. package/dist_ts/integrations/broadlink/broadlink.actions.js +36 -0
  26. package/dist_ts/integrations/broadlink/broadlink.classes.client.d.ts +21 -19
  27. package/dist_ts/integrations/broadlink/broadlink.classes.client.js +185 -124
  28. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.d.ts +5 -4
  29. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.js +64 -83
  30. package/dist_ts/integrations/broadlink/broadlink.classes.integration.d.ts +16 -19
  31. package/dist_ts/integrations/broadlink/broadlink.classes.integration.js +114 -59
  32. package/dist_ts/integrations/broadlink/broadlink.mapper.d.ts +3 -2
  33. package/dist_ts/integrations/broadlink/broadlink.mapper.js +2 -1
  34. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.d.ts +10 -0
  35. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.js +41 -0
  36. package/dist_ts/integrations/broadlink/broadlink.types.d.ts +43 -7
  37. package/dist_ts/integrations/broadlink/broadlink.validation.d.ts +7 -0
  38. package/dist_ts/integrations/broadlink/broadlink.validation.js +63 -0
  39. package/dist_ts/integrations/daikin/daikin.classes.client.d.ts +10 -52
  40. package/dist_ts/integrations/daikin/daikin.classes.client.js +55 -614
  41. package/dist_ts/integrations/daikin/daikin.classes.configflow.d.ts +8 -12
  42. package/dist_ts/integrations/daikin/daikin.classes.configflow.js +77 -138
  43. package/dist_ts/integrations/daikin/daikin.classes.integration.d.ts +7 -24
  44. package/dist_ts/integrations/daikin/daikin.classes.integration.js +175 -67
  45. package/dist_ts/integrations/daikin/daikin.discovery.d.ts +11 -24
  46. package/dist_ts/integrations/daikin/daikin.discovery.js +98 -305
  47. package/dist_ts/integrations/daikin/daikin.mapper.d.ts +6 -7
  48. package/dist_ts/integrations/daikin/daikin.mapper.js +95 -155
  49. package/dist_ts/integrations/daikin/daikin.types.d.ts +24 -44
  50. package/dist_ts/integrations/daikin/daikin.types.js +1 -1
  51. package/dist_ts/integrations/daikin/daikin.validation.d.ts +5 -0
  52. package/dist_ts/integrations/daikin/daikin.validation.js +53 -0
  53. package/dist_ts/integrations/denonavr/denonavr.classes.client.d.ts +31 -40
  54. package/dist_ts/integrations/denonavr/denonavr.classes.client.js +149 -404
  55. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.d.ts +7 -2
  56. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.js +44 -36
  57. package/dist_ts/integrations/denonavr/denonavr.classes.integration.d.ts +6 -11
  58. package/dist_ts/integrations/denonavr/denonavr.classes.integration.js +192 -113
  59. package/dist_ts/integrations/denonavr/denonavr.discovery.d.ts +10 -18
  60. package/dist_ts/integrations/denonavr/denonavr.discovery.js +71 -193
  61. package/dist_ts/integrations/denonavr/denonavr.mapper.d.ts +5 -13
  62. package/dist_ts/integrations/denonavr/denonavr.mapper.js +35 -159
  63. package/dist_ts/integrations/denonavr/denonavr.types.d.ts +55 -90
  64. package/dist_ts/integrations/denonavr/denonavr.validation.d.ts +10 -0
  65. package/dist_ts/integrations/denonavr/denonavr.validation.js +86 -0
  66. package/dist_ts/integrations/kodi/kodi.classes.client.d.ts +11 -45
  67. package/dist_ts/integrations/kodi/kodi.classes.client.js +84 -310
  68. package/dist_ts/integrations/kodi/kodi.classes.configflow.d.ts +9 -8
  69. package/dist_ts/integrations/kodi/kodi.classes.configflow.js +53 -48
  70. package/dist_ts/integrations/kodi/kodi.classes.integration.d.ts +11 -11
  71. package/dist_ts/integrations/kodi/kodi.classes.integration.js +114 -171
  72. package/dist_ts/integrations/kodi/kodi.discovery.js +53 -29
  73. package/dist_ts/integrations/kodi/kodi.mapper.d.ts +7 -2
  74. package/dist_ts/integrations/kodi/kodi.mapper.js +48 -10
  75. package/dist_ts/integrations/kodi/kodi.types.d.ts +32 -28
  76. package/dist_ts/integrations/kodi/kodi.validation.d.ts +9 -0
  77. package/dist_ts/integrations/kodi/kodi.validation.js +62 -0
  78. package/dist_ts/integrations/modbus/modbus.classes.client.d.ts +15 -61
  79. package/dist_ts/integrations/modbus/modbus.classes.client.js +117 -776
  80. package/dist_ts/integrations/modbus/modbus.classes.configflow.d.ts +9 -5
  81. package/dist_ts/integrations/modbus/modbus.classes.configflow.js +70 -38
  82. package/dist_ts/integrations/modbus/modbus.classes.integration.d.ts +6 -17
  83. package/dist_ts/integrations/modbus/modbus.classes.integration.js +133 -57
  84. package/dist_ts/integrations/modbus/modbus.discovery.d.ts +5 -8
  85. package/dist_ts/integrations/modbus/modbus.discovery.js +38 -93
  86. package/dist_ts/integrations/modbus/modbus.mapper.d.ts +8 -32
  87. package/dist_ts/integrations/modbus/modbus.mapper.js +71 -431
  88. package/dist_ts/integrations/modbus/modbus.types.d.ts +82 -332
  89. package/dist_ts/integrations/modbus/modbus.validation.d.ts +10 -0
  90. package/dist_ts/integrations/modbus/modbus.validation.js +128 -0
  91. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.d.ts +12 -34
  92. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.js +143 -231
  93. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.d.ts +6 -1
  94. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.js +105 -18
  95. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.d.ts +8 -8
  96. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.js +141 -155
  97. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.d.ts +9 -0
  98. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.js +35 -0
  99. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.d.ts +6 -18
  100. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.js +45 -220
  101. package/dist_ts/integrations/nanoleaf/nanoleaf.types.d.ts +33 -147
  102. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.d.ts +6 -0
  103. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.js +82 -0
  104. package/dist_ts/integrations/onkyo/onkyo.classes.client.d.ts +15 -20
  105. package/dist_ts/integrations/onkyo/onkyo.classes.client.js +161 -404
  106. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.d.ts +9 -4
  107. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.js +51 -6
  108. package/dist_ts/integrations/onkyo/onkyo.classes.integration.d.ts +22 -6
  109. package/dist_ts/integrations/onkyo/onkyo.classes.integration.js +144 -11
  110. package/dist_ts/integrations/onkyo/onkyo.discovery.d.ts +6 -1
  111. package/dist_ts/integrations/onkyo/onkyo.discovery.js +40 -4
  112. package/dist_ts/integrations/onkyo/onkyo.mapper.d.ts +7 -8
  113. package/dist_ts/integrations/onkyo/onkyo.mapper.js +45 -12
  114. package/dist_ts/integrations/onkyo/onkyo.types.d.ts +58 -8
  115. package/dist_ts/integrations/onkyo/onkyo.types.js +13 -102
  116. package/dist_ts/integrations/onkyo/onkyo.validation.d.ts +16 -0
  117. package/dist_ts/integrations/onkyo/onkyo.validation.js +77 -0
  118. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.d.ts +25 -25
  119. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.js +116 -360
  120. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.d.ts +11 -3
  121. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.js +76 -6
  122. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.d.ts +26 -4
  123. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.js +142 -9
  124. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.d.ts +2 -1
  125. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.js +31 -4
  126. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.d.ts +9 -9
  127. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.js +31 -149
  128. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.d.ts +51 -11
  129. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.js +22 -87
  130. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.d.ts +6 -0
  131. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.js +56 -0
  132. package/dist_ts/integrations/pioneer/pioneer.classes.client.d.ts +31 -16
  133. package/dist_ts/integrations/pioneer/pioneer.classes.client.js +167 -409
  134. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.d.ts +10 -3
  135. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.js +66 -6
  136. package/dist_ts/integrations/pioneer/pioneer.classes.integration.d.ts +13 -5
  137. package/dist_ts/integrations/pioneer/pioneer.classes.integration.js +239 -11
  138. package/dist_ts/integrations/pioneer/pioneer.discovery.d.ts +14 -1
  139. package/dist_ts/integrations/pioneer/pioneer.discovery.js +51 -4
  140. package/dist_ts/integrations/pioneer/pioneer.mapper.d.ts +14 -8
  141. package/dist_ts/integrations/pioneer/pioneer.mapper.js +54 -12
  142. package/dist_ts/integrations/pioneer/pioneer.types.d.ts +79 -12
  143. package/dist_ts/integrations/pioneer/pioneer.types.js +12 -76
  144. package/dist_ts/integrations/pioneer/pioneer.validation.d.ts +10 -0
  145. package/dist_ts/integrations/pioneer/pioneer.validation.js +85 -0
  146. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.d.ts +13 -36
  147. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.js +179 -502
  148. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.d.ts +6 -1
  149. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.js +50 -40
  150. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.d.ts +14 -15
  151. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.js +108 -128
  152. package/dist_ts/integrations/soundtouch/soundtouch.discovery.d.ts +2 -20
  153. package/dist_ts/integrations/soundtouch/soundtouch.discovery.js +23 -113
  154. package/dist_ts/integrations/soundtouch/soundtouch.mapper.d.ts +3 -12
  155. package/dist_ts/integrations/soundtouch/soundtouch.mapper.js +35 -189
  156. package/dist_ts/integrations/soundtouch/soundtouch.types.d.ts +57 -142
  157. package/dist_ts/integrations/soundtouch/soundtouch.types.js +18 -3
  158. package/dist_ts/integrations/soundtouch/soundtouch.validation.d.ts +22 -0
  159. package/dist_ts/integrations/soundtouch/soundtouch.validation.js +65 -0
  160. package/dist_ts/integrations/wiz/index.d.ts +1 -0
  161. package/dist_ts/integrations/wiz/index.js +2 -1
  162. package/dist_ts/integrations/wiz/wiz.classes.client.d.ts +14 -28
  163. package/dist_ts/integrations/wiz/wiz.classes.client.js +93 -229
  164. package/dist_ts/integrations/wiz/wiz.classes.configflow.d.ts +6 -4
  165. package/dist_ts/integrations/wiz/wiz.classes.configflow.js +38 -67
  166. package/dist_ts/integrations/wiz/wiz.classes.integration.d.ts +10 -21
  167. package/dist_ts/integrations/wiz/wiz.classes.integration.js +204 -44
  168. package/dist_ts/integrations/wiz/wiz.discovery.d.ts +10 -31
  169. package/dist_ts/integrations/wiz/wiz.discovery.js +48 -249
  170. package/dist_ts/integrations/wiz/wiz.mapper.d.ts +7 -51
  171. package/dist_ts/integrations/wiz/wiz.mapper.js +82 -668
  172. package/dist_ts/integrations/wiz/wiz.types.d.ts +34 -208
  173. package/dist_ts/integrations/wiz/wiz.validation.d.ts +8 -0
  174. package/dist_ts/integrations/wiz/wiz.validation.js +72 -0
  175. package/dist_ts/integrations/yamaha/index.d.ts +1 -0
  176. package/dist_ts/integrations/yamaha/index.js +2 -1
  177. package/dist_ts/integrations/yamaha/yamaha.classes.client.d.ts +30 -4
  178. package/dist_ts/integrations/yamaha/yamaha.classes.client.js +162 -6
  179. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.d.ts +10 -3
  180. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.js +106 -6
  181. package/dist_ts/integrations/yamaha/yamaha.classes.integration.d.ts +22 -4
  182. package/dist_ts/integrations/yamaha/yamaha.classes.integration.js +243 -8
  183. package/dist_ts/integrations/yamaha/yamaha.discovery.d.ts +13 -1
  184. package/dist_ts/integrations/yamaha/yamaha.discovery.js +57 -4
  185. package/dist_ts/integrations/yamaha/yamaha.mapper.d.ts +16 -8
  186. package/dist_ts/integrations/yamaha/yamaha.mapper.js +58 -12
  187. package/dist_ts/integrations/yamaha/yamaha.types.d.ts +73 -6
  188. package/dist_ts/integrations/yamaha/yamaha.types.js +8 -94
  189. package/dist_ts/integrations/yamaha/yamaha.validation.d.ts +12 -0
  190. package/dist_ts/integrations/yamaha/yamaha.validation.js +89 -0
  191. package/package.json +3 -3
  192. package/readme.md +514 -2
  193. package/ts/00_commitinfo_data.ts +1 -1
  194. package/ts/core/classes.configstore.ts +84 -27
  195. package/ts/core/classes.nativehomeadmission.ts +96 -0
  196. package/ts/core/classes.nativeintegrationowner.ts +297 -0
  197. package/ts/core/index.ts +2 -0
  198. package/ts/core/types.ts +16 -0
  199. package/ts/integrations/braviatv/braviatv.classes.client.ts +245 -709
  200. package/ts/integrations/braviatv/braviatv.classes.configflow.ts +47 -76
  201. package/ts/integrations/braviatv/braviatv.classes.integration.ts +167 -147
  202. package/ts/integrations/braviatv/braviatv.discovery.ts +11 -10
  203. package/ts/integrations/braviatv/braviatv.mapper.ts +39 -142
  204. package/ts/integrations/braviatv/braviatv.types.ts +53 -173
  205. package/ts/integrations/braviatv/braviatv.validation.ts +68 -0
  206. package/ts/integrations/broadlink/broadlink.actions.ts +31 -0
  207. package/ts/integrations/broadlink/broadlink.classes.client.ts +170 -144
  208. package/ts/integrations/broadlink/broadlink.classes.configflow.ts +59 -89
  209. package/ts/integrations/broadlink/broadlink.classes.integration.ts +110 -64
  210. package/ts/integrations/broadlink/broadlink.mapper.ts +5 -4
  211. package/ts/integrations/broadlink/broadlink.selected.mapper.ts +46 -0
  212. package/ts/integrations/broadlink/broadlink.types.ts +48 -8
  213. package/ts/integrations/broadlink/broadlink.validation.ts +66 -0
  214. package/ts/integrations/daikin/daikin.classes.client.ts +52 -661
  215. package/ts/integrations/daikin/daikin.classes.configflow.ts +72 -152
  216. package/ts/integrations/daikin/daikin.classes.integration.ts +166 -71
  217. package/ts/integrations/daikin/daikin.discovery.ts +94 -346
  218. package/ts/integrations/daikin/daikin.mapper.ts +83 -166
  219. package/ts/integrations/daikin/daikin.types.ts +27 -48
  220. package/ts/integrations/daikin/daikin.validation.ts +51 -0
  221. package/ts/integrations/daikin/readme.md +83 -0
  222. package/ts/integrations/denonavr/denonavr.classes.client.ts +132 -421
  223. package/ts/integrations/denonavr/denonavr.classes.configflow.ts +44 -37
  224. package/ts/integrations/denonavr/denonavr.classes.integration.ts +171 -117
  225. package/ts/integrations/denonavr/denonavr.discovery.ts +67 -220
  226. package/ts/integrations/denonavr/denonavr.mapper.ts +36 -182
  227. package/ts/integrations/denonavr/denonavr.types.ts +48 -111
  228. package/ts/integrations/denonavr/denonavr.validation.ts +87 -0
  229. package/ts/integrations/kodi/kodi.classes.client.ts +72 -352
  230. package/ts/integrations/kodi/kodi.classes.configflow.ts +52 -55
  231. package/ts/integrations/kodi/kodi.classes.integration.ts +97 -178
  232. package/ts/integrations/kodi/kodi.discovery.ts +49 -28
  233. package/ts/integrations/kodi/kodi.mapper.ts +52 -10
  234. package/ts/integrations/kodi/kodi.types.ts +33 -58
  235. package/ts/integrations/kodi/kodi.validation.ts +60 -0
  236. package/ts/integrations/modbus/modbus.classes.client.ts +100 -842
  237. package/ts/integrations/modbus/modbus.classes.configflow.ts +70 -41
  238. package/ts/integrations/modbus/modbus.classes.integration.ts +115 -60
  239. package/ts/integrations/modbus/modbus.discovery.ts +38 -106
  240. package/ts/integrations/modbus/modbus.mapper.ts +64 -467
  241. package/ts/integrations/modbus/modbus.types.ts +64 -381
  242. package/ts/integrations/modbus/modbus.validation.ts +119 -0
  243. package/ts/integrations/nanoleaf/nanoleaf.classes.client.ts +115 -249
  244. package/ts/integrations/nanoleaf/nanoleaf.classes.configflow.ts +90 -19
  245. package/ts/integrations/nanoleaf/nanoleaf.classes.integration.ts +130 -181
  246. package/ts/integrations/nanoleaf/nanoleaf.credentials.ts +39 -0
  247. package/ts/integrations/nanoleaf/nanoleaf.mapper.ts +47 -260
  248. package/ts/integrations/nanoleaf/nanoleaf.types.ts +29 -147
  249. package/ts/integrations/nanoleaf/nanoleaf.validation.ts +77 -0
  250. package/ts/integrations/onkyo/onkyo.classes.client.ts +148 -457
  251. package/ts/integrations/onkyo/onkyo.classes.configflow.ts +52 -6
  252. package/ts/integrations/onkyo/onkyo.classes.integration.ts +121 -12
  253. package/ts/integrations/onkyo/onkyo.discovery.ts +41 -3
  254. package/ts/integrations/onkyo/onkyo.mapper.ts +46 -19
  255. package/ts/integrations/onkyo/onkyo.types.ts +55 -110
  256. package/ts/integrations/onkyo/onkyo.validation.ts +85 -0
  257. package/ts/integrations/onkyo/readme.md +126 -0
  258. package/ts/integrations/panasonic_viera/panasonic_viera.classes.client.ts +101 -398
  259. package/ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.ts +69 -5
  260. package/ts/integrations/panasonic_viera/panasonic_viera.classes.integration.ts +141 -9
  261. package/ts/integrations/panasonic_viera/panasonic_viera.discovery.ts +32 -3
  262. package/ts/integrations/panasonic_viera/panasonic_viera.mapper.ts +34 -161
  263. package/ts/integrations/panasonic_viera/panasonic_viera.types.ts +52 -96
  264. package/ts/integrations/panasonic_viera/panasonic_viera.validation.ts +56 -0
  265. package/ts/integrations/pioneer/pioneer.classes.client.ts +132 -428
  266. package/ts/integrations/pioneer/pioneer.classes.configflow.ts +67 -5
  267. package/ts/integrations/pioneer/pioneer.classes.integration.ts +225 -11
  268. package/ts/integrations/pioneer/pioneer.discovery.ts +45 -3
  269. package/ts/integrations/pioneer/pioneer.mapper.ts +57 -13
  270. package/ts/integrations/pioneer/pioneer.types.ts +87 -85
  271. package/ts/integrations/pioneer/pioneer.validation.ts +84 -0
  272. package/ts/integrations/soundtouch/soundtouch.classes.client.ts +152 -571
  273. package/ts/integrations/soundtouch/soundtouch.classes.configflow.ts +47 -42
  274. package/ts/integrations/soundtouch/soundtouch.classes.integration.ts +95 -150
  275. package/ts/integrations/soundtouch/soundtouch.discovery.ts +21 -133
  276. package/ts/integrations/soundtouch/soundtouch.mapper.ts +36 -207
  277. package/ts/integrations/soundtouch/soundtouch.types.ts +50 -195
  278. package/ts/integrations/soundtouch/soundtouch.validation.ts +60 -0
  279. package/ts/integrations/wiz/index.ts +1 -0
  280. package/ts/integrations/wiz/wiz.classes.client.ts +84 -254
  281. package/ts/integrations/wiz/wiz.classes.configflow.ts +39 -70
  282. package/ts/integrations/wiz/wiz.classes.integration.ts +189 -45
  283. package/ts/integrations/wiz/wiz.discovery.ts +48 -291
  284. package/ts/integrations/wiz/wiz.mapper.ts +81 -754
  285. package/ts/integrations/wiz/wiz.types.ts +24 -224
  286. package/ts/integrations/wiz/wiz.validation.ts +73 -0
  287. package/ts/integrations/yamaha/index.ts +1 -0
  288. package/ts/integrations/yamaha/yamaha.classes.client.ts +150 -6
  289. package/ts/integrations/yamaha/yamaha.classes.configflow.ts +100 -5
  290. package/ts/integrations/yamaha/yamaha.classes.integration.ts +236 -8
  291. package/ts/integrations/yamaha/yamaha.discovery.ts +52 -3
  292. package/ts/integrations/yamaha/yamaha.mapper.ts +65 -13
  293. package/ts/integrations/yamaha/yamaha.types.ts +77 -97
  294. package/ts/integrations/yamaha/yamaha.validation.ts +86 -0
@@ -1,47 +1,54 @@
1
1
  import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
2
- import type { IDenonavrConfig } from './denonavr.types.js';
2
+ import { NativeIntegrationOwner, type NativeIntegrationScope } from '../../core/classes.nativeintegrationowner.js';
3
+ import type { IDenonavrConfig, IDenonavrIntegrationOptions } from './denonavr.types.js';
4
+ import { DenonavrClient } from './denonavr.classes.client.js';
5
+ import { denonavrRecord, normalizeDenonavrConfig } from './denonavr.validation.js';
3
6
 
4
7
  export class DenonavrConfigFlow implements IConfigFlow<IDenonavrConfig> {
5
- public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IDenonavrConfig>> {
6
- void contextArg;
8
+ private readonly scope: NativeIntegrationScope;
9
+
10
+ public constructor(options: IDenonavrIntegrationOptions = {}, scope?: NativeIntegrationScope) {
11
+ this.scope = scope ?? new NativeIntegrationOwner('denonavr', options).createFlowScope();
12
+ }
13
+
14
+ public async start(input: IDiscoveryCandidate, context: IConfigFlowContext): Promise<IConfigFlowStep<IDenonavrConfig>> {
15
+ const candidate = denonavrRecord(input);
16
+ if (candidate.integrationDomain !== 'denonavr') return { kind: 'error', error: 'Candidate does not belong to DenonAVR.' };
17
+ const metadata = candidate.metadata === undefined ? {} : denonavrRecord(candidate.metadata);
18
+ const hints = { host: candidate.host, expectedUdn: candidate.id, model: candidate.model, descriptionUrl: metadata.descriptionUrl };
19
+ const admitted = this.scope.admit(context);
7
20
  return {
8
- kind: 'form',
9
- title: 'Connect Denon AVR Network Receiver',
10
- description: 'Configure the local Denon/Marantz AVR HTTP endpoint.',
21
+ kind: 'form', title: 'Connect selected Denon or Marantz receiver',
22
+ description: 'Confirm the exact UPnP identity, selected IPv4 description URL and owner volume ceiling for the host-selected home. LAN identity is unauthenticated. Enable network control in standby when needed.',
11
23
  fields: [
12
- { name: 'host', label: 'Host', type: 'text', required: true },
13
- { name: 'port', label: 'Port', type: 'number' },
14
- { name: 'name', label: 'Name', type: 'text' },
15
- { name: 'model', label: 'Model', type: 'text' },
24
+ { name: 'host', label: 'Selected receiver IPv4', type: 'text', required: true },
25
+ { name: 'descriptionUrl', label: 'Selected UPnP description URL', type: 'text', required: true },
26
+ { name: 'expectedUdn', label: 'Expected UPnP UDN', type: 'text', required: true },
27
+ { name: 'model', label: 'Documented model', type: 'select', required: true, options: ['AVR-1913', 'AVR-2113CI', 'NR1605', 'SR5009'].map((value) => ({ label: value, value })) },
28
+ { name: 'maximumVolumeDb', label: 'Owner maximum volume (dB)', type: 'number', required: true },
29
+ { name: 'name', label: 'Display name', type: 'text' },
16
30
  ],
17
- submit: async (valuesArg) => {
18
- const port = typeof valuesArg.port === 'number' ? valuesArg.port : Number(valuesArg.port || candidateArg.port || 80);
19
- const name = stringValue(valuesArg.name) || candidateArg.name;
20
- const model = stringValue(valuesArg.model) || candidateArg.model;
21
- return {
22
- kind: 'done',
23
- title: 'Denon AVR configured',
24
- config: {
25
- host: stringValue(valuesArg.host) || candidateArg.host || '',
26
- port: Number.isFinite(port) ? port : 80,
27
- name,
28
- model,
29
- manufacturer: candidateArg.manufacturer,
30
- serialNumber: candidateArg.serialNumber,
31
- receiverInfo: name || model || candidateArg.manufacturer || candidateArg.serialNumber ? {
32
- name,
33
- friendlyName: name,
34
- manufacturer: candidateArg.manufacturer,
35
- modelName: model,
36
- serialNumber: candidateArg.serialNumber,
37
- } : undefined,
38
- },
39
- };
31
+ submit: async (inputValues) => {
32
+ try {
33
+ const values = denonavrRecord(inputValues, ['homeId', 'host', 'descriptionUrl', 'expectedUdn', 'model', 'maximumVolumeDb', 'name', 'port', 'timeoutMs', 'maxPendingOperations', 'maxDescriptionBytes']);
34
+ if (values.homeId !== undefined && values.homeId !== admitted.homeId) throw new Error('DenonAVR submitted home conflicts with the host-selected home.');
35
+ const config = normalizeDenonavrConfig({ ...hints, ...values, homeId: admitted.homeId });
36
+ return await this.scope.run(admitted, config.homeId, async (lease) => {
37
+ const client = new DenonavrClient(config, lease.context);
38
+ lease.own(() => client.retryCleanup());
39
+ await client.start(lease.signal);
40
+ lease.assertOpen();
41
+ return { kind: 'done', title: 'Selected receiver admitted', config };
42
+ });
43
+ } catch (error) {
44
+ if (error instanceof AggregateError) throw error;
45
+ return { kind: 'error', title: 'Receiver admission failed', error: error instanceof Error ? error.message : 'Receiver admission failed.' };
46
+ }
40
47
  },
41
48
  };
42
49
  }
43
- }
44
50
 
45
- const stringValue = (valueArg: unknown): string | undefined => {
46
- return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
47
- };
51
+ public destroy(): Promise<void> { return this.scope.close(); }
52
+
53
+ public retryCleanup(): Promise<void> { return this.scope.retryCleanup(); }
54
+ }
@@ -1,157 +1,211 @@
1
- import type * as shxInterfaces from '@smarthome.exchange/interfaces';
1
+ import * as plugins from '../../plugins.js';
2
2
  import { BaseIntegration } from '../../core/classes.baseintegration.js';
3
- import type { IIntegrationEntity, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
3
+ import { NativeIntegrationOwner, type INativeSetupLease } from '../../core/classes.nativeintegrationowner.js';
4
+ import type { IDeviceFeatureWriteRequest, IIntegrationEntity, IIntegrationEvent, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
4
5
  import { DenonavrClient } from './denonavr.classes.client.js';
5
6
  import { DenonavrConfigFlow } from './denonavr.classes.configflow.js';
6
7
  import { createDenonavrDiscoveryDescriptor } from './denonavr.discovery.js';
7
8
  import { DenonavrMapper } from './denonavr.mapper.js';
8
- import type { IDenonavrConfig, TDenonavrCommand, TDenonavrZone } from './denonavr.types.js';
9
+ import { denonavrRecord, normalizeDenonavrConfig, validateDenonavrControl } from './denonavr.validation.js';
10
+ import type { IDenonavrConfig, IDenonavrEffectResult, IDenonavrIntegrationOptions, IDenonavrSnapshot, TDenonavrControl } from './denonavr.types.js';
9
11
 
10
12
  export class DenonavrIntegration extends BaseIntegration<IDenonavrConfig> {
11
13
  public readonly domain = 'denonavr';
12
- public readonly displayName = 'Denon AVR Network Receivers';
14
+ public readonly displayName = 'Denon and Marantz selected receivers';
13
15
  public readonly status = 'control-runtime' as const;
14
16
  public readonly discoveryDescriptor = createDenonavrDiscoveryDescriptor();
15
- public readonly configFlow = new DenonavrConfigFlow();
16
- public readonly metadata = {
17
- source: 'home-assistant/core',
18
- upstreamPath: 'homeassistant/components/denonavr',
19
- upstreamDomain: 'denonavr',
20
- integrationType: 'device',
21
- iotClass: 'local_push',
22
- requirements: ['denonavr==1.3.2'],
23
- dependencies: [],
24
- afterDependencies: [],
25
- codeowners: ['@ol-iver', '@starkillerOG'],
26
- configFlow: true,
27
- documentation: 'https://www.home-assistant.io/integrations/denonavr',
28
- };
29
-
30
- public async setup(configArg: IDenonavrConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
31
- void contextArg;
32
- return new DenonavrRuntime(new DenonavrClient(configArg));
17
+ public readonly configFlow: DenonavrConfigFlow;
18
+ public readonly metadata = { source: 'native-typescript', integrationType: 'device', iotClass: 'local_poll' };
19
+ private readonly owner: NativeIntegrationOwner;
20
+
21
+ public constructor(options: IDenonavrIntegrationOptions = {}) {
22
+ super();
23
+ this.owner = new NativeIntegrationOwner('denonavr', options);
24
+ this.configFlow = new DenonavrConfigFlow(options, this.owner.createFlowScope());
33
25
  }
34
26
 
35
- public async destroy(): Promise<void> {}
27
+ public setup(config: IDenonavrConfig, context: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
28
+ let selected: ReturnType<typeof normalizeDenonavrConfig>;
29
+ try { selected = normalizeDenonavrConfig(config); } catch (error) { return Promise.reject(error); }
30
+ try {
31
+ return this.owner.runSetup(context, selected.homeId, async (lease) => {
32
+ const client = new DenonavrClient(selected, lease.context);
33
+ let runtime: DenonavrRuntime | undefined;
34
+ lease.own(async () => {
35
+ const ownedRuntime = runtime;
36
+ const results = await Promise.allSettled([
37
+ Promise.resolve().then(() => client.retryCleanup()),
38
+ ...(ownedRuntime ? [Promise.resolve().then(() => ownedRuntime.closeSubscriptions())] : []),
39
+ ]);
40
+ const failures = results.filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
41
+ if (failures.length) throw new AggregateError(failures.map((entry) => entry.reason), 'DenonAVR owned client or subscriber cleanup failed.');
42
+ });
43
+ const initial = await client.start(lease.signal);
44
+ lease.assertOpen();
45
+ runtime = new DenonavrRuntime(client, initial, lease);
46
+ lease.promoteToRuntime();
47
+ return runtime;
48
+ });
49
+ } catch (error) { return Promise.reject(error); }
50
+ }
51
+
52
+ public destroy(): Promise<void> {
53
+ return this.owner.close();
54
+ }
55
+
56
+ public retryCleanup(): Promise<void> { return this.owner.retryCleanup(); }
36
57
  }
37
58
 
38
59
  export class HomeAssistantDenonavrIntegration extends DenonavrIntegration {}
39
60
 
61
+ interface IDenonavrSubscription {
62
+ handler: (event: IIntegrationEvent) => void;
63
+ active: boolean;
64
+ failed: boolean;
65
+ failure?: unknown;
66
+ detach(): void;
67
+ stop(): Promise<void>;
68
+ }
69
+
40
70
  class DenonavrRuntime implements IIntegrationRuntime {
41
- public domain = 'denonavr';
71
+ public readonly domain = 'denonavr';
72
+ private readonly subscriptions = new Set<IDenonavrSubscription>();
73
+ private readonly parentAbort: () => void;
74
+ private closePromise?: Promise<void>;
75
+ private closed = false;
76
+
77
+ public constructor(private readonly client: DenonavrClient, private snapshot: IDenonavrSnapshot,
78
+ private readonly lease: INativeSetupLease) {
79
+ // The owning integration retains failed runtimes; closePromise exposes asynchronous abort cleanup failures.
80
+ this.parentAbort = () => { void this.destroy().catch(() => {}); };
81
+ lease.signal.addEventListener('abort', this.parentAbort, { once: true });
82
+ if (lease.signal.aborted) this.parentAbort();
83
+ }
42
84
 
43
- constructor(private readonly client: DenonavrClient) {}
85
+ public isHealthy(): boolean { return !this.closed && this.client.isHealthy(); }
44
86
 
45
- public async devices(): Promise<shxInterfaces.data.IDeviceDefinition[]> {
46
- return DenonavrMapper.toDevices(await this.client.getSnapshot());
87
+ public async devices(signal?: AbortSignal): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]> {
88
+ this.assertOpen();
89
+ const snapshot = await this.client.getSnapshot(signal);
90
+ this.publish(snapshot);
91
+ return DenonavrMapper.toDevices(snapshot);
47
92
  }
48
93
 
49
94
  public async entities(): Promise<IIntegrationEntity[]> {
50
- return DenonavrMapper.toEntities(await this.client.getSnapshot());
95
+ this.assertOpen();
96
+ const snapshot = await this.client.getSnapshot();
97
+ this.publish(snapshot);
98
+ return DenonavrMapper.toEntities(snapshot);
51
99
  }
52
100
 
53
- public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
54
- if (requestArg.domain !== 'media_player') {
55
- return { success: false, error: `Unsupported Denon AVR service domain: ${requestArg.domain}` };
56
- }
57
-
58
- const zone = this.zoneFromRequest(requestArg);
59
- const command = this.commandFromService(requestArg);
60
- if (!command) {
61
- return { success: false, error: `Unsupported Denon AVR media_player service: ${requestArg.service}` };
62
- }
101
+ public async writeFeature(input: IDeviceFeatureWriteRequest, signal?: AbortSignal): Promise<IServiceCallResult> {
102
+ this.assertOpen();
103
+ const request = denonavrRecord(input, ['device', 'feature', 'value']);
104
+ const device = denonavrRecord(request.device);
105
+ const feature = denonavrRecord(request.feature);
106
+ const canonical = DenonavrMapper.toDevices(this.snapshot)[0];
107
+ if (device.id !== canonical.id || device.integrationDomain !== this.domain) throw new Error('DenonAVR feature target is outside the selected home and receiver.');
108
+ const admitted = canonical.features.find((entry) => entry.id === feature.id);
109
+ if (!admitted?.writable || feature.capability !== admitted.capability) throw new Error('DenonAVR feature is not writable for the selected receiver.');
110
+ const control = validateDenonavrControl({ feature: admitted.id, value: request.value });
111
+ return this.control(control, signal);
112
+ }
63
113
 
64
- try {
65
- const result = await this.client.execute({
66
- command,
67
- zone,
68
- source: this.stringData(requestArg, 'source'),
69
- volumeLevel: this.numberData(requestArg, 'volume_level'),
70
- muted: this.boolData(requestArg, 'is_volume_muted') ?? this.boolData(requestArg, 'mute'),
71
- });
72
- return { success: true, data: result };
73
- } catch (error) {
74
- return { success: false, error: error instanceof Error ? error.message : String(error) };
75
- }
114
+ public async callService(input: IServiceCallRequest): Promise<IServiceCallResult> {
115
+ this.assertOpen();
116
+ const request = denonavrRecord(input, ['domain', 'service', 'target', 'data']);
117
+ const target = denonavrRecord(request.target, ['deviceId', 'entityId']);
118
+ const deviceId = DenonavrMapper.deviceId(this.snapshot.homeId, this.snapshot.identity.udn);
119
+ const entityId = DenonavrMapper.entityId(this.snapshot.homeId, this.snapshot.identity.udn);
120
+ if ((!target.deviceId && !target.entityId) || (target.deviceId !== undefined && target.deviceId !== deviceId)
121
+ || (target.entityId !== undefined && target.entityId !== entityId)) throw new Error('DenonAVR service target is outside the selected home and receiver.');
122
+ if (request.domain !== 'media_player') throw new Error('DenonAVR services use media_player.');
123
+ let control: TDenonavrControl;
124
+ if (request.service === 'turn_on' || request.service === 'turn_off') {
125
+ denonavrRecord(request.data ?? {}, []);
126
+ control = { feature: 'power', value: request.service === 'turn_on' };
127
+ } else if (request.service === 'volume_set') {
128
+ const data = denonavrRecord(request.data, ['volume_db']);
129
+ control = validateDenonavrControl({ feature: 'volume_db', value: data.volume_db });
130
+ } else if (request.service === 'volume_mute') {
131
+ const data = denonavrRecord(request.data, ['is_volume_muted']);
132
+ control = validateDenonavrControl({ feature: 'muted', value: data.is_volume_muted });
133
+ } else if (request.service === 'select_source') {
134
+ const data = denonavrRecord(request.data, ['source']);
135
+ control = validateDenonavrControl({ feature: 'input', value: data.source });
136
+ } else throw new Error('DenonAVR supports explicit power, mute, absolute dB volume and observed physical inputs only.');
137
+ return this.control(control);
76
138
  }
77
139
 
78
- public async destroy(): Promise<void> {
79
- await this.client.destroy();
140
+ /** Emits only newly completed adapter observations; it does not create a receiver polling loop. */
141
+ public async subscribe(handler: (event: IIntegrationEvent) => void, signal?: AbortSignal): Promise<() => Promise<void>> {
142
+ this.assertOpen();
143
+ if (typeof handler !== 'function' || (signal !== undefined && !(signal instanceof AbortSignal))) throw new TypeError('DenonAVR subscription requires a callback and optional AbortSignal.');
144
+ signal?.throwIfAborted();
145
+ if (this.subscriptions.size >= 32) throw new Error('DenonAVR subscription capacity reached.');
146
+ const subscription: IDenonavrSubscription = {
147
+ handler, active: true, failed: false,
148
+ detach: () => { subscription.active = false; signal?.removeEventListener('abort', aborted); },
149
+ stop: async () => {
150
+ subscription.detach();
151
+ this.subscriptions.delete(subscription);
152
+ if (subscription.failed) throw subscription.failure;
153
+ },
154
+ };
155
+ const aborted = () => { subscription.detach(); this.subscriptions.delete(subscription); };
156
+ signal?.addEventListener('abort', aborted, { once: true });
157
+ this.subscriptions.add(subscription);
158
+ if (signal?.aborted) aborted();
159
+ return subscription.stop;
80
160
  }
81
161
 
82
- private commandFromService(requestArg: IServiceCallRequest): TDenonavrCommand | undefined {
83
- if (requestArg.service === 'turn_on') {
84
- return 'turn_on';
85
- }
86
- if (requestArg.service === 'turn_off') {
87
- return 'turn_off';
88
- }
89
- if (requestArg.service === 'volume_up') {
90
- return 'volume_up';
162
+ public destroy(): Promise<void> {
163
+ if (!this.closePromise) {
164
+ this.closePromise = Promise.resolve().then(() => this.lease.close());
165
+ this.closed = true;
166
+ this.lease.signal.removeEventListener('abort', this.parentAbort);
167
+ for (const subscription of this.subscriptions) subscription.detach();
91
168
  }
92
- if (requestArg.service === 'volume_down') {
93
- return 'volume_down';
94
- }
95
- if (requestArg.service === 'volume_set') {
96
- return 'set_volume';
97
- }
98
- if (requestArg.service === 'volume_mute') {
99
- return 'mute';
100
- }
101
- if (requestArg.service === 'select_source') {
102
- return 'select_source';
103
- }
104
- if (requestArg.service === 'media_play' || requestArg.service === 'play') {
105
- return 'play';
106
- }
107
- if (requestArg.service === 'media_pause' || requestArg.service === 'pause') {
108
- return 'pause';
109
- }
110
- if (requestArg.service === 'media_stop' || requestArg.service === 'stop') {
111
- return 'stop';
112
- }
113
- if (requestArg.service === 'media_play_pause' || requestArg.service === 'play_pause') {
114
- return 'play_pause';
115
- }
116
- if (requestArg.service === 'media_previous_track' || requestArg.service === 'previous_track') {
117
- return 'previous_track';
118
- }
119
- if (requestArg.service === 'media_next_track' || requestArg.service === 'next_track') {
120
- return 'next_track';
121
- }
122
- return undefined;
169
+ return this.closePromise;
123
170
  }
124
171
 
125
- private zoneFromRequest(requestArg: IServiceCallRequest): TDenonavrZone {
126
- const zone = this.stringData(requestArg, 'zone');
127
- if (zone === 'Zone2' || zone === 'zone2') {
128
- return 'Zone2';
129
- }
130
- if (zone === 'Zone3' || zone === 'zone3') {
131
- return 'Zone3';
132
- }
133
- const entityId = requestArg.target.entityId?.toLowerCase() || '';
134
- if (entityId.includes('zone2')) {
135
- return 'Zone2';
136
- }
137
- if (entityId.includes('zone3')) {
138
- return 'Zone3';
139
- }
140
- return 'Main';
172
+ public async closeSubscriptions(): Promise<void> {
173
+ this.closed = true;
174
+ this.lease.signal.removeEventListener('abort', this.parentAbort);
175
+ const results = await Promise.allSettled([...this.subscriptions].map((entry) => entry.stop()));
176
+ const failures = results.filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
177
+ if (failures.length) throw new AggregateError(failures.map((entry) => entry.reason), 'DenonAVR subscriber cleanup failed.');
141
178
  }
142
179
 
143
- private stringData(requestArg: IServiceCallRequest, keyArg: string): string | undefined {
144
- const value = requestArg.data?.[keyArg];
145
- return typeof value === 'string' ? value : undefined;
180
+ private async control(control: TDenonavrControl, signal?: AbortSignal): Promise<IServiceCallResult> {
181
+ try {
182
+ const result = await this.client.setControl(control, signal);
183
+ this.publish(result.snapshot);
184
+ return this.result(result);
185
+ } catch (error) {
186
+ return { success: false, error: error instanceof Error ? error.message : 'DenonAVR control failed.',
187
+ data: { effectOutcome: error instanceof plugins.ecobridgeDeviceManager.DenonProtocolError ? error.effectOutcome : 'not-sent' } };
188
+ }
146
189
  }
147
190
 
148
- private numberData(requestArg: IServiceCallRequest, keyArg: string): number | undefined {
149
- const value = requestArg.data?.[keyArg];
150
- return typeof value === 'number' ? value : undefined;
191
+ private result(result: IDenonavrEffectResult): IServiceCallResult {
192
+ return { success: result.outcome === 'observed-target', ...(result.outcome === 'indeterminate' ? { error: 'Requested receiver setting was not observed.' } : {}),
193
+ data: { dispatch: result.dispatch, outcome: result.outcome, devices: DenonavrMapper.toDevices(result.snapshot), entities: DenonavrMapper.toEntities(result.snapshot) } };
151
194
  }
152
195
 
153
- private boolData(requestArg: IServiceCallRequest, keyArg: string): boolean | undefined {
154
- const value = requestArg.data?.[keyArg];
155
- return typeof value === 'boolean' ? value : undefined;
196
+ private publish(snapshot: IDenonavrSnapshot): void {
197
+ if (this.closed) return;
198
+ this.snapshot = snapshot;
199
+ for (const subscription of [...this.subscriptions]) {
200
+ if (this.closed) break;
201
+ if (!subscription.active) continue;
202
+ try {
203
+ subscription.handler({ type: 'state_changed', integrationDomain: this.domain,
204
+ deviceId: DenonavrMapper.deviceId(snapshot.homeId, snapshot.identity.udn), entityId: DenonavrMapper.entityId(snapshot.homeId, snapshot.identity.udn),
205
+ data: structuredClone(snapshot), timestamp: Date.now() });
206
+ } catch (error) { subscription.failed = true; subscription.failure = error; subscription.detach(); }
207
+ }
156
208
  }
209
+
210
+ private assertOpen(): void { if (this.closed) throw new Error('DenonAVR runtime is closed.'); }
157
211
  }