@matter/protocol 0.16.0-alpha.0-20251018-dd1ea6a8a → 0.16.0-alpha.0-20251021-cca02fb0e

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 (133) hide show
  1. package/dist/cjs/action/client/ClientInteraction.d.ts.map +1 -1
  2. package/dist/cjs/action/client/ClientInteraction.js +2 -2
  3. package/dist/cjs/action/client/ClientInteraction.js.map +1 -1
  4. package/dist/cjs/certificate/DeviceCertification.d.ts.map +1 -1
  5. package/dist/cjs/certificate/DeviceCertification.js +5 -0
  6. package/dist/cjs/certificate/DeviceCertification.js.map +1 -1
  7. package/dist/cjs/common/FailsafeContext.d.ts +2 -1
  8. package/dist/cjs/common/FailsafeContext.d.ts.map +1 -1
  9. package/dist/cjs/common/FailsafeContext.js +10 -5
  10. package/dist/cjs/common/FailsafeContext.js.map +1 -1
  11. package/dist/cjs/common/FailsafeTimer.d.ts +2 -0
  12. package/dist/cjs/common/FailsafeTimer.d.ts.map +1 -1
  13. package/dist/cjs/common/FailsafeTimer.js +9 -0
  14. package/dist/cjs/common/FailsafeTimer.js.map +1 -1
  15. package/dist/cjs/fabric/FabricAuthority.d.ts +12 -18
  16. package/dist/cjs/fabric/FabricAuthority.d.ts.map +1 -1
  17. package/dist/cjs/fabric/FabricAuthority.js +16 -29
  18. package/dist/cjs/fabric/FabricAuthority.js.map +2 -2
  19. package/dist/cjs/fabric/TestFabric.d.ts +1 -1
  20. package/dist/cjs/fabric/TestFabric.d.ts.map +1 -1
  21. package/dist/cjs/fabric/TestFabric.js +15 -15
  22. package/dist/cjs/fabric/TestFabric.js.map +1 -1
  23. package/dist/cjs/interaction/FabricAccessControl.d.ts.map +1 -1
  24. package/dist/cjs/interaction/FabricAccessControl.js +4 -1
  25. package/dist/cjs/interaction/FabricAccessControl.js.map +1 -1
  26. package/dist/cjs/mdns/MdnsClient.d.ts.map +1 -1
  27. package/dist/cjs/mdns/MdnsClient.js +34 -19
  28. package/dist/cjs/mdns/MdnsClient.js.map +1 -1
  29. package/dist/cjs/peer/ControllerDiscovery.d.ts.map +1 -1
  30. package/dist/cjs/peer/ControllerDiscovery.js +6 -7
  31. package/dist/cjs/peer/ControllerDiscovery.js.map +1 -1
  32. package/dist/cjs/protocol/DeviceAdvertiser.js +2 -2
  33. package/dist/cjs/protocol/DeviceAdvertiser.js.map +1 -1
  34. package/dist/cjs/protocol/MessageExchange.js +2 -2
  35. package/dist/cjs/protocol/MessageExchange.js.map +1 -1
  36. package/dist/cjs/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  37. package/dist/cjs/securechannel/SecureChannelProtocol.js +3 -3
  38. package/dist/cjs/securechannel/SecureChannelProtocol.js.map +1 -1
  39. package/dist/cjs/session/NodeSession.d.ts +1 -0
  40. package/dist/cjs/session/NodeSession.d.ts.map +1 -1
  41. package/dist/cjs/session/NodeSession.js +4 -0
  42. package/dist/cjs/session/NodeSession.js.map +1 -1
  43. package/dist/cjs/session/Session.d.ts +1 -0
  44. package/dist/cjs/session/Session.d.ts.map +1 -1
  45. package/dist/cjs/session/Session.js +4 -0
  46. package/dist/cjs/session/Session.js.map +1 -1
  47. package/dist/cjs/session/SessionManager.d.ts +13 -12
  48. package/dist/cjs/session/SessionManager.d.ts.map +1 -1
  49. package/dist/cjs/session/SessionManager.js.map +1 -1
  50. package/dist/cjs/session/case/CaseMessenger.d.ts.map +1 -1
  51. package/dist/cjs/session/case/CaseMessenger.js.map +1 -1
  52. package/dist/cjs/session/index.d.ts +1 -0
  53. package/dist/cjs/session/index.d.ts.map +1 -1
  54. package/dist/cjs/session/index.js +1 -0
  55. package/dist/cjs/session/index.js.map +1 -1
  56. package/dist/cjs/session/pase/PaseMessenger.d.ts.map +1 -1
  57. package/dist/cjs/session/pase/PaseMessenger.js.map +1 -1
  58. package/dist/esm/action/client/ClientInteraction.d.ts.map +1 -1
  59. package/dist/esm/action/client/ClientInteraction.js +1 -1
  60. package/dist/esm/action/client/ClientInteraction.js.map +1 -1
  61. package/dist/esm/certificate/DeviceCertification.d.ts.map +1 -1
  62. package/dist/esm/certificate/DeviceCertification.js +5 -0
  63. package/dist/esm/certificate/DeviceCertification.js.map +1 -1
  64. package/dist/esm/common/FailsafeContext.d.ts +2 -1
  65. package/dist/esm/common/FailsafeContext.d.ts.map +1 -1
  66. package/dist/esm/common/FailsafeContext.js +10 -5
  67. package/dist/esm/common/FailsafeContext.js.map +1 -1
  68. package/dist/esm/common/FailsafeTimer.d.ts +2 -0
  69. package/dist/esm/common/FailsafeTimer.d.ts.map +1 -1
  70. package/dist/esm/common/FailsafeTimer.js +9 -0
  71. package/dist/esm/common/FailsafeTimer.js.map +1 -1
  72. package/dist/esm/fabric/FabricAuthority.d.ts +12 -18
  73. package/dist/esm/fabric/FabricAuthority.d.ts.map +1 -1
  74. package/dist/esm/fabric/FabricAuthority.js +16 -29
  75. package/dist/esm/fabric/FabricAuthority.js.map +2 -2
  76. package/dist/esm/fabric/TestFabric.d.ts +1 -1
  77. package/dist/esm/fabric/TestFabric.d.ts.map +1 -1
  78. package/dist/esm/fabric/TestFabric.js +15 -15
  79. package/dist/esm/fabric/TestFabric.js.map +1 -1
  80. package/dist/esm/interaction/FabricAccessControl.d.ts.map +1 -1
  81. package/dist/esm/interaction/FabricAccessControl.js +5 -2
  82. package/dist/esm/interaction/FabricAccessControl.js.map +1 -1
  83. package/dist/esm/mdns/MdnsClient.d.ts.map +1 -1
  84. package/dist/esm/mdns/MdnsClient.js +34 -19
  85. package/dist/esm/mdns/MdnsClient.js.map +1 -1
  86. package/dist/esm/peer/ControllerDiscovery.d.ts.map +1 -1
  87. package/dist/esm/peer/ControllerDiscovery.js +6 -7
  88. package/dist/esm/peer/ControllerDiscovery.js.map +1 -1
  89. package/dist/esm/protocol/DeviceAdvertiser.js +2 -2
  90. package/dist/esm/protocol/DeviceAdvertiser.js.map +1 -1
  91. package/dist/esm/protocol/MessageExchange.js +2 -2
  92. package/dist/esm/protocol/MessageExchange.js.map +1 -1
  93. package/dist/esm/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  94. package/dist/esm/securechannel/SecureChannelProtocol.js +3 -3
  95. package/dist/esm/securechannel/SecureChannelProtocol.js.map +1 -1
  96. package/dist/esm/session/NodeSession.d.ts +1 -0
  97. package/dist/esm/session/NodeSession.d.ts.map +1 -1
  98. package/dist/esm/session/NodeSession.js +4 -0
  99. package/dist/esm/session/NodeSession.js.map +1 -1
  100. package/dist/esm/session/Session.d.ts +1 -0
  101. package/dist/esm/session/Session.d.ts.map +1 -1
  102. package/dist/esm/session/Session.js +4 -0
  103. package/dist/esm/session/Session.js.map +1 -1
  104. package/dist/esm/session/SessionManager.d.ts +13 -12
  105. package/dist/esm/session/SessionManager.d.ts.map +1 -1
  106. package/dist/esm/session/SessionManager.js.map +1 -1
  107. package/dist/esm/session/case/CaseMessenger.d.ts.map +1 -1
  108. package/dist/esm/session/case/CaseMessenger.js.map +1 -1
  109. package/dist/esm/session/index.d.ts +1 -0
  110. package/dist/esm/session/index.d.ts.map +1 -1
  111. package/dist/esm/session/index.js +1 -0
  112. package/dist/esm/session/index.js.map +1 -1
  113. package/dist/esm/session/pase/PaseMessenger.d.ts.map +1 -1
  114. package/dist/esm/session/pase/PaseMessenger.js.map +1 -1
  115. package/package.json +6 -6
  116. package/src/action/client/ClientInteraction.ts +1 -1
  117. package/src/certificate/DeviceCertification.ts +10 -0
  118. package/src/common/FailsafeContext.ts +15 -6
  119. package/src/common/FailsafeTimer.ts +11 -0
  120. package/src/fabric/FabricAuthority.ts +24 -38
  121. package/src/fabric/TestFabric.ts +15 -16
  122. package/src/interaction/FabricAccessControl.ts +5 -2
  123. package/src/mdns/MdnsClient.ts +36 -19
  124. package/src/peer/ControllerDiscovery.ts +6 -7
  125. package/src/protocol/DeviceAdvertiser.ts +2 -2
  126. package/src/protocol/MessageExchange.ts +2 -2
  127. package/src/securechannel/SecureChannelProtocol.ts +3 -4
  128. package/src/session/NodeSession.ts +5 -0
  129. package/src/session/Session.ts +5 -0
  130. package/src/session/SessionManager.ts +14 -2
  131. package/src/session/case/CaseMessenger.ts +2 -0
  132. package/src/session/index.ts +1 -0
  133. package/src/session/pase/PaseMessenger.ts +2 -0
@@ -24,21 +24,15 @@ const logger = Logger.get("FabricAuthority");
24
24
  /**
25
25
  * Configuration for fabrics controlled by a FabricAuthority.
26
26
  */
27
- interface FabricAuthorityConfiguration {
28
- adminVendorId?: VendorId;
29
- fabricIndex?: FabricIndex;
30
- fabricId?: FabricId;
31
- caseAuthenticatedTags?: CaseAuthenticatedTag[];
32
- adminFabricLabel: string;
33
- }
34
-
35
- /**
36
- * Concrete {@link FabricAuthorityConfiguration} for environmental configuration.
37
- */
38
- export class FabricAuthorityConfigurationProvider implements FabricAuthorityConfiguration {
39
- get adminFabricLabel(): string {
40
- throw new ImplementationError("Admin Fabric Label must be set for FabricAuthorityConfigurationProvider.");
41
- }
27
+ export interface FabricAuthorityConfiguration {
28
+ readonly adminFabricLabel: string;
29
+ readonly adminVendorId?: VendorId;
30
+ readonly adminNodeId?: NodeId;
31
+
32
+ /** @deprecated Fabric index is assigned automatically, please do not specify this. */
33
+ readonly adminFabricIndex?: FabricIndex;
34
+ readonly adminFabricId?: FabricId;
35
+ readonly caseAuthenticatedTags?: CaseAuthenticatedTag[];
42
36
  }
43
37
 
44
38
  /**
@@ -47,7 +41,6 @@ export class FabricAuthorityConfigurationProvider implements FabricAuthorityConf
47
41
  export interface FabricAuthorityContext {
48
42
  ca: CertificateAuthority;
49
43
  fabrics: FabricManager;
50
- config: FabricAuthorityConfiguration;
51
44
  }
52
45
 
53
46
  export const DEFAULT_ADMIN_VENDOR_ID = VendorId(0xfff1);
@@ -59,13 +52,11 @@ export class FabricAuthority {
59
52
  #construction: Construction<FabricAuthority>;
60
53
  #ca: CertificateAuthority;
61
54
  #fabrics: FabricManager;
62
- #config: FabricAuthorityConfiguration;
63
55
  #fabricAdded = new Observable<[Fabric]>();
64
56
 
65
- constructor({ ca, fabrics, config }: FabricAuthorityContext) {
57
+ constructor({ ca, fabrics }: FabricAuthorityContext) {
66
58
  this.#ca = ca;
67
59
  this.#fabrics = fabrics;
68
- this.#config = config;
69
60
 
70
61
  this.#construction = Construction(this, async () => {
71
62
  await this.#ca.construction;
@@ -87,18 +78,19 @@ export class FabricAuthority {
87
78
  /**
88
79
  * Obtain the default fabric for this authority.
89
80
  */
90
- async defaultFabric() {
81
+ async defaultFabric(config: FabricAuthorityConfiguration) {
91
82
  // First search for a fabric associated with the CA's root certificate
92
- const fabric = this.fabrics[0];
83
+ const caRootCert = this.#ca.rootCert;
84
+ const fabric = this.fabrics.find(fabric => Bytes.areEqual(fabric.rootCert, caRootCert));
93
85
  if (fabric !== undefined) {
94
- if (fabric.label !== this.#config.adminFabricLabel) {
95
- await fabric.setLabel(this.#config.adminFabricLabel);
86
+ if (fabric.label !== config.adminFabricLabel) {
87
+ await fabric.setLabel(config.adminFabricLabel);
96
88
  }
97
89
  return fabric;
98
90
  }
99
91
 
100
92
  // Create a new fabric
101
- return await this.createFabric();
93
+ return await this.createFabric(config);
102
94
  }
103
95
 
104
96
  /**
@@ -125,11 +117,11 @@ export class FabricAuthority {
125
117
  /**
126
118
  * Create a new fabric under our control.
127
119
  */
128
- async createFabric() {
129
- const rootNodeId = NodeId.randomOperationalNodeId(this.#fabrics.crypto);
120
+ async createFabric(config: FabricAuthorityConfiguration) {
121
+ const rootNodeId = config.adminNodeId ?? NodeId.randomOperationalNodeId(this.#fabrics.crypto);
130
122
  const ipkValue = this.#fabrics.crypto.randomBytes(CRYPTO_SYMMETRIC_KEY_LENGTH);
131
123
 
132
- let vendorId = this.#config.adminVendorId;
124
+ let vendorId = config.adminVendorId;
133
125
  if (vendorId === undefined) {
134
126
  vendorId = DEFAULT_ADMIN_VENDOR_ID;
135
127
  logger.warn(`Using test vendor ID 0x${vendorId.toString(16)} for controller fabric`);
@@ -140,20 +132,15 @@ export class FabricAuthority {
140
132
  fabricBuilder
141
133
  .setRootNodeId(rootNodeId)
142
134
  .setIdentityProtectionKey(ipkValue)
143
- .setRootVendorId(this.#config.adminVendorId ?? DEFAULT_ADMIN_VENDOR_ID)
144
- .setLabel(this.#config.adminFabricLabel);
135
+ .setRootVendorId(vendorId)
136
+ .setLabel(config.adminFabricLabel);
145
137
 
146
- const fabricId = this.#config.fabricId ?? FabricId(this.#fabrics.crypto.randomBigInt(8));
138
+ const fabricId = config.adminFabricId ?? FabricId(this.#fabrics.crypto.randomBigInt(8));
147
139
  await fabricBuilder.setOperationalCert(
148
- await this.#ca.generateNoc(
149
- fabricBuilder.publicKey,
150
- fabricId,
151
- rootNodeId,
152
- this.#config.caseAuthenticatedTags,
153
- ),
140
+ await this.#ca.generateNoc(fabricBuilder.publicKey, fabricId, rootNodeId, config.caseAuthenticatedTags),
154
141
  );
155
142
 
156
- let index = this.#config.fabricIndex;
143
+ let index = config.adminFabricIndex;
157
144
  if (index === undefined) {
158
145
  index = this.#fabrics.allocateFabricIndex();
159
146
  } else if (this.#fabrics.findByIndex(index) !== undefined) {
@@ -173,7 +160,6 @@ export class FabricAuthority {
173
160
  const instance = new FabricAuthority({
174
161
  ca: env.get(CertificateAuthority),
175
162
  fabrics: env.get(FabricManager),
176
- config: env.get(FabricAuthorityConfigurationProvider),
177
163
  });
178
164
  env.set(FabricAuthority, instance);
179
165
  return instance;
@@ -19,8 +19,14 @@ import { FabricManager } from "./FabricManager.js";
19
19
  */
20
20
  export async function TestFabric(options: TestFabric.Options = {}) {
21
21
  const authority = await TestFabric.Authority(options);
22
+ const { index } = options;
22
23
 
23
- return authority.createFabric();
24
+ return authority.createFabric({
25
+ adminFabricLabel: `mock-fabric-${index}`,
26
+ adminVendorId: VendorId(0xfff1),
27
+ adminFabricIndex: index !== undefined ? FabricIndex(index) : undefined,
28
+ adminFabricId: FabricId(1),
29
+ });
24
30
  }
25
31
 
26
32
  export namespace TestFabric {
@@ -31,35 +37,28 @@ export namespace TestFabric {
31
37
  *
32
38
  * Crypto matter is stable with respect to {@link index}.
33
39
  */
34
- export async function Authority({ index, fabrics }: Options = {}) {
35
- if (index === undefined) {
40
+ export async function Authority(options: Options = {}) {
41
+ let { fabrics } = options;
42
+ if (options.index === undefined) {
36
43
  if (fabrics) {
37
- index = fabrics.allocateFabricIndex();
44
+ options.index = fabrics.allocateFabricIndex();
38
45
  } else {
39
- index = 1;
46
+ options.index = 1;
40
47
  }
41
48
  }
42
49
 
43
- if (index < 1 || index > 254) {
50
+ if (options.index < 1 || options.index > 254) {
44
51
  throw new ImplementationError("Test fabric indexes must be in the range 1-254");
45
52
  }
46
53
 
47
54
  if (!fabrics) {
48
- fabrics = new FabricManager(MockCrypto(index));
55
+ fabrics = new FabricManager(MockCrypto(options.index));
49
56
  }
50
57
 
51
- const authority = new FabricAuthority({
58
+ return new FabricAuthority({
52
59
  ca: await CertificateAuthority.create(fabrics.crypto),
53
- config: {
54
- adminFabricLabel: `mock-fabric-${index}`,
55
- adminVendorId: VendorId(0xfff1),
56
- fabricIndex: FabricIndex(index),
57
- fabricId: FabricId(1),
58
- },
59
60
  fabrics,
60
61
  });
61
-
62
- return authority;
63
62
  }
64
63
 
65
64
  export interface Options {
@@ -6,7 +6,7 @@
6
6
  import { Subject } from "#action/server/Subject.js";
7
7
  import { AccessControl } from "#clusters/access-control";
8
8
  import type { Fabric } from "#fabric/Fabric.js";
9
- import { InternalError, Logger, MatterFlowError } from "#general";
9
+ import { Diagnostic, InternalError, Logger, MatterFlowError } from "#general";
10
10
  import { AccessLevel } from "#model";
11
11
  import {
12
12
  CaseAuthenticatedTag,
@@ -94,7 +94,10 @@ export class FabricAccessControl {
94
94
  throw new InternalError("ACL entries must match the fabric index of the manager");
95
95
  }
96
96
  this.#aclList = [...aclList] as unknown as AclList; // It is the same structure we just use an internal type for privilege
97
- logger.info("ACL List updated for FabricIndex ", this.#fabricIndex, this.#aclList);
97
+ logger.info(
98
+ "ACL List updated",
99
+ this.#aclList.map(e => Diagnostic.dict(e)),
100
+ );
98
101
  }
99
102
 
100
103
  set extensionEntryAccessCheck(
@@ -184,9 +184,10 @@ export class MdnsClient implements Scanner {
184
184
  this.#updateScanTargets();
185
185
  logger.info(
186
186
  "MDNS Scan targets updated :",
187
- `commissionable = ${this.#scanForCommissionableDevices}`,
188
- "Targets:",
189
- this.#operationalScanTargets,
187
+ Diagnostic.dict({
188
+ commissionable: this.#scanForCommissionableDevices,
189
+ operational: this.#operationalScanTargets,
190
+ }),
190
191
  );
191
192
  }
192
193
 
@@ -220,7 +221,7 @@ export class MdnsClient implements Scanner {
220
221
  this.#updateListeningStatus();
221
222
  }
222
223
 
223
- /** Update the status of we care about MDNS messages or not */
224
+ /** Update the status if we care about MDNS messages or not */
224
225
  #updateListeningStatus() {
225
226
  const formerListenStatus = this.#listening;
226
227
  // Are we interested in MDNS traffic or not?
@@ -786,25 +787,41 @@ export class MdnsClient implements Scanner {
786
787
  },
787
788
  );
788
789
 
789
- while (!canceled) {
790
- this.#getCommissionableDeviceRecords(identifier).forEach(device => {
791
- const { deviceIdentifier } = device;
792
- if (!discoveredDevices.has(deviceIdentifier)) {
793
- discoveredDevices.add(deviceIdentifier);
794
- callback(device);
795
- }
796
- });
790
+ // We scan continuously, so make sure we are registered for commissionable devices
791
+ const criteria: MdnsScannerTargetCriteria = { commissionable: true, operationalTargets: [] };
792
+ this.targetCriteriaProviders.add(criteria);
793
+
794
+ try {
795
+ let lastDiscoveredDevices: CommissionableDevice[] | undefined = undefined;
796
+ while (!canceled) {
797
+ this.#getCommissionableDeviceRecords(identifier).forEach(device => {
798
+ const { deviceIdentifier } = device;
799
+ if (!discoveredDevices.has(deviceIdentifier)) {
800
+ discoveredDevices.add(deviceIdentifier);
801
+ callback(device);
802
+ }
803
+ });
797
804
 
798
- let remainingTime;
799
- if (discoveryEndTime !== undefined) {
800
- remainingTime = Seconds.ceil(Timespan(Time.nowMs, discoveryEndTime).duration);
801
- if (remainingTime <= 0) {
802
- break;
805
+ let remainingTime;
806
+ if (discoveryEndTime !== undefined) {
807
+ remainingTime = Seconds.ceil(Timespan(Time.nowMs, discoveryEndTime).duration);
808
+ if (remainingTime <= 0) {
809
+ break;
810
+ }
803
811
  }
812
+ lastDiscoveredDevices = await this.#registerWaiterPromise(
813
+ queryId,
814
+ true,
815
+ remainingTime,
816
+ () => this.#getCommissionableDeviceRecords(identifier),
817
+ false,
818
+ queryResolver,
819
+ );
804
820
  }
805
- await this.#registerWaiterPromise(queryId, true, remainingTime, undefined, false, queryResolver);
821
+ return lastDiscoveredDevices ?? this.#getCommissionableDeviceRecords(identifier);
822
+ } finally {
823
+ this.targetCriteriaProviders.delete(criteria);
806
824
  }
807
- return this.#getCommissionableDeviceRecords(identifier);
808
825
  }
809
826
 
810
827
  getDiscoveredCommissionableDevices(identifier: CommissionableDeviceIdentifiers) {
@@ -88,9 +88,9 @@ export class ControllerDiscovery {
88
88
  ): Promise<CommissionableDevice[]> {
89
89
  const discoveredDevices = new Map<string, CommissionableDevice>();
90
90
 
91
- await Promise.all(
92
- scanners.map(async scanner => {
93
- await scanner.findCommissionableDevicesContinuously(
91
+ const results = await Promise.all(
92
+ scanners.map(async scanner =>
93
+ scanner.findCommissionableDevicesContinuously(
94
94
  identifier,
95
95
  device => {
96
96
  const { deviceIdentifier } = device;
@@ -100,14 +100,13 @@ export class ControllerDiscovery {
100
100
  }
101
101
  },
102
102
  timeout,
103
- );
104
- }),
103
+ ),
104
+ ),
105
105
  );
106
106
 
107
107
  // The final answer only consists the devices still left, so expired ones will be excluded
108
108
  const finalDiscoveredDevices = new Map<string, CommissionableDevice>();
109
- scanners.forEach(scanner => {
110
- const devices = scanner.getDiscoveredCommissionableDevices(identifier);
109
+ results.forEach(devices => {
111
110
  devices.forEach(device => {
112
111
  const { deviceIdentifier } = device;
113
112
  if (!discoveredDevices.has(deviceIdentifier)) {
@@ -166,7 +166,7 @@ export class DeviceAdvertiser {
166
166
  * Advertise the device as operational.
167
167
  */
168
168
  enterOperationalMode() {
169
- if (this.#isOperational) {
169
+ if (this.#isOperational || this.#isClosing) {
170
170
  return;
171
171
  }
172
172
 
@@ -179,7 +179,7 @@ export class DeviceAdvertiser {
179
179
  * Begin automatic broadcast for fabrics if in operational mode.
180
180
  */
181
181
  #startOperationalAdvertisement() {
182
- if (!this.#isOperational) {
182
+ if (!this.#isOperational || this.#isClosing) {
183
183
  return;
184
184
  }
185
185
 
@@ -494,10 +494,10 @@ export class MessageExchange {
494
494
 
495
495
  #retransmitMessage(message: Message, expectedProcessingTime?: Duration) {
496
496
  this.#retransmissionCounter++;
497
- if (this.#retransmissionCounter >= MRP.MAX_TRANSMISSIONS) {
497
+ if (this.#isClosing || this.#retransmissionCounter >= MRP.MAX_TRANSMISSIONS) {
498
498
  // Ok all 4 resubmissions are done, but we need to wait a bit longer because of processing time and
499
499
  // the resubmissions from the other side
500
- if (expectedProcessingTime) {
500
+ if (expectedProcessingTime && !this.#isClosing) {
501
501
  // We already have waited after the last message was sent, so deduct this time from the final wait time
502
502
  const finalWaitTime = Millis(
503
503
  this.channel.calculateMaximumPeerResponseTime(
@@ -7,6 +7,7 @@
7
7
  import { FabricManager } from "#fabric/FabricManager.js";
8
8
  import { AsyncObservable, Environment, Environmental, Logger, MatterFlowError } from "#general";
9
9
  import { ExchangeManager } from "#protocol/ExchangeManager.js";
10
+ import { NodeSession } from "#session/NodeSession.js";
10
11
  import { SessionManager } from "#session/SessionManager.js";
11
12
  import {
12
13
  GeneralStatusCode,
@@ -19,7 +20,6 @@ import {
19
20
  import { Message } from "../codec/MessageCodec.js";
20
21
  import { MessageExchange } from "../protocol/MessageExchange.js";
21
22
  import { ProtocolHandler } from "../protocol/ProtocolHandler.js";
22
- import { SecureSession } from "../session/SecureSession.js";
23
23
  import { CaseServer } from "../session/case/CaseServer.js";
24
24
  import { MaximumPasePairingErrorsReachedError, PaseServer } from "../session/pase/PaseServer.js";
25
25
  import { ChannelStatusResponseError, SecureChannelMessenger } from "./SecureChannelMessenger.js";
@@ -83,10 +83,9 @@ export class StatusReportOnlySecureChannelProtocol implements ProtocolHandler {
83
83
  }
84
84
 
85
85
  const { session } = exchange;
86
- SecureSession.assert(session);
86
+ NodeSession.assert(session);
87
87
  logger.debug(`Peer requested to close session ${session.name}. Remove session now.`);
88
- // TODO: and do more - see Core Specs 5.5
89
- await session.destroy(false, false);
88
+ await session.closeByPeer();
90
89
  }
91
90
 
92
91
  async close() {
@@ -331,6 +331,11 @@ export class NodeSession extends SecureSession {
331
331
  await this.destroy(sendClose, closeAfterExchangeFinished);
332
332
  }
333
333
 
334
+ async closeByPeer() {
335
+ await this.destroy(false, false);
336
+ await this.closedByPeer.emit();
337
+ }
338
+
334
339
  /** Destroys a session. Outstanding subscription data will be discarded. */
335
340
  async destroy(sendClose = false, closeAfterExchangeFinished = true) {
336
341
  await this.clearSubscriptions(false);
@@ -97,6 +97,7 @@ export abstract class Session {
97
97
  */
98
98
  closer?: Promise<void>;
99
99
  #destroyed = AsyncObservable<[]>();
100
+ #closedByPeer = AsyncObservable<[]>();
100
101
 
101
102
  constructor(args: {
102
103
  manager?: SessionManager;
@@ -143,6 +144,10 @@ export abstract class Session {
143
144
  return this.#destroyed;
144
145
  }
145
146
 
147
+ get closedByPeer() {
148
+ return this.#closedByPeer;
149
+ }
150
+
146
151
  notifyActivity(messageReceived: boolean) {
147
152
  this.timestamp = Time.nowMs;
148
153
  if (messageReceived) {
@@ -31,7 +31,7 @@ import { PeerAddress, PeerAddressMap } from "#peer/PeerAddress.js";
31
31
  import { GroupSession } from "#session/GroupSession.js";
32
32
  import { CaseAuthenticatedTag, DEFAULT_MAX_PATHS_PER_INVOKE, FabricId, FabricIndex, GroupId, NodeId } from "#types";
33
33
  import { UnexpectedDataError } from "@matter/general";
34
- import { Fabric } from "../fabric/Fabric.js";
34
+ import { ExposedFabricInformation, Fabric } from "../fabric/Fabric.js";
35
35
  import { MessageCounter } from "../protocol/MessageCounter.js";
36
36
  import { InsecureSession } from "./InsecureSession.js";
37
37
  import { NodeSession } from "./NodeSession.js";
@@ -90,6 +90,18 @@ type ResumptionStorageRecord = {
90
90
  caseAuthenticatedTags?: CaseAuthenticatedTag[];
91
91
  };
92
92
 
93
+ export interface ActiveSessionInformation {
94
+ name: string;
95
+ nodeId: NodeId;
96
+ peerNodeId: NodeId;
97
+ fabric?: ExposedFabricInformation;
98
+ isPeerActive: boolean;
99
+ secure: boolean;
100
+ lastInteractionTimestamp?: number;
101
+ lastActiveTimestamp?: number;
102
+ numberOfActiveSubscriptions: number;
103
+ }
104
+
93
105
  /**
94
106
  * Interfaces {@link SessionManager} with other components.
95
107
  */
@@ -654,7 +666,7 @@ export class SessionManager {
654
666
  );
655
667
  }
656
668
 
657
- getActiveSessionInformation() {
669
+ getActiveSessionInformation(): ActiveSessionInformation[] {
658
670
  this.#construction.assert();
659
671
  return [...this.#sessions]
660
672
  .filter(session => session.isSecure && !session.isPase)
@@ -47,6 +47,8 @@ export class CaseClientMessenger extends SecureChannelMessenger {
47
47
  payload,
48
48
  payloadHeader: { messageType },
49
49
  } = await this.anyNextMessage("Sigma2(Resume)");
50
+
51
+ // TODO Add support for BUSY response and resend the message after waiting time
50
52
  switch (messageType) {
51
53
  case SecureMessageType.Sigma2:
52
54
  return { sigma2Bytes: payload, sigma2: TlvCaseSigma2.decode(payload) as CaseSigma2 };
@@ -17,4 +17,5 @@ export * from "./pase/PaseMessenger.js";
17
17
  export * from "./pase/PaseServer.js";
18
18
  export * from "./SecureSession.js";
19
19
  export * from "./Session.js";
20
+ export * from "./SessionIntervals.js";
20
21
  export * from "./SessionManager.js";
@@ -60,6 +60,8 @@ export class PaseClientMessenger extends SecureChannelMessenger {
60
60
  SecureMessageType.PbkdfParamResponse,
61
61
  DEFAULT_NORMAL_PROCESSING_TIME,
62
62
  );
63
+
64
+ // TODO Add support for BUSY response and resend the message after waiting time
63
65
  return { responsePayload: payload, response: TlvPbkdfParamResponse.decode(payload) as PbkdfParamResponse };
64
66
  }
65
67