@matter/protocol 0.13.0-alpha.0-20250318-c1aa38b08 → 0.13.0-alpha.0-20250323-770919c6a

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 (173) hide show
  1. package/dist/cjs/ble/BtpSessionHandler.js +2 -2
  2. package/dist/cjs/ble/BtpSessionHandler.js.map +1 -1
  3. package/dist/cjs/certificate/CertificateAuthority.d.ts +1 -0
  4. package/dist/cjs/certificate/CertificateAuthority.d.ts.map +1 -1
  5. package/dist/cjs/certificate/CertificateAuthority.js.map +1 -1
  6. package/dist/cjs/certificate/CertificateManager.d.ts.map +1 -1
  7. package/dist/cjs/certificate/CertificateManager.js +21 -19
  8. package/dist/cjs/certificate/CertificateManager.js.map +1 -1
  9. package/dist/cjs/cluster/client/ClusterClient.d.ts.map +1 -1
  10. package/dist/cjs/cluster/client/ClusterClient.js +3 -0
  11. package/dist/cjs/cluster/client/ClusterClient.js.map +1 -1
  12. package/dist/cjs/cluster/server/AttributeServer.d.ts.map +1 -1
  13. package/dist/cjs/cluster/server/AttributeServer.js +5 -5
  14. package/dist/cjs/cluster/server/AttributeServer.js.map +1 -1
  15. package/dist/cjs/cluster/server/CommandServer.js +2 -2
  16. package/dist/cjs/cluster/server/CommandServer.js.map +1 -1
  17. package/dist/cjs/common/FailsafeContext.js +1 -1
  18. package/dist/cjs/common/FailsafeContext.js.map +1 -1
  19. package/dist/cjs/endpoint/EndpointStructureLogger.js +1 -1
  20. package/dist/cjs/endpoint/EndpointStructureLogger.js.map +1 -1
  21. package/dist/cjs/events/OccurrenceManager.d.ts.map +1 -1
  22. package/dist/cjs/events/OccurrenceManager.js +2 -2
  23. package/dist/cjs/events/OccurrenceManager.js.map +1 -1
  24. package/dist/cjs/interaction/AttributeDataDecoder.d.ts +21 -4
  25. package/dist/cjs/interaction/AttributeDataDecoder.d.ts.map +1 -1
  26. package/dist/cjs/interaction/AttributeDataDecoder.js +41 -2
  27. package/dist/cjs/interaction/AttributeDataDecoder.js.map +1 -1
  28. package/dist/cjs/interaction/AttributeDataEncoder.d.ts.map +1 -1
  29. package/dist/cjs/interaction/AttributeDataEncoder.js +3 -3
  30. package/dist/cjs/interaction/AttributeDataEncoder.js.map +1 -1
  31. package/dist/cjs/interaction/DecodedDataReport.d.ts +4 -2
  32. package/dist/cjs/interaction/DecodedDataReport.d.ts.map +1 -1
  33. package/dist/cjs/interaction/DecodedDataReport.js +6 -2
  34. package/dist/cjs/interaction/DecodedDataReport.js.map +1 -1
  35. package/dist/cjs/interaction/EventDataDecoder.d.ts +15 -3
  36. package/dist/cjs/interaction/EventDataDecoder.d.ts.map +1 -1
  37. package/dist/cjs/interaction/EventDataDecoder.js +39 -2
  38. package/dist/cjs/interaction/EventDataDecoder.js.map +1 -1
  39. package/dist/cjs/interaction/InteractionClient.d.ts +44 -4
  40. package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
  41. package/dist/cjs/interaction/InteractionClient.js +71 -18
  42. package/dist/cjs/interaction/InteractionClient.js.map +1 -1
  43. package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
  44. package/dist/cjs/interaction/InteractionMessenger.js +7 -4
  45. package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
  46. package/dist/cjs/interaction/InteractionServer.d.ts.map +1 -1
  47. package/dist/cjs/interaction/InteractionServer.js +7 -7
  48. package/dist/cjs/interaction/InteractionServer.js.map +1 -1
  49. package/dist/cjs/interaction/ServerSubscription.d.ts.map +1 -1
  50. package/dist/cjs/interaction/ServerSubscription.js +1 -1
  51. package/dist/cjs/interaction/ServerSubscription.js.map +1 -1
  52. package/dist/cjs/mdns/MdnsScanner.js +2 -2
  53. package/dist/cjs/mdns/MdnsScanner.js.map +1 -1
  54. package/dist/cjs/peer/ControllerCommissioner.d.ts +15 -3
  55. package/dist/cjs/peer/ControllerCommissioner.d.ts.map +1 -1
  56. package/dist/cjs/peer/ControllerCommissioner.js +17 -6
  57. package/dist/cjs/peer/ControllerCommissioner.js.map +1 -1
  58. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts +47 -1
  59. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  60. package/dist/cjs/peer/ControllerCommissioningFlow.js +136 -136
  61. package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
  62. package/dist/cjs/peer/ControllerDiscovery.d.ts.map +1 -1
  63. package/dist/cjs/peer/ControllerDiscovery.js +4 -4
  64. package/dist/cjs/peer/ControllerDiscovery.js.map +1 -1
  65. package/dist/cjs/peer/PeerSet.d.ts +2 -2
  66. package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
  67. package/dist/cjs/peer/PeerSet.js +6 -1
  68. package/dist/cjs/peer/PeerSet.js.map +1 -1
  69. package/dist/cjs/protocol/ChannelManager.d.ts.map +1 -1
  70. package/dist/cjs/protocol/ChannelManager.js +11 -4
  71. package/dist/cjs/protocol/ChannelManager.js.map +1 -1
  72. package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
  73. package/dist/cjs/protocol/ExchangeManager.js +1 -2
  74. package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
  75. package/dist/esm/ble/BtpSessionHandler.js +2 -2
  76. package/dist/esm/ble/BtpSessionHandler.js.map +1 -1
  77. package/dist/esm/certificate/CertificateAuthority.d.ts +1 -0
  78. package/dist/esm/certificate/CertificateAuthority.d.ts.map +1 -1
  79. package/dist/esm/certificate/CertificateAuthority.js.map +1 -1
  80. package/dist/esm/certificate/CertificateManager.d.ts.map +1 -1
  81. package/dist/esm/certificate/CertificateManager.js +22 -19
  82. package/dist/esm/certificate/CertificateManager.js.map +1 -1
  83. package/dist/esm/cluster/client/ClusterClient.d.ts.map +1 -1
  84. package/dist/esm/cluster/client/ClusterClient.js +3 -0
  85. package/dist/esm/cluster/client/ClusterClient.js.map +1 -1
  86. package/dist/esm/cluster/server/AttributeServer.d.ts.map +1 -1
  87. package/dist/esm/cluster/server/AttributeServer.js +15 -6
  88. package/dist/esm/cluster/server/AttributeServer.js.map +1 -1
  89. package/dist/esm/cluster/server/CommandServer.js +3 -3
  90. package/dist/esm/cluster/server/CommandServer.js.map +1 -1
  91. package/dist/esm/common/FailsafeContext.js +1 -1
  92. package/dist/esm/common/FailsafeContext.js.map +1 -1
  93. package/dist/esm/endpoint/EndpointStructureLogger.js +1 -1
  94. package/dist/esm/endpoint/EndpointStructureLogger.js.map +1 -1
  95. package/dist/esm/events/OccurrenceManager.d.ts.map +1 -1
  96. package/dist/esm/events/OccurrenceManager.js +3 -2
  97. package/dist/esm/events/OccurrenceManager.js.map +1 -1
  98. package/dist/esm/interaction/AttributeDataDecoder.d.ts +21 -4
  99. package/dist/esm/interaction/AttributeDataDecoder.d.ts.map +1 -1
  100. package/dist/esm/interaction/AttributeDataDecoder.js +41 -2
  101. package/dist/esm/interaction/AttributeDataDecoder.js.map +1 -1
  102. package/dist/esm/interaction/AttributeDataEncoder.d.ts.map +1 -1
  103. package/dist/esm/interaction/AttributeDataEncoder.js +4 -4
  104. package/dist/esm/interaction/AttributeDataEncoder.js.map +1 -1
  105. package/dist/esm/interaction/DecodedDataReport.d.ts +4 -2
  106. package/dist/esm/interaction/DecodedDataReport.d.ts.map +1 -1
  107. package/dist/esm/interaction/DecodedDataReport.js +12 -4
  108. package/dist/esm/interaction/DecodedDataReport.js.map +1 -1
  109. package/dist/esm/interaction/EventDataDecoder.d.ts +15 -3
  110. package/dist/esm/interaction/EventDataDecoder.d.ts.map +1 -1
  111. package/dist/esm/interaction/EventDataDecoder.js +39 -2
  112. package/dist/esm/interaction/EventDataDecoder.js.map +1 -1
  113. package/dist/esm/interaction/InteractionClient.d.ts +44 -4
  114. package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
  115. package/dist/esm/interaction/InteractionClient.js +74 -18
  116. package/dist/esm/interaction/InteractionClient.js.map +1 -1
  117. package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
  118. package/dist/esm/interaction/InteractionMessenger.js +8 -4
  119. package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
  120. package/dist/esm/interaction/InteractionServer.d.ts.map +1 -1
  121. package/dist/esm/interaction/InteractionServer.js +17 -8
  122. package/dist/esm/interaction/InteractionServer.js.map +1 -1
  123. package/dist/esm/interaction/ServerSubscription.d.ts.map +1 -1
  124. package/dist/esm/interaction/ServerSubscription.js +2 -1
  125. package/dist/esm/interaction/ServerSubscription.js.map +1 -1
  126. package/dist/esm/mdns/MdnsScanner.js +2 -2
  127. package/dist/esm/mdns/MdnsScanner.js.map +1 -1
  128. package/dist/esm/peer/ControllerCommissioner.d.ts +15 -3
  129. package/dist/esm/peer/ControllerCommissioner.d.ts.map +1 -1
  130. package/dist/esm/peer/ControllerCommissioner.js +18 -6
  131. package/dist/esm/peer/ControllerCommissioner.js.map +1 -1
  132. package/dist/esm/peer/ControllerCommissioningFlow.d.ts +47 -1
  133. package/dist/esm/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  134. package/dist/esm/peer/ControllerCommissioningFlow.js +147 -137
  135. package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
  136. package/dist/esm/peer/ControllerDiscovery.d.ts.map +1 -1
  137. package/dist/esm/peer/ControllerDiscovery.js +5 -5
  138. package/dist/esm/peer/ControllerDiscovery.js.map +1 -1
  139. package/dist/esm/peer/PeerSet.d.ts +2 -2
  140. package/dist/esm/peer/PeerSet.d.ts.map +1 -1
  141. package/dist/esm/peer/PeerSet.js +7 -2
  142. package/dist/esm/peer/PeerSet.js.map +1 -1
  143. package/dist/esm/protocol/ChannelManager.d.ts.map +1 -1
  144. package/dist/esm/protocol/ChannelManager.js +11 -4
  145. package/dist/esm/protocol/ChannelManager.js.map +1 -1
  146. package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
  147. package/dist/esm/protocol/ExchangeManager.js +2 -2
  148. package/dist/esm/protocol/ExchangeManager.js.map +1 -1
  149. package/package.json +6 -6
  150. package/src/ble/BtpSessionHandler.ts +2 -2
  151. package/src/certificate/CertificateAuthority.ts +1 -0
  152. package/src/certificate/CertificateManager.ts +22 -19
  153. package/src/cluster/client/ClusterClient.ts +3 -0
  154. package/src/cluster/server/AttributeServer.ts +15 -6
  155. package/src/cluster/server/CommandServer.ts +3 -3
  156. package/src/common/FailsafeContext.ts +1 -1
  157. package/src/endpoint/EndpointStructureLogger.ts +1 -1
  158. package/src/events/OccurrenceManager.ts +3 -2
  159. package/src/interaction/AttributeDataDecoder.ts +67 -7
  160. package/src/interaction/AttributeDataEncoder.ts +4 -4
  161. package/src/interaction/DecodedDataReport.ts +24 -5
  162. package/src/interaction/EventDataDecoder.ts +57 -5
  163. package/src/interaction/InteractionClient.ts +112 -18
  164. package/src/interaction/InteractionMessenger.ts +8 -4
  165. package/src/interaction/InteractionServer.ts +19 -9
  166. package/src/interaction/ServerSubscription.ts +2 -1
  167. package/src/mdns/MdnsScanner.ts +2 -2
  168. package/src/peer/ControllerCommissioner.ts +32 -7
  169. package/src/peer/ControllerCommissioningFlow.ts +160 -146
  170. package/src/peer/ControllerDiscovery.ts +5 -5
  171. package/src/peer/PeerSet.ts +7 -2
  172. package/src/protocol/ChannelManager.ts +11 -4
  173. package/src/protocol/ExchangeManager.ts +2 -2
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import {
8
+ Diagnostic,
8
9
  Environment,
9
10
  Environmental,
10
11
  ImplementationError,
@@ -31,7 +32,9 @@ import {
31
32
  Event,
32
33
  EventId,
33
34
  EventNumber,
35
+ FabricIndex,
34
36
  NodeId,
37
+ ObjectSchema,
35
38
  RequestType,
36
39
  ResponseType,
37
40
  StatusCode,
@@ -46,10 +49,11 @@ import {
46
49
  resolveCommandName,
47
50
  resolveEventName,
48
51
  } from "#types";
52
+ import { MessageChannel } from "../protocol/ExchangeManager.js";
49
53
  import { ExchangeProvider, ReconnectableExchangeProvider } from "../protocol/ExchangeProvider.js";
50
- import { DecodedAttributeReportValue } from "./AttributeDataDecoder.js";
54
+ import { DecodedAttributeReportStatus, DecodedAttributeReportValue } from "./AttributeDataDecoder.js";
51
55
  import { DecodedDataReport } from "./DecodedDataReport.js";
52
- import { DecodedEventData, DecodedEventReportValue } from "./EventDataDecoder.js";
56
+ import { DecodedEventData, DecodedEventReportStatus, DecodedEventReportValue } from "./EventDataDecoder.js";
53
57
  import { DataReport, InteractionClientMessenger, ReadRequest } from "./InteractionMessenger.js";
54
58
  import { RegisteredSubscription, SubscriptionClient } from "./SubscriptionClient.js";
55
59
 
@@ -103,6 +107,17 @@ export class InteractionClientProvider {
103
107
  return this.getInteractionClient(address, discoveryOptions);
104
108
  }
105
109
 
110
+ async getInteractionClientForChannel(channel: MessageChannel): Promise<InteractionClient> {
111
+ const exchangeProvider = await this.#peers.exchangeProviderFor(channel);
112
+
113
+ return new InteractionClient(
114
+ exchangeProvider,
115
+ this.#peers.subscriptionClient,
116
+ undefined,
117
+ this.#peers.interactionQueue,
118
+ );
119
+ }
120
+
106
121
  async getInteractionClient(address: PeerAddress, discoveryOptions: DiscoveryOptions) {
107
122
  let client = this.#clients.get(address);
108
123
  if (client !== undefined) {
@@ -141,11 +156,12 @@ export class InteractionClient {
141
156
  readonly #ownSubscriptionIds = new Set<number>();
142
157
  readonly #subscriptionClient: SubscriptionClient;
143
158
  readonly #queue?: PromiseQueue;
159
+ readonly #address?: PeerAddress;
144
160
 
145
161
  constructor(
146
162
  exchangeProvider: ExchangeProvider,
147
163
  subscriptionClient: SubscriptionClient,
148
- readonly address: PeerAddress,
164
+ address?: PeerAddress,
149
165
  queue?: PromiseQueue,
150
166
  nodeStore?: PeerDataStore,
151
167
  ) {
@@ -153,6 +169,18 @@ export class InteractionClient {
153
169
  this.#nodeStore = nodeStore;
154
170
  this.#subscriptionClient = subscriptionClient;
155
171
  this.#queue = queue;
172
+ this.#address = address;
173
+ }
174
+
175
+ get address() {
176
+ if (this.#address === undefined) {
177
+ throw new ImplementationError("This InteractionClient is not bound to a specific peer.");
178
+ }
179
+ return this.#address;
180
+ }
181
+
182
+ get isReconnectable() {
183
+ return this.#exchangeProvider instanceof ReconnectableExchangeProvider;
156
184
  }
157
185
 
158
186
  get channelUpdated() {
@@ -233,6 +261,22 @@ export class InteractionClient {
233
261
  return (await this.getMultipleAttributesAndEvents(options)).attributeReports;
234
262
  }
235
263
 
264
+ async getMultipleAttributesAndStatus(
265
+ options: {
266
+ attributes?: { endpointId?: EndpointNumber; clusterId?: ClusterId; attributeId?: AttributeId }[];
267
+ dataVersionFilters?: { endpointId: EndpointNumber; clusterId: ClusterId; dataVersion: number }[];
268
+ enrichCachedAttributeData?: boolean;
269
+ isFabricFiltered?: boolean;
270
+ executeQueued?: boolean;
271
+ } = {},
272
+ ): Promise<{
273
+ attributeData: DecodedAttributeReportValue<any>[];
274
+ attributeStatus?: DecodedAttributeReportStatus[];
275
+ }> {
276
+ const { attributeReports, attributeStatus } = await this.getMultipleAttributesAndEvents(options);
277
+ return { attributeData: attributeReports, attributeStatus };
278
+ }
279
+
236
280
  async getMultipleEvents(
237
281
  options: {
238
282
  events?: { endpointId?: EndpointNumber; clusterId?: ClusterId; eventId?: EventId }[];
@@ -244,6 +288,18 @@ export class InteractionClient {
244
288
  return (await this.getMultipleAttributesAndEvents(options)).eventReports;
245
289
  }
246
290
 
291
+ async getMultipleEventsAndStatus(
292
+ options: {
293
+ events?: { endpointId?: EndpointNumber; clusterId?: ClusterId; eventId?: EventId }[];
294
+ eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];
295
+ isFabricFiltered?: boolean;
296
+ executeQueued?: boolean;
297
+ } = {},
298
+ ): Promise<{ eventData: DecodedEventReportValue<any>[]; eventStatus?: DecodedEventReportStatus[] }> {
299
+ const { eventReports, eventStatus } = await this.getMultipleAttributesAndEvents(options);
300
+ return { eventData: eventReports, eventStatus };
301
+ }
302
+
247
303
  async getMultipleAttributesAndEvents(
248
304
  options: {
249
305
  attributes?: { endpointId?: EndpointNumber; clusterId?: ClusterId; attributeId?: AttributeId }[];
@@ -405,12 +461,23 @@ export class InteractionClient {
405
461
 
406
462
  // Normalize and decode the response
407
463
  const normalizedResult = DecodedDataReport(response);
464
+ const { attributeReports, attributeStatus, eventReports, eventStatus } = normalizedResult;
465
+
466
+ const logData = Array<string>();
467
+ if (attributeReports.length > 0) {
468
+ logData.push(`attributes ${attributeReports.map(({ path }) => resolveAttributeName(path)).join(", ")}`);
469
+ }
470
+ if (eventReports.length > 0) {
471
+ logData.push(`events ${eventReports.map(({ path }) => resolveEventName(path)).join(", ")}`);
472
+ }
473
+ if (attributeStatus !== undefined && attributeStatus.length > 0) {
474
+ logData.push(`attributeErrors ${attributeStatus.map(({ path }) => resolveAttributeName(path)).join(", ")}`);
475
+ }
476
+ if (eventStatus !== undefined && eventStatus.length > 0) {
477
+ logData.push(`eventErrors ${eventStatus.map(({ path }) => resolveEventName(path)).join(", ")}`);
478
+ }
408
479
  logger.debug(
409
- `Received read response with attributes ${normalizedResult.attributeReports
410
- .map(({ path, value }) => `${resolveAttributeName(path)} = ${Logger.toJSON(value)}`)
411
- .join(", ")} and events ${normalizedResult.eventReports
412
- .map(({ path, events }) => `${resolveEventName(path)} = ${Logger.toJSON(events)}`)
413
- .join(", ")}`,
480
+ logData.length ? `Received read response with ${logData.join(", ")}` : "Received empty read response",
414
481
  );
415
482
  return normalizedResult;
416
483
  }
@@ -483,7 +550,7 @@ export class InteractionClient {
483
550
  `Sending write request: ${attributes
484
551
  .map(
485
552
  ({ endpointId, clusterId, attribute: { id }, value, dataVersion }) =>
486
- `${resolveAttributeName({ endpointId, clusterId, attributeId: id })} = ${Logger.toJSON(
553
+ `${resolveAttributeName({ endpointId, clusterId, attributeId: id })} = ${Diagnostic.json(
487
554
  value,
488
555
  )} (version=${dataVersion})`,
489
556
  )
@@ -893,11 +960,11 @@ export class InteractionClient {
893
960
  eventReports?: DecodedEventReportValue<any>[];
894
961
  subscriptionId?: number;
895
962
  }) => {
896
- updateReceived?.();
897
963
  if (
898
964
  (!Array.isArray(dataReport.attributeReports) || !dataReport.attributeReports.length) &&
899
965
  (!Array.isArray(dataReport.eventReports) || !dataReport.eventReports.length)
900
966
  ) {
967
+ updateReceived?.();
901
968
  return;
902
969
  }
903
970
  const { attributeReports, eventReports } = dataReport;
@@ -907,7 +974,7 @@ export class InteractionClient {
907
974
  let maxEventNumber = this.#nodeStore?.maxEventNumber ?? eventReports[0].events[0].eventNumber;
908
975
  eventReports.forEach(data => {
909
976
  logger.debug(
910
- `Received event update: ${resolveEventName(data.path)}: ${Logger.toJSON(data.events)}`,
977
+ `Received event update: ${resolveEventName(data.path)}: ${Diagnostic.json(data.events)}`,
911
978
  );
912
979
  const { events } = data;
913
980
 
@@ -935,7 +1002,7 @@ export class InteractionClient {
935
1002
  endpointId,
936
1003
  clusterId,
937
1004
  attributeId,
938
- })} = ${Logger.toJSON(value)} (version=${version})`,
1005
+ })} = ${Diagnostic.json(value)} (version=${version})`,
939
1006
  );
940
1007
  if (value === undefined) throw new MatterFlowError("Received empty subscription result value.");
941
1008
  const { value: oldValue } =
@@ -948,6 +1015,7 @@ export class InteractionClient {
948
1015
  attributeListener?.(data, changed, oldValue);
949
1016
  }
950
1017
  }
1018
+ updateReceived?.();
951
1019
  };
952
1020
 
953
1021
  const seedReport = DecodedDataReport(report);
@@ -977,33 +1045,59 @@ export class InteractionClient {
977
1045
  clusterId: ClusterId;
978
1046
  request: RequestType<C>;
979
1047
  command: C;
1048
+
1049
+ /** Send as timed request. If no timedRequestTimeoutMs is provided the default of 10s will be used. */
980
1050
  asTimedRequest?: boolean;
1051
+
1052
+ /** Use this timeout and send the request as Timed Request. If this is specified the above parameter is implied. */
981
1053
  timedRequestTimeoutMs?: number;
1054
+
1055
+ /** Use an extended Message Response Timeout as defined for FailSafe cases which is 30s. */
982
1056
  useExtendedFailSafeMessageResponseTimeout?: boolean;
1057
+
1058
+ /** Execute this request queued - mainly used to execute invokes sequentially for thread devices. */
983
1059
  executeQueued?: boolean;
1060
+
1061
+ /** Skip request data validation. Use this only when you know that your data is correct and validation would return an error. */
1062
+ skipValidation?: boolean;
984
1063
  }): Promise<ResponseType<C>> {
985
1064
  const { executeQueued } = options;
986
1065
 
987
1066
  const {
988
1067
  endpointId,
989
1068
  clusterId,
990
- request,
991
1069
  command: { requestId, requestSchema, responseId, responseSchema, optional, timed },
992
1070
  asTimedRequest,
993
1071
  timedRequestTimeoutMs = DEFAULT_TIMED_REQUEST_TIMEOUT_MS,
994
1072
  useExtendedFailSafeMessageResponseTimeout = false,
1073
+ skipValidation,
995
1074
  } = options;
996
- const timedRequest = timed || asTimedRequest === true || options.timedRequestTimeoutMs !== undefined;
1075
+ let { request } = options;
1076
+ const timedRequest =
1077
+ (timed && !skipValidation) || asTimedRequest === true || options.timedRequestTimeoutMs !== undefined;
1078
+
1079
+ if (requestSchema instanceof ObjectSchema) {
1080
+ if (request === undefined) {
1081
+ // If developer did not provide a request object, create an empty one if it needs to be an object
1082
+ // This can happen when all object properties are optional
1083
+ request = {} as RequestType<C>;
1084
+ }
1085
+ if (requestSchema.isFabricScoped && request.fabricIndex === undefined) {
1086
+ request.fabricIndex = FabricIndex.NO_FABRIC;
1087
+ }
1088
+ }
997
1089
 
998
1090
  logger.debug(
999
1091
  `Invoking command: ${resolveCommandName({
1000
1092
  endpointId,
1001
1093
  clusterId,
1002
1094
  commandId: requestId,
1003
- })} with ${Logger.toJSON(request)}`,
1095
+ })} with ${Diagnostic.json(request)}`,
1004
1096
  );
1005
1097
 
1006
- requestSchema.validate(request);
1098
+ if (!skipValidation) {
1099
+ requestSchema.validate(request);
1100
+ }
1007
1101
 
1008
1102
  const commandFields = requestSchema.encodeTlv(request);
1009
1103
 
@@ -1067,7 +1161,7 @@ export class InteractionClient {
1067
1161
  endpointId,
1068
1162
  clusterId,
1069
1163
  commandId: requestId,
1070
- })} with ${Logger.toJSON(response)})}`,
1164
+ })} with ${Diagnostic.json(response)})}`,
1071
1165
  );
1072
1166
  return response;
1073
1167
  }
@@ -1103,7 +1197,7 @@ export class InteractionClient {
1103
1197
  endpointId,
1104
1198
  clusterId,
1105
1199
  commandId: requestId,
1106
- })} with ${Logger.toJSON(request)}`,
1200
+ })} with ${Diagnostic.json(request)}`,
1107
1201
  );
1108
1202
  const commandFields = requestSchema.encodeTlv(request);
1109
1203
 
@@ -14,6 +14,7 @@ import {
14
14
  } from "#general";
15
15
  import { Specification } from "#model";
16
16
  import {
17
+ ReceivedStatusResponseError,
17
18
  Status,
18
19
  StatusCode,
19
20
  StatusResponseError,
@@ -184,7 +185,10 @@ class InteractionMessenger {
184
185
  if (messageType !== MessageType.StatusResponse) return;
185
186
  const { status } = TlvStatusResponse.decode(payload);
186
187
  if (status !== StatusCode.Success)
187
- throw new StatusResponseError(`Received error status: ${status}${logHint ? ` (${logHint})` : ""}`, status);
188
+ throw new ReceivedStatusResponseError(
189
+ `Received error status: ${status}${logHint ? ` (${logHint})` : ""}`,
190
+ status,
191
+ );
188
192
  }
189
193
 
190
194
  getExchangeChannelName() {
@@ -629,7 +633,7 @@ export class InteractionServerMessenger extends InteractionMessenger {
629
633
  const encodedMessage = TlvDataReportForSend.encode(dataReportToSend);
630
634
  if (encodedMessage.length > this.exchange.maxPayloadSize) {
631
635
  throw new MatterFlowError(
632
- `DataReport with ${encodedMessage.length}bytes is too long to fit in a single chunk (${this.exchange.maxPayloadSize}bytes), This should not happen! Data: ${Logger.toJSON(
636
+ `DataReport with ${encodedMessage.length}bytes is too long to fit in a single chunk (${this.exchange.maxPayloadSize}bytes), This should not happen! Data: ${Diagnostic.json(
633
637
  dataReportToSend,
634
638
  )}`,
635
639
  );
@@ -680,7 +684,7 @@ export class IncomingInteractionClientMessenger extends InteractionMessenger {
680
684
  if (receivedMessageType !== messageType) {
681
685
  if (receivedMessageType === MessageType.StatusResponse) {
682
686
  const statusCode = TlvStatusResponse.decode(message.payload).status;
683
- throw new StatusResponseError(`Received status response ${statusCode}`, statusCode);
687
+ throw new ReceivedStatusResponseError(`Received status response ${statusCode}`, statusCode);
684
688
  }
685
689
  throw new MatterFlowError(
686
690
  `Received unexpected message type ${receivedMessageType.toString(16)}. Expected ${messageType.toString(
@@ -852,7 +856,7 @@ export class InteractionClientMessenger extends IncomingInteractionClientMesseng
852
856
  });
853
857
  if (requestWithoutDataVersionFilters.length > this.exchange.maxPayloadSize) {
854
858
  throw new MatterFlowError(
855
- `Request is too long to fit in a single chunk, This should not happen! Data: ${Logger.toJSON(request)}`,
859
+ `Request is too long to fit in a single chunk, This should not happen! Data: ${Diagnostic.json(request)}`,
856
860
  );
857
861
  }
858
862
 
@@ -4,7 +4,16 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import { Crypto, Diagnostic, InternalError, Logger, MatterFlowError, Observable, ServerAddressIp } from "#general";
7
+ import {
8
+ Crypto,
9
+ Diagnostic,
10
+ InternalError,
11
+ Logger,
12
+ MatterError,
13
+ MatterFlowError,
14
+ Observable,
15
+ ServerAddressIp,
16
+ } from "#general";
8
17
  import { AttributeModel, ClusterModel, CommandModel, GLOBAL_IDS, MatterModel, Specification } from "#model";
9
18
  import { PeerAddress } from "#peer/PeerAddress.js";
10
19
  import { SessionManager } from "#session/SessionManager.js";
@@ -19,6 +28,7 @@ import {
19
28
  EventNumber,
20
29
  INTERACTION_PROTOCOL_ID,
21
30
  NodeId,
31
+ ReceivedStatusResponseError,
22
32
  StatusCode,
23
33
  StatusResponseError,
24
34
  TlvAny,
@@ -355,7 +365,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
355
365
  logger.debug(
356
366
  `Read event from ${exchange.channel.name}: ${this.#endpointStructure.resolveEventName(
357
367
  path,
358
- )}=${Logger.toJSON(matchingEvents)}`,
368
+ )}=${Diagnostic.json(matchingEvents)}`,
359
369
  );
360
370
  const { schema } = event;
361
371
  reportsForPath.push(
@@ -513,7 +523,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
513
523
  logger.debug(
514
524
  `Read attribute from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(
515
525
  path,
516
- )}=${Logger.toJSON(value)} (version=${version}) ignored because of dataVersionFilter`,
526
+ )}=${Diagnostic.json(value)} (version=${version}) ignored because of dataVersionFilter`,
517
527
  );
518
528
  continue;
519
529
  }
@@ -521,7 +531,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
521
531
  logger.debug(
522
532
  `Read attribute from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(
523
533
  path,
524
- )}=${Logger.toJSON(value)} (version=${version})`,
534
+ )}=${Diagnostic.json(value)} (version=${version})`,
525
535
  );
526
536
 
527
537
  const { schema } = attribute;
@@ -868,7 +878,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
868
878
  logger.debug(
869
879
  `Handle write request from ${
870
880
  exchange.channel.name
871
- } resolved to: ${this.#endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(
881
+ } resolved to: ${this.#endpointStructure.resolveAttributeName(path)}=${Diagnostic.json(
872
882
  value,
873
883
  )} (listIndex=${listIndex}, for-version=${dataVersion})`,
874
884
  );
@@ -950,7 +960,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
950
960
  ? `with following errors: ${errorResults
951
961
  .map(
952
962
  ({ path, statusCode }) =>
953
- `${this.#endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(statusCode)}`,
963
+ `${this.#endpointStructure.resolveAttributeName(path)}=${Diagnostic.json(statusCode)}`,
954
964
  )
955
965
  .join(", ")}`
956
966
  : "without errors"
@@ -1115,12 +1125,12 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
1115
1125
  exchange,
1116
1126
  message,
1117
1127
  );
1118
- } catch (error: any) {
1128
+ } catch (error) {
1119
1129
  logger.error(
1120
1130
  `Subscription ${subscriptionId} for Session ${session.id}: Error while sending initial data reports`,
1121
- error,
1131
+ error instanceof MatterError ? error.message : error,
1122
1132
  );
1123
- if (error instanceof StatusResponseError) {
1133
+ if (error instanceof StatusResponseError && !(error instanceof ReceivedStatusResponseError)) {
1124
1134
  logger.info(`Sending status response ${error.code} for interaction error: ${error.message}`);
1125
1135
  await messenger.sendStatus(error.code, {
1126
1136
  logContext: {
@@ -6,6 +6,7 @@
6
6
 
7
7
  import { NumberedOccurrence } from "#events/Occurrence.js";
8
8
  import {
9
+ Diagnostic,
9
10
  InternalError,
10
11
  Logger,
11
12
  MatterAggregateError,
@@ -989,7 +990,7 @@ export class ServerSubscription extends Subscription {
989
990
  `Subscription attribute changes for ID ${this.id}: ${attributes
990
991
  .map(
991
992
  ({ path, value, version }) =>
992
- `${this.#structure.resolveAttributeName(path)}=${Logger.toJSON(value)} (${version})`,
993
+ `${this.#structure.resolveAttributeName(path)}=${Diagnostic.json(value)} (${version})`,
993
994
  )
994
995
  .join(", ")}`,
995
996
  ); // TODO Format path better using endpoint structure
@@ -213,7 +213,7 @@ export class MdnsScanner implements Scanner {
213
213
  if (dnsMessageDataToSend.answers.length === 0) {
214
214
  // The first answer is already too big, log at least a warning
215
215
  logger.warn(
216
- `MDNS Query with ${Logger.toJSON(
216
+ `MDNS Query with ${Diagnostic.json(
217
217
  queries,
218
218
  )} is too big to fit into a single MDNS message. Send anyway, but please report!`,
219
219
  );
@@ -265,7 +265,7 @@ export class MdnsScanner implements Scanner {
265
265
  answers = this.#combineStructuredAnswers(activeExistingQuery.answers, answers);
266
266
  }
267
267
  this.#activeAnnounceQueries.set(queryId, { queries, answers });
268
- logger.debug(`Set ${queries.length} query records for query ${queryId}: ${Logger.toJSON(queries)}`);
268
+ logger.debug(`Set ${queries.length} query records for query ${queryId}: ${Diagnostic.json(queries)}`);
269
269
  this.#queryTimer?.stop();
270
270
  this.#nextAnnounceIntervalSeconds = START_ANNOUNCE_INTERVAL_SECONDS; // Reset query interval
271
271
  this.#queryTimer = Time.getTimer("MDNS discovery", 0, () => this.#sendQueries()).start();
@@ -11,6 +11,8 @@ import { Fabric } from "#fabric/Fabric.js";
11
11
  import {
12
12
  Channel,
13
13
  ChannelType,
14
+ ClassExtends,
15
+ Diagnostic,
14
16
  Environment,
15
17
  Environmental,
16
18
  isIPv6,
@@ -55,6 +57,12 @@ export interface CommissioningOptions extends Partial<ControllerCommissioningFlo
55
57
  * not throw, the commissioner considers commissioning complete.
56
58
  */
57
59
  finalizeCommissioning?: (peerAddress: PeerAddress, discoveryData?: DiscoveryData) => Promise<void>;
60
+
61
+ /**
62
+ * Commissioning Flow Implementation as class that extends the official implementation to use for commissioning.
63
+ * Defaults to the matter.js default implementation {@link ControllerCommissioningFlow}.
64
+ */
65
+ commissioningFlowImpl?: ClassExtends<ControllerCommissioningFlow>;
58
66
  }
59
67
 
60
68
  /**
@@ -169,9 +177,11 @@ export class ControllerCommissioner {
169
177
  }
170
178
 
171
179
  /**
172
- * Commission a node with discovery.
180
+ * Discover and establish a PASE channel with a device.
173
181
  */
174
- async commissionWithDiscovery(options: DiscoveryAndCommissioningOptions): Promise<PeerAddress> {
182
+ async discoverAndEstablishPase(
183
+ options: DiscoveryAndCommissioningOptions,
184
+ ): Promise<{ paseSecureChannel: MessageChannel; discoveryData?: DiscoveryData }> {
175
185
  const {
176
186
  discovery: { timeoutSeconds = 30 },
177
187
  passcode,
@@ -211,9 +221,9 @@ export class ControllerCommissioner {
211
221
  const scannersToUse = this.#context.scanners.select(discoveryCapabilities);
212
222
 
213
223
  logger.info(
214
- `Commissioning device with identifier ${Logger.toJSON(identifierData)} and ${
224
+ `Connecting to device with identifier ${Diagnostic.json(identifierData)} and ${
215
225
  scannersToUse.length
216
- } scanners and knownAddress ${Logger.toJSON(knownAddress)}`,
226
+ } scanners and knownAddress ${Diagnostic.json(knownAddress)}`,
217
227
  );
218
228
 
219
229
  // If we have a known address we try this first before we discover the device
@@ -251,6 +261,17 @@ export class ControllerCommissioner {
251
261
  paseSecureChannel = result;
252
262
  }
253
263
 
264
+ return { paseSecureChannel, discoveryData };
265
+ }
266
+
267
+ /**
268
+ * Commission a node with discovery.
269
+ */
270
+ async commissionWithDiscovery(options: DiscoveryAndCommissioningOptions): Promise<PeerAddress> {
271
+ // Establish PASE channel
272
+ const { paseSecureChannel, discoveryData } = await this.discoverAndEstablishPase(options);
273
+
274
+ // Commission the node
254
275
  return await this.#commissionConnectedNode(paseSecureChannel, options, discoveryData);
255
276
  }
256
277
 
@@ -266,7 +287,7 @@ export class ControllerCommissioner {
266
287
  ): Promise<MessageChannel> {
267
288
  let paseChannel: Channel<Uint8Array>;
268
289
  if (device !== undefined) {
269
- logger.info(`Commissioning device`, MdnsScanner.discoveryDataDiagnostics(device));
290
+ logger.info(`Establish PASE to device`, MdnsScanner.discoveryDataDiagnostics(device));
270
291
  }
271
292
  if (address.type === "udp") {
272
293
  const { ip } = address;
@@ -347,7 +368,11 @@ export class ControllerCommissioner {
347
368
  ...options,
348
369
  };
349
370
 
350
- const { fabric, finalizeCommissioning: performCaseCommissioning } = commissioningOptions;
371
+ const {
372
+ fabric,
373
+ finalizeCommissioning: performCaseCommissioning,
374
+ commissioningFlowImpl = ControllerCommissioningFlow,
375
+ } = commissioningOptions;
351
376
 
352
377
  // TODO: Create the fabric only when needed before commissioning (to do when refactoring MatterController away)
353
378
  // TODO also move certificateManager and other parts into that class to get rid of them here
@@ -381,7 +406,7 @@ export class ControllerCommissioner {
381
406
  logger.info(
382
407
  `Start commissioning of node ${address.nodeId} into fabric ${fabric.fabricId} (index ${address.fabricIndex})`,
383
408
  );
384
- const commissioningManager = new ControllerCommissioningFlow(
409
+ const commissioningManager = new commissioningFlowImpl(
385
410
  // Use the created secure session to do the commissioning
386
411
  new InteractionClient(
387
412
  new DedicatedChannelExchangeProvider(this.#context.exchanges, paseSecureMessageChannel),