@matter/protocol 0.12.4-alpha.0-20250223-1e0341a1a → 0.12.4-alpha.0-20250224-46934b522

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 (245) hide show
  1. package/dist/cjs/action/client/ClientInteraction.d.ts +38 -0
  2. package/dist/cjs/action/client/ClientInteraction.d.ts.map +1 -0
  3. package/dist/cjs/action/client/ClientInteraction.js +91 -0
  4. package/dist/cjs/action/client/ClientInteraction.js.map +6 -0
  5. package/dist/cjs/action/client/index.d.ts +7 -0
  6. package/dist/cjs/action/client/index.d.ts.map +1 -0
  7. package/dist/cjs/action/client/index.js +24 -0
  8. package/dist/cjs/action/client/index.js.map +6 -0
  9. package/dist/cjs/action/index.d.ts +1 -0
  10. package/dist/cjs/action/index.d.ts.map +1 -1
  11. package/dist/cjs/action/index.js +1 -0
  12. package/dist/cjs/action/index.js.map +1 -1
  13. package/dist/cjs/interaction/DecodedDataReport.d.ts +15 -0
  14. package/dist/cjs/interaction/DecodedDataReport.d.ts.map +1 -0
  15. package/dist/cjs/interaction/DecodedDataReport.js +42 -0
  16. package/dist/cjs/interaction/DecodedDataReport.js.map +6 -0
  17. package/dist/cjs/interaction/InteractionClient.d.ts +17 -23
  18. package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
  19. package/dist/cjs/interaction/InteractionClient.js +100 -127
  20. package/dist/cjs/interaction/InteractionClient.js.map +1 -1
  21. package/dist/cjs/interaction/InteractionMessenger.d.ts +94 -1
  22. package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
  23. package/dist/cjs/interaction/InteractionMessenger.js +56 -37
  24. package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
  25. package/dist/cjs/interaction/InteractionServer.d.ts +22 -3
  26. package/dist/cjs/interaction/InteractionServer.d.ts.map +1 -1
  27. package/dist/cjs/interaction/InteractionServer.js +129 -45
  28. package/dist/cjs/interaction/InteractionServer.js.map +1 -1
  29. package/dist/cjs/interaction/ServerSubscription.d.ts +8 -16
  30. package/dist/cjs/interaction/ServerSubscription.d.ts.map +1 -1
  31. package/dist/cjs/interaction/ServerSubscription.js +78 -55
  32. package/dist/cjs/interaction/ServerSubscription.js.map +1 -1
  33. package/dist/cjs/interaction/Subscription.d.ts +7 -1
  34. package/dist/cjs/interaction/Subscription.d.ts.map +1 -1
  35. package/dist/cjs/interaction/Subscription.js +25 -2
  36. package/dist/cjs/interaction/Subscription.js.map +1 -1
  37. package/dist/cjs/interaction/SubscriptionClient.d.ts +38 -0
  38. package/dist/cjs/interaction/SubscriptionClient.d.ts.map +1 -0
  39. package/dist/cjs/interaction/SubscriptionClient.js +98 -0
  40. package/dist/cjs/interaction/SubscriptionClient.js.map +6 -0
  41. package/dist/cjs/interaction/index.d.ts +1 -0
  42. package/dist/cjs/interaction/index.d.ts.map +1 -1
  43. package/dist/cjs/interaction/index.js +1 -0
  44. package/dist/cjs/interaction/index.js.map +1 -1
  45. package/dist/cjs/peer/ControllerCommissioner.d.ts +2 -2
  46. package/dist/cjs/peer/ControllerCommissioner.d.ts.map +1 -1
  47. package/dist/cjs/peer/ControllerCommissioner.js +7 -7
  48. package/dist/cjs/peer/ControllerCommissioner.js.map +1 -1
  49. package/dist/cjs/peer/InteractionQueue.d.ts +11 -0
  50. package/dist/cjs/peer/InteractionQueue.d.ts.map +1 -0
  51. package/dist/cjs/peer/InteractionQueue.js +42 -0
  52. package/dist/cjs/peer/InteractionQueue.js.map +6 -0
  53. package/dist/cjs/peer/PeerAddress.d.ts +5 -0
  54. package/dist/cjs/peer/PeerAddress.d.ts.map +1 -1
  55. package/dist/cjs/peer/PeerAddress.js +13 -1
  56. package/dist/cjs/peer/PeerAddress.js.map +1 -1
  57. package/dist/cjs/peer/PeerAddressStore.d.ts +1 -1
  58. package/dist/cjs/peer/PeerAddressStore.d.ts.map +1 -1
  59. package/dist/cjs/peer/PeerSet.d.ts +20 -7
  60. package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
  61. package/dist/cjs/peer/PeerSet.js +74 -67
  62. package/dist/cjs/peer/PeerSet.js.map +1 -1
  63. package/dist/cjs/peer/PhysicalDeviceProperties.d.ts +26 -0
  64. package/dist/cjs/peer/PhysicalDeviceProperties.d.ts.map +1 -0
  65. package/dist/cjs/peer/PhysicalDeviceProperties.js +74 -0
  66. package/dist/cjs/peer/PhysicalDeviceProperties.js.map +6 -0
  67. package/dist/cjs/peer/index.d.ts +1 -0
  68. package/dist/cjs/peer/index.d.ts.map +1 -1
  69. package/dist/cjs/peer/index.js +1 -0
  70. package/dist/cjs/peer/index.js.map +1 -1
  71. package/dist/cjs/protocol/ExchangeManager.d.ts +1 -0
  72. package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
  73. package/dist/cjs/protocol/ExchangeManager.js +6 -3
  74. package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
  75. package/dist/cjs/protocol/ExchangeProvider.d.ts +13 -1
  76. package/dist/cjs/protocol/ExchangeProvider.d.ts.map +1 -1
  77. package/dist/cjs/protocol/ExchangeProvider.js +2 -0
  78. package/dist/cjs/protocol/ExchangeProvider.js.map +1 -1
  79. package/dist/cjs/protocol/ProtocolHandler.d.ts +1 -1
  80. package/dist/cjs/protocol/ProtocolHandler.d.ts.map +1 -1
  81. package/dist/cjs/securechannel/SecureChannelMessenger.d.ts +1 -0
  82. package/dist/cjs/securechannel/SecureChannelMessenger.d.ts.map +1 -1
  83. package/dist/cjs/securechannel/SecureChannelMessenger.js +3 -0
  84. package/dist/cjs/securechannel/SecureChannelMessenger.js.map +1 -1
  85. package/dist/cjs/securechannel/SecureChannelProtocol.d.ts +1 -1
  86. package/dist/cjs/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  87. package/dist/cjs/securechannel/SecureChannelProtocol.js +1 -3
  88. package/dist/cjs/securechannel/SecureChannelProtocol.js.map +1 -1
  89. package/dist/cjs/session/SecureSession.d.ts +1 -1
  90. package/dist/cjs/session/SecureSession.d.ts.map +1 -1
  91. package/dist/cjs/session/SecureSession.js +3 -2
  92. package/dist/cjs/session/SecureSession.js.map +1 -1
  93. package/dist/cjs/session/Session.d.ts +1 -0
  94. package/dist/cjs/session/Session.d.ts.map +1 -1
  95. package/dist/cjs/session/Session.js +1 -0
  96. package/dist/cjs/session/Session.js.map +1 -1
  97. package/dist/cjs/session/SessionManager.d.ts +2 -2
  98. package/dist/cjs/session/SessionManager.d.ts.map +1 -1
  99. package/dist/cjs/session/SessionManager.js +6 -9
  100. package/dist/cjs/session/SessionManager.js.map +1 -1
  101. package/dist/cjs/session/case/CaseServer.d.ts +1 -1
  102. package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
  103. package/dist/cjs/session/case/CaseServer.js +1 -3
  104. package/dist/cjs/session/case/CaseServer.js.map +1 -1
  105. package/dist/cjs/session/pase/PaseServer.d.ts +2 -3
  106. package/dist/cjs/session/pase/PaseServer.d.ts.map +1 -1
  107. package/dist/cjs/session/pase/PaseServer.js +12 -14
  108. package/dist/cjs/session/pase/PaseServer.js.map +1 -1
  109. package/dist/esm/action/client/ClientInteraction.d.ts +38 -0
  110. package/dist/esm/action/client/ClientInteraction.d.ts.map +1 -0
  111. package/dist/esm/action/client/ClientInteraction.js +71 -0
  112. package/dist/esm/action/client/ClientInteraction.js.map +6 -0
  113. package/dist/esm/action/client/index.d.ts +7 -0
  114. package/dist/esm/action/client/index.d.ts.map +1 -0
  115. package/dist/esm/action/client/index.js +7 -0
  116. package/dist/esm/action/client/index.js.map +6 -0
  117. package/dist/esm/action/index.d.ts +1 -0
  118. package/dist/esm/action/index.d.ts.map +1 -1
  119. package/dist/esm/action/index.js +1 -0
  120. package/dist/esm/action/index.js.map +1 -1
  121. package/dist/esm/interaction/DecodedDataReport.d.ts +15 -0
  122. package/dist/esm/interaction/DecodedDataReport.d.ts.map +1 -0
  123. package/dist/esm/interaction/DecodedDataReport.js +22 -0
  124. package/dist/esm/interaction/DecodedDataReport.js.map +6 -0
  125. package/dist/esm/interaction/InteractionClient.d.ts +17 -23
  126. package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
  127. package/dist/esm/interaction/InteractionClient.js +102 -134
  128. package/dist/esm/interaction/InteractionClient.js.map +1 -1
  129. package/dist/esm/interaction/InteractionMessenger.d.ts +94 -1
  130. package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
  131. package/dist/esm/interaction/InteractionMessenger.js +56 -37
  132. package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
  133. package/dist/esm/interaction/InteractionServer.d.ts +22 -3
  134. package/dist/esm/interaction/InteractionServer.d.ts.map +1 -1
  135. package/dist/esm/interaction/InteractionServer.js +130 -46
  136. package/dist/esm/interaction/InteractionServer.js.map +1 -1
  137. package/dist/esm/interaction/ServerSubscription.d.ts +8 -16
  138. package/dist/esm/interaction/ServerSubscription.d.ts.map +1 -1
  139. package/dist/esm/interaction/ServerSubscription.js +78 -55
  140. package/dist/esm/interaction/ServerSubscription.js.map +1 -1
  141. package/dist/esm/interaction/Subscription.d.ts +7 -1
  142. package/dist/esm/interaction/Subscription.d.ts.map +1 -1
  143. package/dist/esm/interaction/Subscription.js +26 -3
  144. package/dist/esm/interaction/Subscription.js.map +1 -1
  145. package/dist/esm/interaction/SubscriptionClient.d.ts +38 -0
  146. package/dist/esm/interaction/SubscriptionClient.d.ts.map +1 -0
  147. package/dist/esm/interaction/SubscriptionClient.js +78 -0
  148. package/dist/esm/interaction/SubscriptionClient.js.map +6 -0
  149. package/dist/esm/interaction/index.d.ts +1 -0
  150. package/dist/esm/interaction/index.d.ts.map +1 -1
  151. package/dist/esm/interaction/index.js +1 -0
  152. package/dist/esm/interaction/index.js.map +1 -1
  153. package/dist/esm/peer/ControllerCommissioner.d.ts +2 -2
  154. package/dist/esm/peer/ControllerCommissioner.d.ts.map +1 -1
  155. package/dist/esm/peer/ControllerCommissioner.js +9 -9
  156. package/dist/esm/peer/ControllerCommissioner.js.map +1 -1
  157. package/dist/esm/peer/InteractionQueue.d.ts +11 -0
  158. package/dist/esm/peer/InteractionQueue.d.ts.map +1 -0
  159. package/dist/esm/peer/InteractionQueue.js +22 -0
  160. package/dist/esm/peer/InteractionQueue.js.map +6 -0
  161. package/dist/esm/peer/PeerAddress.d.ts +5 -0
  162. package/dist/esm/peer/PeerAddress.d.ts.map +1 -1
  163. package/dist/esm/peer/PeerAddress.js +13 -1
  164. package/dist/esm/peer/PeerAddress.js.map +1 -1
  165. package/dist/esm/peer/PeerAddressStore.d.ts +1 -1
  166. package/dist/esm/peer/PeerAddressStore.d.ts.map +1 -1
  167. package/dist/esm/peer/PeerSet.d.ts +20 -7
  168. package/dist/esm/peer/PeerSet.d.ts.map +1 -1
  169. package/dist/esm/peer/PeerSet.js +75 -68
  170. package/dist/esm/peer/PeerSet.js.map +1 -1
  171. package/dist/esm/peer/PhysicalDeviceProperties.d.ts +26 -0
  172. package/dist/esm/peer/PhysicalDeviceProperties.d.ts.map +1 -0
  173. package/dist/esm/peer/PhysicalDeviceProperties.js +54 -0
  174. package/dist/esm/peer/PhysicalDeviceProperties.js.map +6 -0
  175. package/dist/esm/peer/index.d.ts +1 -0
  176. package/dist/esm/peer/index.d.ts.map +1 -1
  177. package/dist/esm/peer/index.js +1 -0
  178. package/dist/esm/peer/index.js.map +1 -1
  179. package/dist/esm/protocol/ExchangeManager.d.ts +1 -0
  180. package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
  181. package/dist/esm/protocol/ExchangeManager.js +6 -3
  182. package/dist/esm/protocol/ExchangeManager.js.map +1 -1
  183. package/dist/esm/protocol/ExchangeProvider.d.ts +13 -1
  184. package/dist/esm/protocol/ExchangeProvider.d.ts.map +1 -1
  185. package/dist/esm/protocol/ExchangeProvider.js +2 -0
  186. package/dist/esm/protocol/ExchangeProvider.js.map +1 -1
  187. package/dist/esm/protocol/ProtocolHandler.d.ts +1 -1
  188. package/dist/esm/protocol/ProtocolHandler.d.ts.map +1 -1
  189. package/dist/esm/securechannel/SecureChannelMessenger.d.ts +1 -0
  190. package/dist/esm/securechannel/SecureChannelMessenger.d.ts.map +1 -1
  191. package/dist/esm/securechannel/SecureChannelMessenger.js +3 -0
  192. package/dist/esm/securechannel/SecureChannelMessenger.js.map +1 -1
  193. package/dist/esm/securechannel/SecureChannelProtocol.d.ts +1 -1
  194. package/dist/esm/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  195. package/dist/esm/securechannel/SecureChannelProtocol.js +1 -3
  196. package/dist/esm/securechannel/SecureChannelProtocol.js.map +1 -1
  197. package/dist/esm/session/SecureSession.d.ts +1 -1
  198. package/dist/esm/session/SecureSession.d.ts.map +1 -1
  199. package/dist/esm/session/SecureSession.js +3 -2
  200. package/dist/esm/session/SecureSession.js.map +1 -1
  201. package/dist/esm/session/Session.d.ts +1 -0
  202. package/dist/esm/session/Session.d.ts.map +1 -1
  203. package/dist/esm/session/Session.js +1 -0
  204. package/dist/esm/session/Session.js.map +1 -1
  205. package/dist/esm/session/SessionManager.d.ts +2 -2
  206. package/dist/esm/session/SessionManager.d.ts.map +1 -1
  207. package/dist/esm/session/SessionManager.js +7 -10
  208. package/dist/esm/session/SessionManager.js.map +1 -1
  209. package/dist/esm/session/case/CaseServer.d.ts +1 -1
  210. package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
  211. package/dist/esm/session/case/CaseServer.js +1 -3
  212. package/dist/esm/session/case/CaseServer.js.map +1 -1
  213. package/dist/esm/session/pase/PaseServer.d.ts +2 -3
  214. package/dist/esm/session/pase/PaseServer.d.ts.map +1 -1
  215. package/dist/esm/session/pase/PaseServer.js +12 -14
  216. package/dist/esm/session/pase/PaseServer.js.map +1 -1
  217. package/package.json +6 -6
  218. package/src/action/client/ClientInteraction.ts +110 -0
  219. package/src/action/client/index.ts +7 -0
  220. package/src/action/index.ts +1 -0
  221. package/src/interaction/DecodedDataReport.ts +29 -0
  222. package/src/interaction/InteractionClient.ts +118 -165
  223. package/src/interaction/InteractionMessenger.ts +63 -43
  224. package/src/interaction/InteractionServer.ts +176 -50
  225. package/src/interaction/ServerSubscription.ts +87 -63
  226. package/src/interaction/Subscription.ts +34 -6
  227. package/src/interaction/SubscriptionClient.ts +107 -0
  228. package/src/interaction/index.ts +1 -0
  229. package/src/peer/ControllerCommissioner.ts +10 -10
  230. package/src/peer/InteractionQueue.ts +22 -0
  231. package/src/peer/PeerAddress.ts +14 -0
  232. package/src/peer/PeerAddressStore.ts +1 -1
  233. package/src/peer/PeerSet.ts +98 -83
  234. package/src/peer/PhysicalDeviceProperties.ts +80 -0
  235. package/src/peer/index.ts +1 -0
  236. package/src/protocol/ExchangeManager.ts +7 -3
  237. package/src/protocol/ExchangeProvider.ts +14 -1
  238. package/src/protocol/ProtocolHandler.ts +1 -1
  239. package/src/securechannel/SecureChannelMessenger.ts +4 -0
  240. package/src/securechannel/SecureChannelProtocol.ts +1 -3
  241. package/src/session/SecureSession.ts +3 -2
  242. package/src/session/Session.ts +1 -0
  243. package/src/session/SessionManager.ts +6 -9
  244. package/src/session/case/CaseServer.ts +2 -4
  245. package/src/session/pase/PaseServer.ts +13 -15
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { Interactable } from "#action/Interactable.js";
8
+ import { Invoke } from "#action/request/Invoke.js";
9
+ import { Read } from "#action/request/Read.js";
10
+ import { Subscribe } from "#action/request/Subscribe.js";
11
+ import { Write } from "#action/request/Write.js";
12
+ import { InvokeResult } from "#action/response/InvokeResult.js";
13
+ import { ReadResult } from "#action/response/ReadResult.js";
14
+ import { SubscribeResult } from "#action/response/SubscribeResult.js";
15
+ import { WriteResult } from "#action/response/WriteResult.js";
16
+ import { AccessControl } from "#action/server/AccessControl.js";
17
+ import { CancelablePromise, Environment, Environmental, NotImplementedError, PromiseQueue } from "#general";
18
+ import { InteractionClientMessenger } from "#interaction/InteractionMessenger.js";
19
+ import { SubscriptionClient } from "#interaction/SubscriptionClient.js";
20
+ import { InteractionQueue } from "#peer/InteractionQueue.js";
21
+ import { ExchangeProvider } from "#protocol/ExchangeProvider.js";
22
+ import { WriteResponse } from "#types";
23
+
24
+ export interface ClientInteractableContext {
25
+ exchanges: ExchangeProvider;
26
+ subscriptions: SubscriptionClient;
27
+ queue: PromiseQueue;
28
+ }
29
+
30
+ /**
31
+ * This is a WIP and currently largely a stub.
32
+ */
33
+ export class ClientInteraction<SessionT extends AccessControl.Session = AccessControl.Session>
34
+ implements Interactable<SessionT>
35
+ {
36
+ readonly #exchanges: ExchangeProvider;
37
+ readonly #subscriptions: SubscriptionClient;
38
+ readonly #queue?: PromiseQueue;
39
+
40
+ constructor(context: ClientInteractableContext) {
41
+ this.#exchanges = context.exchanges;
42
+ this.#subscriptions = context.subscriptions;
43
+ this.#queue = context.queue;
44
+ }
45
+
46
+ get subscriptions() {
47
+ return this.#subscriptions;
48
+ }
49
+
50
+ get queue() {
51
+ return this.#queue;
52
+ }
53
+
54
+ static [Environmental.create](env: Environment) {
55
+ const instance = new ClientInteraction({
56
+ exchanges: env.get(ExchangeProvider),
57
+ subscriptions: env.get(SubscriptionClient),
58
+ queue: env.get(InteractionQueue),
59
+ });
60
+ env.set(ClientInteraction, instance);
61
+ return instance;
62
+ }
63
+
64
+ read(_request: Read, _session?: SessionT): ReadResult {
65
+ // TODO
66
+ throw new NotImplementedError();
67
+ }
68
+
69
+ write<T extends Write>(request: T, _session?: SessionT) {
70
+ return new CancelablePromise<void | WriteResponse>((resolve, reject) => {
71
+ InteractionClientMessenger.create(this.#exchanges).then(messenger => {
72
+ const send = messenger.sendWriteCommand(request);
73
+
74
+ let sendResolve;
75
+ if (request.suppressResponse) {
76
+ sendResolve = send.then(() => {
77
+ resolve();
78
+ });
79
+ } else {
80
+ sendResolve = send.then(resolve);
81
+ }
82
+
83
+ sendResolve.catch(reject);
84
+ }, reject);
85
+ }) as WriteResult<T>;
86
+ }
87
+
88
+ invoke<T extends Invoke>(request: Invoke, _session?: SessionT): InvokeResult<T> {
89
+ if (request.suppressResponse) {
90
+ return new CancelablePromise<void>((resolve, reject) => {
91
+ InteractionClientMessenger.create(this.#exchanges)
92
+ .then(messenger =>
93
+ messenger
94
+ .sendInvokeCommand(request)
95
+ .then(() => resolve())
96
+ .catch(reject),
97
+ )
98
+ .then(resolve, reject);
99
+ }) as InvokeResult<T>;
100
+ }
101
+
102
+ // TODO
103
+ throw new NotImplementedError();
104
+ }
105
+
106
+ subscribe(_request: Subscribe, _session?: SessionT): SubscribeResult {
107
+ // TODO
108
+ throw new NotImplementedError();
109
+ }
110
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Project CHIP Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ export * from "./ClientInteraction.js";
@@ -4,6 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ export * from "./client/index.js";
7
8
  export * from "./errors.js";
8
9
  export * from "./Interactable.js";
9
10
  export * from "./protocols.js";
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { DataReport } from "#types";
8
+ import { DecodedAttributeReportValue, normalizeAndDecodeReadAttributeReport } from "./AttributeDataDecoder.js";
9
+ import { DecodedEventReportValue, normalizeAndDecodeReadEventReport } from "./EventDataDecoder.js";
10
+
11
+ export interface DecodedDataReport extends DataReport {
12
+ isNormalized: true;
13
+ attributeReports: DecodedAttributeReportValue<any>[];
14
+ eventReports: DecodedEventReportValue<any>[];
15
+ }
16
+
17
+ export function DecodedDataReport(report: DataReport): DecodedDataReport {
18
+ if ((report as DecodedDataReport).isNormalized) {
19
+ return report as DecodedDataReport;
20
+ }
21
+
22
+ return {
23
+ ...report,
24
+ isNormalized: true,
25
+ attributeReports:
26
+ report.attributeReports === undefined ? [] : normalizeAndDecodeReadAttributeReport(report.attributeReports),
27
+ eventReports: report.eventReports === undefined ? [] : normalizeAndDecodeReadEventReport(report.eventReports),
28
+ };
29
+ }
@@ -5,20 +5,21 @@
5
5
  */
6
6
 
7
7
  import {
8
+ Environment,
9
+ Environmental,
8
10
  ImplementationError,
9
- InternalError,
10
11
  Logger,
11
12
  MatterFlowError,
12
- MaybePromise,
13
13
  PromiseQueue,
14
- Time,
14
+ ServerAddressIp,
15
15
  Timer,
16
16
  UnexpectedDataError,
17
17
  isDeepEqual,
18
18
  } from "#general";
19
19
  import { Specification } from "#model";
20
- import { PeerAddress } from "#peer/PeerAddress.js";
20
+ import { PeerAddress, PeerAddressMap } from "#peer/PeerAddress.js";
21
21
  import { PeerDataStore } from "#peer/PeerAddressStore.js";
22
+ import { DiscoveryOptions, PeerSet } from "#peer/PeerSet.js";
22
23
  import {
23
24
  ArraySchema,
24
25
  Attribute,
@@ -30,7 +31,6 @@ import {
30
31
  Event,
31
32
  EventId,
32
33
  EventNumber,
33
- INTERACTION_PROTOCOL_ID,
34
34
  NodeId,
35
35
  RequestType,
36
36
  ResponseType,
@@ -47,16 +47,11 @@ import {
47
47
  resolveEventName,
48
48
  } from "#types";
49
49
  import { ExchangeProvider, ReconnectableExchangeProvider } from "../protocol/ExchangeProvider.js";
50
- import { MessageExchange } from "../protocol/MessageExchange.js";
51
- import { ProtocolHandler } from "../protocol/ProtocolHandler.js";
52
- import { DecodedAttributeReportValue, normalizeAndDecodeReadAttributeReport } from "./AttributeDataDecoder.js";
53
- import { DecodedEventData, DecodedEventReportValue, normalizeAndDecodeReadEventReport } from "./EventDataDecoder.js";
54
- import {
55
- DataReport,
56
- IncomingInteractionClientMessenger,
57
- InteractionClientMessenger,
58
- ReadRequest,
59
- } from "./InteractionMessenger.js";
50
+ import { DecodedAttributeReportValue } from "./AttributeDataDecoder.js";
51
+ import { DecodedDataReport } from "./DecodedDataReport.js";
52
+ import { DecodedEventData, DecodedEventReportValue } from "./EventDataDecoder.js";
53
+ import { DataReport, InteractionClientMessenger, ReadRequest } from "./InteractionMessenger.js";
54
+ import { RegisteredSubscription, SubscriptionClient } from "./SubscriptionClient.js";
60
55
 
61
56
  const logger = Logger.get("InteractionClient");
62
57
 
@@ -74,102 +69,102 @@ export interface AttributeStatus {
74
69
  status: StatusCode;
75
70
  }
76
71
 
77
- export class SubscriptionClient implements ProtocolHandler {
78
- private readonly subscriptionListeners = new Map<number, (dataReport: DataReport) => MaybePromise<void>>();
79
- private readonly subscriptionUpdateTimers = new Map<number, Timer>();
80
-
81
- constructor() {}
82
-
83
- getId() {
84
- return INTERACTION_PROTOCOL_ID;
85
- }
72
+ export class InteractionClientProvider {
73
+ readonly #peers: PeerSet;
74
+ readonly #clients = new PeerAddressMap<InteractionClient>();
86
75
 
87
- registerSubscriptionListener(subscriptionId: number, listener: (dataReport: DataReport) => MaybePromise<void>) {
88
- this.subscriptionListeners.set(subscriptionId, listener);
76
+ constructor(peers: PeerSet) {
77
+ this.#peers = peers;
78
+ this.#peers.deleted.on(peer => this.#onPeerLoss(peer.address));
79
+ this.#peers.disconnected.on(address => this.#onPeerLoss(address));
89
80
  }
90
81
 
91
- removeSubscriptionListener(subscriptionId: number) {
92
- this.subscriptionListeners.delete(subscriptionId);
82
+ static [Environmental.create](env: Environment) {
83
+ const instance = new InteractionClientProvider(env.get(PeerSet));
84
+ env.set(InteractionClientProvider, instance);
85
+ return instance;
93
86
  }
94
87
 
95
- registerSubscriptionUpdateTimer(subscriptionId: number, timer: Timer) {
96
- this.subscriptionUpdateTimers.set(subscriptionId, timer);
88
+ get peers() {
89
+ return this.#peers;
97
90
  }
98
91
 
99
- removeSubscriptionUpdateTimer(subscriptionId: number) {
100
- this.subscriptionUpdateTimers.get(subscriptionId)?.stop();
101
- this.subscriptionUpdateTimers.delete(subscriptionId);
92
+ async connect(
93
+ address: PeerAddress,
94
+ options: {
95
+ discoveryOptions: DiscoveryOptions;
96
+ allowUnknownPeer?: boolean;
97
+ operationalAddress?: ServerAddressIp;
98
+ },
99
+ ): Promise<InteractionClient> {
100
+ await this.#peers.ensureConnection(address, options);
101
+
102
+ const { discoveryOptions } = options;
103
+ return this.getInteractionClient(address, discoveryOptions);
102
104
  }
103
105
 
104
- async onNewExchange(exchange: MessageExchange) {
105
- const messenger = new IncomingInteractionClientMessenger(exchange);
106
-
107
- let dataReport: DataReport;
108
- try {
109
- // TODO Adjust this to getting packages as callback when received to handle error cases and checks outside
110
- dataReport = await messenger.readDataReports([...this.subscriptionListeners.keys()]);
111
- } finally {
112
- messenger.close().catch(error => logger.info("Error closing client messenger", error));
106
+ async getInteractionClient(address: PeerAddress, discoveryOptions: DiscoveryOptions) {
107
+ let client = this.#clients.get(address);
108
+ if (client !== undefined) {
109
+ return client;
113
110
  }
114
- const subscriptionId = dataReport.subscriptionId as number; // this is checked in the messenger already because we hand over allowed list
115
111
 
116
- const listener = this.subscriptionListeners.get(subscriptionId);
117
- const timer = this.subscriptionUpdateTimers.get(subscriptionId);
112
+ const nodeStore = this.#peers.get(address)?.dataStore;
113
+ await nodeStore?.construction; // Lazy initialize the data if not already done
118
114
 
119
- if (timer !== undefined) {
120
- timer.stop().start(); // Restart timer because we received data
121
- }
115
+ const exchangeProvider = await this.#peers.exchangeProviderFor(address, discoveryOptions);
116
+
117
+ client = new InteractionClient(
118
+ exchangeProvider,
119
+ this.#peers.subscriptionClient,
120
+ address,
121
+ this.#peers.interactionQueue,
122
+ nodeStore,
123
+ );
124
+ this.#clients.set(address, client);
122
125
 
123
- await listener?.(dataReport);
126
+ return client;
124
127
  }
125
128
 
126
- async close() {
127
- this.subscriptionListeners.clear();
128
- this.subscriptionUpdateTimers.forEach(timer => timer.stop());
129
- this.subscriptionUpdateTimers.clear();
129
+ #onPeerLoss(address: PeerAddress) {
130
+ const client = this.#clients.get(address);
131
+ if (client !== undefined) {
132
+ client.close();
133
+ this.#clients.delete(address);
134
+ }
130
135
  }
131
136
  }
132
137
 
133
138
  export class InteractionClient {
139
+ readonly #exchangeProvider: ExchangeProvider;
134
140
  readonly #nodeStore?: PeerDataStore;
135
141
  readonly #ownSubscriptionIds = new Set<number>();
136
142
  readonly #subscriptionClient: SubscriptionClient;
137
143
  readonly #queue?: PromiseQueue;
138
144
 
139
145
  constructor(
140
- private readonly exchangeProvider: ExchangeProvider,
146
+ exchangeProvider: ExchangeProvider,
147
+ subscriptionClient: SubscriptionClient,
141
148
  readonly address: PeerAddress,
142
149
  queue?: PromiseQueue,
143
150
  nodeStore?: PeerDataStore,
144
151
  ) {
152
+ this.#exchangeProvider = exchangeProvider;
145
153
  this.#nodeStore = nodeStore;
154
+ this.#subscriptionClient = subscriptionClient;
146
155
  this.#queue = queue;
147
-
148
- const client = this.exchangeProvider.getProtocolHandler(INTERACTION_PROTOCOL_ID);
149
- if (client === undefined || !(client instanceof SubscriptionClient)) {
150
- throw new InternalError(
151
- `Subscription protocol handler ${INTERACTION_PROTOCOL_ID} missing or unexpected type.`,
152
- );
153
- }
154
- this.#subscriptionClient = client;
155
156
  }
156
157
 
157
158
  get channelUpdated() {
158
- if (this.exchangeProvider instanceof ReconnectableExchangeProvider) {
159
- return this.exchangeProvider.channelUpdated;
159
+ if (this.#exchangeProvider instanceof ReconnectableExchangeProvider) {
160
+ return this.#exchangeProvider.channelUpdated;
160
161
  }
161
162
  throw new ImplementationError("ExchangeProvider does not support channelUpdated");
162
163
  }
163
164
 
164
- registerSubscriptionListener(subscriptionId: number, listener: (dataReport: DataReport) => MaybePromise<void>) {
165
- this.#ownSubscriptionIds.add(subscriptionId);
166
- this.#subscriptionClient.registerSubscriptionListener(subscriptionId, listener);
167
- }
168
-
169
165
  removeSubscription(subscriptionId: number) {
170
166
  this.#ownSubscriptionIds.delete(subscriptionId);
171
- this.#subscriptionClient.removeSubscriptionListener(subscriptionId);
172
- this.#subscriptionClient.removeSubscriptionUpdateTimer(subscriptionId);
167
+ this.#subscriptionClient.delete(subscriptionId);
173
168
  }
174
169
 
175
170
  async getAllAttributes(
@@ -259,10 +254,7 @@ export class InteractionClient {
259
254
  isFabricFiltered?: boolean;
260
255
  executeQueued?: boolean;
261
256
  } = {},
262
- ): Promise<{
263
- attributeReports: DecodedAttributeReportValue<any>[];
264
- eventReports: DecodedEventReportValue<any>[];
265
- }> {
257
+ ): Promise<DecodedDataReport> {
266
258
  const {
267
259
  attributes: attributeRequests,
268
260
  dataVersionFilters,
@@ -302,10 +294,7 @@ export class InteractionClient {
302
294
  );
303
295
  }
304
296
 
305
- const result = await this.withMessenger<{
306
- attributeReports: DecodedAttributeReportValue<any>[];
307
- eventReports: DecodedEventReportValue<any>[];
308
- }>(async messenger => {
297
+ const result = await this.withMessenger(async messenger => {
309
298
  const { isFabricFiltered = true } = options;
310
299
  return await this.processReadRequest(messenger, {
311
300
  attributeRequests,
@@ -404,7 +393,7 @@ export class InteractionClient {
404
393
  private async processReadRequest(
405
394
  messenger: InteractionClientMessenger,
406
395
  request: ReadRequest,
407
- ): Promise<{ attributeReports: DecodedAttributeReportValue<any>[]; eventReports: DecodedEventReportValue<any>[] }> {
396
+ ): Promise<DecodedDataReport> {
408
397
  const { attributeRequests, eventRequests } = request;
409
398
  logger.debug(
410
399
  `Sending read request to ${messenger.getExchangeChannelName()} for attributes ${attributeRequests
@@ -415,10 +404,7 @@ export class InteractionClient {
415
404
  const response = await messenger.sendReadRequest(request);
416
405
 
417
406
  // Normalize and decode the response
418
- const normalizedResult = {
419
- attributeReports: normalizeAndDecodeReadAttributeReport(response.attributeReports ?? []),
420
- eventReports: normalizeAndDecodeReadEventReport(response.eventReports ?? []),
421
- };
407
+ const normalizedResult = DecodedDataReport(response);
422
408
  logger.debug(
423
409
  `Received read response with attributes ${normalizedResult.attributeReports
424
410
  .map(({ path, value }) => `${resolveAttributeName(path)} = ${Logger.toJSON(value)}`)
@@ -643,33 +629,39 @@ export class InteractionClient {
643
629
  return;
644
630
  }
645
631
 
646
- const data = normalizeAndDecodeReadAttributeReport(dataReport.attributeReports);
632
+ const { attributeReports } = DecodedDataReport(dataReport);
647
633
 
648
- if (data.length === 0) {
634
+ if (attributeReports.length === 0) {
649
635
  throw new MatterFlowError("Subscription result reporting undefined/no value not specified");
650
636
  }
651
- if (data.length > 1) {
637
+ if (attributeReports.length > 1) {
652
638
  throw new UnexpectedDataError("Unexpected response with more then one attribute");
653
639
  }
654
- const { value, version } = data[0];
640
+ const { value, version } = attributeReports[0];
655
641
  if (value === undefined)
656
642
  throw new MatterFlowError("Subscription result reporting undefined value not specified.");
657
643
 
658
- await this.#nodeStore?.persistAttributes([data[0]]);
644
+ await this.#nodeStore?.persistAttributes([attributeReports[0]]);
659
645
 
660
646
  listener?.(value, version);
661
647
  };
662
648
 
663
- this.registerSubscriptionListener(subscriptionId, subscriptionListener);
664
- if (updateTimeoutHandler !== undefined) {
665
- this.registerSubscriptionUpdateTimer(
649
+ await this.#registerSubscription(
650
+ {
651
+ id: subscriptionId,
666
652
  maximumPeerResponseTime,
667
- subscriptionId,
668
- maxInterval,
669
- updateTimeoutHandler,
670
- );
671
- }
672
- await subscriptionListener(report);
653
+ maxIntervalS: maxInterval,
654
+ onData: subscriptionListener,
655
+ onTimeout: updateTimeoutHandler,
656
+ },
657
+ report,
658
+ );
659
+ }
660
+
661
+ async #registerSubscription(subscription: RegisteredSubscription, initialReport: DataReport) {
662
+ this.#ownSubscriptionIds.add(subscription.id);
663
+ this.#subscriptionClient.add(subscription);
664
+ await subscription.onData(initialReport);
673
665
  }
674
666
 
675
667
  async subscribeEvent<T, E extends Event<T, any>>(options: {
@@ -736,30 +728,30 @@ export class InteractionClient {
736
728
  return;
737
729
  }
738
730
 
739
- const data = normalizeAndDecodeReadEventReport(dataReport.eventReports);
731
+ const { eventReports } = DecodedDataReport(dataReport);
740
732
 
741
- if (data.length === 0) {
733
+ if (eventReports.length === 0) {
742
734
  throw new MatterFlowError("Received empty subscription result value.");
743
735
  }
744
- if (data.length > 1) {
736
+ if (eventReports.length > 1) {
745
737
  throw new UnexpectedDataError("Unexpected response with more then one attribute.");
746
738
  }
747
- const { events } = data[0];
739
+ const { events } = eventReports[0];
748
740
  if (events === undefined)
749
741
  throw new MatterFlowError("Subscription result reporting undefined value not specified.");
750
742
 
751
743
  events.forEach(event => listener?.(event));
752
744
  };
753
- this.registerSubscriptionListener(subscriptionId, subscriptionListener);
754
- if (updateTimeoutHandler !== undefined) {
755
- this.registerSubscriptionUpdateTimer(
745
+ await this.#registerSubscription(
746
+ {
747
+ id: subscriptionId,
756
748
  maximumPeerResponseTime,
757
- subscriptionId,
758
- maxInterval,
759
- updateTimeoutHandler,
760
- );
761
- }
762
- subscriptionListener(report);
749
+ maxIntervalS: maxInterval,
750
+ onData: subscriptionListener,
751
+ onTimeout: updateTimeoutHandler,
752
+ },
753
+ report,
754
+ );
763
755
  }
764
756
 
765
757
  async subscribeAllAttributesAndEvents(options: {
@@ -957,39 +949,21 @@ export class InteractionClient {
957
949
  }
958
950
  }
959
951
  };
960
- this.registerSubscriptionListener(subscriptionId, async dataReport => {
961
- await subscriptionListener({
962
- ...dataReport,
963
- attributeReports:
964
- dataReport.attributeReports !== undefined
965
- ? normalizeAndDecodeReadAttributeReport(dataReport.attributeReports)
966
- : undefined,
967
- eventReports:
968
- dataReport.eventReports !== undefined
969
- ? normalizeAndDecodeReadEventReport(dataReport.eventReports)
970
- : undefined,
971
- });
972
- });
973
952
 
974
- if (updateTimeoutHandler !== undefined) {
975
- this.registerSubscriptionUpdateTimer(
953
+ const seedReport = DecodedDataReport(report);
954
+
955
+ await this.#registerSubscription(
956
+ {
957
+ id: subscriptionId,
976
958
  maximumPeerResponseTime,
977
- subscriptionId,
978
- maxInterval,
979
- updateTimeoutHandler,
980
- );
981
- }
959
+ maxIntervalS: maxInterval,
982
960
 
983
- const seedReport = {
984
- attributeReports:
985
- report.attributeReports !== undefined
986
- ? normalizeAndDecodeReadAttributeReport(report.attributeReports)
987
- : undefined,
988
- eventReports:
989
- report.eventReports !== undefined ? normalizeAndDecodeReadEventReport(report.eventReports) : undefined,
990
- subscriptionId,
991
- };
992
- await subscriptionListener(seedReport);
961
+ onData: dataReport => subscriptionListener(DecodedDataReport(dataReport)),
962
+
963
+ onTimeout: updateTimeoutHandler,
964
+ },
965
+ seedReport,
966
+ );
993
967
 
994
968
  if (dataVersionFilters !== undefined && dataVersionFilters.length > 0 && enrichCachedAttributeData) {
995
969
  this.#enrichCachedAttributeData(seedReport.attributeReports ?? [], dataVersionFilters);
@@ -1164,7 +1138,7 @@ export class InteractionClient {
1164
1138
  invoke: (messenger: InteractionClientMessenger) => Promise<T>,
1165
1139
  executeQueued = false,
1166
1140
  ): Promise<T> {
1167
- const messenger = await InteractionClientMessenger.create(this.exchangeProvider);
1141
+ const messenger = await InteractionClientMessenger.create(this.#exchangeProvider);
1168
1142
  let result: T;
1169
1143
  try {
1170
1144
  if (executeQueued) {
@@ -1181,27 +1155,6 @@ export class InteractionClient {
1181
1155
  return result;
1182
1156
  }
1183
1157
 
1184
- private registerSubscriptionUpdateTimer(
1185
- maximumPeerResponseTime: number,
1186
- subscriptionId: number,
1187
- maxIntervalS: number,
1188
- updateTimeoutHandler: Timer.Callback,
1189
- ) {
1190
- if (!this.#ownSubscriptionIds.has(subscriptionId)) {
1191
- throw new MatterFlowError(
1192
- `Cannot register update timer for subscription ${subscriptionId} because it is not owned by this client.`,
1193
- );
1194
- }
1195
- const maxIntervalMs = maxIntervalS * 1000 + maximumPeerResponseTime;
1196
-
1197
- const timer = Time.getTimer("Subscription timeout", maxIntervalMs, () => {
1198
- logger.info(`Subscription ${subscriptionId} timed out after ${maxIntervalMs}ms ...`);
1199
- this.removeSubscription(subscriptionId);
1200
- updateTimeoutHandler();
1201
- }).start();
1202
- this.#subscriptionClient.registerSubscriptionUpdateTimer(subscriptionId, timer);
1203
- }
1204
-
1205
1158
  removeAllSubscriptions() {
1206
1159
  for (const subscriptionId of this.#ownSubscriptionIds) {
1207
1160
  this.removeSubscription(subscriptionId);
@@ -1213,11 +1166,11 @@ export class InteractionClient {
1213
1166
  }
1214
1167
 
1215
1168
  get session() {
1216
- return this.exchangeProvider.session;
1169
+ return this.#exchangeProvider.session;
1217
1170
  }
1218
1171
 
1219
1172
  get channelType() {
1220
- return this.exchangeProvider.channelType;
1173
+ return this.#exchangeProvider.channelType;
1221
1174
  }
1222
1175
 
1223
1176
  /** Enrich cached data to get complete responses when data version filters were used. */