homematic-manager 3.0.0-beta.2 → 3.0.0-beta.21

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 (332) hide show
  1. package/README.md +2 -1
  2. package/data/easymode-time-selectors.json +285 -0
  3. package/data/icons/106_hm-lc-sw1-dr.webp +0 -0
  4. package/data/icons/108_hm-rc-dis-h-x-eu.webp +0 -0
  5. package/data/icons/109_hm-lc-sw1-pl-ct.webp +0 -0
  6. package/data/icons/110_hm-es-pmsw1-dr.webp +0 -0
  7. package/data/icons/112_hmip-wrc2.webp +0 -0
  8. package/data/icons/113_hmip-psm-ch.webp +0 -0
  9. package/data/icons/113_hmip-psm-it.webp +0 -0
  10. package/data/icons/113_hmip-psm-pe.webp +0 -0
  11. package/data/icons/113_hmip-psm-uk.webp +0 -0
  12. package/data/icons/113_hmip-psm.webp +0 -0
  13. package/data/icons/114_hm-lc-dim1t-fm-lf_3.webp +0 -0
  14. package/data/icons/116_hm-rc-4-3_brc-h3.webp +0 -0
  15. package/data/icons/118_hmip-swdo.webp +0 -0
  16. package/data/icons/119_hmip-rc8.webp +0 -0
  17. package/data/icons/120_hmip-etrv.webp +0 -0
  18. package/data/icons/121_hmip-wth.webp +0 -0
  19. package/data/icons/123_oligo.smart.ip.hm.webp +0 -0
  20. package/data/icons/125_hmip-smi.webp +0 -0
  21. package/data/icons/130_hmip-srh.webp +0 -0
  22. package/data/icons/131_hmip-wrc6.webp +0 -0
  23. package/data/icons/132_hmip-smo.webp +0 -0
  24. package/data/icons/133_hmip-asir.webp +0 -0
  25. package/data/icons/134_hmip-fsm.webp +0 -0
  26. package/data/icons/135_hmip-fsm16.webp +0 -0
  27. package/data/icons/136_hmip-miob.webp +0 -0
  28. package/data/icons/137_hmip-fal-c6.webp +0 -0
  29. package/data/icons/138_hmip-fal-c10.webp +0 -0
  30. package/data/icons/140_alpha-ip-rgb.webp +0 -0
  31. package/data/icons/141_alpha-ip-rgba.webp +0 -0
  32. package/data/icons/144_hmip-wgc.webp +0 -0
  33. package/data/icons/145_hmip-froll_hmip-fbl.webp +0 -0
  34. package/data/icons/146_hmip-sth.webp +0 -0
  35. package/data/icons/147_hmip-sthd.webp +0 -0
  36. package/data/icons/148_hmip-stho.webp +0 -0
  37. package/data/icons/149_hmip-sam.webp +0 -0
  38. package/data/icons/151_hmip-pcbs-bat.webp +0 -0
  39. package/data/icons/152_hmip-swdo-i.webp +0 -0
  40. package/data/icons/153_hmip-spi.webp +0 -0
  41. package/data/icons/154_hmip-spdr.webp +0 -0
  42. package/data/icons/155_hmip-whs2.webp +0 -0
  43. package/data/icons/156_hmip-mod-oc8.webp +0 -0
  44. package/data/icons/158_hmip-etrv-uk.webp +0 -0
  45. package/data/icons/159_hmip-mod-rc8.webp +0 -0
  46. package/data/icons/160_hmipw-drs4.webp +0 -0
  47. package/data/icons/161_hmipw-drs8.webp +0 -0
  48. package/data/icons/162_hmipw-drap.webp +0 -0
  49. package/data/icons/163_hmipw-drbl4.webp +0 -0
  50. package/data/icons/164_hmipw-dri16.webp +0 -0
  51. package/data/icons/165_hmipw-fio6.webp +0 -0
  52. package/data/icons/166_hmipw-drd3.webp +0 -0
  53. package/data/icons/167_hmipw-dri32.webp +0 -0
  54. package/data/icons/168_hmip-smi55.webp +0 -0
  55. package/data/icons/169_hmip-swo-pr.webp +0 -0
  56. package/data/icons/170_hmip-swo-pl.webp +0 -0
  57. package/data/icons/171_hmip-swo-b.webp +0 -0
  58. package/data/icons/172_hmip-swd.webp +0 -0
  59. package/data/icons/173_hmip-bsl.webp +0 -0
  60. package/data/icons/174_hmip-slo.webp +0 -0
  61. package/data/icons/175_hmip-group-heating.webp +0 -0
  62. package/data/icons/177_hmip-dbb.webp +0 -0
  63. package/data/icons/178_hmip-etrv-b1.webp +0 -0
  64. package/data/icons/179_hmip-swdm-b2.webp +0 -0
  65. package/data/icons/180_hmip-etrv-b.webp +0 -0
  66. package/data/icons/181_hmip-swdm.webp +0 -0
  67. package/data/icons/182_hmip-fci1.webp +0 -0
  68. package/data/icons/183_hmip-mod-tm.webp +0 -0
  69. package/data/icons/184_hmip-pcbs2.webp +0 -0
  70. package/data/icons/185_hmip-FCI6.webp +0 -0
  71. package/data/icons/186_hmip-mp3p.webp +0 -0
  72. package/data/icons/187_hmip-rcb1.webp +0 -0
  73. package/data/icons/188_hmip-etrv-c.webp +0 -0
  74. package/data/icons/190_hmip-sci.webp +0 -0
  75. package/data/icons/191_hmip-mod-ho.webp +0 -0
  76. package/data/icons/192_hmip-asir-o.webp +0 -0
  77. package/data/icons/193_hmip-wt.webp +0 -0
  78. package/data/icons/194_hmip-wrcd.webp +0 -0
  79. package/data/icons/195_hmipw-smi55.webp +0 -0
  80. package/data/icons/196_hmip-ASIR-2.webp +0 -0
  81. package/data/icons/197_hmip-swdo-pl.webp +0 -0
  82. package/data/icons/198_hmip-falmot-c12.webp +0 -0
  83. package/data/icons/199_hmip-mio16-pcb.webp +0 -0
  84. package/data/icons/200_hmip-wth-b.webp +0 -0
  85. package/data/icons/201_hmip-stv.webp +0 -0
  86. package/data/icons/202_hmip-wrcr.webp +0 -0
  87. package/data/icons/203_hmip-fsi16.webp +0 -0
  88. package/data/icons/204_hmip-drdi3.webp +0 -0
  89. package/data/icons/205_hmip-drsi4.webp +0 -0
  90. package/data/icons/206_hmip-drbli4.webp +0 -0
  91. package/data/icons/207_hmip-srdo.webp +0 -0
  92. package/data/icons/208_hmip-dsd-pcb.webp +0 -0
  93. package/data/icons/209_hmip-etrv-b-uk.webp +0 -0
  94. package/data/icons/210_hmip-ste2-pcb.webp +0 -0
  95. package/data/icons/211_hmip-drg-dali.webp +0 -0
  96. package/data/icons/211_hmip-drsi1.webp +0 -0
  97. package/data/icons/212_hmip-sfd.webp +0 -0
  98. package/data/icons/212_hmipw-scthd.webp +0 -0
  99. package/data/icons/213_hmip-smo230.webp +0 -0
  100. package/data/icons/213_hmip-wua.webp +0 -0
  101. package/data/icons/214_hmip-dld.webp +0 -0
  102. package/data/icons/215_hmip-psm-pe-2.webp +0 -0
  103. package/data/icons/215_hmip-scth230.webp +0 -0
  104. package/data/icons/216_hmip-etrv-e.webp +0 -0
  105. package/data/icons/216_hmip-psm-ch-2.webp +0 -0
  106. package/data/icons/217_hmip-usbsm.webp +0 -0
  107. package/data/icons/218_hmip-dls.webp +0 -0
  108. package/data/icons/219_hmip-fwi.webp +0 -0
  109. package/data/icons/220_hmip-wsc.webp +0 -0
  110. package/data/icons/221_hmip-sti.webp +0 -0
  111. package/data/icons/221_hmip-wkp.webp +0 -0
  112. package/data/icons/222_hmipw-wgd.webp +0 -0
  113. package/data/icons/223_hmip-mod-wd-vk.webp +0 -0
  114. package/data/icons/224_hmip-etrv-cl.webp +0 -0
  115. package/data/icons/225_hmip-rgbw.webp +0 -0
  116. package/data/icons/226_hmip-esi.webp +0 -0
  117. package/data/icons/227_hmip-lsc.webp +0 -0
  118. package/data/icons/228_elv-sh-sw1-bat.webp +0 -0
  119. package/data/icons/229_elv-sh-bm-s.webp +0 -0
  120. package/data/icons/230_hmip-etrv-f.webp +0 -0
  121. package/data/icons/231_elv-sh-cth.webp +0 -0
  122. package/data/icons/232_elv-sh-taco.webp +0 -0
  123. package/data/icons/233_hmip-flc.webp +0 -0
  124. package/data/icons/234_hmip-etrv-3.webp +0 -0
  125. package/data/icons/235_hmip-psmco.webp +0 -0
  126. package/data/icons/236_elv-sh-sb8.webp +0 -0
  127. package/data/icons/237_elv-sh-ctv.webp +0 -0
  128. package/data/icons/238_elv-sh-cap.webp +0 -0
  129. package/data/icons/239_hmip-wgs-f.webp +0 -0
  130. package/data/icons/240_hmip-wgtc-f.webp +0 -0
  131. package/data/icons/241_hmip-wgt-f.webp +0 -0
  132. package/data/icons/242_elv-sh-smsi.webp +0 -0
  133. package/data/icons/243_elv-sh-crc.webp +0 -0
  134. package/data/icons/244_elv-sh-krco.webp +0 -0
  135. package/data/icons/245_hmip-falmot-c8.webp +0 -0
  136. package/data/icons/246_elv-sh-wsm.webp +0 -0
  137. package/data/icons/247_hmip-hap-2.webp +0 -0
  138. package/data/icons/248_hmip-dlp.webp +0 -0
  139. package/data/icons/249_elv-sh-psmci.webp +0 -0
  140. package/data/icons/250_elv-sh-sps25.webp +0 -0
  141. package/data/icons/252_elv-sh-pti2.webp +0 -0
  142. package/data/icons/253_hmip-udi-smi55.webp +0 -0
  143. package/data/icons/254_hmip-udi-pb2.webp +0 -0
  144. package/data/icons/256_ELV-SH-SMS2.webp +0 -0
  145. package/data/icons/257_ELV-SH-FSI.webp +0 -0
  146. package/data/icons/258_hmip-m-td15.webp +0 -0
  147. package/data/icons/259_elv-sh-dusi.webp +0 -0
  148. package/data/icons/260_hmip-wss.webp +0 -0
  149. package/data/icons/54a_lc-ddc1-pcb.webp +0 -0
  150. package/data/icons/72_hm-rc-brc-h.webp +0 -0
  151. package/data/icons/73_hm-atent.webp +0 -0
  152. package/data/icons/79_hm-lc-dim1pwm-cv.webp +0 -0
  153. package/data/icons/84_hm-rc-4-3.webp +0 -0
  154. package/data/icons/85_hm-rc-sec4-3.webp +0 -0
  155. package/data/icons/86_hm-rc-key4-3.webp +0 -0
  156. package/data/icons/CCU3-1-50.webp +0 -0
  157. package/data/icons/CCU3.webp +0 -0
  158. package/data/icons/hm-coupling-dim.webp +0 -0
  159. package/data/icons/hm-coupling-group.webp +0 -0
  160. package/data/icons/hm-coupling-onoff.webp +0 -0
  161. package/data/icons/hm-coupling-rgb-dim.webp +0 -0
  162. package/data/icons/hm-coupling-rgb.webp +0 -0
  163. package/data/icons/hm-coupling-rgbw-dim.webp +0 -0
  164. package/data/icons/hm-coupling-rgbw.webp +0 -0
  165. package/data/icons/hm-coupling-white-dim.webp +0 -0
  166. package/data/icons/hm-coupling-white.webp +0 -0
  167. package/data/icons/hm-hue_gateway.webp +0 -0
  168. package/data/icons/hm-lightify_gateway.webp +0 -0
  169. package/data/icons/hm_resc-win-pcb-sc.webp +0 -0
  170. package/data/icons/unknown_device.webp +0 -0
  171. package/data/manifest.json +7 -1
  172. package/data/master-metadata.json +1997 -33
  173. package/data/profiles/ACCESS_RECEIVER.json +26 -13
  174. package/data/profiles/ACOUSTIC_SIGNAL_VIRTUAL_RECEIVER.json +3270 -76
  175. package/data/profiles/ACTOR_SECURITY.json +90 -10
  176. package/data/profiles/ACTOR_WINDOW.json +580 -43
  177. package/data/profiles/ALARMACTUATOR.json +564 -37
  178. package/data/profiles/ALARM_COND_SWITCH_RECEIVER.json +36 -4
  179. package/data/profiles/ALARM_SWITCH_VIRTUAL_RECEIVER.json +735 -33
  180. package/data/profiles/ARMING.json +115 -5
  181. package/data/profiles/BLIND.json +1038 -49
  182. package/data/profiles/BLIND_VIRTUAL_RECEIVER.json +4624 -124
  183. package/data/profiles/CLIMATECONTROL_FLOOR_PUMP_TRANSCEIVER.json +27 -1
  184. package/data/profiles/DIMMER.json +2233 -71
  185. package/data/profiles/DIMMER_VIRTUAL_RECEIVER.json +5773 -102
  186. package/data/profiles/DIMMER_woLongKeyPress.json +117 -4
  187. package/data/profiles/DOOR_RECEIVER.json +138 -10
  188. package/data/profiles/DUAL_WHITE_BRIGHTNESS.json +305 -11
  189. package/data/profiles/DUAL_WHITE_COLOR.json +730 -23
  190. package/data/profiles/HEATING_KEY_RECEIVER.json +127 -10
  191. package/data/profiles/HMW_BLIND.json +555 -20
  192. package/data/profiles/HMW_DIMMER.json +1337 -47
  193. package/data/profiles/HMW_INPUT_OUTPUT.json +375 -20
  194. package/data/profiles/HMW_SWITCH.json +375 -20
  195. package/data/profiles/JALOUSIE.json +1320 -52
  196. package/data/profiles/KEYMATIC.json +120 -12
  197. package/data/profiles/REMOTECONTROL_RECEIVER.json +10 -2
  198. package/data/profiles/RGBW_AUTOMATIC.json +46 -6
  199. package/data/profiles/RGBW_COLOR.json +14 -4
  200. package/data/profiles/SERVO_VIRTUAL_RECEIVER.json +117 -3
  201. package/data/profiles/SHUTTER_VIRTUAL_RECEIVER.json +4263 -128
  202. package/data/profiles/SIGNAL_CHIME.json +195 -14
  203. package/data/profiles/SIGNAL_CHIMEM.json +195 -14
  204. package/data/profiles/SIGNAL_LED.json +195 -14
  205. package/data/profiles/SIGNAL_LEDM.json +195 -14
  206. package/data/profiles/SIMPLE_SWITCH_RECEIVER.json +113 -9
  207. package/data/profiles/STATUS_INDICATOR.json +1073 -45
  208. package/data/profiles/SWITCH.json +1412 -60
  209. package/data/profiles/SWITCH_PANIC.json +315 -13
  210. package/data/profiles/SWITCH_SENSOR.json +243 -11
  211. package/data/profiles/SWITCH_VIRTUAL_RECEIVER.json +3963 -131
  212. package/data/profiles/UNIVERSAL_ACTOR.json +4319 -90
  213. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_LSC.json +6094 -196
  214. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_PWM.json +4920 -101
  215. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_RGB(W).json +2353 -80
  216. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_RGBW_DALI.json +6116 -176
  217. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_TW.json +3844 -104
  218. package/data/profiles/VIRTUAL_DIMMER.json +305 -11
  219. package/data/profiles/VIRTUAL_DUAL_WHITE_COLOR.json +730 -23
  220. package/data/profiles/WATER_SWITCH_VIRTUAL_RECEIVER.json +3903 -128
  221. package/data/profiles/WINDOW_DRIVE_RECEIVER.json +220 -8
  222. package/data/profiles/WINMATIC.json +505 -23
  223. package/dist/cli.js +24 -0
  224. package/dist/occulite.d.ts +86 -0
  225. package/dist/occulite.js +140 -0
  226. package/dist/options.d.ts +37 -6
  227. package/dist/options.js +49 -6
  228. package/dist/server.d.ts +47 -4
  229. package/dist/server.js +237 -27
  230. package/dist/sessions.d.ts +9 -1
  231. package/dist/sessions.js +8 -2
  232. package/dist/testSupport.js +9 -2
  233. package/node_modules/@homematic-manager/backend/dist/api/backend.d.ts +33 -0
  234. package/node_modules/@homematic-manager/backend/dist/api/backend.js +558 -46
  235. package/node_modules/@homematic-manager/backend/dist/cache/names.d.ts +9 -0
  236. package/node_modules/@homematic-manager/backend/dist/cache/names.js +21 -0
  237. package/node_modules/@homematic-manager/backend/dist/config/defaults.js +10 -1
  238. package/node_modules/@homematic-manager/backend/dist/config/store.d.ts +28 -1
  239. package/node_modules/@homematic-manager/backend/dist/config/store.js +59 -3
  240. package/node_modules/@homematic-manager/backend/dist/devices/installMode.js +9 -0
  241. package/node_modules/@homematic-manager/backend/dist/errors.d.ts +18 -0
  242. package/node_modules/@homematic-manager/backend/dist/errors.js +51 -2
  243. package/node_modules/@homematic-manager/backend/dist/images/deviceImages.d.ts +6 -0
  244. package/node_modules/@homematic-manager/backend/dist/images/deviceImages.js +38 -2
  245. package/node_modules/@homematic-manager/backend/dist/index.d.ts +3 -1
  246. package/node_modules/@homematic-manager/backend/dist/index.js +4 -1
  247. package/node_modules/@homematic-manager/backend/dist/interfaces/manager.d.ts +70 -8
  248. package/node_modules/@homematic-manager/backend/dist/interfaces/manager.js +333 -44
  249. package/node_modules/@homematic-manager/backend/dist/meta/client.d.ts +120 -0
  250. package/node_modules/@homematic-manager/backend/dist/meta/client.js +307 -0
  251. package/node_modules/@homematic-manager/backend/dist/meta/credentials.d.ts +38 -0
  252. package/node_modules/@homematic-manager/backend/dist/meta/credentials.js +53 -0
  253. package/node_modules/@homematic-manager/backend/dist/meta/index.d.ts +12 -0
  254. package/node_modules/@homematic-manager/backend/dist/meta/index.js +12 -0
  255. package/node_modules/@homematic-manager/backend/dist/meta/localProvider.d.ts +47 -0
  256. package/node_modules/@homematic-manager/backend/dist/meta/localProvider.js +119 -0
  257. package/node_modules/@homematic-manager/backend/dist/meta/occuliteProvider.d.ts +79 -0
  258. package/node_modules/@homematic-manager/backend/dist/meta/occuliteProvider.js +305 -0
  259. package/node_modules/@homematic-manager/backend/dist/meta/provider.d.ts +68 -0
  260. package/node_modules/@homematic-manager/backend/dist/meta/provider.js +19 -0
  261. package/node_modules/@homematic-manager/backend/dist/meta/regaProvider.d.ts +84 -0
  262. package/node_modules/@homematic-manager/backend/dist/meta/regaProvider.js +403 -0
  263. package/node_modules/@homematic-manager/backend/dist/meta/service.d.ts +137 -0
  264. package/node_modules/@homematic-manager/backend/dist/meta/service.js +412 -0
  265. package/node_modules/@homematic-manager/backend/dist/rega/client.d.ts +11 -0
  266. package/node_modules/@homematic-manager/backend/dist/rega/client.js +13 -0
  267. package/node_modules/@homematic-manager/backend/dist/rega/scripts.d.ts +51 -0
  268. package/node_modules/@homematic-manager/backend/dist/rega/scripts.js +171 -0
  269. package/node_modules/@homematic-manager/backend/dist/rpc/client.d.ts +18 -5
  270. package/node_modules/@homematic-manager/backend/dist/rpc/client.js +11 -5
  271. package/node_modules/@homematic-manager/backend/dist/rpc/log.d.ts +86 -0
  272. package/node_modules/@homematic-manager/backend/dist/rpc/log.js +241 -0
  273. package/node_modules/@homematic-manager/backend/dist/rpc/origin.d.ts +30 -0
  274. package/node_modules/@homematic-manager/backend/dist/rpc/origin.js +35 -0
  275. package/node_modules/@homematic-manager/backend/dist/rpc/server.d.ts +12 -0
  276. package/node_modules/@homematic-manager/backend/dist/rpc/server.js +37 -5
  277. package/node_modules/@homematic-manager/backend/dist/util/net.d.ts +86 -1
  278. package/node_modules/@homematic-manager/backend/dist/util/net.js +223 -9
  279. package/node_modules/@homematic-manager/backend/package.json +1 -1
  280. package/node_modules/@homematic-manager/core/dist/api/types.d.ts +397 -10
  281. package/node_modules/@homematic-manager/core/dist/api/types.js +23 -2
  282. package/node_modules/@homematic-manager/core/dist/data/memory.d.ts +3 -1
  283. package/node_modules/@homematic-manager/core/dist/data/memory.js +3 -0
  284. package/node_modules/@homematic-manager/core/dist/data/types.d.ts +60 -0
  285. package/node_modules/@homematic-manager/core/dist/data/types.js +2 -0
  286. package/node_modules/@homematic-manager/core/dist/devices/index.d.ts +19 -0
  287. package/node_modules/@homematic-manager/core/dist/devices/index.js +53 -0
  288. package/node_modules/@homematic-manager/core/dist/easymodes/engine.d.ts +3 -1
  289. package/node_modules/@homematic-manager/core/dist/easymodes/engine.js +1 -0
  290. package/node_modules/@homematic-manager/core/dist/easymodes/form.d.ts +43 -0
  291. package/node_modules/@homematic-manager/core/dist/easymodes/form.js +84 -0
  292. package/node_modules/@homematic-manager/core/dist/i18n/messages.js +61 -0
  293. package/node_modules/@homematic-manager/core/dist/index.d.ts +3 -0
  294. package/node_modules/@homematic-manager/core/dist/index.js +4 -0
  295. package/node_modules/@homematic-manager/core/dist/interfaces/table.d.ts +23 -2
  296. package/node_modules/@homematic-manager/core/dist/interfaces/table.js +18 -1
  297. package/node_modules/@homematic-manager/core/dist/meta/document.d.ts +71 -0
  298. package/node_modules/@homematic-manager/core/dist/meta/document.js +260 -0
  299. package/node_modules/@homematic-manager/core/dist/meta/follow.d.ts +27 -0
  300. package/node_modules/@homematic-manager/core/dist/meta/follow.js +180 -0
  301. package/node_modules/@homematic-manager/core/dist/meta/index.d.ts +16 -0
  302. package/node_modules/@homematic-manager/core/dist/meta/index.js +16 -0
  303. package/node_modules/@homematic-manager/core/dist/meta/paths.d.ts +96 -0
  304. package/node_modules/@homematic-manager/core/dist/meta/paths.js +182 -0
  305. package/node_modules/@homematic-manager/core/dist/meta/slug.d.ts +22 -0
  306. package/node_modules/@homematic-manager/core/dist/meta/slug.js +59 -0
  307. package/node_modules/@homematic-manager/core/dist/meta/store.d.ts +147 -0
  308. package/node_modules/@homematic-manager/core/dist/meta/store.js +537 -0
  309. package/node_modules/@homematic-manager/core/dist/meta/tree.d.ts +19 -0
  310. package/node_modules/@homematic-manager/core/dist/meta/tree.js +53 -0
  311. package/node_modules/@homematic-manager/core/dist/meta/types.d.ts +143 -0
  312. package/node_modules/@homematic-manager/core/dist/meta/types.js +63 -0
  313. package/node_modules/@homematic-manager/core/dist/meta/view.d.ts +50 -0
  314. package/node_modules/@homematic-manager/core/dist/meta/view.js +103 -0
  315. package/node_modules/@homematic-manager/core/dist/rpc/methods.d.ts +10 -0
  316. package/node_modules/@homematic-manager/core/dist/rpc/methods.js +51 -1
  317. package/node_modules/@homematic-manager/core/dist/rpc/text.d.ts +22 -0
  318. package/node_modules/@homematic-manager/core/dist/rpc/text.js +46 -0
  319. package/node_modules/@homematic-manager/core/dist/rssi/index.d.ts +125 -13
  320. package/node_modules/@homematic-manager/core/dist/rssi/index.js +146 -29
  321. package/node_modules/@homematic-manager/core/dist/serviceMessages/index.d.ts +28 -2
  322. package/node_modules/@homematic-manager/core/dist/serviceMessages/index.js +44 -6
  323. package/node_modules/@homematic-manager/core/package.json +1 -1
  324. package/package.json +3 -3
  325. package/ui/assets/index-D-NsbBVS.css +1 -0
  326. package/ui/assets/index-DNUNMBbb.js +16 -0
  327. package/ui/favicon.ico +0 -0
  328. package/ui/index.html +3 -2
  329. package/node_modules/@homematic-manager/backend/dist/write/log.d.ts +0 -51
  330. package/node_modules/@homematic-manager/backend/dist/write/log.js +0 -151
  331. package/ui/assets/index-lB-HxsKR.js +0 -13
  332. package/ui/assets/index-qbhgN2pA.css +0 -1
@@ -0,0 +1,537 @@
1
+ /**
2
+ * The metadata store, in memory: every operation of the metadata API, with its revisions and its
3
+ * change stream.
4
+ *
5
+ * This is the second implementation of openccu-lite's D-16 - `occulited` in Go is the first - and
6
+ * the conformance corpus is what keeps the two honest. It is used twice here: it *is* the `local`
7
+ * provider (a user on Homegear, on a bare rfd or on the desktop gets rooms and functions without
8
+ * any box at all), and it is the model the `occulite` provider keeps of what the box holds, so the
9
+ * UI reads the same shapes whichever provider is on.
10
+ *
11
+ * Three rules run through all of it:
12
+ *
13
+ * - **a write that changes nothing is not a write.** It returns `changed: false` and the revision
14
+ * stays where it was. Setting a name to the name it already has must not bump a revision that
15
+ * every consumer of the change stream is watching.
16
+ * - **all or nothing.** A bulk, an import and a move that rewrites member paths are one revision;
17
+ * a validation error leaves the store exactly as it was.
18
+ * - **every refusal is a code**, never a boolean: the UI shows a message per code and the corpus
19
+ * compares them.
20
+ */
21
+ var _a;
22
+ import { documentEquals, knownPaths, normaliseEnumList, normaliseEnumName, normaliseMeta, parseDocument, } from './document.js';
23
+ import { indexOfNode, insertAt, removeAt } from './tree.js';
24
+ import { childPath, enumPaths, findNode, isValidIcon, isValidId, normaliseName, parsePath, pathMatches, requireDepth, requireId, requireRef, } from './paths.js';
25
+ import { MetaError, emptyDocument, } from './types.js';
26
+ /** How many events the change stream keeps for a consumer that reconnects. The API asks for 1000. */
27
+ export const DEFAULT_EVENT_HISTORY = 1000;
28
+ export class MetaStore {
29
+ #revision;
30
+ #objects;
31
+ #enums;
32
+ #history = [];
33
+ #historySize;
34
+ /** The lowest `since` a replay can still answer; below it the answer is `resync`. */
35
+ #replayFrom;
36
+ #onEvent;
37
+ constructor(options = {}) {
38
+ const document = options.document ?? emptyDocument();
39
+ this.#revision = document.revision;
40
+ this.#objects = new Map(Object.entries(document.objects));
41
+ this.#enums = new Map(Object.entries(document.enums));
42
+ this.#historySize = options.eventHistory ?? DEFAULT_EVENT_HISTORY;
43
+ this.#replayFrom = document.revision;
44
+ this.#onEvent = options.onEvent;
45
+ }
46
+ get revision() {
47
+ return this.#revision;
48
+ }
49
+ get size() {
50
+ return this.#objects.size;
51
+ }
52
+ /** The whole store, as `/snapshot` serves it and as it is written to disk. */
53
+ document() {
54
+ return {
55
+ format: 1,
56
+ revision: this.#revision,
57
+ objects: Object.fromEntries([...this.#objects].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))),
58
+ enums: Object.fromEntries([...this.#enums]),
59
+ };
60
+ }
61
+ /**
62
+ * Replaces everything without producing an import event or a revision of our own.
63
+ *
64
+ * This is how the `occulite` provider takes a snapshot from the box: the box owns the revision,
65
+ * and a consumer that renumbered it would break every `?since=` it sends afterwards.
66
+ */
67
+ load(document) {
68
+ this.#revision = document.revision;
69
+ this.#objects = new Map(Object.entries(document.objects));
70
+ this.#enums = new Map(Object.entries(document.enums));
71
+ this.#history.length = 0;
72
+ this.#replayFrom = document.revision;
73
+ }
74
+ /*
75
+ * reads
76
+ */
77
+ /** One object, or `unknown-object`. */
78
+ get(ref) {
79
+ const object = this.#objects.get(ref);
80
+ if (!object) {
81
+ throw new MetaError('unknown-object', `${ref} is not in the store`);
82
+ }
83
+ return object;
84
+ }
85
+ /** One object, or `undefined` - the read that a UI does for every row of a grid. */
86
+ find(ref) {
87
+ return this.#objects.get(ref);
88
+ }
89
+ /** Every object, keyed by ref. */
90
+ objects() {
91
+ return Object.fromEntries(this.#objects);
92
+ }
93
+ /** Every enum with its tree. */
94
+ enums() {
95
+ return Object.fromEntries(this.#enums);
96
+ }
97
+ /** One enum, or `unknown-enum`. */
98
+ getEnum(id) {
99
+ const definition = this.#enums.get(id);
100
+ if (!definition) {
101
+ throw new MetaError('unknown-enum', `${id} is not an enum`);
102
+ }
103
+ return definition;
104
+ }
105
+ /**
106
+ * The refs that belong to a node **or anything below it**, sorted.
107
+ *
108
+ * `room/eg` answers with everything on the ground floor, `room` with everything that is in any
109
+ * room at all. That is what the tree buys and why membership is a path and not an id.
110
+ */
111
+ query(target, orphaned) {
112
+ this.#requireTarget(target);
113
+ const refs = [];
114
+ for (const [ref, object] of this.#objects) {
115
+ if (!object.enums.some((path) => pathMatches(path, target))) {
116
+ continue;
117
+ }
118
+ if (orphaned !== undefined && (object.orphaned === true) !== orphaned) {
119
+ continue;
120
+ }
121
+ refs.push(ref);
122
+ }
123
+ return refs.sort();
124
+ }
125
+ /**
126
+ * The change stream since a revision: the events, or "fetch the snapshot again".
127
+ *
128
+ * A consumer that was away longer than the history, or that asks for something impossible, is
129
+ * told to resync rather than served a gap it cannot see.
130
+ */
131
+ since(revision) {
132
+ if (!Number.isInteger(revision) || revision < 0 || revision > this.#revision || revision < this.#replayFrom) {
133
+ return { revision: this.#revision, resync: true };
134
+ }
135
+ return { revision: this.#revision, events: this.#history.filter((event) => event.revision > revision) };
136
+ }
137
+ /*
138
+ * objects
139
+ */
140
+ /** `PATCH /objects/{ref}`: create or update; absent fields are left alone. */
141
+ set(ref, patch) {
142
+ requireRef(ref);
143
+ if (patch.orphaned !== undefined) {
144
+ throw new MetaError('forbidden', 'orphaned is set by the process that owns the addresses');
145
+ }
146
+ const existing = this.#objects.get(ref);
147
+ const name = patch.name === undefined ? existing?.name : normaliseName(patch.name);
148
+ if (name === undefined) {
149
+ throw new MetaError('invalid-name', `${ref} is new and needs a name`);
150
+ }
151
+ const enums = patch.enums === undefined ? (existing?.enums ?? []) : this.#requirePaths(normaliseEnumList(patch.enums));
152
+ const meta = patch.meta === undefined ? (existing?.meta ?? {}) : mergeMeta(existing?.meta ?? {}, patch.meta);
153
+ return this.#putObject(ref, buildObject(name, enums, meta, existing?.orphaned === true));
154
+ }
155
+ /** `PUT /objects/{ref}`: create or replace; missing optional fields go back to their defaults. */
156
+ put(ref, body) {
157
+ requireRef(ref);
158
+ const existing = this.#objects.get(ref);
159
+ const name = normaliseName(body.name);
160
+ const enums = this.#requirePaths(normaliseEnumList(body.enums));
161
+ const meta = normaliseMeta(body.meta);
162
+ return this.#putObject(ref, buildObject(name, enums, meta, existing?.orphaned === true));
163
+ }
164
+ /**
165
+ * `DELETE /objects/{ref}`: forgets an entry for good.
166
+ *
167
+ * Normally unnecessary - `orphaned` is how "gone" is expressed, so that a replaced device keeps
168
+ * its room - but a user may really want to forget one. Deleting what is not there is not an
169
+ * error: it is the state the caller asked for, and a bulk that carries one must not fail.
170
+ */
171
+ delete(ref) {
172
+ if (!this.#objects.has(ref)) {
173
+ return { revision: this.#revision, changed: false };
174
+ }
175
+ this.#objects.delete(ref);
176
+ return this.#commit([{ kind: 'object.deleted', ref }]);
177
+ }
178
+ /** `POST /objects:bulk`: any number of writes and deletes as **one** revision. */
179
+ bulk(sets, deletes = []) {
180
+ // validated against a copy first, so a bad entry leaves the store untouched
181
+ const draft = this.#clone();
182
+ const events = [];
183
+ for (const [ref, patch] of Object.entries(sets)) {
184
+ if (draft.set(ref, patch).changed) {
185
+ events.push({ kind: 'object.updated', ref, value: draft.get(ref) });
186
+ }
187
+ }
188
+ for (const ref of deletes) {
189
+ if (draft.delete(ref).changed) {
190
+ events.push({ kind: 'object.deleted', ref });
191
+ }
192
+ }
193
+ if (events.length === 0) {
194
+ return { revision: this.#revision, changed: false };
195
+ }
196
+ this.#adopt(draft);
197
+ return this.#commit(events);
198
+ }
199
+ /**
200
+ * The `orphaned` flag, which only the process that owns the addresses may set.
201
+ *
202
+ * It is a mutation like any other - a consumer has to learn that a device disappeared - and it
203
+ * never touches the assignments: a device that comes back is in its room again.
204
+ */
205
+ setOrphaned(ref, orphaned) {
206
+ const object = this.get(ref);
207
+ if ((object.orphaned === true) === orphaned) {
208
+ return { revision: this.#revision, changed: false };
209
+ }
210
+ const next = buildObject(object.name, object.enums, object.meta, orphaned);
211
+ this.#objects.set(ref, next);
212
+ return this.#commit([{ kind: 'object.updated', ref, value: next }]);
213
+ }
214
+ /*
215
+ * enums
216
+ */
217
+ /** `POST /enums`. */
218
+ createEnum(id, name) {
219
+ requireId(id);
220
+ if (this.#enums.has(id)) {
221
+ throw new MetaError('duplicate-id', `${id} exists`);
222
+ }
223
+ const definition = { name: normaliseEnumName(name), tree: [] };
224
+ this.#enums.set(id, definition);
225
+ return this.#commit([{ kind: 'enum.created', enum: id, value: definition }]);
226
+ }
227
+ /** `PATCH /enums/{enum}`: the display name, nothing else. */
228
+ updateEnum(id, name) {
229
+ const existing = this.getEnum(id);
230
+ const next = { name: normaliseEnumName(name), tree: existing.tree };
231
+ if (JSON.stringify(next.name) === JSON.stringify(existing.name)) {
232
+ return { revision: this.#revision, changed: false };
233
+ }
234
+ this.#enums.set(id, next);
235
+ return this.#commit([{ kind: 'enum.updated', enum: id, value: next }]);
236
+ }
237
+ /**
238
+ * `DELETE /enums/{enum}`: the enum and every node in it.
239
+ *
240
+ * Refused while anything is a member, unless the caller says `detach` - in which case the
241
+ * paths are removed from every object **in the same revision**, so no consumer ever sees an
242
+ * object pointing at a node that is already gone.
243
+ */
244
+ deleteEnum(id, members = 'refuse') {
245
+ const definition = this.getEnum(id);
246
+ const affected = this.#membersOf([...enumPaths(id, definition)]);
247
+ if (affected.refs.length > 0 && members !== 'detach') {
248
+ throw new MetaError('has-members', `${id} still has members`, { refs: [...affected.refs] });
249
+ }
250
+ this.#enums.delete(id);
251
+ this.#detach(affected);
252
+ return this.#commit([{ kind: 'enum.deleted', enum: id }]);
253
+ }
254
+ /*
255
+ * nodes
256
+ */
257
+ /** `POST /enums/{enum}/nodes`: a node under a parent, or at the root when `parent` is null. */
258
+ createNode(enumId, parent, id, name, options = {}) {
259
+ const definition = this.getEnum(enumId);
260
+ requireId(id);
261
+ const nodeName = normaliseName(name);
262
+ if (options.icon !== undefined && !isValidIcon(options.icon)) {
263
+ throw new MetaError('invalid-id', `${options.icon} is not a valid icon name`);
264
+ }
265
+ const parentPath = parent ?? enumId;
266
+ const parentIds = this.#requireParent(enumId, parentPath);
267
+ const siblings = parentIds.length === 0 ? definition.tree : (findNode(definition.tree, parentIds)?.children ?? []);
268
+ if (siblings.some((node) => node.id === id)) {
269
+ throw new MetaError('duplicate-id', `${childPath(parentPath, id)} exists`);
270
+ }
271
+ const node = { id, name: nodeName, ...(options.icon === undefined ? {} : { icon: options.icon }) };
272
+ const tree = insertAt(definition.tree, parentIds, node, options.position);
273
+ requireDepth(tree);
274
+ this.#enums.set(enumId, { name: definition.name, tree });
275
+ return this.#commit([{ kind: 'node.created', enum: enumId, path: childPath(parentPath, id), value: node }]);
276
+ }
277
+ /**
278
+ * `PATCH /enums/{enum}/nodes/{path}`: rename, re-icon, move, reorder.
279
+ *
280
+ * A move keeps the id, so every member path is rewritten **in the same revision** and consumers
281
+ * see one `node.moved` carrying `from` and `to` rather than a delete and a create that would
282
+ * briefly leave objects pointing nowhere.
283
+ */
284
+ updateNode(path, patch) {
285
+ const { enumId, ids } = this.#requireNode(path);
286
+ const definition = this.getEnum(enumId);
287
+ const node = findNode(definition.tree, ids);
288
+ if (!node) {
289
+ throw new MetaError('unknown-path', `${path} does not exist`);
290
+ }
291
+ const name = patch.name === undefined ? node.name : normaliseName(patch.name);
292
+ if (patch.icon !== undefined && !isValidIcon(patch.icon)) {
293
+ throw new MetaError('invalid-id', `${patch.icon} is not a valid icon name`);
294
+ }
295
+ const icon = patch.icon ?? node.icon;
296
+ const currentParentIds = ids.slice(0, -1);
297
+ let targetParentIds = currentParentIds;
298
+ let targetParentPath = [enumId, ...currentParentIds].join('/');
299
+ if (patch.parent !== undefined) {
300
+ const parentPath = patch.parent ?? enumId;
301
+ if (pathMatches(parentPath, path)) {
302
+ throw new MetaError('invalid-move', `${path} cannot be moved under itself`);
303
+ }
304
+ targetParentIds = this.#requireParent(enumId, parentPath);
305
+ targetParentPath = parentPath;
306
+ }
307
+ const target = childPath(targetParentPath, node.id);
308
+ const moved = target !== path;
309
+ if (moved) {
310
+ const siblings = targetParentIds.length === 0
311
+ ? definition.tree
312
+ : (findNode(definition.tree, targetParentIds)?.children ?? []);
313
+ if (siblings.some((sibling) => sibling.id === node.id)) {
314
+ throw new MetaError('duplicate-id', `${target} exists`);
315
+ }
316
+ }
317
+ const next = {
318
+ id: node.id,
319
+ name,
320
+ ...(icon === undefined ? {} : { icon }),
321
+ ...(node.children === undefined ? {} : { children: node.children }),
322
+ };
323
+ const withoutNode = removeAt(definition.tree, ids);
324
+ const position = patch.position ?? (moved ? undefined : indexOfNode(definition.tree, ids));
325
+ const tree = insertAt(withoutNode, targetParentIds, next, position);
326
+ requireDepth(tree);
327
+ if (JSON.stringify(tree) === JSON.stringify(definition.tree)) {
328
+ return { revision: this.#revision, changed: false };
329
+ }
330
+ this.#enums.set(enumId, { name: definition.name, tree });
331
+ const events = [];
332
+ if (moved) {
333
+ // one event, not one per member: the specification says a move is a single `node.moved`
334
+ // carrying `from` and `to`, and every consumer rewrites its own member paths from it -
335
+ // an object.updated per member would be the same information twice and, on a store with
336
+ // two hundred channels in a room, two hundred messages for one drag of a node
337
+ this.#rewrite(path, target);
338
+ events.push({ kind: 'node.moved', enum: enumId, from: path, to: target });
339
+ }
340
+ else if (patch.position !== undefined && position !== indexOfNode(definition.tree, ids)) {
341
+ events.push({ kind: 'node.moved', enum: enumId, from: path, to: path });
342
+ }
343
+ else {
344
+ events.push({ kind: 'node.updated', enum: enumId, path, value: next });
345
+ }
346
+ return this.#commit(events);
347
+ }
348
+ /** `DELETE /enums/{enum}/nodes/{path}`: the node and its subtree, with the same `detach` rule. */
349
+ deleteNode(path, members = 'refuse') {
350
+ const { enumId, ids } = this.#requireNode(path);
351
+ const definition = this.getEnum(enumId);
352
+ const node = findNode(definition.tree, ids);
353
+ if (!node) {
354
+ throw new MetaError('unknown-path', `${path} does not exist`);
355
+ }
356
+ const affected = this.#membersOf([path]);
357
+ if (affected.refs.length > 0 && members !== 'detach') {
358
+ throw new MetaError('has-members', `${path} still has members`, { refs: [...affected.refs] });
359
+ }
360
+ this.#enums.set(enumId, { name: definition.name, tree: removeAt(definition.tree, ids) });
361
+ this.#detach(affected);
362
+ return this.#commit([{ kind: 'node.deleted', enum: enumId, path }]);
363
+ }
364
+ /*
365
+ * import
366
+ */
367
+ /**
368
+ * `PUT /import`: a whole document, validated completely and applied as one revision.
369
+ *
370
+ * `replace` swaps the store; `merge` keeps the objects and enums the import does not mention
371
+ * and overwrites the ones it does. Either way the *result* is validated - a merge that would
372
+ * leave an object pointing at a node the import removed is refused, not repaired.
373
+ */
374
+ import(raw, mode = 'replace') {
375
+ const incoming = parseDocument(raw);
376
+ const current = this.document();
377
+ const merged = mode === 'merge'
378
+ ? parseDocument({
379
+ format: 1,
380
+ revision: current.revision,
381
+ objects: { ...current.objects, ...incoming.objects },
382
+ enums: { ...current.enums, ...incoming.enums },
383
+ })
384
+ : incoming;
385
+ if (documentEquals(current, merged)) {
386
+ return { revision: this.#revision, changed: false };
387
+ }
388
+ this.#objects = new Map(Object.entries(merged.objects));
389
+ this.#enums = new Map(Object.entries(merged.enums));
390
+ return this.#commit([
391
+ {
392
+ kind: 'import',
393
+ objects: Object.keys(merged.objects).length,
394
+ enums: Object.keys(merged.enums).length,
395
+ },
396
+ ]);
397
+ }
398
+ /*
399
+ * internals
400
+ */
401
+ #putObject(ref, next) {
402
+ const existing = this.#objects.get(ref);
403
+ if (existing && JSON.stringify(existing) === JSON.stringify(next)) {
404
+ return { revision: this.#revision, changed: false };
405
+ }
406
+ this.#objects.set(ref, next);
407
+ return this.#commit([{ kind: 'object.updated', ref, value: next }]);
408
+ }
409
+ /** Every path in the list has to exist; that is what makes a dangling membership impossible. */
410
+ #requirePaths(paths) {
411
+ const known = knownPaths(this.enums());
412
+ for (const path of paths) {
413
+ if (!known.has(path)) {
414
+ throw new MetaError('unknown-path', `${path} does not exist`, { path });
415
+ }
416
+ }
417
+ return paths;
418
+ }
419
+ /** A query target: an enum id (everything in it) or a node path (that subtree). */
420
+ #requireTarget(target) {
421
+ const parsed = parsePath(target);
422
+ if (!parsed) {
423
+ throw new MetaError('unknown-path', `${target} is not a node path`);
424
+ }
425
+ const definition = this.getEnum(parsed.enumId);
426
+ if (parsed.ids.length > 0 && !findNode(definition.tree, parsed.ids)) {
427
+ throw new MetaError('unknown-path', `${target} does not exist`);
428
+ }
429
+ }
430
+ /** A node path, split - the enum has to exist, the node is looked up by the caller. */
431
+ #requireNode(path) {
432
+ const parsed = parsePath(path);
433
+ if (!parsed || parsed.ids.length === 0) {
434
+ throw new MetaError('unknown-path', `${path} is not a node path`);
435
+ }
436
+ return { enumId: parsed.enumId, ids: parsed.ids };
437
+ }
438
+ /** The ids of a parent inside its enum; `[]` for the enum itself, i.e. the root. */
439
+ #requireParent(enumId, parentPath) {
440
+ const parsed = parsePath(parentPath);
441
+ if (!parsed || parsed.enumId !== enumId) {
442
+ throw new MetaError('unknown-path', `${parentPath} is not a path of ${enumId}`);
443
+ }
444
+ if (parsed.ids.length > 0 && !findNode(this.getEnum(enumId).tree, parsed.ids)) {
445
+ throw new MetaError('unknown-path', `${parentPath} does not exist`);
446
+ }
447
+ return parsed.ids;
448
+ }
449
+ /** Which objects would lose which paths if these subtrees went away. */
450
+ #membersOf(targets) {
451
+ const refs = [];
452
+ for (const [ref, object] of this.#objects) {
453
+ if (object.enums.some((path) => targets.some((target) => pathMatches(path, target)))) {
454
+ refs.push(ref);
455
+ }
456
+ }
457
+ return { paths: targets, refs: refs.sort() };
458
+ }
459
+ /**
460
+ * Removes the paths of a deleted subtree from every object that carried one.
461
+ *
462
+ * Silent, like the rewrite of a move: the `node.deleted` / `enum.deleted` event is what a
463
+ * consumer acts on, and it already says which paths stopped existing.
464
+ */
465
+ #detach(members) {
466
+ for (const ref of members.refs) {
467
+ const object = this.#objects.get(ref);
468
+ if (!object) {
469
+ continue;
470
+ }
471
+ const enums = object.enums.filter((path) => !members.paths.some((target) => pathMatches(path, target)));
472
+ this.#objects.set(ref, buildObject(object.name, enums, object.meta, object.orphaned === true));
473
+ }
474
+ }
475
+ /** Rewrites the member paths of a moved subtree; part of the move's own revision. */
476
+ #rewrite(from, to) {
477
+ for (const [ref, object] of this.#objects) {
478
+ if (!object.enums.some((path) => pathMatches(path, from))) {
479
+ continue;
480
+ }
481
+ const enums = object.enums.map((path) => pathMatches(path, from) ? `${to}${path.slice(from.length)}` : path);
482
+ this.#objects.set(ref, buildObject(object.name, enums, object.meta, object.orphaned === true));
483
+ }
484
+ }
485
+ /** One revision for a set of events, appended to the history and handed to the listener. */
486
+ #commit(events) {
487
+ this.#revision += 1;
488
+ for (const event of events) {
489
+ const full = { ...event, revision: this.#revision };
490
+ this.#history.push(full);
491
+ this.#onEvent?.(full);
492
+ }
493
+ while (this.#history.length > this.#historySize) {
494
+ const dropped = this.#history.shift();
495
+ if (dropped) {
496
+ this.#replayFrom = dropped.revision;
497
+ }
498
+ }
499
+ return { revision: this.#revision, changed: true };
500
+ }
501
+ /** A detached copy, used to validate a bulk before anything is written. */
502
+ #clone() {
503
+ return new _a({ document: this.document(), eventHistory: 0 });
504
+ }
505
+ #adopt(other) {
506
+ const document = other.document();
507
+ this.#objects = new Map(Object.entries(document.objects));
508
+ this.#enums = new Map(Object.entries(document.enums));
509
+ }
510
+ }
511
+ _a = MetaStore;
512
+ /** An object in the shape the store keeps: `orphaned` only when it is true. */
513
+ function buildObject(name, enums, meta, orphaned) {
514
+ return orphaned ? { name, enums, meta, orphaned: true } : { name, enums, meta };
515
+ }
516
+ /**
517
+ * `meta` merged per namespace: `null` removes one, any other value replaces it whole.
518
+ *
519
+ * Per namespace and not per key, on purpose: the store does not interpret what is inside a
520
+ * namespace, so it cannot merge it either - only its owner knows what half an update would mean.
521
+ */
522
+ export function mergeMeta(current, patch) {
523
+ const merged = { ...current };
524
+ for (const [namespace, value] of Object.entries(normaliseMeta(patch))) {
525
+ if (value === null) {
526
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- the key is a namespace the caller named
527
+ delete merged[namespace];
528
+ }
529
+ else {
530
+ merged[namespace] = value;
531
+ }
532
+ }
533
+ return normaliseMeta(merged);
534
+ }
535
+ /** Is this a valid enum or node id? Re-exported so a dialog can check before it offers to save. */
536
+ export { isValidId };
537
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Immutable edits of an enum tree: insert, remove, reorder.
3
+ *
4
+ * Both writers need them - {@link MetaStore}, which owns a store, and {@link applyEvent}, which
5
+ * follows somebody else's - and both have to produce byte-identical trees for the same edit, or a
6
+ * consumer of the change stream would slowly drift away from the box it is watching. So they are
7
+ * one implementation, here, and every one of them returns a new tree rather than mutating one:
8
+ * a half-applied edit that threw in the middle is the one failure a store may never have.
9
+ */
10
+ import type { MetaNode } from './types.js';
11
+ /** The index a node sits at among its siblings, or `undefined` when it is not there. */
12
+ export declare function indexOfNode(tree: readonly MetaNode[], ids: readonly string[]): number | undefined;
13
+ /** A tree with one node inserted under a parent, at a position or appended. */
14
+ export declare function insertAt(tree: readonly MetaNode[], parentIds: readonly string[], node: MetaNode, position?: number): readonly MetaNode[];
15
+ /** A tree without the node a path addresses. */
16
+ export declare function removeAt(tree: readonly MetaNode[], ids: readonly string[]): readonly MetaNode[];
17
+ export declare function withoutChildren(node: MetaNode): MetaNode;
18
+ export declare function spliceIn(nodes: readonly MetaNode[], node: MetaNode, position?: number): readonly MetaNode[];
19
+ //# sourceMappingURL=tree.d.ts.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Immutable edits of an enum tree: insert, remove, reorder.
3
+ *
4
+ * Both writers need them - {@link MetaStore}, which owns a store, and {@link applyEvent}, which
5
+ * follows somebody else's - and both have to produce byte-identical trees for the same edit, or a
6
+ * consumer of the change stream would slowly drift away from the box it is watching. So they are
7
+ * one implementation, here, and every one of them returns a new tree rather than mutating one:
8
+ * a half-applied edit that threw in the middle is the one failure a store may never have.
9
+ */
10
+ import { findNode } from './paths.js';
11
+ /** The index a node sits at among its siblings, or `undefined` when it is not there. */
12
+ export function indexOfNode(tree, ids) {
13
+ const parentIds = ids.slice(0, -1);
14
+ const id = ids[ids.length - 1];
15
+ const siblings = parentIds.length === 0 ? tree : (findNode(tree, parentIds)?.children ?? []);
16
+ const index = siblings.findIndex((node) => node.id === id);
17
+ return index === -1 ? undefined : index;
18
+ }
19
+ /** A tree with one node inserted under a parent, at a position or appended. */
20
+ export function insertAt(tree, parentIds, node, position) {
21
+ if (parentIds.length === 0) {
22
+ return spliceIn(tree, node, position);
23
+ }
24
+ const [head, ...rest] = parentIds;
25
+ return tree.map((child) => child.id === head ? { ...child, children: insertAt(child.children ?? [], rest, node, position) } : child);
26
+ }
27
+ /** A tree without the node a path addresses. */
28
+ export function removeAt(tree, ids) {
29
+ const [head, ...rest] = ids;
30
+ if (head === undefined) {
31
+ return tree;
32
+ }
33
+ if (rest.length === 0) {
34
+ return tree.filter((node) => node.id !== head);
35
+ }
36
+ return tree.map((node) => {
37
+ if (node.id !== head) {
38
+ return node;
39
+ }
40
+ const children = removeAt(node.children ?? [], rest);
41
+ return children.length === 0 ? withoutChildren(node) : { ...node, children };
42
+ });
43
+ }
44
+ export function withoutChildren(node) {
45
+ return { id: node.id, name: node.name, ...(node.icon === undefined ? {} : { icon: node.icon }) };
46
+ }
47
+ export function spliceIn(nodes, node, position) {
48
+ const next = [...nodes];
49
+ const index = position === undefined ? next.length : Math.max(0, Math.min(next.length, Math.trunc(position)));
50
+ next.splice(index, 0, node);
51
+ return next;
52
+ }
53
+ //# sourceMappingURL=tree.js.map