@matter/protocol 0.13.0-alpha.0-20250322-f085fa576 → 0.13.0-alpha.0-20250324-d7b7d9731

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 (117) 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/CertificateManager.d.ts.map +1 -1
  4. package/dist/cjs/certificate/CertificateManager.js +21 -19
  5. package/dist/cjs/certificate/CertificateManager.js.map +1 -1
  6. package/dist/cjs/cluster/client/AttributeClient.d.ts +14 -4
  7. package/dist/cjs/cluster/client/AttributeClient.d.ts.map +1 -1
  8. package/dist/cjs/cluster/client/AttributeClient.js +24 -14
  9. package/dist/cjs/cluster/client/AttributeClient.js.map +1 -1
  10. package/dist/cjs/cluster/server/AttributeServer.d.ts.map +1 -1
  11. package/dist/cjs/cluster/server/AttributeServer.js +5 -5
  12. package/dist/cjs/cluster/server/AttributeServer.js.map +1 -1
  13. package/dist/cjs/cluster/server/CommandServer.js +2 -2
  14. package/dist/cjs/cluster/server/CommandServer.js.map +1 -1
  15. package/dist/cjs/endpoint/EndpointStructureLogger.js +1 -1
  16. package/dist/cjs/endpoint/EndpointStructureLogger.js.map +1 -1
  17. package/dist/cjs/events/OccurrenceManager.d.ts.map +1 -1
  18. package/dist/cjs/events/OccurrenceManager.js +2 -2
  19. package/dist/cjs/events/OccurrenceManager.js.map +1 -1
  20. package/dist/cjs/interaction/AttributeDataDecoder.js +1 -1
  21. package/dist/cjs/interaction/AttributeDataDecoder.js.map +1 -1
  22. package/dist/cjs/interaction/AttributeDataEncoder.d.ts.map +1 -1
  23. package/dist/cjs/interaction/AttributeDataEncoder.js +3 -3
  24. package/dist/cjs/interaction/AttributeDataEncoder.js.map +1 -1
  25. package/dist/cjs/interaction/InteractionClient.d.ts +2 -2
  26. package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
  27. package/dist/cjs/interaction/InteractionClient.js +18 -20
  28. package/dist/cjs/interaction/InteractionClient.js.map +1 -1
  29. package/dist/cjs/interaction/InteractionMessenger.js +2 -2
  30. package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
  31. package/dist/cjs/interaction/InteractionServer.js +5 -5
  32. package/dist/cjs/interaction/InteractionServer.js.map +1 -1
  33. package/dist/cjs/interaction/ServerSubscription.d.ts.map +1 -1
  34. package/dist/cjs/interaction/ServerSubscription.js +1 -1
  35. package/dist/cjs/interaction/ServerSubscription.js.map +1 -1
  36. package/dist/cjs/mdns/MdnsScanner.js +2 -2
  37. package/dist/cjs/mdns/MdnsScanner.js.map +1 -1
  38. package/dist/cjs/peer/ControllerCommissioner.d.ts.map +1 -1
  39. package/dist/cjs/peer/ControllerCommissioner.js +1 -1
  40. package/dist/cjs/peer/ControllerCommissioner.js.map +1 -1
  41. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  42. package/dist/cjs/peer/ControllerCommissioningFlow.js +5 -5
  43. package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
  44. package/dist/cjs/peer/ControllerDiscovery.d.ts.map +1 -1
  45. package/dist/cjs/peer/ControllerDiscovery.js +4 -4
  46. package/dist/cjs/peer/ControllerDiscovery.js.map +1 -1
  47. package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
  48. package/dist/cjs/protocol/ExchangeManager.js +1 -1
  49. package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
  50. package/dist/esm/ble/BtpSessionHandler.js +2 -2
  51. package/dist/esm/ble/BtpSessionHandler.js.map +1 -1
  52. package/dist/esm/certificate/CertificateManager.d.ts.map +1 -1
  53. package/dist/esm/certificate/CertificateManager.js +22 -19
  54. package/dist/esm/certificate/CertificateManager.js.map +1 -1
  55. package/dist/esm/cluster/client/AttributeClient.d.ts +14 -4
  56. package/dist/esm/cluster/client/AttributeClient.d.ts.map +1 -1
  57. package/dist/esm/cluster/client/AttributeClient.js +24 -14
  58. package/dist/esm/cluster/client/AttributeClient.js.map +1 -1
  59. package/dist/esm/cluster/server/AttributeServer.d.ts.map +1 -1
  60. package/dist/esm/cluster/server/AttributeServer.js +15 -6
  61. package/dist/esm/cluster/server/AttributeServer.js.map +1 -1
  62. package/dist/esm/cluster/server/CommandServer.js +3 -3
  63. package/dist/esm/cluster/server/CommandServer.js.map +1 -1
  64. package/dist/esm/endpoint/EndpointStructureLogger.js +1 -1
  65. package/dist/esm/endpoint/EndpointStructureLogger.js.map +1 -1
  66. package/dist/esm/events/OccurrenceManager.d.ts.map +1 -1
  67. package/dist/esm/events/OccurrenceManager.js +3 -2
  68. package/dist/esm/events/OccurrenceManager.js.map +1 -1
  69. package/dist/esm/interaction/AttributeDataDecoder.js +1 -1
  70. package/dist/esm/interaction/AttributeDataDecoder.js.map +1 -1
  71. package/dist/esm/interaction/AttributeDataEncoder.d.ts.map +1 -1
  72. package/dist/esm/interaction/AttributeDataEncoder.js +4 -4
  73. package/dist/esm/interaction/AttributeDataEncoder.js.map +1 -1
  74. package/dist/esm/interaction/InteractionClient.d.ts +2 -2
  75. package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
  76. package/dist/esm/interaction/InteractionClient.js +19 -20
  77. package/dist/esm/interaction/InteractionClient.js.map +1 -1
  78. package/dist/esm/interaction/InteractionMessenger.js +2 -2
  79. package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
  80. package/dist/esm/interaction/InteractionServer.js +5 -5
  81. package/dist/esm/interaction/InteractionServer.js.map +1 -1
  82. package/dist/esm/interaction/ServerSubscription.d.ts.map +1 -1
  83. package/dist/esm/interaction/ServerSubscription.js +2 -1
  84. package/dist/esm/interaction/ServerSubscription.js.map +1 -1
  85. package/dist/esm/mdns/MdnsScanner.js +2 -2
  86. package/dist/esm/mdns/MdnsScanner.js.map +1 -1
  87. package/dist/esm/peer/ControllerCommissioner.d.ts.map +1 -1
  88. package/dist/esm/peer/ControllerCommissioner.js +2 -1
  89. package/dist/esm/peer/ControllerCommissioner.js.map +1 -1
  90. package/dist/esm/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  91. package/dist/esm/peer/ControllerCommissioningFlow.js +16 -6
  92. package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
  93. package/dist/esm/peer/ControllerDiscovery.d.ts.map +1 -1
  94. package/dist/esm/peer/ControllerDiscovery.js +5 -5
  95. package/dist/esm/peer/ControllerDiscovery.js.map +1 -1
  96. package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
  97. package/dist/esm/protocol/ExchangeManager.js +2 -1
  98. package/dist/esm/protocol/ExchangeManager.js.map +1 -1
  99. package/package.json +6 -6
  100. package/src/ble/BtpSessionHandler.ts +2 -2
  101. package/src/certificate/CertificateManager.ts +22 -19
  102. package/src/cluster/client/AttributeClient.ts +24 -14
  103. package/src/cluster/server/AttributeServer.ts +15 -6
  104. package/src/cluster/server/CommandServer.ts +3 -3
  105. package/src/endpoint/EndpointStructureLogger.ts +1 -1
  106. package/src/events/OccurrenceManager.ts +3 -2
  107. package/src/interaction/AttributeDataDecoder.ts +1 -1
  108. package/src/interaction/AttributeDataEncoder.ts +4 -4
  109. package/src/interaction/InteractionClient.ts +21 -22
  110. package/src/interaction/InteractionMessenger.ts +2 -2
  111. package/src/interaction/InteractionServer.ts +5 -5
  112. package/src/interaction/ServerSubscription.ts +2 -1
  113. package/src/mdns/MdnsScanner.ts +2 -2
  114. package/src/peer/ControllerCommissioner.ts +3 -2
  115. package/src/peer/ControllerCommissioningFlow.ts +16 -6
  116. package/src/peer/ControllerDiscovery.ts +5 -5
  117. package/src/protocol/ExchangeManager.ts +2 -1
@@ -15,6 +15,7 @@ import {
15
15
  DerKey,
16
16
  DerObject,
17
17
  DerType,
18
+ Diagnostic,
18
19
  ImplementationError,
19
20
  Key,
20
21
  Logger,
@@ -788,13 +789,13 @@ export namespace CertificateManager {
788
789
  if (rootCert.subject.fabricId !== undefined) {
789
790
  if (Array.isArray(rootCert.subject.fabricId)) {
790
791
  throw new CertificateError(
791
- `Invalid fabricId in NoC certificate: ${Logger.toJSON(rootCert.subject.fabricId)}`,
792
+ `Invalid fabricId in NoC certificate: ${Diagnostic.json(rootCert.subject.fabricId)}`,
792
793
  );
793
794
  }
794
795
  // If present, the matter-fabric-id attribute’s value SHALL NOT be 0
795
796
  if (rootCert.subject.fabricId === FabricId(0)) {
796
797
  throw new CertificateError(
797
- `Invalid fabricId in NoC certificate: ${Logger.toJSON(rootCert.subject.fabricId)}`,
798
+ `Invalid fabricId in NoC certificate: ${Diagnostic.json(rootCert.subject.fabricId)}`,
798
799
  );
799
800
  }
800
801
  }
@@ -806,7 +807,9 @@ export namespace CertificateManager {
806
807
 
807
808
  // The subject DN SHALL encode exactly one matter-rcac-id attribute.
808
809
  if (rootCert.subject.rcacId === undefined || Array.isArray(rootCert.subject.rcacId)) {
809
- throw new CertificateError(`Invalid rcacId in Root certificate: ${Logger.toJSON(rootCert.subject.rcacId)}`);
810
+ throw new CertificateError(
811
+ `Invalid rcacId in Root certificate: ${Diagnostic.json(rootCert.subject.rcacId)}`,
812
+ );
810
813
  }
811
814
 
812
815
  // The subject DN SHALL NOT encode any matter-noc-cat attribute.
@@ -874,23 +877,23 @@ export namespace CertificateManager {
874
877
 
875
878
  // The subject DN SHALL encode exactly one matter-node-id attribute.
876
879
  if (nocCert.subject.nodeId === undefined || Array.isArray(nocCert.subject.nodeId)) {
877
- throw new CertificateError(`Invalid nodeId in NoC certificate: ${Logger.toJSON(nocCert.subject.nodeId)}`);
880
+ throw new CertificateError(`Invalid nodeId in NoC certificate: ${Diagnostic.json(nocCert.subject.nodeId)}`);
878
881
  }
879
882
  // The matter-node-id attribute’s value SHALL be in the Operational Node ID
880
883
  if (!NodeId.isOperationalNodeId(nocCert.subject.nodeId)) {
881
- throw new CertificateError(`Invalid nodeId in NoC certificate: ${Logger.toJSON(nocCert.subject.nodeId)}`);
884
+ throw new CertificateError(`Invalid nodeId in NoC certificate: ${Diagnostic.json(nocCert.subject.nodeId)}`);
882
885
  }
883
886
 
884
887
  // The subject DN SHALL encode exactly one matter-fabric-id attribute.
885
888
  if (nocCert.subject.fabricId === undefined || Array.isArray(nocCert.subject.fabricId)) {
886
889
  throw new CertificateError(
887
- `Invalid fabricId in NoC certificate: ${Logger.toJSON(nocCert.subject.fabricId)}`,
890
+ `Invalid fabricId in NoC certificate: ${Diagnostic.json(nocCert.subject.fabricId)}`,
888
891
  );
889
892
  }
890
893
  // The matter-fabric-id attribute’s value SHALL NOT be 0
891
894
  if (nocCert.subject.fabricId === FabricId(0)) {
892
895
  throw new CertificateError(
893
- `Invalid fabricId in NoC certificate: ${Logger.toJSON(nocCert.subject.fabricId)}`,
896
+ `Invalid fabricId in NoC certificate: ${Diagnostic.json(nocCert.subject.fabricId)}`,
894
897
  );
895
898
  }
896
899
 
@@ -914,9 +917,9 @@ export namespace CertificateManager {
914
917
  // the same certificate chain.
915
918
  if (rootCert.subject.fabricId !== undefined && rootCert.subject.fabricId !== nocCert.subject.fabricId) {
916
919
  throw new CertificateError(
917
- `FabricId in NoC certificate does not match the fabricId in the parent certificate. ${Logger.toJSON(
920
+ `FabricId in NoC certificate does not match the fabricId in the parent certificate. ${Diagnostic.json(
918
921
  rootCert.subject.fabricId,
919
- )} !== ${Logger.toJSON(nocCert.subject.fabricId)}`,
922
+ )} !== ${Diagnostic.json(nocCert.subject.fabricId)}`,
920
923
  );
921
924
  }
922
925
  if (
@@ -925,9 +928,9 @@ export namespace CertificateManager {
925
928
  icaCert.subject.fabricId !== nocCert.subject.fabricId
926
929
  ) {
927
930
  throw new CertificateError(
928
- `FabricId in NoC certificate does not match the fabricId in the parent certificate. ${Logger.toJSON(
931
+ `FabricId in NoC certificate does not match the fabricId in the parent certificate. ${Diagnostic.json(
929
932
  icaCert.subject.fabricId,
930
- )} !== ${Logger.toJSON(nocCert.subject.fabricId)}`,
933
+ )} !== ${Diagnostic.json(nocCert.subject.fabricId)}`,
931
934
  );
932
935
  }
933
936
 
@@ -950,7 +953,7 @@ export namespace CertificateManager {
950
953
  (!nocCert.extensions.extendedKeyUsage.includes(1) && !nocCert.extensions.extendedKeyUsage.includes(2))
951
954
  ) {
952
955
  throw new CertificateError(
953
- `Noc certificate must have extendedKeyUsage with serverAuth and clientAuth: ${Logger.toJSON(nocCert.extensions.extendedKeyUsage)}`,
956
+ `Noc certificate must have extendedKeyUsage with serverAuth and clientAuth: ${Diagnostic.json(nocCert.extensions.extendedKeyUsage)}`,
954
957
  );
955
958
  }
956
959
 
@@ -1005,20 +1008,20 @@ export namespace CertificateManager {
1005
1008
  if (icaCert.subject.fabricId !== undefined) {
1006
1009
  if (Array.isArray(icaCert.subject.fabricId)) {
1007
1010
  throw new CertificateError(
1008
- `Invalid fabricId in NoC certificate: ${Logger.toJSON(icaCert.subject.fabricId)}`,
1011
+ `Invalid fabricId in NoC certificate: ${Diagnostic.json(icaCert.subject.fabricId)}`,
1009
1012
  );
1010
1013
  }
1011
1014
  // If present, the matter-fabric-id attribute’s value SHALL NOT be 0
1012
1015
  if (icaCert.subject.fabricId === FabricId(0)) {
1013
1016
  throw new CertificateError(
1014
- `Invalid fabricId in NoC certificate: ${Logger.toJSON(icaCert.subject.fabricId)}`,
1017
+ `Invalid fabricId in NoC certificate: ${Diagnostic.json(icaCert.subject.fabricId)}`,
1015
1018
  );
1016
1019
  }
1017
1020
  }
1018
1021
 
1019
1022
  // The subject DN SHALL encode exactly one matter-icac-id attribute.
1020
1023
  if (icaCert.subject.icacId === undefined || Array.isArray(icaCert.subject.icacId)) {
1021
- throw new CertificateError(`Invalid icacId in Ica certificate: ${Logger.toJSON(icaCert.subject.icacId)}`);
1024
+ throw new CertificateError(`Invalid icacId in Ica certificate: ${Diagnostic.json(icaCert.subject.icacId)}`);
1022
1025
  }
1023
1026
 
1024
1027
  // The subject DN SHALL NOT encode any matter-rcac-id attribute.
@@ -1041,18 +1044,18 @@ export namespace CertificateManager {
1041
1044
  rootCert.subject.fabricId !== icaCert.subject.fabricId
1042
1045
  ) {
1043
1046
  throw new CertificateError(
1044
- `FabricId in Ica certificate does not match the fabricId in the parent certificate. ${Logger.toJSON(
1047
+ `FabricId in Ica certificate does not match the fabricId in the parent certificate. ${Diagnostic.json(
1045
1048
  rootCert.subject.fabricId,
1046
- )} !== ${Logger.toJSON(icaCert.subject.fabricId)}`,
1049
+ )} !== ${Diagnostic.json(icaCert.subject.fabricId)}`,
1047
1050
  );
1048
1051
  }
1049
1052
 
1050
1053
  // Verify the certificate chain by checking rcac ids in subject and issuer
1051
1054
  if (rootCert.subject.rcacId !== icaCert.issuer.rcacId) {
1052
1055
  throw new CertificateError(
1053
- `RcacId in Ica certificate does not match the rcacId in the parent certificate. ${Logger.toJSON(
1056
+ `RcacId in Ica certificate does not match the rcacId in the parent certificate. ${Diagnostic.json(
1054
1057
  rootCert.subject.rcacId,
1055
- )} !== ${Logger.toJSON(icaCert.issuer.rcacId)}`,
1058
+ )} !== ${Diagnostic.json(icaCert.issuer.rcacId)}`,
1056
1059
  );
1057
1060
  }
1058
1061
 
@@ -106,37 +106,47 @@ export class AttributeClient<T = any> {
106
106
  });
107
107
  }
108
108
 
109
- /** Get the value of the attribute. Fabric scoped reads are always done with the remote. */
110
- async get(alwaysRequestFromRemote?: boolean, isFabricFiltered = true) {
111
- if (alwaysRequestFromRemote === undefined) {
112
- alwaysRequestFromRemote = this.#isFabricScoped || !this.#updatedBySubscriptions;
113
- } else if (!alwaysRequestFromRemote && this.#isFabricScoped) {
114
- alwaysRequestFromRemote = true;
109
+ /**
110
+ * Get the value of the attribute. Fabric scoped reads are always done with the remote.
111
+ * The `requestFromRemote` parameter allowed to force or prevent remote reads:
112
+ * - `true` forces a remote read
113
+ * - `false` forces a local read, return undefined if no value is available
114
+ * - `undefined` returns local values if available or if the read is fabric filtered, otherwise remote read
115
+ */
116
+ async get(requestFromRemote?: boolean, isFabricFiltered = true) {
117
+ if (requestFromRemote === undefined) {
118
+ requestFromRemote = this.#isFabricScoped || !this.#updatedBySubscriptions ? true : undefined;
119
+ } else if (!requestFromRemote && this.#isFabricScoped) {
120
+ requestFromRemote = true;
115
121
  }
116
122
  return await this.#interactionClient.getAttribute({
117
123
  endpointId: this.endpointId,
118
124
  clusterId: this.clusterId,
119
125
  attribute: this.attribute,
120
126
  isFabricFiltered,
121
- alwaysRequestFromRemote,
127
+ requestFromRemote,
122
128
  });
123
129
  }
124
130
 
125
131
  /**
126
132
  * Get the value with version of the attribute. Fabric scoped reads are always done with the remote.
127
- * */
128
- async getWithVersion(alwaysRequestFromRemote?: boolean, isFabricFiltered = true) {
129
- if (alwaysRequestFromRemote === undefined) {
130
- alwaysRequestFromRemote = this.#isFabricScoped;
131
- } else if (!alwaysRequestFromRemote && this.#isFabricScoped) {
132
- alwaysRequestFromRemote = true;
133
+ * The `requestFromRemote` parameter allowed to force or prevent remote reads:
134
+ * - `true` forces a remote read
135
+ * - `false` forces a local read, return undefined if no value is available
136
+ * - `undefined` returns local values if available or if the read is fabric filtered, otherwise remote read
137
+ */
138
+ async getWithVersion(requestFromRemote?: boolean, isFabricFiltered = true) {
139
+ if (requestFromRemote === undefined) {
140
+ requestFromRemote = this.#isFabricScoped || !this.#updatedBySubscriptions ? true : undefined;
141
+ } else if (!requestFromRemote && this.#isFabricScoped) {
142
+ requestFromRemote = true;
133
143
  }
134
144
  return await this.#interactionClient.getAttributeWithVersion({
135
145
  endpointId: this.endpointId,
136
146
  clusterId: this.clusterId,
137
147
  attribute: this.attribute,
138
148
  isFabricFiltered,
139
- alwaysRequestFromRemote,
149
+ requestFromRemote,
140
150
  });
141
151
  }
142
152
 
@@ -4,7 +4,16 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import { ImplementationError, InternalError, Logger, MatterError, MaybePromise, camelize, isDeepEqual } from "#general";
7
+ import {
8
+ Diagnostic,
9
+ ImplementationError,
10
+ InternalError,
11
+ Logger,
12
+ MatterError,
13
+ MaybePromise,
14
+ camelize,
15
+ isDeepEqual,
16
+ } from "#general";
8
17
  import { AccessLevel, AttributeModel, ClusterModel, DatatypeModel, FabricIndex, MatterModel } from "#model";
9
18
  import {
10
19
  Attribute,
@@ -165,9 +174,9 @@ export abstract class BaseAttributeServer<T> {
165
174
  this.value = initValue;
166
175
  } catch (error) {
167
176
  logger.warn(
168
- `Attribute value to initialize for ${name} has an invalid value ${Logger.toJSON(
177
+ `Attribute value to initialize for ${name} has an invalid value ${Diagnostic.json(
169
178
  initValue,
170
- )}. Restore to default ${Logger.toJSON(defaultValue)}`,
179
+ )}. Restore to default ${Diagnostic.json(defaultValue)}`,
171
180
  );
172
181
  if (defaultValue === undefined) {
173
182
  throw new ImplementationError(`Attribute value to initialize for ${name} cannot be undefined.`);
@@ -524,7 +533,7 @@ export class AttributeServer<T> extends FixedAttributeServer<T> {
524
533
  newValue: value,
525
534
  changed: !!this.delayedChangeData?.changed || valueChanged, // We combine the changed flag
526
535
  };
527
- logger.info(`Delay change for attribute "${this.name}" with value ${Logger.toJSON(value)}`);
536
+ logger.info(`Delay change for attribute "${this.name}" with value ${Diagnostic.json(value)}`);
528
537
  } else {
529
538
  this.handleVersionAndTriggerListeners(value, oldValue, valueChanged);
530
539
  }
@@ -534,7 +543,7 @@ export class AttributeServer<T> extends FixedAttributeServer<T> {
534
543
  if (this.delayedChangeData !== undefined) {
535
544
  const { oldValue, newValue, changed } = this.delayedChangeData;
536
545
  this.delayedChangeData = undefined;
537
- logger.info(`Trigger delayed change for attribute "${this.name}" with value ${Logger.toJSON(newValue)}`);
546
+ logger.info(`Trigger delayed change for attribute "${this.name}" with value ${Diagnostic.json(newValue)}`);
538
547
  this.handleVersionAndTriggerListeners(newValue, oldValue, changed);
539
548
  }
540
549
  }
@@ -909,7 +918,7 @@ export class FabricScopedAttributeServer<T> extends AttributeServer<T> {
909
918
  () => !preserveFabricIndex, // No one should send any index and if we simply SHALL ignore it, but internally we might need it
910
919
  );
911
920
  logger.info(
912
- `Set remote value for fabric scoped attribute "${this.name}" to ${Logger.toJSON(value)} (delayed=${delayChangeEvents})`,
921
+ `Set remote value for fabric scoped attribute "${this.name}" to ${Diagnostic.json(value)} (delayed=${delayChangeEvents})`,
913
922
  );
914
923
 
915
924
  super.setRemote(value, session, message, delayChangeEvents);
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import { Logger } from "#general";
7
+ import { Diagnostic, Logger } from "#general";
8
8
  import { AccessLevel, FabricIndex } from "#model";
9
9
  import { CommandId, StatusCode, TlvSchema, TlvStream } from "#types";
10
10
  import { Message } from "../../codec/MessageCodec.js";
@@ -69,9 +69,9 @@ export class CommandServer<RequestT = any, ResponseT = any> {
69
69
  }
70
70
 
71
71
  this.requestSchema.validate(request);
72
- this.debug(`Invoke ${this.name} with data ${Logger.toJSON(request)}`);
72
+ this.debug(`Invoke ${this.name} with data ${Diagnostic.json(request)}`);
73
73
  const response = await this.handler(request, session, message, endpoint);
74
- this.debug(`Invoke ${this.name} response : ${Logger.toJSON(response)}`);
74
+ this.debug(`Invoke ${this.name} response : ${Diagnostic.json(response)}`);
75
75
  return {
76
76
  code: StatusCode.Success,
77
77
  responseId: this.responseId,
@@ -52,7 +52,7 @@ function getAttributeServerValue(attribute: AnyAttributeServer<any>, options: En
52
52
  attributeValue !== null &&
53
53
  options.logAttributeObjectValues !== false
54
54
  ) {
55
- value = Logger.toJSON(attributeValue);
55
+ value = Diagnostic.json(attributeValue);
56
56
  }
57
57
  } catch (error) {
58
58
  if (error instanceof FabricScopeError) {
@@ -7,6 +7,7 @@
7
7
  import {
8
8
  asyncNew,
9
9
  Construction,
10
+ Diagnostic,
10
11
  ImplementationError,
11
12
  isObject,
12
13
  Logger,
@@ -151,7 +152,7 @@ export class OccurrenceManager {
151
152
 
152
153
  // TODO - log after fabric filtering and include fabric filter in log message?
153
154
  logger.debug(
154
- `Got ${occurrences.length} events for ${resolveEventName(eventPath)} with filters: ${Logger.toJSON(filters)}`,
155
+ `Got ${occurrences.length} events for ${resolveEventName(eventPath)} with filters: ${Diagnostic.json(filters)}`,
155
156
  );
156
157
 
157
158
  // Convert from MaybePromise[] to MaybePromise<[]>
@@ -210,7 +211,7 @@ export class OccurrenceManager {
210
211
 
211
212
  add(occurrence: Occurrence): MaybePromise<NumberedOccurrence> {
212
213
  return MaybePromise.then(this.#store.add(occurrence), entry => {
213
- logger.debug(`Recorded event #${entry.number}: ${Logger.toJSON(occurrence)}`);
214
+ logger.debug(`Recorded event #${entry.number}: ${Diagnostic.json(occurrence)}`);
214
215
  this.#occurrences[occurrence.priority].push(entry);
215
216
  this.#storedEventCount++;
216
217
  if (this.#storedEventCount > this.#bufferConfig.maxEventAllowance) {
@@ -107,7 +107,7 @@ export function expandPathsInAttributeData(
107
107
  dataVersion: value.dataVersion,
108
108
  };
109
109
  } else if (!acceptWildcardPaths) {
110
- throw new UnexpectedDataError("Tag compression disabled, but path is incomplete: " + Logger.toJSON(path));
110
+ throw new UnexpectedDataError("Tag compression disabled, but path is incomplete: " + Diagnostic.json(path));
111
111
  }
112
112
  });
113
113
  return data;
@@ -3,7 +3,7 @@
3
3
  * Copyright 2022-2025 Matter.js Authors
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { Logger, MatterFlowError } from "#general";
6
+ import { Diagnostic, MatterFlowError } from "#general";
7
7
  import {
8
8
  ArraySchema,
9
9
  AttributeId,
@@ -77,7 +77,7 @@ export function encodeAttributePayloadData(
77
77
  const { attributeData } = attributePayload;
78
78
  if (attributeData === undefined) {
79
79
  throw new MatterFlowError(
80
- `Cannot encode Attribute Payload data with just a attributeStatus: ${Logger.toJSON(attributePayload)}`,
80
+ `Cannot encode Attribute Payload data with just a attributeStatus: ${Diagnostic.json(attributePayload)}`,
81
81
  );
82
82
  }
83
83
 
@@ -152,13 +152,13 @@ export function chunkAttributePayload(attributePayload: AttributeReportPayload):
152
152
  const { hasFabricSensitiveData, attributeData } = attributePayload;
153
153
  if (attributeData === undefined) {
154
154
  throw new MatterFlowError(
155
- `Cannot chunk an AttributePayload with just a attributeStatus: ${Logger.toJSON(attributePayload)}`,
155
+ `Cannot chunk an AttributePayload with just a attributeStatus: ${Diagnostic.json(attributePayload)}`,
156
156
  );
157
157
  }
158
158
  const { schema, path, dataVersion, payload } = attributeData;
159
159
  if (!(schema instanceof ArraySchema) || !Array.isArray(payload)) {
160
160
  throw new MatterFlowError(
161
- `Cannot chunk an AttributePayload with attributeData that is not an array: ${Logger.toJSON(
161
+ `Cannot chunk an AttributePayload with attributeData that is not an array: ${Diagnostic.json(
162
162
  attributePayload,
163
163
  )}`,
164
164
  );
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import {
8
+ Diagnostic,
8
9
  Environment,
9
10
  Environmental,
10
11
  ImplementationError,
@@ -376,13 +377,13 @@ export class InteractionClient {
376
377
  clusterId: ClusterId;
377
378
  attribute: A;
378
379
  isFabricFiltered?: boolean;
379
- alwaysRequestFromRemote?: boolean;
380
+ requestFromRemote?: boolean;
380
381
  executeQueued?: boolean;
381
382
  }): Promise<AttributeJsType<A> | undefined> {
382
- const { alwaysRequestFromRemote = false } = options;
383
+ const { requestFromRemote } = options;
383
384
  const response = await this.getAttributeWithVersion({
384
385
  ...options,
385
- alwaysRequestFromRemote,
386
+ requestFromRemote,
386
387
  });
387
388
  return response?.value;
388
389
  }
@@ -392,22 +393,20 @@ export class InteractionClient {
392
393
  clusterId: ClusterId;
393
394
  attribute: A;
394
395
  isFabricFiltered?: boolean;
395
- alwaysRequestFromRemote?: boolean;
396
+ requestFromRemote?: boolean;
396
397
  executeQueued?: boolean;
397
398
  }): Promise<{ value: AttributeJsType<A>; version: number } | undefined> {
398
- const {
399
- endpointId,
400
- clusterId,
401
- attribute,
402
- alwaysRequestFromRemote = false,
403
- isFabricFiltered,
404
- executeQueued,
405
- } = options;
399
+ const { endpointId, clusterId, attribute, requestFromRemote, isFabricFiltered, executeQueued } = options;
406
400
  const { id: attributeId } = attribute;
407
- if (!alwaysRequestFromRemote && this.#nodeStore !== undefined) {
408
- const { value, version } = this.#nodeStore.retrieveAttribute(endpointId, clusterId, attributeId) ?? {};
409
- if (value !== undefined && version !== undefined) {
410
- return { value, version } as { value: AttributeJsType<A>; version: number };
401
+ if (this.#nodeStore !== undefined) {
402
+ if (!requestFromRemote) {
403
+ const { value, version } = this.#nodeStore.retrieveAttribute(endpointId, clusterId, attributeId) ?? {};
404
+ if (value !== undefined && version !== undefined) {
405
+ return { value, version } as { value: AttributeJsType<A>; version: number };
406
+ }
407
+ }
408
+ if (requestFromRemote === false) {
409
+ return undefined;
411
410
  }
412
411
  }
413
412
 
@@ -549,7 +548,7 @@ export class InteractionClient {
549
548
  `Sending write request: ${attributes
550
549
  .map(
551
550
  ({ endpointId, clusterId, attribute: { id }, value, dataVersion }) =>
552
- `${resolveAttributeName({ endpointId, clusterId, attributeId: id })} = ${Logger.toJSON(
551
+ `${resolveAttributeName({ endpointId, clusterId, attributeId: id })} = ${Diagnostic.json(
553
552
  value,
554
553
  )} (version=${dataVersion})`,
555
554
  )
@@ -973,7 +972,7 @@ export class InteractionClient {
973
972
  let maxEventNumber = this.#nodeStore?.maxEventNumber ?? eventReports[0].events[0].eventNumber;
974
973
  eventReports.forEach(data => {
975
974
  logger.debug(
976
- `Received event update: ${resolveEventName(data.path)}: ${Logger.toJSON(data.events)}`,
975
+ `Received event update: ${resolveEventName(data.path)}: ${Diagnostic.json(data.events)}`,
977
976
  );
978
977
  const { events } = data;
979
978
 
@@ -1001,7 +1000,7 @@ export class InteractionClient {
1001
1000
  endpointId,
1002
1001
  clusterId,
1003
1002
  attributeId,
1004
- })} = ${Logger.toJSON(value)} (version=${version})`,
1003
+ })} = ${Diagnostic.json(value)} (version=${version})`,
1005
1004
  );
1006
1005
  if (value === undefined) throw new MatterFlowError("Received empty subscription result value.");
1007
1006
  const { value: oldValue } =
@@ -1091,7 +1090,7 @@ export class InteractionClient {
1091
1090
  endpointId,
1092
1091
  clusterId,
1093
1092
  commandId: requestId,
1094
- })} with ${Logger.toJSON(request)}`,
1093
+ })} with ${Diagnostic.json(request)}`,
1095
1094
  );
1096
1095
 
1097
1096
  if (!skipValidation) {
@@ -1160,7 +1159,7 @@ export class InteractionClient {
1160
1159
  endpointId,
1161
1160
  clusterId,
1162
1161
  commandId: requestId,
1163
- })} with ${Logger.toJSON(response)})}`,
1162
+ })} with ${Diagnostic.json(response)})}`,
1164
1163
  );
1165
1164
  return response;
1166
1165
  }
@@ -1196,7 +1195,7 @@ export class InteractionClient {
1196
1195
  endpointId,
1197
1196
  clusterId,
1198
1197
  commandId: requestId,
1199
- })} with ${Logger.toJSON(request)}`,
1198
+ })} with ${Diagnostic.json(request)}`,
1200
1199
  );
1201
1200
  const commandFields = requestSchema.encodeTlv(request);
1202
1201
 
@@ -633,7 +633,7 @@ export class InteractionServerMessenger extends InteractionMessenger {
633
633
  const encodedMessage = TlvDataReportForSend.encode(dataReportToSend);
634
634
  if (encodedMessage.length > this.exchange.maxPayloadSize) {
635
635
  throw new MatterFlowError(
636
- `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(
637
637
  dataReportToSend,
638
638
  )}`,
639
639
  );
@@ -856,7 +856,7 @@ export class InteractionClientMessenger extends IncomingInteractionClientMesseng
856
856
  });
857
857
  if (requestWithoutDataVersionFilters.length > this.exchange.maxPayloadSize) {
858
858
  throw new MatterFlowError(
859
- `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)}`,
860
860
  );
861
861
  }
862
862
 
@@ -365,7 +365,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
365
365
  logger.debug(
366
366
  `Read event from ${exchange.channel.name}: ${this.#endpointStructure.resolveEventName(
367
367
  path,
368
- )}=${Logger.toJSON(matchingEvents)}`,
368
+ )}=${Diagnostic.json(matchingEvents)}`,
369
369
  );
370
370
  const { schema } = event;
371
371
  reportsForPath.push(
@@ -523,7 +523,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
523
523
  logger.debug(
524
524
  `Read attribute from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(
525
525
  path,
526
- )}=${Logger.toJSON(value)} (version=${version}) ignored because of dataVersionFilter`,
526
+ )}=${Diagnostic.json(value)} (version=${version}) ignored because of dataVersionFilter`,
527
527
  );
528
528
  continue;
529
529
  }
@@ -531,7 +531,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
531
531
  logger.debug(
532
532
  `Read attribute from ${exchange.channel.name}: ${this.#endpointStructure.resolveAttributeName(
533
533
  path,
534
- )}=${Logger.toJSON(value)} (version=${version})`,
534
+ )}=${Diagnostic.json(value)} (version=${version})`,
535
535
  );
536
536
 
537
537
  const { schema } = attribute;
@@ -878,7 +878,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
878
878
  logger.debug(
879
879
  `Handle write request from ${
880
880
  exchange.channel.name
881
- } resolved to: ${this.#endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(
881
+ } resolved to: ${this.#endpointStructure.resolveAttributeName(path)}=${Diagnostic.json(
882
882
  value,
883
883
  )} (listIndex=${listIndex}, for-version=${dataVersion})`,
884
884
  );
@@ -960,7 +960,7 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
960
960
  ? `with following errors: ${errorResults
961
961
  .map(
962
962
  ({ path, statusCode }) =>
963
- `${this.#endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(statusCode)}`,
963
+ `${this.#endpointStructure.resolveAttributeName(path)}=${Diagnostic.json(statusCode)}`,
964
964
  )
965
965
  .join(", ")}`
966
966
  : "without errors"
@@ -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();
@@ -12,6 +12,7 @@ import {
12
12
  Channel,
13
13
  ChannelType,
14
14
  ClassExtends,
15
+ Diagnostic,
15
16
  Environment,
16
17
  Environmental,
17
18
  isIPv6,
@@ -220,9 +221,9 @@ export class ControllerCommissioner {
220
221
  const scannersToUse = this.#context.scanners.select(discoveryCapabilities);
221
222
 
222
223
  logger.info(
223
- `Connecting to device with identifier ${Logger.toJSON(identifierData)} and ${
224
+ `Connecting to device with identifier ${Diagnostic.json(identifierData)} and ${
224
225
  scannersToUse.length
225
- } scanners and knownAddress ${Logger.toJSON(knownAddress)}`,
226
+ } scanners and knownAddress ${Diagnostic.json(knownAddress)}`,
226
227
  );
227
228
 
228
229
  // If we have a known address we try this first before we discover the device