@matter/protocol 0.14.0 → 0.14.1-alpha.0-20250606-a9bcd03f9

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 (312) hide show
  1. package/dist/cjs/action/server/AccessControl.d.ts +5 -7
  2. package/dist/cjs/action/server/AccessControl.d.ts.map +1 -1
  3. package/dist/cjs/action/server/AccessControl.js.map +1 -1
  4. package/dist/cjs/action/server/AttributeWriteResponse.d.ts.map +1 -1
  5. package/dist/cjs/action/server/AttributeWriteResponse.js +23 -0
  6. package/dist/cjs/action/server/AttributeWriteResponse.js.map +1 -1
  7. package/dist/cjs/action/server/CommandInvokeResponse.d.ts.map +1 -1
  8. package/dist/cjs/action/server/CommandInvokeResponse.js +24 -1
  9. package/dist/cjs/action/server/CommandInvokeResponse.js.map +1 -1
  10. package/dist/cjs/action/server/DataResponse.d.ts +1 -1
  11. package/dist/cjs/action/server/DataResponse.d.ts.map +1 -1
  12. package/dist/cjs/action/server/Subject.d.ts +25 -0
  13. package/dist/cjs/action/server/Subject.d.ts.map +1 -0
  14. package/dist/cjs/action/server/Subject.js +54 -0
  15. package/dist/cjs/action/server/Subject.js.map +6 -0
  16. package/dist/cjs/action/server/index.d.ts +1 -0
  17. package/dist/cjs/action/server/index.d.ts.map +1 -1
  18. package/dist/cjs/action/server/index.js +1 -0
  19. package/dist/cjs/action/server/index.js.map +1 -1
  20. package/dist/cjs/certificate/DeviceCertification.d.ts +2 -2
  21. package/dist/cjs/certificate/DeviceCertification.d.ts.map +1 -1
  22. package/dist/cjs/certificate/DeviceCertification.js.map +1 -1
  23. package/dist/cjs/cluster/client/AttributeClient.d.ts +3 -3
  24. package/dist/cjs/cluster/client/AttributeClient.d.ts.map +1 -1
  25. package/dist/cjs/cluster/client/AttributeClient.js +14 -2
  26. package/dist/cjs/cluster/client/AttributeClient.js.map +1 -1
  27. package/dist/cjs/cluster/client/ClusterClient.d.ts +3 -2
  28. package/dist/cjs/cluster/client/ClusterClient.d.ts.map +1 -1
  29. package/dist/cjs/cluster/client/ClusterClient.js +60 -1
  30. package/dist/cjs/cluster/client/ClusterClient.js.map +1 -1
  31. package/dist/cjs/cluster/client/ClusterClientTypes.d.ts +33 -8
  32. package/dist/cjs/cluster/client/ClusterClientTypes.d.ts.map +1 -1
  33. package/dist/cjs/cluster/client/EventClient.d.ts +3 -3
  34. package/dist/cjs/cluster/client/EventClient.d.ts.map +1 -1
  35. package/dist/cjs/cluster/client/EventClient.js +7 -0
  36. package/dist/cjs/cluster/client/EventClient.js.map +1 -1
  37. package/dist/cjs/codec/MessageCodec.d.ts.map +1 -1
  38. package/dist/cjs/codec/MessageCodec.js +31 -6
  39. package/dist/cjs/codec/MessageCodec.js.map +1 -1
  40. package/dist/cjs/fabric/Fabric.d.ts +20 -30
  41. package/dist/cjs/fabric/Fabric.d.ts.map +1 -1
  42. package/dist/cjs/fabric/Fabric.js +38 -62
  43. package/dist/cjs/fabric/Fabric.js.map +2 -2
  44. package/dist/cjs/fabric/FabricManager.d.ts.map +1 -1
  45. package/dist/cjs/fabric/FabricManager.js +10 -4
  46. package/dist/cjs/fabric/FabricManager.js.map +1 -1
  47. package/dist/cjs/groups/FabricGroupsManager.d.ts +46 -0
  48. package/dist/cjs/groups/FabricGroupsManager.d.ts.map +1 -0
  49. package/dist/cjs/groups/FabricGroupsManager.js +155 -0
  50. package/dist/cjs/groups/FabricGroupsManager.js.map +6 -0
  51. package/dist/cjs/groups/Groups.d.ts +34 -0
  52. package/dist/cjs/groups/Groups.d.ts.map +1 -0
  53. package/dist/cjs/groups/Groups.js +89 -0
  54. package/dist/cjs/groups/Groups.js.map +6 -0
  55. package/dist/cjs/groups/KeySets.d.ts +64 -0
  56. package/dist/cjs/groups/KeySets.d.ts.map +1 -0
  57. package/dist/cjs/groups/KeySets.js +179 -0
  58. package/dist/cjs/groups/KeySets.js.map +6 -0
  59. package/dist/cjs/groups/MessagingState.d.ts +24 -0
  60. package/dist/cjs/groups/MessagingState.d.ts.map +1 -0
  61. package/dist/cjs/groups/MessagingState.js +91 -0
  62. package/dist/cjs/groups/MessagingState.js.map +6 -0
  63. package/dist/cjs/groups/index.d.ts +8 -0
  64. package/dist/cjs/groups/index.d.ts.map +1 -0
  65. package/dist/cjs/groups/index.js +25 -0
  66. package/dist/cjs/groups/index.js.map +6 -0
  67. package/dist/cjs/index.d.ts +1 -0
  68. package/dist/cjs/index.d.ts.map +1 -1
  69. package/dist/cjs/index.js +1 -0
  70. package/dist/cjs/index.js.map +1 -1
  71. package/dist/cjs/interaction/AccessControlManager.d.ts +4 -13
  72. package/dist/cjs/interaction/AccessControlManager.d.ts.map +1 -1
  73. package/dist/cjs/interaction/AccessControlManager.js +38 -47
  74. package/dist/cjs/interaction/AccessControlManager.js.map +1 -1
  75. package/dist/cjs/interaction/InteractionClient.d.ts +5 -4
  76. package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
  77. package/dist/cjs/interaction/InteractionClient.js +53 -3
  78. package/dist/cjs/interaction/InteractionClient.js.map +1 -1
  79. package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
  80. package/dist/cjs/interaction/InteractionMessenger.js +15 -0
  81. package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
  82. package/dist/cjs/interaction/Subscription.d.ts +3 -3
  83. package/dist/cjs/interaction/Subscription.d.ts.map +1 -1
  84. package/dist/cjs/interaction/Subscription.js.map +1 -1
  85. package/dist/cjs/peer/PeerAddress.d.ts +1 -0
  86. package/dist/cjs/peer/PeerAddress.d.ts.map +1 -1
  87. package/dist/cjs/peer/PeerAddress.js +5 -0
  88. package/dist/cjs/peer/PeerAddress.js.map +1 -1
  89. package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
  90. package/dist/cjs/peer/PeerSet.js +31 -2
  91. package/dist/cjs/peer/PeerSet.js.map +1 -1
  92. package/dist/cjs/protocol/ChannelManager.d.ts.map +1 -1
  93. package/dist/cjs/protocol/ChannelManager.js +7 -8
  94. package/dist/cjs/protocol/ChannelManager.js.map +1 -1
  95. package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
  96. package/dist/cjs/protocol/ExchangeManager.js +39 -25
  97. package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
  98. package/dist/cjs/protocol/MessageExchange.d.ts +1 -1
  99. package/dist/cjs/protocol/MessageExchange.d.ts.map +1 -1
  100. package/dist/cjs/protocol/MessageExchange.js +32 -4
  101. package/dist/cjs/protocol/MessageExchange.js.map +1 -1
  102. package/dist/cjs/protocol/MessageReceptionState.d.ts +1 -1
  103. package/dist/cjs/securechannel/SecureChannelProtocol.js +1 -1
  104. package/dist/cjs/securechannel/SecureChannelProtocol.js.map +1 -1
  105. package/dist/cjs/session/GroupSession.d.ts +56 -0
  106. package/dist/cjs/session/GroupSession.d.ts.map +1 -0
  107. package/dist/cjs/session/GroupSession.js +188 -0
  108. package/dist/cjs/session/GroupSession.js.map +6 -0
  109. package/dist/cjs/session/InsecureSession.d.ts +2 -1
  110. package/dist/cjs/session/InsecureSession.d.ts.map +1 -1
  111. package/dist/cjs/session/InsecureSession.js +3 -2
  112. package/dist/cjs/session/InsecureSession.js.map +1 -1
  113. package/dist/cjs/session/NodeSession.d.ts +88 -0
  114. package/dist/cjs/session/NodeSession.d.ts.map +1 -0
  115. package/dist/cjs/session/NodeSession.js +318 -0
  116. package/dist/cjs/session/NodeSession.js.map +6 -0
  117. package/dist/cjs/session/SecureSession.d.ts +10 -75
  118. package/dist/cjs/session/SecureSession.d.ts.map +1 -1
  119. package/dist/cjs/session/SecureSession.js +9 -280
  120. package/dist/cjs/session/SecureSession.js.map +2 -2
  121. package/dist/cjs/session/Session.d.ts +6 -5
  122. package/dist/cjs/session/Session.d.ts.map +1 -1
  123. package/dist/cjs/session/Session.js +11 -1
  124. package/dist/cjs/session/Session.js.map +1 -1
  125. package/dist/cjs/session/SessionManager.d.ts +27 -9
  126. package/dist/cjs/session/SessionManager.d.ts.map +1 -1
  127. package/dist/cjs/session/SessionManager.js +83 -5
  128. package/dist/cjs/session/SessionManager.js.map +2 -2
  129. package/dist/cjs/session/case/CaseClient.d.ts +1 -1
  130. package/dist/cjs/session/case/CaseClient.js +2 -2
  131. package/dist/cjs/session/case/CaseClient.js.map +1 -1
  132. package/dist/cjs/session/index.d.ts +2 -0
  133. package/dist/cjs/session/index.d.ts.map +1 -1
  134. package/dist/cjs/session/index.js +2 -0
  135. package/dist/cjs/session/index.js.map +1 -1
  136. package/dist/cjs/session/pase/PaseClient.d.ts +1 -1
  137. package/dist/esm/action/server/AccessControl.d.ts +5 -7
  138. package/dist/esm/action/server/AccessControl.d.ts.map +1 -1
  139. package/dist/esm/action/server/AccessControl.js.map +1 -1
  140. package/dist/esm/action/server/AttributeWriteResponse.d.ts.map +1 -1
  141. package/dist/esm/action/server/AttributeWriteResponse.js +23 -0
  142. package/dist/esm/action/server/AttributeWriteResponse.js.map +1 -1
  143. package/dist/esm/action/server/CommandInvokeResponse.d.ts.map +1 -1
  144. package/dist/esm/action/server/CommandInvokeResponse.js +24 -1
  145. package/dist/esm/action/server/CommandInvokeResponse.js.map +1 -1
  146. package/dist/esm/action/server/DataResponse.d.ts +1 -1
  147. package/dist/esm/action/server/DataResponse.d.ts.map +1 -1
  148. package/dist/esm/action/server/Subject.d.ts +25 -0
  149. package/dist/esm/action/server/Subject.d.ts.map +1 -0
  150. package/dist/esm/action/server/Subject.js +34 -0
  151. package/dist/esm/action/server/Subject.js.map +6 -0
  152. package/dist/esm/action/server/index.d.ts +1 -0
  153. package/dist/esm/action/server/index.d.ts.map +1 -1
  154. package/dist/esm/action/server/index.js +1 -0
  155. package/dist/esm/action/server/index.js.map +1 -1
  156. package/dist/esm/certificate/DeviceCertification.d.ts +2 -2
  157. package/dist/esm/certificate/DeviceCertification.d.ts.map +1 -1
  158. package/dist/esm/certificate/DeviceCertification.js.map +1 -1
  159. package/dist/esm/cluster/client/AttributeClient.d.ts +3 -3
  160. package/dist/esm/cluster/client/AttributeClient.d.ts.map +1 -1
  161. package/dist/esm/cluster/client/AttributeClient.js +13 -1
  162. package/dist/esm/cluster/client/AttributeClient.js.map +1 -1
  163. package/dist/esm/cluster/client/ClusterClient.d.ts +3 -2
  164. package/dist/esm/cluster/client/ClusterClient.d.ts.map +1 -1
  165. package/dist/esm/cluster/client/ClusterClient.js +61 -2
  166. package/dist/esm/cluster/client/ClusterClient.js.map +1 -1
  167. package/dist/esm/cluster/client/ClusterClientTypes.d.ts +33 -8
  168. package/dist/esm/cluster/client/ClusterClientTypes.d.ts.map +1 -1
  169. package/dist/esm/cluster/client/EventClient.d.ts +3 -3
  170. package/dist/esm/cluster/client/EventClient.d.ts.map +1 -1
  171. package/dist/esm/cluster/client/EventClient.js +7 -0
  172. package/dist/esm/cluster/client/EventClient.js.map +1 -1
  173. package/dist/esm/codec/MessageCodec.d.ts.map +1 -1
  174. package/dist/esm/codec/MessageCodec.js +41 -7
  175. package/dist/esm/codec/MessageCodec.js.map +1 -1
  176. package/dist/esm/fabric/Fabric.d.ts +20 -30
  177. package/dist/esm/fabric/Fabric.d.ts.map +1 -1
  178. package/dist/esm/fabric/Fabric.js +38 -62
  179. package/dist/esm/fabric/Fabric.js.map +2 -2
  180. package/dist/esm/fabric/FabricManager.d.ts.map +1 -1
  181. package/dist/esm/fabric/FabricManager.js +10 -4
  182. package/dist/esm/fabric/FabricManager.js.map +1 -1
  183. package/dist/esm/groups/FabricGroupsManager.d.ts +46 -0
  184. package/dist/esm/groups/FabricGroupsManager.d.ts.map +1 -0
  185. package/dist/esm/groups/FabricGroupsManager.js +135 -0
  186. package/dist/esm/groups/FabricGroupsManager.js.map +6 -0
  187. package/dist/esm/groups/Groups.d.ts +34 -0
  188. package/dist/esm/groups/Groups.d.ts.map +1 -0
  189. package/dist/esm/groups/Groups.js +69 -0
  190. package/dist/esm/groups/Groups.js.map +6 -0
  191. package/dist/esm/groups/KeySets.d.ts +64 -0
  192. package/dist/esm/groups/KeySets.d.ts.map +1 -0
  193. package/dist/esm/groups/KeySets.js +159 -0
  194. package/dist/esm/groups/KeySets.js.map +6 -0
  195. package/dist/esm/groups/MessagingState.d.ts +24 -0
  196. package/dist/esm/groups/MessagingState.d.ts.map +1 -0
  197. package/dist/esm/groups/MessagingState.js +71 -0
  198. package/dist/esm/groups/MessagingState.js.map +6 -0
  199. package/dist/esm/groups/index.d.ts +8 -0
  200. package/dist/esm/groups/index.d.ts.map +1 -0
  201. package/dist/esm/groups/index.js +8 -0
  202. package/dist/esm/groups/index.js.map +6 -0
  203. package/dist/esm/index.d.ts +1 -0
  204. package/dist/esm/index.d.ts.map +1 -1
  205. package/dist/esm/index.js +1 -0
  206. package/dist/esm/index.js.map +1 -1
  207. package/dist/esm/interaction/AccessControlManager.d.ts +4 -13
  208. package/dist/esm/interaction/AccessControlManager.d.ts.map +1 -1
  209. package/dist/esm/interaction/AccessControlManager.js +39 -48
  210. package/dist/esm/interaction/AccessControlManager.js.map +1 -1
  211. package/dist/esm/interaction/InteractionClient.d.ts +5 -4
  212. package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
  213. package/dist/esm/interaction/InteractionClient.js +54 -4
  214. package/dist/esm/interaction/InteractionClient.js.map +1 -1
  215. package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
  216. package/dist/esm/interaction/InteractionMessenger.js +15 -0
  217. package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
  218. package/dist/esm/interaction/Subscription.d.ts +3 -3
  219. package/dist/esm/interaction/Subscription.d.ts.map +1 -1
  220. package/dist/esm/interaction/Subscription.js.map +1 -1
  221. package/dist/esm/peer/PeerAddress.d.ts +1 -0
  222. package/dist/esm/peer/PeerAddress.d.ts.map +1 -1
  223. package/dist/esm/peer/PeerAddress.js +5 -0
  224. package/dist/esm/peer/PeerAddress.js.map +1 -1
  225. package/dist/esm/peer/PeerSet.d.ts.map +1 -1
  226. package/dist/esm/peer/PeerSet.js +33 -3
  227. package/dist/esm/peer/PeerSet.js.map +1 -1
  228. package/dist/esm/protocol/ChannelManager.d.ts.map +1 -1
  229. package/dist/esm/protocol/ChannelManager.js +7 -8
  230. package/dist/esm/protocol/ChannelManager.js.map +1 -1
  231. package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
  232. package/dist/esm/protocol/ExchangeManager.js +41 -27
  233. package/dist/esm/protocol/ExchangeManager.js.map +1 -1
  234. package/dist/esm/protocol/MessageExchange.d.ts +1 -1
  235. package/dist/esm/protocol/MessageExchange.d.ts.map +1 -1
  236. package/dist/esm/protocol/MessageExchange.js +39 -5
  237. package/dist/esm/protocol/MessageExchange.js.map +1 -1
  238. package/dist/esm/protocol/MessageReceptionState.d.ts +1 -1
  239. package/dist/esm/securechannel/SecureChannelProtocol.js +2 -2
  240. package/dist/esm/securechannel/SecureChannelProtocol.js.map +1 -1
  241. package/dist/esm/session/GroupSession.d.ts +56 -0
  242. package/dist/esm/session/GroupSession.d.ts.map +1 -0
  243. package/dist/esm/session/GroupSession.js +177 -0
  244. package/dist/esm/session/GroupSession.js.map +6 -0
  245. package/dist/esm/session/InsecureSession.d.ts +2 -1
  246. package/dist/esm/session/InsecureSession.d.ts.map +1 -1
  247. package/dist/esm/session/InsecureSession.js +3 -2
  248. package/dist/esm/session/InsecureSession.js.map +1 -1
  249. package/dist/esm/session/NodeSession.d.ts +88 -0
  250. package/dist/esm/session/NodeSession.d.ts.map +1 -0
  251. package/dist/esm/session/NodeSession.js +298 -0
  252. package/dist/esm/session/NodeSession.js.map +6 -0
  253. package/dist/esm/session/SecureSession.d.ts +10 -75
  254. package/dist/esm/session/SecureSession.d.ts.map +1 -1
  255. package/dist/esm/session/SecureSession.js +10 -291
  256. package/dist/esm/session/SecureSession.js.map +2 -2
  257. package/dist/esm/session/Session.d.ts +6 -5
  258. package/dist/esm/session/Session.d.ts.map +1 -1
  259. package/dist/esm/session/Session.js +12 -2
  260. package/dist/esm/session/Session.js.map +1 -1
  261. package/dist/esm/session/SessionManager.d.ts +27 -9
  262. package/dist/esm/session/SessionManager.d.ts.map +1 -1
  263. package/dist/esm/session/SessionManager.js +84 -6
  264. package/dist/esm/session/SessionManager.js.map +1 -1
  265. package/dist/esm/session/case/CaseClient.d.ts +1 -1
  266. package/dist/esm/session/case/CaseClient.js +2 -2
  267. package/dist/esm/session/case/CaseClient.js.map +1 -1
  268. package/dist/esm/session/index.d.ts +2 -0
  269. package/dist/esm/session/index.d.ts.map +1 -1
  270. package/dist/esm/session/index.js +2 -0
  271. package/dist/esm/session/index.js.map +1 -1
  272. package/dist/esm/session/pase/PaseClient.d.ts +1 -1
  273. package/package.json +6 -6
  274. package/src/action/server/AccessControl.ts +4 -7
  275. package/src/action/server/AttributeWriteResponse.ts +29 -7
  276. package/src/action/server/CommandInvokeResponse.ts +28 -7
  277. package/src/action/server/DataResponse.ts +1 -1
  278. package/src/action/server/Subject.ts +45 -0
  279. package/src/action/server/index.ts +1 -0
  280. package/src/certificate/DeviceCertification.ts +2 -2
  281. package/src/cluster/client/AttributeClient.ts +15 -3
  282. package/src/cluster/client/ClusterClient.ts +90 -4
  283. package/src/cluster/client/ClusterClientTypes.ts +38 -9
  284. package/src/cluster/client/EventClient.ts +9 -2
  285. package/src/codec/MessageCodec.ts +49 -8
  286. package/src/fabric/Fabric.ts +51 -85
  287. package/src/fabric/FabricManager.ts +11 -4
  288. package/src/groups/FabricGroupsManager.ts +164 -0
  289. package/src/groups/Groups.ts +81 -0
  290. package/src/groups/KeySets.ts +194 -0
  291. package/src/groups/MessagingState.ts +76 -0
  292. package/src/groups/index.ts +8 -0
  293. package/src/index.ts +1 -0
  294. package/src/interaction/AccessControlManager.ts +49 -81
  295. package/src/interaction/InteractionClient.ts +66 -6
  296. package/src/interaction/InteractionMessenger.ts +15 -0
  297. package/src/interaction/Subscription.ts +3 -3
  298. package/src/peer/PeerAddress.ts +4 -0
  299. package/src/peer/PeerSet.ts +39 -4
  300. package/src/protocol/ChannelManager.ts +7 -9
  301. package/src/protocol/ExchangeManager.ts +51 -35
  302. package/src/protocol/MessageExchange.ts +42 -7
  303. package/src/protocol/MessageReceptionState.ts +2 -2
  304. package/src/securechannel/SecureChannelProtocol.ts +2 -2
  305. package/src/session/GroupSession.ts +223 -0
  306. package/src/session/InsecureSession.ts +3 -2
  307. package/src/session/NodeSession.ts +367 -0
  308. package/src/session/SecureSession.ts +14 -363
  309. package/src/session/Session.ts +17 -6
  310. package/src/session/SessionManager.ts +94 -14
  311. package/src/session/case/CaseClient.ts +2 -2
  312. package/src/session/index.ts +2 -3
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import { capitalize, Diagnostic, Logger, Merge } from "#general";
7
+ import { capitalize, Diagnostic, ImplementationError, Logger, Merge } from "#general";
8
8
  import {
9
9
  Attribute,
10
10
  AttributeId,
@@ -31,18 +31,37 @@ import {
31
31
  AttributeClientValues,
32
32
  ClusterClientObj,
33
33
  EventClients,
34
+ GroupClusterClientObj,
34
35
  SignatureFromCommandSpec,
36
+ SignatureFromCommandSpecWithoutResponse,
35
37
  } from "./ClusterClientTypes.js";
36
38
  import { createEventClient } from "./EventClient.js";
37
39
 
38
40
  const logger = Logger.get("ClusterClient");
39
41
 
42
+ export function GroupClusterClient<const T extends ClusterType>(
43
+ clusterDef: T,
44
+ interactionClient: InteractionClient,
45
+ globalAttributeValues: Partial<AttributeClientValues<GlobalAttributes<T["features"]>>> = {},
46
+ ): GroupClusterClientObj<T> {
47
+ if (!interactionClient.isGroupAddress) {
48
+ throw new Error("GroupClusterClient must be used with a GroupAddress InteractionClient");
49
+ }
50
+
51
+ return ClusterClient(clusterDef, undefined, interactionClient, globalAttributeValues);
52
+ }
53
+
40
54
  export function ClusterClient<const T extends ClusterType>(
41
55
  clusterDef: T,
42
- endpointId: EndpointNumber,
56
+ endpointId: EndpointNumber | undefined,
43
57
  interactionClient: InteractionClient,
44
58
  globalAttributeValues: Partial<AttributeClientValues<GlobalAttributes<T["features"]>>> = {},
45
59
  ): ClusterClientObj<T> {
60
+ const isGroupAddress = interactionClient.isGroupAddress;
61
+ if (isGroupAddress !== (endpointId === undefined)) {
62
+ throw new Error("Endpoint ID must be defined for a Non-Group ClusterClient");
63
+ }
64
+
46
65
  function addAttributeToResult(attribute: Attribute<any, any>, attributeName: string) {
47
66
  (attributes as any)[attributeName] = createAttributeClient(
48
67
  attribute,
@@ -59,6 +78,10 @@ export function ClusterClient<const T extends ClusterType>(
59
78
  requestFromRemote?: boolean,
60
79
  isFabricFiltered = true,
61
80
  ) => {
81
+ if (isGroupAddress) {
82
+ throw new ImplementationError("Group cluster clients do not support reading attributes");
83
+ }
84
+
62
85
  try {
63
86
  return await (attributes as any)[attributeName].get(requestFromRemote, isFabricFiltered);
64
87
  } catch (e) {
@@ -77,6 +100,10 @@ export function ClusterClient<const T extends ClusterType>(
77
100
  knownDataVersion?: number,
78
101
  isFabricFiltered?: boolean,
79
102
  ) => {
103
+ if (isGroupAddress) {
104
+ throw new ImplementationError("Group cluster clients do not support subscribing attributes");
105
+ }
106
+
80
107
  (attributes as any)[attributeName].addListener(listener);
81
108
  return (attributes as any)[attributeName].subscribe(
82
109
  minIntervalS,
@@ -86,9 +113,17 @@ export function ClusterClient<const T extends ClusterType>(
86
113
  );
87
114
  };
88
115
  result[`add${capitalizedAttributeName}AttributeListener`] = <T>(listener: (value: T) => void) => {
116
+ if (isGroupAddress) {
117
+ throw new ImplementationError("Group cluster clients do not support subscribing attributes");
118
+ }
119
+
89
120
  (attributes as any)[attributeName].addListener(listener);
90
121
  };
91
122
  result[`remove${capitalizedAttributeName}AttributeListener`] = <T>(listener: (value: T) => void) => {
123
+ if (isGroupAddress) {
124
+ throw new ImplementationError("Group cluster clients do not support subscribing attributes");
125
+ }
126
+
92
127
  (attributes as any)[attributeName].removeListener(listener);
93
128
  };
94
129
  }
@@ -102,6 +137,10 @@ export function ClusterClient<const T extends ClusterType>(
102
137
  minimumEventNumber?: number | bigint,
103
138
  isFabricFiltered?: boolean,
104
139
  ) => {
140
+ if (isGroupAddress) {
141
+ throw new ImplementationError("Group cluster clients do not support reading events");
142
+ }
143
+
105
144
  try {
106
145
  return await (events as any)[eventName].get(minimumEventNumber, isFabricFiltered);
107
146
  } catch (e) {
@@ -119,6 +158,10 @@ export function ClusterClient<const T extends ClusterType>(
119
158
  minimumEventNumber?: number | bigint,
120
159
  isFabricFiltered?: boolean,
121
160
  ) => {
161
+ if (isGroupAddress) {
162
+ throw new ImplementationError("Group cluster clients do not support subscribing to events");
163
+ }
164
+
122
165
  (events as any)[eventName].addListener(listener);
123
166
  return (events as any)[eventName].subscribe(
124
167
  minIntervalS,
@@ -129,9 +172,17 @@ export function ClusterClient<const T extends ClusterType>(
129
172
  );
130
173
  };
131
174
  result[`add${capitalizedEventName}EventListener`] = <T>(listener: (value: DecodedEventData<T>) => void) => {
175
+ if (isGroupAddress) {
176
+ throw new ImplementationError("Group cluster clients do not support subscribing events");
177
+ }
178
+
132
179
  (events as any)[eventName].addListener(listener);
133
180
  };
134
181
  result[`remove${capitalizedEventName}EventListener`] = <T>(listener: (value: DecodedEventData<T>) => void) => {
182
+ if (isGroupAddress) {
183
+ throw new ImplementationError("Group cluster clients do not support subscribing events");
184
+ }
185
+
135
186
  (events as any)[eventName].removeListener(listener);
136
187
  };
137
188
  }
@@ -149,7 +200,13 @@ export function ClusterClient<const T extends ClusterType>(
149
200
  } = clusterDef;
150
201
  const attributes = <AttributeClients<T["features"], T["attributes"]>>{};
151
202
  const events = <EventClients<T["events"]>>{};
152
- const commands = <{ [P in keyof T["commands"]]: SignatureFromCommandSpec<T["commands"][P]> }>{};
203
+ const commands = <
204
+ {
205
+ [P in keyof T["commands"]]:
206
+ | SignatureFromCommandSpec<T["commands"][P]>
207
+ | SignatureFromCommandSpecWithoutResponse<T["commands"][P]>;
208
+ }
209
+ >{};
153
210
 
154
211
  let reportedFeatures: TypeFromPartialBitSchema<T["features"]> | undefined = undefined;
155
212
  // If we have global attribute values we use them to modify
@@ -178,6 +235,10 @@ export function ClusterClient<const T extends ClusterType>(
178
235
  eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];
179
236
  dataVersionFilters?: { endpointId: EndpointNumber; clusterId: ClusterId; dataVersion: number }[];
180
237
  }) => {
238
+ if (isGroupAddress) {
239
+ throw new ImplementationError("Group cluster clients do not support subscribing attributes");
240
+ }
241
+
181
242
  const {
182
243
  minIntervalFloorSeconds,
183
244
  maxIntervalCeilingSeconds,
@@ -237,10 +298,18 @@ export function ClusterClient<const T extends ClusterType>(
237
298
  },
238
299
 
239
300
  isAttributeSupported: (attributeId: AttributeId) => {
301
+ if (isGroupAddress) {
302
+ throw new ImplementationError("Group cluster clients do not allow to determine attribute existence.");
303
+ }
304
+
240
305
  return !!globalAttributeValues?.attributeList?.includes(attributeId);
241
306
  },
242
307
 
243
308
  isAttributeSupportedByName: (attributeName: string) => {
309
+ if (isGroupAddress) {
310
+ throw new ImplementationError("Group cluster clients do not allow to determine attribute existence.");
311
+ }
312
+
244
313
  const attribute = (attributes as any)[attributeName];
245
314
  if (attribute === undefined) {
246
315
  return false;
@@ -249,10 +318,18 @@ export function ClusterClient<const T extends ClusterType>(
249
318
  },
250
319
 
251
320
  isCommandSupported: (commandId: CommandId) => {
321
+ if (isGroupAddress) {
322
+ throw new ImplementationError("Group cluster clients do not allow to determine command existence.");
323
+ }
324
+
252
325
  return !!globalAttributeValues?.acceptedCommandList?.includes(commandId);
253
326
  },
254
327
 
255
328
  isCommandSupportedByName: (commandName: string) => {
329
+ if (isGroupAddress) {
330
+ throw new ImplementationError("Group cluster clients do not allow to determine attribute existence.");
331
+ }
332
+
256
333
  const command = commandDef[commandName];
257
334
  if (command === undefined) {
258
335
  return false;
@@ -308,8 +385,17 @@ export function ClusterClient<const T extends ClusterType>(
308
385
  } = {},
309
386
  ) => {
310
387
  const { asTimedRequest, timedRequestTimeoutMs, useExtendedFailSafeMessageResponseTimeout } = options;
388
+ if (isGroupAddress) {
389
+ return interactionClient.invokeWithSuppressedResponse<Command<RequestT, ResponseT, any>>({
390
+ clusterId,
391
+ command: commandDef[commandName],
392
+ request,
393
+ asTimedRequest,
394
+ timedRequestTimeoutMs,
395
+ });
396
+ }
311
397
  return interactionClient.invoke<Command<RequestT, ResponseT, any>>({
312
- endpointId,
398
+ endpointId: endpointId!,
313
399
  clusterId,
314
400
  command: commandDef[commandName],
315
401
  request,
@@ -72,6 +72,23 @@ export type SignatureFromCommandSpec<C extends Command<any, any, any>> = (
72
72
  useExtendedFailSafeMessageResponseTimeout?: boolean;
73
73
  },
74
74
  ) => Promise<ResponseType<C>>;
75
+
76
+ export type SignatureFromCommandSpecWithoutResponse<C extends Command<any, any, any>> = (
77
+ request: RequestType<C>,
78
+ options?: {
79
+ /** Send this command as a timed request also when not required. Default timeout are 10 seconds. */
80
+ asTimedRequest?: boolean;
81
+
82
+ /** Override the request timeout when the command is sent as times request. Default are 10s. */
83
+ timedRequestTimeoutMs?: number;
84
+
85
+ /**
86
+ * Use the extended fail-safe message response timeout of 30 seconds. Use this for all commands
87
+ * executed during an activated FailSafe context!
88
+ */
89
+ useExtendedFailSafeMessageResponseTimeout?: boolean;
90
+ },
91
+ ) => Promise<void>;
75
92
  type GetterTypeFromSpec<A extends Attribute<any, any>> =
76
93
  A extends OptionalAttribute<infer T, any> ? T | undefined : AttributeJsType<A>;
77
94
  type ClientAttributeGetters<A extends Attributes> = Omit<
@@ -116,6 +133,7 @@ type ClientAttributeListeners<A extends Attributes> = {
116
133
  };
117
134
 
118
135
  type CommandServers<C extends Commands> = { [P in keyof C]: SignatureFromCommandSpec<C[P]> };
136
+ type NoResponseCommandServers<C extends Commands> = { [P in keyof C]: SignatureFromCommandSpecWithoutResponse<C[P]> };
119
137
 
120
138
  type ClientEventGetters<E extends Events> = {
121
139
  [P in keyof E as `get${Capitalize<string & P>}Event`]: (
@@ -143,8 +161,8 @@ type ClientEventListeners<E extends Events> = {
143
161
  ) => void;
144
162
  };
145
163
 
146
- /** Strongly typed interface of a cluster client */
147
- export type ClusterClientObj<T extends ClusterType = ClusterType> = {
164
+ /** Strongly typed interface of a group cluster client (limited functionalities) */
165
+ export type BaseClusterClientObj<T extends ClusterType = ClusterType> = {
148
166
  /**
149
167
  * Cluster ID
150
168
  * @readonly
@@ -177,12 +195,6 @@ export type ClusterClientObj<T extends ClusterType = ClusterType> = {
177
195
  */
178
196
  readonly isUnknown: boolean;
179
197
 
180
- /**
181
- * Endpoint ID the cluster is on.
182
- * @readonly
183
- */
184
- readonly endpointId: number;
185
-
186
198
  /**
187
199
  * Supported Features of the cluster
188
200
  * @readonly
@@ -195,6 +207,24 @@ export type ClusterClientObj<T extends ClusterType = ClusterType> = {
195
207
  * @readonly
196
208
  */
197
209
  readonly attributes: AttributeClients<T["features"], T["attributes"]>;
210
+ } & ClientAttributeSetters<T["attributes"]>;
211
+
212
+ export type GroupClusterClientObj<T extends ClusterType = ClusterType> = BaseClusterClientObj<T> & {
213
+ /**
214
+ * Commands of the cluster as object with named keys. This can be used to discover the commands of the cluster
215
+ * programmatically.
216
+ * @readonly
217
+ */
218
+ readonly commands: NoResponseCommandServers<T["commands"]>;
219
+ } & NoResponseCommandServers<T["commands"]>;
220
+
221
+ /** Strongly typed interface of a cluster client */
222
+ export type ClusterClientObj<T extends ClusterType = ClusterType> = BaseClusterClientObj<T> & {
223
+ /**
224
+ * Endpoint ID the cluster is on.
225
+ * @readonly
226
+ */
227
+ readonly endpointId: number;
198
228
 
199
229
  /**
200
230
  * Events of the cluster as object with named keys. This can be used to discover the events of the cluster
@@ -236,7 +266,6 @@ export type ClusterClientObj<T extends ClusterType = ClusterType> = {
236
266
  isCommandSupportedByName: (commandName: string) => boolean;
237
267
  } & ClientAttributeGetters<T["attributes"]> &
238
268
  ClientGlobalAttributeGetters<T["features"]> &
239
- ClientAttributeSetters<T["attributes"]> &
240
269
  ClientAttributeSubscribers<T["attributes"]> &
241
270
  ClientAttributeListeners<T["attributes"]> &
242
271
  CommandServers<T["commands"]> &
@@ -4,6 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ import { ImplementationError } from "#general";
7
8
  import { ClusterId, EndpointNumber, Event, EventId, EventNumber } from "#types";
8
9
  import { DecodedEventData } from "../../interaction/EventDataDecoder.js";
9
10
  import { InteractionClient } from "../../interaction/InteractionClient.js";
@@ -14,7 +15,7 @@ import { InteractionClient } from "../../interaction/InteractionClient.js";
14
15
  export function createEventClient<T>(
15
16
  event: Event<T, any>,
16
17
  name: string,
17
- endpointId: EndpointNumber,
18
+ endpointId: EndpointNumber | undefined,
18
19
  clusterId: ClusterId,
19
20
  interactionClient: InteractionClient,
20
21
  ): EventClient<T> {
@@ -32,7 +33,7 @@ export class EventClient<T> {
32
33
  constructor(
33
34
  readonly event: Event<T, any>,
34
35
  readonly name: string,
35
- readonly endpointId: EndpointNumber,
36
+ readonly endpointId: EndpointNumber | undefined,
36
37
  readonly clusterId: ClusterId,
37
38
  interactionClient: InteractionClient,
38
39
  ) {
@@ -44,6 +45,9 @@ export class EventClient<T> {
44
45
  minimumEventNumber?: EventNumber,
45
46
  isFabricFiltered?: boolean,
46
47
  ): Promise<DecodedEventData<T>[] | undefined> {
48
+ if (this.endpointId === undefined) {
49
+ throw new ImplementationError("Cannot read event without endpointId");
50
+ }
47
51
  return await this.#interactionClient.getEvent({
48
52
  endpointId: this.endpointId,
49
53
  clusterId: this.clusterId,
@@ -60,6 +64,9 @@ export class EventClient<T> {
60
64
  minimumEventNumber?: EventNumber,
61
65
  isFabricFiltered?: boolean,
62
66
  ) {
67
+ if (this.endpointId === undefined) {
68
+ throw new ImplementationError("Cannot read event without endpointId");
69
+ }
63
70
  return await this.#interactionClient.subscribeEvent({
64
71
  endpointId: this.endpointId,
65
72
  clusterId: this.clusterId,
@@ -4,7 +4,16 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import { Bytes, DataReader, DataWriter, Diagnostic, Endian, NotImplementedError, UnexpectedDataError } from "#general";
7
+ import {
8
+ Bytes,
9
+ DataReader,
10
+ DataWriter,
11
+ Diagnostic,
12
+ Endian,
13
+ InternalError,
14
+ NotImplementedError,
15
+ UnexpectedDataError,
16
+ } from "#general";
8
17
  import { ExchangeLogContext } from "#protocol/index.js";
9
18
  import { GroupId, INTERACTION_PROTOCOL_ID, NodeId, SECURE_CHANNEL_PROTOCOL_ID, SecureMessageType } from "#types";
10
19
  import { MessageType } from "../interaction/InteractionMessenger.js";
@@ -84,6 +93,7 @@ const enum SecurityFlag {
84
93
  HasPrivacyEnhancements = 0b10000000,
85
94
  IsControlMessage = 0b01000000,
86
95
  HasMessageExtension = 0b00100000,
96
+ SessionTypeMask = 0b00000011,
87
97
  }
88
98
 
89
99
  function mapProtocolAndMessageType(protocolId: number, messageType: number): { type: string; for?: string } {
@@ -129,6 +139,13 @@ export class MessageCodec {
129
139
  const extensionLength = reader.readUInt16();
130
140
  securityExtension = reader.readByteArray(extensionLength);
131
141
  }
142
+
143
+ if (header.sessionType === SessionType.Group && !header.isControlMessage) {
144
+ if (payloadHeader.requiresAck || payloadHeader.ackedMessageId) {
145
+ throw new UnexpectedDataError(`Group data messages cannot have requiresAck or ackedMessageId set.`);
146
+ }
147
+ }
148
+
132
149
  return {
133
150
  packetHeader: header,
134
151
  payloadHeader,
@@ -176,13 +193,31 @@ export class MessageCodec {
176
193
  const destNodeId = hasDestNodeId ? NodeId(reader.readUInt64()) : undefined;
177
194
  const destGroupId = hasDestGroupId ? GroupId(reader.readUInt16()) : undefined;
178
195
 
179
- const sessionType = securityFlags & 0b00000011;
180
- if (sessionType !== SessionType.Group && sessionType !== SessionType.Unicast)
181
- throw new UnexpectedDataError(`Unsupported session type ${sessionType}`);
196
+ const sessionType = securityFlags & SecurityFlag.SessionTypeMask;
197
+
198
+ if (sessionType !== SessionType.Group && sessionType !== SessionType.Unicast) {
199
+ throw new UnexpectedDataError(`Unsupported session type ${sessionType}.`);
200
+ }
201
+ if (sessionType === SessionType.Unicast && hasDestGroupId) {
202
+ throw new UnexpectedDataError(`Unicast session cannot have destination group id.`);
203
+ }
204
+ if (sessionType === SessionType.Group) {
205
+ if (!hasDestGroupId && !hasDestNodeId) {
206
+ throw new UnexpectedDataError(`Group session must have destination group id or destination node id.`);
207
+ }
208
+ if (!hasSourceNodeId) {
209
+ throw new UnexpectedDataError(`Group session must have source node id.`);
210
+ }
211
+ }
182
212
  const hasPrivacyEnhancements = (securityFlags & SecurityFlag.HasPrivacyEnhancements) !== 0;
183
- if (hasPrivacyEnhancements) throw new NotImplementedError(`Privacy enhancements not supported`);
213
+ if (hasPrivacyEnhancements) {
214
+ throw new NotImplementedError(`Privacy enhancements not supported.`);
215
+ }
184
216
  const isControlMessage = (securityFlags & SecurityFlag.IsControlMessage) !== 0;
185
- if (isControlMessage) throw new NotImplementedError(`Control Messages not supported`);
217
+ if (isControlMessage) {
218
+ // And also currently not needed because MCP is not relevant
219
+ throw new NotImplementedError(`Control Messages not supported.`);
220
+ }
186
221
  const hasMessageExtensions = (securityFlags & SecurityFlag.HasMessageExtension) !== 0;
187
222
 
188
223
  return {
@@ -207,7 +242,7 @@ export class MessageCodec {
207
242
  const hasSecuredExtension = (exchangeFlags & PayloadHeaderFlag.HasSecureExtension) !== 0;
208
243
  const hasVendorId = (exchangeFlags & PayloadHeaderFlag.HasVendorId) !== 0;
209
244
 
210
- const messageType = reader.readUInt8();
245
+ const messageType = reader.readUInt8(); // Protocol Opcode
211
246
  const exchangeId = reader.readUInt16();
212
247
  const vendorId = hasVendorId ? reader.readUInt16() : COMMON_VENDOR_ID;
213
248
  const protocolId = (vendorId << 16) | reader.readUInt16();
@@ -232,6 +267,12 @@ export class MessageCodec {
232
267
  sourceNodeId,
233
268
  sessionType,
234
269
  }: PacketHeader) {
270
+ if (
271
+ sessionType === SessionType.Group &&
272
+ (destGroupId === undefined || sourceNodeId === undefined || destNodeId !== undefined)
273
+ ) {
274
+ throw new InternalError(`Group session must have destination group id or source node id.`);
275
+ }
235
276
  const writer = new DataWriter(Endian.Little);
236
277
  const flags =
237
278
  (HEADER_VERSION << 4) |
@@ -246,7 +287,7 @@ export class MessageCodec {
246
287
  writer.writeUInt32(messageCounter);
247
288
  if (sourceNodeId !== undefined) writer.writeUInt64(sourceNodeId);
248
289
  if (destNodeId !== undefined) writer.writeUInt64(destNodeId);
249
- if (destGroupId !== undefined) writer.writeUInt32(destGroupId);
290
+ if (destGroupId !== undefined) writer.writeUInt16(destGroupId);
250
291
  return writer.toByteArray();
251
292
  }
252
293
 
@@ -10,7 +10,6 @@ import {
10
10
  TlvOperationalCertificate,
11
11
  TlvRootCertificate,
12
12
  } from "#certificate/CertificateManager.js";
13
- import { GroupKeyManagement } from "#clusters/group-key-management";
14
13
  import {
15
14
  BinaryKeyPair,
16
15
  Bytes,
@@ -25,56 +24,19 @@ import {
25
24
  MatterFlowError,
26
25
  MaybePromise,
27
26
  PrivateKey,
27
+ StorageContext,
28
28
  } from "#general";
29
+ import { FabricGroupsManager, GROUP_SECURITY_INFO } from "#groups/FabricGroupsManager.js";
29
30
  import { PeerAddress } from "#peer/PeerAddress.js";
30
- import { CaseAuthenticatedTag, FabricId, FabricIndex, NodeId, TypeFromSchema, VendorId } from "#types";
31
- import { SecureSession } from "../session/SecureSession.js";
31
+ import { Session } from "#session/Session.js";
32
+ import { CaseAuthenticatedTag, FabricId, FabricIndex, GroupId, NodeId, VendorId } from "#types";
32
33
 
33
34
  const logger = Logger.get("Fabric");
34
35
 
35
36
  const COMPRESSED_FABRIC_ID_INFO = Bytes.fromString("CompressedFabric");
36
- const GROUP_SECURITY_INFO = Bytes.fromString("GroupKey v1.0");
37
37
 
38
38
  export class PublicKeyError extends MatterError {}
39
39
 
40
- type OperationalGroupKeySet = TypeFromSchema<typeof GroupKeyManagement.TlvGroupKeySet> & {
41
- operationalEpochKey0: Uint8Array;
42
- groupSessionId0: number | null;
43
- operationalEpochKey1: Uint8Array | null;
44
- groupSessionId1: number | null;
45
- operationalEpochKey2: Uint8Array | null;
46
- groupSessionId2: number | null;
47
- };
48
-
49
- namespace OperationalGroupKeySet {
50
- export const asTlvGroupSet = (
51
- operationalGroupSet: OperationalGroupKeySet,
52
- ): TypeFromSchema<typeof GroupKeyManagement.TlvGroupKeySet> => {
53
- const {
54
- groupKeySetId,
55
- epochKey0,
56
- epochStartTime0,
57
- epochKey1,
58
- epochStartTime1,
59
- epochKey2,
60
- epochStartTime2,
61
- groupKeySecurityPolicy,
62
- groupKeyMulticastPolicy,
63
- } = operationalGroupSet;
64
- return {
65
- groupKeySetId,
66
- epochKey0,
67
- epochStartTime0,
68
- epochKey1,
69
- epochStartTime1,
70
- epochKey2,
71
- epochStartTime2,
72
- groupKeySecurityPolicy,
73
- groupKeyMulticastPolicy,
74
- };
75
- };
76
- }
77
-
78
40
  export type ExposedFabricInformation = {
79
41
  fabricIndex: FabricIndex;
80
42
  fabricId: FabricId;
@@ -97,14 +59,13 @@ export class Fabric {
97
59
  readonly operationalIdentityProtectionKey: Uint8Array;
98
60
  readonly intermediateCACert: Uint8Array | undefined;
99
61
  readonly operationalCert: Uint8Array;
100
-
101
62
  readonly #keyPair: Key;
102
-
103
- readonly #sessions = new Set<SecureSession>();
104
-
63
+ readonly #sessions = new Set<Session>();
64
+ readonly #groupManager: FabricGroupsManager;
105
65
  #label: string;
106
66
  #removeCallbacks = new Array<() => MaybePromise<void>>();
107
67
  #persistCallback: ((isUpdate?: boolean) => MaybePromise<void>) | undefined;
68
+ #storage?: StorageContext;
108
69
 
109
70
  constructor(config: Fabric.Config) {
110
71
  this.fabricIndex = config.fabricIndex;
@@ -120,8 +81,8 @@ export class Fabric {
120
81
  this.intermediateCACert = config.intermediateCACert;
121
82
  this.operationalCert = config.operationalCert;
122
83
  this.#label = config.label;
123
-
124
84
  this.#keyPair = PrivateKey(config.keyPair);
85
+ this.#groupManager = new FabricGroupsManager(this);
125
86
  }
126
87
 
127
88
  get config(): Fabric.Config {
@@ -158,6 +119,19 @@ export class Fabric {
158
119
  await this.persist();
159
120
  }
160
121
 
122
+ set storage(storage: StorageContext) {
123
+ this.#storage = storage;
124
+ this.#groupManager.storage = storage;
125
+ }
126
+
127
+ get storage(): StorageContext | undefined {
128
+ return this.#storage;
129
+ }
130
+
131
+ get groups() {
132
+ return this.#groupManager;
133
+ }
134
+
161
135
  get publicKey() {
162
136
  return this.#keyPair.publicKey;
163
137
  }
@@ -190,20 +164,39 @@ export class Fabric {
190
164
  );
191
165
  }
192
166
 
193
- getDestinationId(nodeId: NodeId, random: Uint8Array) {
167
+ #generateSalt(nodeId: NodeId, random: Uint8Array) {
194
168
  const writer = new DataWriter(Endian.Little);
195
169
  writer.writeByteArray(random);
196
170
  writer.writeByteArray(this.rootPublicKey);
197
171
  writer.writeUInt64(this.fabricId);
198
172
  writer.writeUInt64(nodeId);
199
- return Crypto.hmac(this.operationalIdentityProtectionKey, writer.toByteArray());
173
+ return writer.toByteArray();
174
+ }
175
+
176
+ /**
177
+ * Returns the destination IDs for a given nodeId, random value and optional groupId.
178
+ * When groupId is provided, it returns the time-wise valid operational keys for that groupId.
179
+ */
180
+ async currentDestinationIdFor(nodeId: NodeId, random: Uint8Array) {
181
+ return await Crypto.hmac(this.groups.keySets.currentKeyForId(0).key, this.#generateSalt(nodeId, random));
182
+ }
183
+
184
+ /**
185
+ * Returns the destination IDs for a given nodeId, random value and optional groupId.
186
+ * When groupId is provided, it returns all operational keys for that groupId.
187
+ */
188
+ async destinationIdsFor(nodeId: NodeId, random: Uint8Array) {
189
+ const salt = this.#generateSalt(nodeId, random);
190
+ // Check all keys of keyset 0 - typically it is only the IPK
191
+ const destinationIds = this.groups.keySets.allKeysForId(0).map(({ key }) => Crypto.hmac(key, salt));
192
+ return await Promise.all(destinationIds);
200
193
  }
201
194
 
202
- addSession(session: SecureSession) {
195
+ addSession(session: Session) {
203
196
  this.#sessions.add(session);
204
197
  }
205
198
 
206
- removeSession(session: SecureSession) {
199
+ removeSession(session: Session) {
207
200
  this.#sessions.delete(session);
208
201
  }
209
202
 
@@ -236,39 +229,6 @@ export class Fabric {
236
229
  return this.#persistCallback?.(isUpdate);
237
230
  }
238
231
 
239
- getGroupKeySet(groupKeySetId: number) {
240
- if (groupKeySetId === 0) {
241
- return OperationalGroupKeySet.asTlvGroupSet(this.getGroupSetForIpk());
242
- }
243
- // TODO add correct group handling later, right now only IPK exists
244
- return undefined;
245
- }
246
-
247
- private getGroupSetForIpk(): OperationalGroupKeySet {
248
- return {
249
- groupKeySetId: 0,
250
- epochKey0: this.identityProtectionKey,
251
- operationalEpochKey0: this.operationalIdentityProtectionKey,
252
- epochStartTime0: 0, // or do we need to track Fabric creation date?
253
- groupSessionId0: null,
254
- epochKey1: null,
255
- operationalEpochKey1: null,
256
- epochStartTime1: null,
257
- groupSessionId1: null,
258
- epochKey2: null,
259
- operationalEpochKey2: null,
260
- epochStartTime2: null,
261
- groupSessionId2: null,
262
- groupKeySecurityPolicy: GroupKeyManagement.GroupKeySecurityPolicy.TrustFirst,
263
- groupKeyMulticastPolicy: GroupKeyManagement.GroupKeyMulticastPolicy.PerGroupId,
264
- };
265
- }
266
-
267
- getAllGroupKeySets() {
268
- // TODO add correct group handling later, right now only IPK exists
269
- return [OperationalGroupKeySet.asTlvGroupSet(this.getGroupSetForIpk())];
270
- }
271
-
272
232
  get externalInformation(): ExposedFabricInformation {
273
233
  return {
274
234
  fabricIndex: this.fabricIndex,
@@ -283,6 +243,12 @@ export class Fabric {
283
243
  addressOf(nodeId: NodeId) {
284
244
  return PeerAddress({ fabricIndex: this.fabricIndex, nodeId });
285
245
  }
246
+
247
+ groupAddressOf(groupId: GroupId) {
248
+ GroupId.assertGroupId(groupId);
249
+
250
+ return PeerAddress({ fabricIndex: this.fabricIndex, nodeId: NodeId.fromGroupId(groupId) });
251
+ }
286
252
  }
287
253
 
288
254
  export class FabricBuilder {
@@ -433,7 +399,7 @@ export class FabricBuilder {
433
399
  throw new InternalError("operationalCert needs to be set");
434
400
 
435
401
  this.#fabricIndex = fabricIndex;
436
- const saltWriter = new DataWriter(Endian.Big);
402
+ const saltWriter = new DataWriter();
437
403
  saltWriter.writeUInt64(this.#fabricId);
438
404
  const operationalId = await Crypto.hkdf(
439
405
  this.#rootPublicKey.slice(1),