@matter/protocol 0.16.0-alpha.0-20251213-e83db3732 → 0.16.0-alpha.0-20251217-038f88085

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 (309) hide show
  1. package/LICENSE +1 -1
  2. package/dist/cjs/action/client/ClientInteraction.d.ts +12 -5
  3. package/dist/cjs/action/client/ClientInteraction.d.ts.map +1 -1
  4. package/dist/cjs/action/client/ClientInteraction.js +39 -15
  5. package/dist/cjs/action/client/ClientInteraction.js.map +1 -1
  6. package/dist/cjs/action/client/ClientRead.d.ts +10 -0
  7. package/dist/cjs/action/client/ClientRead.d.ts.map +1 -0
  8. package/dist/cjs/action/client/ClientRead.js +22 -0
  9. package/dist/cjs/action/client/ClientRead.js.map +6 -0
  10. package/dist/cjs/action/client/ClientRequest.d.ts +20 -0
  11. package/dist/cjs/action/client/ClientRequest.d.ts.map +1 -0
  12. package/dist/cjs/action/client/ClientRequest.js +22 -0
  13. package/dist/cjs/action/client/ClientRequest.js.map +6 -0
  14. package/dist/cjs/action/client/ClientWrite.d.ts +10 -0
  15. package/dist/cjs/action/client/ClientWrite.d.ts.map +1 -0
  16. package/dist/cjs/action/client/ClientWrite.js +22 -0
  17. package/dist/cjs/action/client/ClientWrite.js.map +6 -0
  18. package/dist/cjs/action/client/QueuedClientInteraction.d.ts +49 -0
  19. package/dist/cjs/action/client/QueuedClientInteraction.d.ts.map +1 -0
  20. package/dist/cjs/action/client/QueuedClientInteraction.js +160 -0
  21. package/dist/cjs/action/client/QueuedClientInteraction.js.map +6 -0
  22. package/dist/cjs/action/client/index.d.ts +4 -0
  23. package/dist/cjs/action/client/index.d.ts.map +1 -1
  24. package/dist/cjs/action/client/index.js +4 -0
  25. package/dist/cjs/action/client/index.js.map +1 -1
  26. package/dist/cjs/action/client/subscription/ClientSubscribe.d.ts +2 -1
  27. package/dist/cjs/action/client/subscription/ClientSubscribe.d.ts.map +1 -1
  28. package/dist/cjs/action/client/subscription/ClientSubscriptionHandler.d.ts.map +1 -1
  29. package/dist/cjs/action/client/subscription/ClientSubscriptionHandler.js +14 -3
  30. package/dist/cjs/action/client/subscription/ClientSubscriptionHandler.js.map +1 -1
  31. package/dist/cjs/action/client/subscription/SustainedSubscription.d.ts +1 -1
  32. package/dist/cjs/action/client/subscription/SustainedSubscription.d.ts.map +1 -1
  33. package/dist/cjs/action/client/subscription/SustainedSubscription.js +1 -4
  34. package/dist/cjs/action/client/subscription/SustainedSubscription.js.map +1 -1
  35. package/dist/cjs/action/request/Invoke.d.ts +7 -1
  36. package/dist/cjs/action/request/Invoke.d.ts.map +1 -1
  37. package/dist/cjs/action/request/Invoke.js +0 -3
  38. package/dist/cjs/action/request/Invoke.js.map +1 -1
  39. package/dist/cjs/action/request/Read.d.ts.map +1 -1
  40. package/dist/cjs/action/request/Read.js +3 -2
  41. package/dist/cjs/action/request/Read.js.map +1 -1
  42. package/dist/cjs/action/request/Specifier.d.ts +1 -1
  43. package/dist/cjs/action/request/Specifier.d.ts.map +1 -1
  44. package/dist/cjs/action/request/Specifier.js +3 -0
  45. package/dist/cjs/action/request/Specifier.js.map +1 -1
  46. package/dist/cjs/action/request/Write.d.ts +1 -0
  47. package/dist/cjs/action/request/Write.d.ts.map +1 -1
  48. package/dist/cjs/action/request/Write.js +10 -2
  49. package/dist/cjs/action/request/Write.js.map +1 -1
  50. package/dist/cjs/action/response/ReadResult.d.ts +1 -1
  51. package/dist/cjs/action/response/ReadResult.d.ts.map +1 -1
  52. package/dist/cjs/cluster/client/ClusterClientTypes.d.ts +37 -8
  53. package/dist/cjs/cluster/client/ClusterClientTypes.d.ts.map +1 -1
  54. package/dist/cjs/cluster/client/index.d.ts +0 -3
  55. package/dist/cjs/cluster/client/index.d.ts.map +1 -1
  56. package/dist/cjs/cluster/client/index.js +0 -3
  57. package/dist/cjs/cluster/client/index.js.map +1 -1
  58. package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
  59. package/dist/cjs/interaction/InteractionMessenger.js +3 -2
  60. package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
  61. package/dist/cjs/interaction/SubscriptionClient.d.ts.map +1 -1
  62. package/dist/cjs/interaction/SubscriptionClient.js +2 -1
  63. package/dist/cjs/interaction/SubscriptionClient.js.map +1 -1
  64. package/dist/cjs/interaction/index.d.ts +1 -1
  65. package/dist/cjs/interaction/index.d.ts.map +1 -1
  66. package/dist/cjs/interaction/index.js +1 -1
  67. package/dist/cjs/interaction/index.js.map +1 -1
  68. package/dist/cjs/peer/CommissioningError.d.ts +13 -0
  69. package/dist/cjs/peer/CommissioningError.d.ts.map +1 -0
  70. package/dist/cjs/peer/CommissioningError.js +32 -0
  71. package/dist/cjs/peer/CommissioningError.js.map +6 -0
  72. package/dist/cjs/peer/ControllerCommissioner.d.ts +2 -3
  73. package/dist/cjs/peer/ControllerCommissioner.d.ts.map +1 -1
  74. package/dist/cjs/peer/ControllerCommissioner.js +20 -13
  75. package/dist/cjs/peer/ControllerCommissioner.js.map +2 -2
  76. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts +7 -16
  77. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  78. package/dist/cjs/peer/ControllerCommissioningFlow.js +395 -178
  79. package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
  80. package/dist/cjs/peer/ControllerDiscovery.d.ts +4 -0
  81. package/dist/cjs/peer/ControllerDiscovery.d.ts.map +1 -1
  82. package/dist/cjs/peer/ControllerDiscovery.js +6 -3
  83. package/dist/cjs/peer/ControllerDiscovery.js.map +1 -1
  84. package/dist/cjs/peer/InteractionQueue.d.ts +2 -2
  85. package/dist/cjs/peer/InteractionQueue.d.ts.map +1 -1
  86. package/dist/cjs/peer/InteractionQueue.js +1 -1
  87. package/dist/cjs/peer/InteractionQueue.js.map +1 -1
  88. package/dist/cjs/peer/PeerAddressStore.d.ts +0 -9
  89. package/dist/cjs/peer/PeerAddressStore.d.ts.map +1 -1
  90. package/dist/cjs/peer/PeerAddressStore.js.map +1 -1
  91. package/dist/cjs/peer/PeerSet.d.ts +0 -2
  92. package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
  93. package/dist/cjs/peer/PeerSet.js +32 -18
  94. package/dist/cjs/peer/PeerSet.js.map +1 -1
  95. package/dist/cjs/peer/PhysicalDeviceProperties.js +1 -1
  96. package/dist/cjs/peer/PhysicalDeviceProperties.js.map +1 -1
  97. package/dist/cjs/peer/index.d.ts +1 -0
  98. package/dist/cjs/peer/index.d.ts.map +1 -1
  99. package/dist/cjs/peer/index.js +1 -0
  100. package/dist/cjs/peer/index.js.map +1 -1
  101. package/dist/cjs/protocol/DeviceCommissioner.d.ts.map +1 -1
  102. package/dist/cjs/protocol/DeviceCommissioner.js.map +1 -1
  103. package/dist/cjs/protocol/ExchangeManager.js +2 -2
  104. package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
  105. package/dist/cjs/protocol/ExchangeProvider.d.ts +13 -4
  106. package/dist/cjs/protocol/ExchangeProvider.d.ts.map +1 -1
  107. package/dist/cjs/protocol/ExchangeProvider.js +5 -3
  108. package/dist/cjs/protocol/ExchangeProvider.js.map +1 -1
  109. package/dist/cjs/session/NodeSession.d.ts +5 -2
  110. package/dist/cjs/session/NodeSession.d.ts.map +1 -1
  111. package/dist/cjs/session/NodeSession.js +5 -4
  112. package/dist/cjs/session/NodeSession.js.map +1 -1
  113. package/dist/cjs/session/Session.d.ts +5 -3
  114. package/dist/cjs/session/Session.d.ts.map +1 -1
  115. package/dist/cjs/session/Session.js +8 -4
  116. package/dist/cjs/session/Session.js.map +1 -1
  117. package/dist/cjs/session/SessionManager.d.ts +8 -0
  118. package/dist/cjs/session/SessionManager.d.ts.map +1 -1
  119. package/dist/cjs/session/SessionManager.js +16 -2
  120. package/dist/cjs/session/SessionManager.js.map +1 -1
  121. package/dist/esm/action/client/ClientInteraction.d.ts +12 -5
  122. package/dist/esm/action/client/ClientInteraction.d.ts.map +1 -1
  123. package/dist/esm/action/client/ClientInteraction.js +42 -16
  124. package/dist/esm/action/client/ClientInteraction.js.map +1 -1
  125. package/dist/esm/action/client/ClientRead.d.ts +10 -0
  126. package/dist/esm/action/client/ClientRead.d.ts.map +1 -0
  127. package/dist/esm/action/client/ClientRead.js +6 -0
  128. package/dist/esm/action/client/ClientRead.js.map +6 -0
  129. package/dist/esm/action/client/ClientRequest.d.ts +20 -0
  130. package/dist/esm/action/client/ClientRequest.d.ts.map +1 -0
  131. package/dist/esm/action/client/ClientRequest.js +6 -0
  132. package/dist/esm/action/client/ClientRequest.js.map +6 -0
  133. package/dist/esm/action/client/ClientWrite.d.ts +10 -0
  134. package/dist/esm/action/client/ClientWrite.d.ts.map +1 -0
  135. package/dist/esm/action/client/ClientWrite.js +6 -0
  136. package/dist/esm/action/client/ClientWrite.js.map +6 -0
  137. package/dist/esm/action/client/QueuedClientInteraction.d.ts +49 -0
  138. package/dist/esm/action/client/QueuedClientInteraction.d.ts.map +1 -0
  139. package/dist/esm/action/client/QueuedClientInteraction.js +140 -0
  140. package/dist/esm/action/client/QueuedClientInteraction.js.map +6 -0
  141. package/dist/esm/action/client/index.d.ts +4 -0
  142. package/dist/esm/action/client/index.d.ts.map +1 -1
  143. package/dist/esm/action/client/index.js +4 -0
  144. package/dist/esm/action/client/index.js.map +1 -1
  145. package/dist/esm/action/client/subscription/ClientSubscribe.d.ts +2 -1
  146. package/dist/esm/action/client/subscription/ClientSubscribe.d.ts.map +1 -1
  147. package/dist/esm/action/client/subscription/ClientSubscriptionHandler.d.ts.map +1 -1
  148. package/dist/esm/action/client/subscription/ClientSubscriptionHandler.js +14 -3
  149. package/dist/esm/action/client/subscription/ClientSubscriptionHandler.js.map +1 -1
  150. package/dist/esm/action/client/subscription/SustainedSubscription.d.ts +1 -1
  151. package/dist/esm/action/client/subscription/SustainedSubscription.d.ts.map +1 -1
  152. package/dist/esm/action/client/subscription/SustainedSubscription.js +1 -4
  153. package/dist/esm/action/client/subscription/SustainedSubscription.js.map +1 -1
  154. package/dist/esm/action/request/Invoke.d.ts +7 -1
  155. package/dist/esm/action/request/Invoke.d.ts.map +1 -1
  156. package/dist/esm/action/request/Invoke.js +0 -3
  157. package/dist/esm/action/request/Invoke.js.map +1 -1
  158. package/dist/esm/action/request/Read.d.ts.map +1 -1
  159. package/dist/esm/action/request/Read.js +3 -2
  160. package/dist/esm/action/request/Read.js.map +1 -1
  161. package/dist/esm/action/request/Specifier.d.ts +1 -1
  162. package/dist/esm/action/request/Specifier.d.ts.map +1 -1
  163. package/dist/esm/action/request/Specifier.js +3 -0
  164. package/dist/esm/action/request/Specifier.js.map +1 -1
  165. package/dist/esm/action/request/Write.d.ts +1 -0
  166. package/dist/esm/action/request/Write.d.ts.map +1 -1
  167. package/dist/esm/action/request/Write.js +10 -2
  168. package/dist/esm/action/request/Write.js.map +1 -1
  169. package/dist/esm/action/response/ReadResult.d.ts +1 -1
  170. package/dist/esm/action/response/ReadResult.d.ts.map +1 -1
  171. package/dist/esm/cluster/client/ClusterClientTypes.d.ts +37 -8
  172. package/dist/esm/cluster/client/ClusterClientTypes.d.ts.map +1 -1
  173. package/dist/esm/cluster/client/index.d.ts +0 -3
  174. package/dist/esm/cluster/client/index.d.ts.map +1 -1
  175. package/dist/esm/cluster/client/index.js +0 -3
  176. package/dist/esm/cluster/client/index.js.map +1 -1
  177. package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
  178. package/dist/esm/interaction/InteractionMessenger.js +4 -3
  179. package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
  180. package/dist/esm/interaction/SubscriptionClient.d.ts.map +1 -1
  181. package/dist/esm/interaction/SubscriptionClient.js +2 -1
  182. package/dist/esm/interaction/SubscriptionClient.js.map +1 -1
  183. package/dist/esm/interaction/index.d.ts +1 -1
  184. package/dist/esm/interaction/index.d.ts.map +1 -1
  185. package/dist/esm/interaction/index.js +1 -1
  186. package/dist/esm/peer/CommissioningError.d.ts +13 -0
  187. package/dist/esm/peer/CommissioningError.d.ts.map +1 -0
  188. package/dist/esm/peer/CommissioningError.js +12 -0
  189. package/dist/esm/peer/CommissioningError.js.map +6 -0
  190. package/dist/esm/peer/ControllerCommissioner.d.ts +2 -3
  191. package/dist/esm/peer/ControllerCommissioner.d.ts.map +1 -1
  192. package/dist/esm/peer/ControllerCommissioner.js +19 -13
  193. package/dist/esm/peer/ControllerCommissioner.js.map +2 -2
  194. package/dist/esm/peer/ControllerCommissioningFlow.d.ts +7 -16
  195. package/dist/esm/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  196. package/dist/esm/peer/ControllerCommissioningFlow.js +380 -162
  197. package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
  198. package/dist/esm/peer/ControllerDiscovery.d.ts +4 -0
  199. package/dist/esm/peer/ControllerDiscovery.d.ts.map +1 -1
  200. package/dist/esm/peer/ControllerDiscovery.js +4 -1
  201. package/dist/esm/peer/ControllerDiscovery.js.map +1 -1
  202. package/dist/esm/peer/InteractionQueue.d.ts +2 -2
  203. package/dist/esm/peer/InteractionQueue.d.ts.map +1 -1
  204. package/dist/esm/peer/InteractionQueue.js +2 -2
  205. package/dist/esm/peer/InteractionQueue.js.map +1 -1
  206. package/dist/esm/peer/PeerAddressStore.d.ts +0 -9
  207. package/dist/esm/peer/PeerAddressStore.d.ts.map +1 -1
  208. package/dist/esm/peer/PeerAddressStore.js.map +1 -1
  209. package/dist/esm/peer/PeerSet.d.ts +0 -2
  210. package/dist/esm/peer/PeerSet.d.ts.map +1 -1
  211. package/dist/esm/peer/PeerSet.js +32 -18
  212. package/dist/esm/peer/PeerSet.js.map +1 -1
  213. package/dist/esm/peer/PhysicalDeviceProperties.js +1 -1
  214. package/dist/esm/peer/PhysicalDeviceProperties.js.map +1 -1
  215. package/dist/esm/peer/index.d.ts +1 -0
  216. package/dist/esm/peer/index.d.ts.map +1 -1
  217. package/dist/esm/peer/index.js +1 -0
  218. package/dist/esm/peer/index.js.map +1 -1
  219. package/dist/esm/protocol/DeviceCommissioner.d.ts.map +1 -1
  220. package/dist/esm/protocol/DeviceCommissioner.js.map +1 -1
  221. package/dist/esm/protocol/ExchangeManager.js +2 -2
  222. package/dist/esm/protocol/ExchangeManager.js.map +1 -1
  223. package/dist/esm/protocol/ExchangeProvider.d.ts +13 -4
  224. package/dist/esm/protocol/ExchangeProvider.d.ts.map +1 -1
  225. package/dist/esm/protocol/ExchangeProvider.js +5 -3
  226. package/dist/esm/protocol/ExchangeProvider.js.map +1 -1
  227. package/dist/esm/session/NodeSession.d.ts +5 -2
  228. package/dist/esm/session/NodeSession.d.ts.map +1 -1
  229. package/dist/esm/session/NodeSession.js +5 -4
  230. package/dist/esm/session/NodeSession.js.map +1 -1
  231. package/dist/esm/session/Session.d.ts +5 -3
  232. package/dist/esm/session/Session.d.ts.map +1 -1
  233. package/dist/esm/session/Session.js +8 -4
  234. package/dist/esm/session/Session.js.map +1 -1
  235. package/dist/esm/session/SessionManager.d.ts +8 -0
  236. package/dist/esm/session/SessionManager.d.ts.map +1 -1
  237. package/dist/esm/session/SessionManager.js +17 -2
  238. package/dist/esm/session/SessionManager.js.map +1 -1
  239. package/package.json +6 -6
  240. package/src/action/client/ClientInteraction.ts +58 -19
  241. package/src/action/client/ClientRead.ts +10 -0
  242. package/src/action/client/ClientRequest.ts +20 -0
  243. package/src/action/client/ClientWrite.ts +10 -0
  244. package/src/action/client/QueuedClientInteraction.ts +91 -0
  245. package/src/action/client/index.ts +4 -0
  246. package/src/action/client/subscription/ClientSubscribe.ts +2 -1
  247. package/src/action/client/subscription/ClientSubscriptionHandler.ts +14 -3
  248. package/src/action/client/subscription/SustainedSubscription.ts +6 -9
  249. package/src/action/request/Invoke.ts +11 -4
  250. package/src/action/request/Read.ts +3 -2
  251. package/src/action/request/Specifier.ts +4 -1
  252. package/src/action/request/Write.ts +11 -2
  253. package/src/action/response/ReadResult.ts +1 -1
  254. package/src/cluster/client/ClusterClientTypes.ts +47 -7
  255. package/src/cluster/client/index.ts +0 -3
  256. package/src/interaction/InteractionMessenger.ts +5 -4
  257. package/src/interaction/SubscriptionClient.ts +2 -1
  258. package/src/interaction/index.ts +1 -1
  259. package/src/peer/CommissioningError.ts +13 -0
  260. package/src/peer/ControllerCommissioner.ts +21 -13
  261. package/src/peer/ControllerCommissioningFlow.ts +418 -186
  262. package/src/peer/ControllerDiscovery.ts +4 -1
  263. package/src/peer/InteractionQueue.ts +2 -2
  264. package/src/peer/PeerAddressStore.ts +0 -9
  265. package/src/peer/PeerSet.ts +56 -23
  266. package/src/peer/PhysicalDeviceProperties.ts +1 -1
  267. package/src/peer/index.ts +1 -0
  268. package/src/protocol/DeviceCommissioner.ts +0 -1
  269. package/src/protocol/ExchangeManager.ts +2 -2
  270. package/src/protocol/ExchangeProvider.ts +9 -7
  271. package/src/session/NodeSession.ts +5 -4
  272. package/src/session/Session.ts +8 -4
  273. package/src/session/SessionManager.ts +19 -2
  274. package/dist/cjs/cluster/client/AttributeClient.d.ts +0 -75
  275. package/dist/cjs/cluster/client/AttributeClient.d.ts.map +0 -1
  276. package/dist/cjs/cluster/client/AttributeClient.js +0 -209
  277. package/dist/cjs/cluster/client/AttributeClient.js.map +0 -6
  278. package/dist/cjs/cluster/client/ClusterClient.d.ts +0 -11
  279. package/dist/cjs/cluster/client/ClusterClient.d.ts.map +0 -1
  280. package/dist/cjs/cluster/client/ClusterClient.js +0 -335
  281. package/dist/cjs/cluster/client/ClusterClient.js.map +0 -6
  282. package/dist/cjs/cluster/client/EventClient.d.ts +0 -33
  283. package/dist/cjs/cluster/client/EventClient.d.ts.map +0 -1
  284. package/dist/cjs/cluster/client/EventClient.js +0 -89
  285. package/dist/cjs/cluster/client/EventClient.js.map +0 -6
  286. package/dist/cjs/interaction/InteractionClient.d.ts +0 -375
  287. package/dist/cjs/interaction/InteractionClient.d.ts.map +0 -1
  288. package/dist/cjs/interaction/InteractionClient.js +0 -1046
  289. package/dist/cjs/interaction/InteractionClient.js.map +0 -6
  290. package/dist/esm/cluster/client/AttributeClient.d.ts +0 -75
  291. package/dist/esm/cluster/client/AttributeClient.d.ts.map +0 -1
  292. package/dist/esm/cluster/client/AttributeClient.js +0 -189
  293. package/dist/esm/cluster/client/AttributeClient.js.map +0 -6
  294. package/dist/esm/cluster/client/ClusterClient.d.ts +0 -11
  295. package/dist/esm/cluster/client/ClusterClient.d.ts.map +0 -1
  296. package/dist/esm/cluster/client/ClusterClient.js +0 -320
  297. package/dist/esm/cluster/client/ClusterClient.js.map +0 -6
  298. package/dist/esm/cluster/client/EventClient.d.ts +0 -33
  299. package/dist/esm/cluster/client/EventClient.d.ts.map +0 -1
  300. package/dist/esm/cluster/client/EventClient.js +0 -69
  301. package/dist/esm/cluster/client/EventClient.js.map +0 -6
  302. package/dist/esm/interaction/InteractionClient.d.ts +0 -375
  303. package/dist/esm/interaction/InteractionClient.d.ts.map +0 -1
  304. package/dist/esm/interaction/InteractionClient.js +0 -1047
  305. package/dist/esm/interaction/InteractionClient.js.map +0 -6
  306. package/src/cluster/client/AttributeClient.ts +0 -230
  307. package/src/cluster/client/ClusterClient.ts +0 -433
  308. package/src/cluster/client/EventClient.ts +0 -99
  309. package/src/interaction/InteractionClient.ts +0 -1614
@@ -1,1047 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2022-2025 Matter.js Authors
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- import { ReadScope } from "#action/client/ReadScope.js";
7
- import { AccessControl } from "#clusters/access-control";
8
- import { Mark } from "#common/Mark.js";
9
- import {
10
- Diagnostic,
11
- Duration,
12
- Environmental,
13
- ImplementationError,
14
- Logger,
15
- MatterFlowError,
16
- Seconds,
17
- UnexpectedDataError,
18
- isDeepEqual,
19
- serialize
20
- } from "#general";
21
- import { Specification } from "#model";
22
- import { PeerAddress, PeerAddressMap } from "#peer/PeerAddress.js";
23
- import { PeerSet } from "#peer/PeerSet.js";
24
- import {
25
- ArraySchema,
26
- FabricIndex,
27
- ObjectSchema,
28
- StatusCode,
29
- StatusResponseError,
30
- TlvNoResponse,
31
- resolveAttributeName,
32
- resolveCommandName,
33
- resolveEventName
34
- } from "#types";
35
- import { ReconnectableExchangeProvider } from "../protocol/ExchangeProvider.js";
36
- import { InteractionClientMessenger } from "./InteractionMessenger.js";
37
- import { Subscription } from "./Subscription.js";
38
- import { SubscriptionClient } from "./SubscriptionClient.js";
39
- const logger = Logger.get("InteractionClient");
40
- const REQUEST_ALL = [{}];
41
- const DEFAULT_TIMED_REQUEST_TIMEOUT = Seconds(10);
42
- const DEFAULT_MINIMUM_RESPONSE_TIMEOUT_WITH_FAILSAFE = Seconds(30);
43
- const AclClusterId = AccessControl.Complete.id;
44
- const AclAttributeId = AccessControl.Complete.attributes.acl.id;
45
- const AclExtensionAttributeId = AccessControl.Complete.attributes.extension.id;
46
- function isAclOrExtensionPath(path) {
47
- const { clusterId, attributeId } = path;
48
- return clusterId === AclClusterId && (attributeId === AclAttributeId || attributeId === AclExtensionAttributeId);
49
- }
50
- class InteractionClientProvider {
51
- #peers;
52
- #clients = new PeerAddressMap();
53
- #subscriptionClient = new SubscriptionClient();
54
- constructor(peers) {
55
- this.#peers = peers;
56
- this.#peers.deleted.on((peer) => this.#onPeerLoss(peer.address));
57
- this.#peers.disconnected.on((peer) => this.#onPeerLoss(peer.address));
58
- }
59
- static [Environmental.create](env) {
60
- const instance = new InteractionClientProvider(env.get(PeerSet));
61
- env.set(InteractionClientProvider, instance);
62
- return instance;
63
- }
64
- get peers() {
65
- return this.#peers;
66
- }
67
- get subscriptionClient() {
68
- return this.#subscriptionClient;
69
- }
70
- async connect(address, options) {
71
- await this.#peers.connect(address, options);
72
- return this.getInteractionClient(address, options);
73
- }
74
- async interactionClientFor(session) {
75
- const exchangeProvider = await this.#peers.exchangeProviderFor(session);
76
- return new InteractionClient(
77
- exchangeProvider,
78
- this.#subscriptionClient,
79
- void 0,
80
- this.#peers.interactionQueue
81
- );
82
- }
83
- async getInteractionClient(address, options = {}) {
84
- let client = this.#clients.get(address);
85
- if (client !== void 0) {
86
- return client;
87
- }
88
- const isGroupAddress = PeerAddress.isGroup(address);
89
- const nodeStore = isGroupAddress ? void 0 : this.#peers.get(address)?.descriptor.dataStore;
90
- await nodeStore?.construction;
91
- const exchangeProvider = await this.#peers.exchangeProviderFor(address, options);
92
- client = new InteractionClient(
93
- exchangeProvider,
94
- this.#subscriptionClient,
95
- address,
96
- this.#peers.interactionQueue,
97
- nodeStore
98
- );
99
- this.#clients.set(address, client);
100
- return client;
101
- }
102
- #onPeerLoss(address) {
103
- const client = this.#clients.get(address);
104
- if (client !== void 0) {
105
- client.close();
106
- this.#clients.delete(address);
107
- }
108
- }
109
- }
110
- class InteractionClient {
111
- #exchangeProvider;
112
- #nodeStore;
113
- #ownSubscriptionIds = /* @__PURE__ */ new Set();
114
- #queue;
115
- #address;
116
- isGroupAddress;
117
- // TODO - SubscriptionClient is used by CommissioningController but not ClientNode. However InteractionClient *is*
118
- // used by ClientNode to perform commissioning, during which time SubscriptionClient is unnecessary. So this should
119
- // be set after commissioning
120
- //
121
- // If we remove CommissioningController then this entire class goes away; if we first move commissioning to
122
- // ClientInteraction then this should become required
123
- #subscriptionClient;
124
- constructor(exchangeProvider, subscriptionClient, address, queue, nodeStore) {
125
- this.#exchangeProvider = exchangeProvider;
126
- this.#nodeStore = nodeStore;
127
- this.#subscriptionClient = subscriptionClient;
128
- this.#queue = queue;
129
- this.#address = address;
130
- this.isGroupAddress = address !== void 0 ? PeerAddress.isGroup(address) : false;
131
- }
132
- get address() {
133
- if (this.#address === void 0) {
134
- throw new ImplementationError("This InteractionClient is not bound to a specific peer.");
135
- }
136
- return this.#address;
137
- }
138
- get isReconnectable() {
139
- return this.#exchangeProvider instanceof ReconnectableExchangeProvider;
140
- }
141
- get channelUpdated() {
142
- if (this.#exchangeProvider instanceof ReconnectableExchangeProvider) {
143
- return this.#exchangeProvider.channelUpdated;
144
- }
145
- throw new ImplementationError("ExchangeProvider does not support channelUpdated");
146
- }
147
- /** Calculates the current maximum response time for a message use in additional logic like timers. */
148
- maximumPeerResponseTime(expectedProcessingTime) {
149
- return this.#exchangeProvider.maximumPeerResponseTime(expectedProcessingTime);
150
- }
151
- removeSubscription(subscriptionId) {
152
- this.#ownSubscriptionIds.delete(subscriptionId);
153
- this.#subscriptionClient?.delete(subscriptionId);
154
- }
155
- async getAllAttributes(options = {}) {
156
- return (await this.getMultipleAttributesAndEvents({
157
- attributes: REQUEST_ALL,
158
- ...options
159
- })).attributeReports;
160
- }
161
- async getAllEvents(options = {}) {
162
- return (await this.getMultipleAttributesAndEvents({
163
- events: REQUEST_ALL,
164
- ...options
165
- })).eventReports;
166
- }
167
- async getAllAttributesAndEvents(options = {}) {
168
- return this.getMultipleAttributesAndEvents({
169
- attributes: REQUEST_ALL,
170
- events: REQUEST_ALL,
171
- ...options
172
- });
173
- }
174
- async getMultipleAttributes(options = {}) {
175
- return (await this.getMultipleAttributesAndEvents(options)).attributeReports;
176
- }
177
- async getMultipleAttributesAndStatus(options = {}) {
178
- const { attributeReports, attributeStatus } = await this.getMultipleAttributesAndEvents(options);
179
- return { attributeData: attributeReports, attributeStatus };
180
- }
181
- async getMultipleEvents(options = {}) {
182
- return (await this.getMultipleAttributesAndEvents(options)).eventReports;
183
- }
184
- async getMultipleEventsAndStatus(options = {}) {
185
- const { eventReports, eventStatus } = await this.getMultipleAttributesAndEvents(options);
186
- return { eventData: eventReports, eventStatus };
187
- }
188
- async getMultipleAttributesAndEvents(options = {}) {
189
- if (this.isGroupAddress) {
190
- throw new ImplementationError("Reading data from group addresses is not supported.");
191
- }
192
- const {
193
- attributes: attributeRequests,
194
- dataVersionFilters,
195
- executeQueued,
196
- events: eventRequests,
197
- enrichCachedAttributeData,
198
- eventFilters,
199
- isFabricFiltered = true,
200
- attributeChangeListener
201
- } = options;
202
- if (attributeRequests === void 0 && eventRequests === void 0) {
203
- throw new ImplementationError("When reading attributes and events, at least one must be specified.");
204
- }
205
- const readPathsCount = (attributeRequests?.length ?? 0) + (eventRequests?.length ?? 0);
206
- if (readPathsCount > 9) {
207
- logger.debug(
208
- "Read interactions with more then 9 paths might be not allowed by the device. Consider splitting then into several read requests."
209
- );
210
- }
211
- const result = await this.withMessenger(async (messenger) => {
212
- return await this.processReadRequest(
213
- messenger,
214
- {
215
- attributeRequests,
216
- dataVersionFilters: dataVersionFilters?.map(({ endpointId, clusterId, dataVersion }) => ({
217
- path: { endpointId, clusterId },
218
- dataVersion
219
- })),
220
- eventRequests,
221
- eventFilters,
222
- isFabricFiltered,
223
- interactionModelRevision: Specification.INTERACTION_MODEL_REVISION
224
- },
225
- attributeChangeListener
226
- );
227
- }, executeQueued);
228
- if (dataVersionFilters !== void 0 && dataVersionFilters.length > 0 && enrichCachedAttributeData) {
229
- this.#enrichCachedAttributeData(result.attributeReports, dataVersionFilters);
230
- }
231
- return result;
232
- }
233
- async getAttribute(options) {
234
- const { requestFromRemote } = options;
235
- const response = await this.getAttributeWithVersion({
236
- ...options,
237
- requestFromRemote
238
- });
239
- return response?.value;
240
- }
241
- getStoredAttribute(options) {
242
- return this.getStoredAttributeWithVersion(options)?.value;
243
- }
244
- getStoredAttributeWithVersion(options) {
245
- if (this.isGroupAddress) {
246
- throw new ImplementationError("Reading data from group addresses is not supported.");
247
- }
248
- const { endpointId, clusterId, attribute } = options;
249
- const { id: attributeId } = attribute;
250
- if (this.#nodeStore !== void 0) {
251
- const { value, version } = this.#nodeStore.retrieveAttribute(endpointId, clusterId, attributeId) ?? {};
252
- if (value !== void 0 && version !== void 0) {
253
- return { value, version };
254
- }
255
- }
256
- return void 0;
257
- }
258
- async getAttributeWithVersion(options) {
259
- if (this.isGroupAddress) {
260
- throw new ImplementationError("Reading data from group addresses is not supported.");
261
- }
262
- const {
263
- endpointId,
264
- clusterId,
265
- attribute,
266
- requestFromRemote,
267
- isFabricFiltered,
268
- executeQueued,
269
- attributeChangeListener
270
- } = options;
271
- const { id: attributeId } = attribute;
272
- if (this.#nodeStore !== void 0) {
273
- if (!requestFromRemote) {
274
- const { value, version } = this.#nodeStore.retrieveAttribute(endpointId, clusterId, attributeId) ?? {};
275
- if (value !== void 0 && version !== void 0) {
276
- return { value, version };
277
- }
278
- }
279
- if (requestFromRemote === false) {
280
- return void 0;
281
- }
282
- }
283
- const { attributeReports } = await this.getMultipleAttributesAndEvents({
284
- attributes: [{ endpointId, clusterId, attributeId }],
285
- isFabricFiltered,
286
- executeQueued,
287
- attributeChangeListener
288
- });
289
- if (attributeReports.length === 0) {
290
- return void 0;
291
- }
292
- if (attributeReports.length > 1) {
293
- throw new UnexpectedDataError("Unexpected response with more then one attribute");
294
- }
295
- return { value: attributeReports[0].value, version: attributeReports[0].version };
296
- }
297
- async getEvent(options) {
298
- const { endpointId, clusterId, event, minimumEventNumber, isFabricFiltered = true, executeQueued } = options;
299
- const { id: eventId } = event;
300
- const response = await this.getMultipleAttributesAndEvents({
301
- events: [{ endpointId, clusterId, eventId }],
302
- eventFilters: minimumEventNumber !== void 0 ? [{ eventMin: minimumEventNumber }] : void 0,
303
- isFabricFiltered,
304
- executeQueued
305
- });
306
- return response?.eventReports[0]?.events;
307
- }
308
- async processReadRequest(messenger, request, attributeChangeListener) {
309
- const { attributeRequests, eventRequests, dataVersionFilters, eventFilters, isFabricFiltered } = request;
310
- logger.debug(() => [
311
- "Read",
312
- Mark.OUTBOUND,
313
- messenger.exchange.via,
314
- Diagnostic.dict({
315
- attributes: attributeRequests?.length ? attributeRequests?.map((path) => resolveAttributeName(path)).join(", ") : void 0,
316
- events: eventRequests?.length ? eventRequests?.map((path) => resolveEventName(path)).join(", ") : void 0,
317
- dataVersionFilters: dataVersionFilters?.length ? dataVersionFilters.map(
318
- ({ path: { endpointId, clusterId }, dataVersion }) => `${endpointId}/${clusterId}=${dataVersion}`
319
- ).join(", ") : void 0,
320
- eventFilters: eventFilters?.length ? eventFilters.map(({ nodeId, eventMin }) => `${nodeId}=${eventMin}`).join(", ") : void 0,
321
- fabricFiltered: isFabricFiltered
322
- })
323
- ]);
324
- await messenger.sendReadRequest(request);
325
- const scope = ReadScope(request);
326
- const response = await messenger.readAggregateDataReport(
327
- (chunk) => this.processAttributeUpdates(scope, chunk, attributeChangeListener)
328
- );
329
- const { attributeReports, attributeStatus, eventReports, eventStatus } = response;
330
- if (attributeReports.length || eventReports.length || attributeStatus?.length || eventStatus?.length) {
331
- logger.debug(() => [
332
- "Read",
333
- Mark.INBOUND,
334
- messenger.exchange.via,
335
- Diagnostic.dict({
336
- attributes: attributeReports.length ? attributeReports.map(({ path, value }) => `${resolveAttributeName(path)}=${serialize(value)}`).join(", ") : void 0,
337
- events: eventReports.length ? eventReports.map(({ path }) => resolveEventName(path)).join(", ") : void 0,
338
- attributeStatus: attributeStatus?.length ? attributeStatus.map(({ path }) => resolveAttributeName(path)).join(", ") : void 0,
339
- eventStatus: eventStatus?.length ? eventStatus.map(({ path }) => resolveEventName(path)).join(", ") : void 0,
340
- fabricFiltered: isFabricFiltered
341
- })
342
- ]);
343
- } else {
344
- logger.debug("Read", Mark.INBOUND, messenger.exchange.via, "empty response");
345
- }
346
- return response;
347
- }
348
- async setAttribute(options) {
349
- const { attributeData, asTimedRequest, timedRequestTimeout, suppressResponse, executeQueued, chunkLists } = options;
350
- const { endpointId, clusterId, attribute, value, dataVersion } = attributeData;
351
- const response = await this.setMultipleAttributes({
352
- attributes: [{ endpointId, clusterId, attribute, value, dataVersion }],
353
- asTimedRequest,
354
- timedRequestTimeout,
355
- suppressResponse,
356
- executeQueued,
357
- chunkLists
358
- });
359
- if (response.length) {
360
- const {
361
- path: { endpointId: endpointId2, clusterId: clusterId2, attributeId },
362
- status
363
- } = response[0];
364
- if (status !== void 0 && status !== StatusCode.Success) {
365
- throw new StatusResponseError(
366
- `Error setting attribute ${endpointId2}/${clusterId2}/${attributeId}`,
367
- status
368
- );
369
- }
370
- }
371
- }
372
- async setMultipleAttributes(options) {
373
- const { executeQueued } = options;
374
- const {
375
- attributes,
376
- asTimedRequest,
377
- timedRequestTimeout = DEFAULT_TIMED_REQUEST_TIMEOUT,
378
- suppressResponse = this.isGroupAddress,
379
- chunkLists = true
380
- // Should be true currently to stay in sync with chip sdk
381
- } = options;
382
- if (this.isGroupAddress) {
383
- if (!suppressResponse) {
384
- throw new ImplementationError("Writing attributes on a group address can not return a response.");
385
- }
386
- if (attributes.some(
387
- ({ endpointId, clusterId, attribute }) => endpointId !== void 0 || clusterId === void 0 || attribute.id === void 0
388
- )) {
389
- throw new ImplementationError("Not all attribute write paths are valid for group address writes.");
390
- }
391
- }
392
- const writeRequests = attributes.flatMap(
393
- ({ endpointId, clusterId, attribute: { id, schema }, value, dataVersion }) => {
394
- if (chunkLists && Array.isArray(value) && schema instanceof ArraySchema && // As implemented for Matter 1.4.2 in https://github.com/project-chip/connectedhomeip/pull/38263
395
- // Acl writes will no longer be chunked by default, all others still
396
- // Will be streamlined later ... see https://github.com/project-chip/connectedhomeip/issues/38270
397
- !isAclOrExtensionPath({ clusterId, attributeId: id })) {
398
- return schema.encodeAsChunkedArray(value, { forWriteInteraction: true }).map(({ element: data, listIndex }) => ({
399
- path: { endpointId, clusterId, attributeId: id, listIndex },
400
- data,
401
- dataVersion
402
- }));
403
- }
404
- return [
405
- {
406
- path: { endpointId, clusterId, attributeId: id },
407
- data: schema.encodeTlv(value, { forWriteInteraction: true }),
408
- dataVersion
409
- }
410
- ];
411
- }
412
- );
413
- const timedRequest = attributes.some(({ attribute: { timed } }) => timed) || asTimedRequest === true || options.timedRequestTimeout !== void 0;
414
- if (this.isGroupAddress && timedRequest) {
415
- throw new ImplementationError("Timed requests are not supported for group address writes.");
416
- }
417
- const response = await this.withMessenger(
418
- async (messenger) => {
419
- if (timedRequest) {
420
- await messenger.sendTimedRequest(timedRequestTimeout);
421
- }
422
- logger.debug(() => [
423
- "Write",
424
- Mark.OUTBOUND,
425
- messenger.exchange.via,
426
- Diagnostic.dict({
427
- attributes: attributes.map(
428
- ({ endpointId, clusterId, attribute: { id }, value, dataVersion }) => `${resolveAttributeName({ endpointId, clusterId, attributeId: id })} = ${Diagnostic.json(
429
- value
430
- )} (version=${dataVersion})`
431
- ).join(", ")
432
- })
433
- ]);
434
- return await messenger.sendWriteCommand({
435
- suppressResponse,
436
- timedRequest,
437
- writeRequests,
438
- moreChunkedMessages: false,
439
- interactionModelRevision: Specification.INTERACTION_MODEL_REVISION
440
- });
441
- },
442
- executeQueued
443
- );
444
- if (response === void 0) {
445
- if (!suppressResponse) {
446
- throw new MatterFlowError(`No response received from write interaction but expected.`);
447
- }
448
- return [];
449
- }
450
- return response.writeResponses.flatMap(({ status: { status, clusterStatus }, path: { nodeId, endpointId, clusterId, attributeId } }) => {
451
- return {
452
- path: { nodeId, endpointId, clusterId, attributeId },
453
- status: status ?? clusterStatus ?? StatusCode.Failure
454
- };
455
- }).filter(({ status }) => status !== StatusCode.Success);
456
- }
457
- async subscribeAttribute(options) {
458
- if (this.isGroupAddress) {
459
- throw new ImplementationError("Subscribing to attributes on a group address is not supported.");
460
- }
461
- const {
462
- endpointId,
463
- clusterId,
464
- attribute,
465
- minIntervalFloorSeconds,
466
- maxIntervalCeilingSeconds,
467
- isFabricFiltered = true,
468
- listener,
469
- knownDataVersion,
470
- keepSubscriptions = true,
471
- updateTimeoutHandler,
472
- updateReceived,
473
- executeQueued
474
- } = options;
475
- const { id: attributeId } = attribute;
476
- if (!keepSubscriptions) {
477
- for (const subscriptionId2 of this.#ownSubscriptionIds) {
478
- logger.debug(
479
- `Removing subscription ${Subscription.idStrOf(subscriptionId2)} from InteractionClient because new subscription replaces it`
480
- );
481
- this.removeSubscription(subscriptionId2);
482
- }
483
- }
484
- const request = {
485
- interactionModelRevision: Specification.INTERACTION_MODEL_REVISION,
486
- attributeRequests: [{ endpointId, clusterId, attributeId }],
487
- dataVersionFilters: knownDataVersion !== void 0 ? [{ path: { endpointId, clusterId }, dataVersion: knownDataVersion }] : void 0,
488
- keepSubscriptions,
489
- minIntervalFloorSeconds,
490
- maxIntervalCeilingSeconds,
491
- isFabricFiltered
492
- };
493
- const scope = ReadScope(request);
494
- const {
495
- subscribeResponse: { subscriptionId, maxInterval },
496
- report,
497
- maximumPeerResponseTime
498
- } = await this.withMessenger(async (messenger) => {
499
- logger.debug(() => [
500
- "Subscribe",
501
- Mark.OUTBOUND,
502
- messenger.exchange.via,
503
- Diagnostic.dict({
504
- attributes: resolveAttributeName({ endpointId, clusterId, attributeId }),
505
- dataVersionFilter: knownDataVersion,
506
- fabricFiltered: isFabricFiltered,
507
- minInterval: Duration.format(Seconds(minIntervalFloorSeconds)),
508
- maxInterval: Duration.format(Seconds(maxIntervalCeilingSeconds))
509
- })
510
- ]);
511
- await messenger.sendSubscribeRequest(request);
512
- const { subscribeResponse, report: report2 } = await messenger.readAggregateSubscribeResponse();
513
- return {
514
- subscribeResponse,
515
- report: report2,
516
- maximumPeerResponseTime: this.maximumPeerResponseTime()
517
- };
518
- }, executeQueued);
519
- const subscriptionListener = async (dataReport) => {
520
- const { attributeReports } = dataReport;
521
- if (attributeReports.length === 0) {
522
- throw new MatterFlowError("Subscription result reporting undefined/no value not specified");
523
- }
524
- if (attributeReports.length > 1) {
525
- throw new UnexpectedDataError("Unexpected response with more then one attribute");
526
- }
527
- const { value, version } = attributeReports[0];
528
- if (value === void 0)
529
- throw new MatterFlowError("Subscription result reporting undefined value not specified.");
530
- await this.#nodeStore?.persistAttributes(attributeReports, scope);
531
- listener?.(value, version);
532
- updateReceived?.();
533
- };
534
- await this.#registerSubscription(
535
- {
536
- id: subscriptionId,
537
- maximumPeerResponseTime,
538
- maxInterval: Seconds(maxInterval),
539
- onData: subscriptionListener,
540
- onTimeout: updateTimeoutHandler
541
- },
542
- report
543
- );
544
- return { maxInterval };
545
- }
546
- async #registerSubscription(subscription, initialReport) {
547
- this.#ownSubscriptionIds.add(subscription.id);
548
- this.#subscriptionClient?.add(subscription);
549
- await subscription.onData(initialReport);
550
- }
551
- async subscribeEvent(options) {
552
- if (this.isGroupAddress) {
553
- throw new ImplementationError("Subscribing to events on a group address is not supported.");
554
- }
555
- const {
556
- endpointId,
557
- clusterId,
558
- event,
559
- minIntervalFloor,
560
- maxIntervalCeiling,
561
- isUrgent,
562
- minimumEventNumber,
563
- isFabricFiltered = true,
564
- listener,
565
- updateTimeoutHandler,
566
- updateReceived,
567
- executeQueued
568
- } = options;
569
- const { id: eventId } = event;
570
- const {
571
- report,
572
- subscribeResponse: { subscriptionId, maxInterval },
573
- maximumPeerResponseTime
574
- } = await this.withMessenger(async (messenger) => {
575
- logger.debug(() => [
576
- "Subscribe",
577
- Mark.OUTBOUND,
578
- messenger.exchange.via,
579
- Diagnostic.dict({
580
- events: resolveEventName({ endpointId, clusterId, eventId }),
581
- fabricFiltered: isFabricFiltered,
582
- minInterval: Duration.format(minIntervalFloor),
583
- maxInterval: Duration.format(maxIntervalCeiling)
584
- })
585
- ]);
586
- await messenger.sendSubscribeRequest({
587
- interactionModelRevision: Specification.INTERACTION_MODEL_REVISION,
588
- eventRequests: [{ endpointId, clusterId, eventId, isUrgent }],
589
- eventFilters: minimumEventNumber !== void 0 ? [{ eventMin: minimumEventNumber }] : void 0,
590
- keepSubscriptions: true,
591
- minIntervalFloorSeconds: Seconds.of(minIntervalFloor),
592
- maxIntervalCeilingSeconds: Seconds.of(maxIntervalCeiling),
593
- isFabricFiltered
594
- });
595
- const { subscribeResponse, report: report2 } = await messenger.readAggregateSubscribeResponse();
596
- return {
597
- subscribeResponse,
598
- report: report2,
599
- maximumPeerResponseTime: this.maximumPeerResponseTime()
600
- };
601
- }, executeQueued);
602
- const subscriptionListener = (dataReport) => {
603
- const { eventReports } = dataReport;
604
- if (eventReports.length === 0) {
605
- throw new MatterFlowError("Received empty subscription result value.");
606
- }
607
- if (eventReports.length > 1) {
608
- throw new UnexpectedDataError("Unexpected response with more then one attribute.");
609
- }
610
- const { events } = eventReports[0];
611
- if (events === void 0)
612
- throw new MatterFlowError("Subscription result reporting undefined value not specified.");
613
- events.forEach((event2) => listener?.(event2));
614
- updateReceived?.();
615
- };
616
- await this.#registerSubscription(
617
- {
618
- id: subscriptionId,
619
- maximumPeerResponseTime,
620
- maxInterval: Seconds(maxInterval),
621
- onData: subscriptionListener,
622
- onTimeout: updateTimeoutHandler
623
- },
624
- report
625
- );
626
- return { maxInterval };
627
- }
628
- async subscribeAllAttributesAndEvents(options) {
629
- const { isUrgent } = options;
630
- return this.subscribeMultipleAttributesAndEvents({
631
- ...options,
632
- attributes: REQUEST_ALL,
633
- events: [{ isUrgent }]
634
- });
635
- }
636
- async subscribeMultipleAttributesAndEvents(options) {
637
- if (this.isGroupAddress) {
638
- throw new ImplementationError("Subscribing to attributes or events on a group address is not supported.");
639
- }
640
- const {
641
- attributes: attributeRequests = [],
642
- events: eventRequests = [],
643
- executeQueued,
644
- minIntervalFloorSeconds,
645
- maxIntervalCeilingSeconds,
646
- keepSubscriptions = true,
647
- isFabricFiltered = true,
648
- attributeListener,
649
- eventListener,
650
- eventFilters,
651
- dataVersionFilters,
652
- updateTimeoutHandler,
653
- updateReceived,
654
- enrichCachedAttributeData
655
- } = options;
656
- const subscriptionPathsCount = (attributeRequests?.length ?? 0) + (eventRequests?.length ?? 0);
657
- if (subscriptionPathsCount > 3) {
658
- logger.debug("Subscribe interactions with more then 3 paths might be not allowed by the device.");
659
- }
660
- if (!keepSubscriptions) {
661
- for (const subscriptionId2 of this.#ownSubscriptionIds) {
662
- logger.debug(
663
- `Removing subscription with ID ${Subscription.idStrOf(subscriptionId2)} from InteractionClient because new subscription replaces it`
664
- );
665
- this.removeSubscription(subscriptionId2);
666
- }
667
- }
668
- const request = {
669
- interactionModelRevision: Specification.INTERACTION_MODEL_REVISION,
670
- attributeRequests,
671
- eventRequests,
672
- keepSubscriptions,
673
- minIntervalFloorSeconds,
674
- maxIntervalCeilingSeconds,
675
- isFabricFiltered,
676
- eventFilters,
677
- dataVersionFilters: dataVersionFilters?.map(({ endpointId, clusterId, dataVersion }) => ({
678
- path: { endpointId, clusterId },
679
- dataVersion
680
- }))
681
- };
682
- const scope = ReadScope(request);
683
- let processNewAttributeChangesInListener = false;
684
- const {
685
- report,
686
- subscribeResponse: { subscriptionId, maxInterval },
687
- maximumPeerResponseTime
688
- } = await this.withMessenger(async (messenger) => {
689
- logger.debug(() => [
690
- "Subscribe",
691
- Mark.OUTBOUND,
692
- messenger.exchange.via,
693
- Diagnostic.dict({
694
- attributes: attributeRequests.length ? attributeRequests.map((path) => resolveAttributeName(path)).join(", ") : void 0,
695
- events: eventRequests.length ? eventRequests.map((path) => resolveEventName(path)).join(", ") : void 0,
696
- dataVersionFilter: dataVersionFilters?.length ? dataVersionFilters.map(
697
- ({ endpointId, clusterId, dataVersion }) => `${endpointId}/${clusterId}=${dataVersion}`
698
- ).join(", ") : void 0,
699
- eventFilters: eventFilters?.length ? eventFilters.map(({ nodeId, eventMin }) => `${nodeId}=${eventMin}`).join(", ") : void 0,
700
- fabricFiltered: isFabricFiltered,
701
- keepSubscriptions,
702
- minInterval: Duration.format(Seconds(minIntervalFloorSeconds)),
703
- maxInterval: Duration.format(Seconds(maxIntervalCeilingSeconds))
704
- })
705
- ]);
706
- await messenger.sendSubscribeRequest(request);
707
- const { subscribeResponse, report: report2 } = await messenger.readAggregateSubscribeResponse(
708
- (attributeReports) => this.processAttributeUpdates(scope, attributeReports, attributeListener)
709
- );
710
- logger.info(
711
- "Subscription successful",
712
- Mark.INBOUND,
713
- messenger.exchange.via,
714
- Diagnostic.dict({
715
- ...Subscription.diagnosticOf(subscribeResponse.subscriptionId),
716
- maxInterval: Duration.format(Seconds(subscribeResponse.maxInterval))
717
- })
718
- );
719
- return {
720
- subscribeResponse,
721
- report: report2,
722
- maximumPeerResponseTime: this.maximumPeerResponseTime()
723
- };
724
- }, executeQueued);
725
- const subscriptionListener = async (dataReport) => {
726
- if ((!Array.isArray(dataReport.attributeReports) || !dataReport.attributeReports.length) && (!Array.isArray(dataReport.eventReports) || !dataReport.eventReports.length)) {
727
- updateReceived?.();
728
- return;
729
- }
730
- const { attributeReports, eventReports } = dataReport;
731
- if (eventReports?.length) {
732
- let maxEventNumber = this.#nodeStore?.maxEventNumber ?? eventReports[0].events[0].eventNumber;
733
- eventReports.forEach((data) => {
734
- logger.debug(
735
- `Event update ${Mark.INBOUND} ${resolveEventName(data.path)}: ${Diagnostic.json(data.events)}`
736
- );
737
- const { events } = data;
738
- maxEventNumber = events.length === 1 ? events[0].eventNumber : events.reduce(
739
- (max, { eventNumber }) => max < eventNumber ? eventNumber : max,
740
- maxEventNumber
741
- );
742
- eventListener?.(data);
743
- });
744
- await this.#nodeStore?.updateLastEventNumber(maxEventNumber);
745
- }
746
- if (processNewAttributeChangesInListener && attributeReports !== void 0) {
747
- await this.processAttributeUpdates(scope, attributeReports, attributeListener);
748
- }
749
- updateReceived?.();
750
- };
751
- await this.#registerSubscription(
752
- {
753
- id: subscriptionId,
754
- maximumPeerResponseTime,
755
- maxInterval: Seconds(maxInterval),
756
- onData: (dataReport) => subscriptionListener(dataReport),
757
- onTimeout: updateTimeoutHandler
758
- },
759
- report
760
- );
761
- processNewAttributeChangesInListener = true;
762
- if (dataVersionFilters !== void 0 && dataVersionFilters.length > 0 && enrichCachedAttributeData) {
763
- this.#enrichCachedAttributeData(report.attributeReports, dataVersionFilters);
764
- }
765
- return {
766
- ...report,
767
- maxInterval
768
- };
769
- }
770
- /**
771
- * Process changed attributes, detect changes and persist them to the node store
772
- */
773
- async processAttributeUpdates(scope, attributeReports, attributeListener) {
774
- for (const data of attributeReports) {
775
- const {
776
- path: { endpointId, clusterId, attributeId },
777
- value,
778
- version
779
- } = data;
780
- if (value === void 0) {
781
- throw new MatterFlowError("Received empty subscription result value.");
782
- }
783
- const { value: oldValue, version: oldVersion } = this.#nodeStore?.retrieveAttribute(endpointId, clusterId, attributeId) ?? {};
784
- const changed = oldValue !== void 0 ? !isDeepEqual(oldValue, value) : void 0;
785
- if (changed !== false || version !== oldVersion) {
786
- await this.#nodeStore?.persistAttributes([data], scope);
787
- }
788
- logger.debug(
789
- `Attribute update ${Mark.INBOUND}${changed ? " (value changed)" : ""}: ${resolveAttributeName({
790
- endpointId,
791
- clusterId,
792
- attributeId
793
- })} = ${serialize(value)} (version=${version})`
794
- );
795
- attributeListener?.(data, changed, oldValue);
796
- }
797
- }
798
- async invoke(options) {
799
- const { executeQueued } = options;
800
- const {
801
- endpointId,
802
- clusterId,
803
- command: { requestId, requestSchema, responseId, responseSchema, optional, timed },
804
- asTimedRequest,
805
- timedRequestTimeout: timedRequestTimeoutMs = DEFAULT_TIMED_REQUEST_TIMEOUT,
806
- expectedProcessingTime,
807
- useExtendedFailSafeMessageResponseTimeout = false,
808
- skipValidation
809
- } = options;
810
- let { request } = options;
811
- const timedRequest = timed && !skipValidation || asTimedRequest === true || options.timedRequestTimeout !== void 0;
812
- if (this.isGroupAddress) {
813
- if (endpointId !== void 0) {
814
- throw new ImplementationError("Invoking a concrete command on a group address is not supported.");
815
- }
816
- if (timedRequest) {
817
- throw new ImplementationError("Timed requests are not supported for group address invokes.");
818
- }
819
- }
820
- if (requestSchema instanceof ObjectSchema) {
821
- if (request === void 0) {
822
- request = {};
823
- }
824
- if (requestSchema.isFabricScoped && request.fabricIndex === void 0) {
825
- request.fabricIndex = FabricIndex.NO_FABRIC;
826
- }
827
- }
828
- logger.debug(
829
- `Invoking command: ${resolveCommandName({
830
- endpointId,
831
- clusterId,
832
- commandId: requestId
833
- })} with ${Diagnostic.json(request)}`
834
- );
835
- if (!skipValidation) {
836
- requestSchema.validate(request);
837
- }
838
- const commandFields = requestSchema.encodeTlv(request);
839
- const invokeResponse = await this.withMessenger(async (messenger) => {
840
- if (timedRequest) {
841
- await messenger.sendTimedRequest(timedRequestTimeoutMs);
842
- }
843
- const response = await messenger.sendInvokeCommand(
844
- {
845
- invokeRequests: [{ commandPath: { endpointId, clusterId, commandId: requestId }, commandFields }],
846
- timedRequest,
847
- suppressResponse: false,
848
- interactionModelRevision: Specification.INTERACTION_MODEL_REVISION
849
- },
850
- expectedProcessingTime ?? (useExtendedFailSafeMessageResponseTimeout ? DEFAULT_MINIMUM_RESPONSE_TIMEOUT_WITH_FAILSAFE : void 0)
851
- );
852
- if (response === void 0) {
853
- throw new MatterFlowError("No response received from invoke interaction but expected.");
854
- }
855
- return response;
856
- }, executeQueued);
857
- const { invokeResponses } = invokeResponse;
858
- if (invokeResponses.length === 0) {
859
- throw new MatterFlowError("Received invoke response with no invoke results.");
860
- }
861
- const { command, status } = invokeResponses[0];
862
- if (status !== void 0) {
863
- const resultCode = status.status.status;
864
- if (resultCode !== StatusCode.Success)
865
- throw new StatusResponseError(
866
- `Received non-success result: ${resultCode}`,
867
- resultCode ?? StatusCode.Failure,
868
- status.status.clusterStatus
869
- );
870
- if (responseSchema !== TlvNoResponse)
871
- throw new MatterFlowError("A response was expected for this command.");
872
- return void 0;
873
- }
874
- if (command !== void 0) {
875
- const {
876
- commandPath: { commandId },
877
- commandFields: commandFields2
878
- } = command;
879
- if (commandId !== responseId) {
880
- throw new MatterFlowError(
881
- `Received invoke response with unexpected command ID ${commandId}, expected ${responseId}.`
882
- );
883
- }
884
- if (commandFields2 === void 0) {
885
- if (responseSchema !== TlvNoResponse)
886
- throw new MatterFlowError(`A response was expected for command ${requestId}.`);
887
- return void 0;
888
- }
889
- const response = responseSchema.decodeTlv(commandFields2);
890
- logger.debug(
891
- "Invoke",
892
- Mark.INBOUND,
893
- resolveCommandName({
894
- endpointId,
895
- clusterId,
896
- commandId: requestId
897
- }),
898
- "with",
899
- Diagnostic.json(response)
900
- );
901
- return response;
902
- }
903
- if (optional) {
904
- return void 0;
905
- }
906
- throw new MatterFlowError("Received invoke response with no result nor response.");
907
- }
908
- // TODO Add to ClusterClient when needed/when Group communication is implemented
909
- // TODO Additionally support it without endpoint
910
- async invokeWithSuppressedResponse(options) {
911
- const { executeQueued } = options;
912
- const {
913
- endpointId,
914
- clusterId,
915
- request,
916
- command: { requestId, requestSchema, timed },
917
- asTimedRequest,
918
- timedRequestTimeout = DEFAULT_TIMED_REQUEST_TIMEOUT
919
- } = options;
920
- const timedRequest = timed || asTimedRequest === true || options.timedRequestTimeout !== void 0;
921
- if (this.isGroupAddress) {
922
- if (timed) {
923
- throw new ImplementationError("Timed requests are not supported for group address invokes.");
924
- }
925
- if (endpointId !== void 0) {
926
- throw new ImplementationError("Invoking a concrete command on a group address is not supported.");
927
- }
928
- }
929
- logger.debug(
930
- `Invoking command with suppressedResponse: ${resolveCommandName({
931
- endpointId,
932
- clusterId,
933
- commandId: requestId
934
- })} with ${Diagnostic.json(request)}`
935
- );
936
- const commandFields = requestSchema.encodeTlv(request);
937
- await this.withMessenger(async (messenger) => {
938
- if (timedRequest) {
939
- await messenger.sendTimedRequest(timedRequestTimeout);
940
- }
941
- const response = await messenger.sendInvokeCommand({
942
- invokeRequests: [{ commandPath: { endpointId, clusterId, commandId: requestId }, commandFields }],
943
- timedRequest,
944
- suppressResponse: true,
945
- interactionModelRevision: Specification.INTERACTION_MODEL_REVISION
946
- });
947
- if (response !== void 0) {
948
- throw new MatterFlowError(
949
- "Response received from invoke interaction but none expected because response is suppressed."
950
- );
951
- }
952
- }, executeQueued);
953
- logger.debug(
954
- "Invoke successful",
955
- Mark.INBOUND,
956
- resolveCommandName({
957
- endpointId,
958
- clusterId,
959
- commandId: requestId
960
- })
961
- );
962
- }
963
- async withMessenger(invoke, executeQueued = false) {
964
- const messenger = await InteractionClientMessenger.create(this.#exchangeProvider);
965
- let result;
966
- try {
967
- if (executeQueued) {
968
- if (this.#queue === void 0) {
969
- throw new ImplementationError("Cannot execute queued operation without a queue.");
970
- }
971
- return await this.#queue.add(() => invoke(messenger));
972
- }
973
- result = await invoke(messenger);
974
- } finally {
975
- messenger.close().catch((error) => logger.info(`Error closing messenger: ${error}`));
976
- }
977
- return result;
978
- }
979
- removeAllSubscriptions() {
980
- for (const subscriptionId of this.#ownSubscriptionIds) {
981
- this.removeSubscription(subscriptionId);
982
- }
983
- }
984
- close() {
985
- this.removeAllSubscriptions();
986
- }
987
- get session() {
988
- return this.#exchangeProvider.session;
989
- }
990
- get channelType() {
991
- return this.#exchangeProvider.channelType;
992
- }
993
- /** Enrich cached data to get complete responses when data version filters were used. */
994
- #enrichCachedAttributeData(attributeReports, dataVersionFilters) {
995
- if (this.#nodeStore === void 0) {
996
- return;
997
- }
998
- const candidates = /* @__PURE__ */ new Map();
999
- for (const { endpointId, clusterId, dataVersion } of dataVersionFilters) {
1000
- if (!candidates.has(endpointId)) {
1001
- candidates.set(endpointId, /* @__PURE__ */ new Map());
1002
- }
1003
- candidates.get(endpointId)?.set(clusterId, this.#nodeStore.getClusterDataVersion(endpointId, clusterId) ?? dataVersion);
1004
- }
1005
- attributeReports.forEach(({ path: { endpointId, clusterId } }) => {
1006
- if (candidates.has(endpointId)) {
1007
- candidates.get(endpointId)?.delete(clusterId);
1008
- }
1009
- });
1010
- for (const [endpointId, clusters] of candidates) {
1011
- for (const [clusterId, version] of clusters) {
1012
- const clusterValues = this.#nodeStore.retrieveAttributes(endpointId, clusterId);
1013
- logger.debug(
1014
- `Enriching cached data (${clusterValues.length} attributes) for ${endpointId}/${clusterId} with version=${version}`
1015
- );
1016
- attributeReports.push(...clusterValues);
1017
- }
1018
- }
1019
- }
1020
- /**
1021
- * Returns the list (optionally filtered by endpointId and/or clusterId) of the dataVersions of the currently cached
1022
- * values to use them as knownDataVersion for read or subscription requests.
1023
- */
1024
- getCachedClusterDataVersions(filter) {
1025
- if (this.#nodeStore === void 0) {
1026
- return [];
1027
- }
1028
- const { endpointId, clusterId } = filter ?? {};
1029
- return this.#nodeStore.getClusterDataVersions(endpointId, clusterId);
1030
- }
1031
- get maxKnownEventNumber() {
1032
- return this.#nodeStore?.maxEventNumber;
1033
- }
1034
- cleanupAttributeData(endpointId, clusterIds) {
1035
- return this.#nodeStore?.cleanupAttributeData(endpointId, clusterIds);
1036
- }
1037
- getAllCachedClusterData() {
1038
- const result = new Array();
1039
- this.#enrichCachedAttributeData(result, this.getCachedClusterDataVersions());
1040
- return result;
1041
- }
1042
- }
1043
- export {
1044
- InteractionClient,
1045
- InteractionClientProvider
1046
- };
1047
- //# sourceMappingURL=InteractionClient.js.map