@matter/protocol 0.14.0-alpha.0-20250531-7ed2d6da8 → 0.14.0-alpha.0-20250601-939a65f46

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 (57) hide show
  1. package/dist/cjs/peer/ControllerCommissioner.d.ts.map +1 -1
  2. package/dist/cjs/peer/ControllerCommissioner.js +2 -2
  3. package/dist/cjs/peer/ControllerCommissioner.js.map +1 -1
  4. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts +34 -1
  5. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  6. package/dist/cjs/peer/ControllerCommissioningFlow.js +81 -27
  7. package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
  8. package/dist/cjs/peer/ControllerDiscovery.d.ts.map +1 -1
  9. package/dist/cjs/peer/ControllerDiscovery.js +3 -3
  10. package/dist/cjs/peer/ControllerDiscovery.js.map +1 -1
  11. package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
  12. package/dist/cjs/peer/PeerSet.js +39 -26
  13. package/dist/cjs/peer/PeerSet.js.map +1 -1
  14. package/dist/cjs/securechannel/SecureChannelMessenger.d.ts.map +1 -1
  15. package/dist/cjs/securechannel/SecureChannelMessenger.js +3 -1
  16. package/dist/cjs/securechannel/SecureChannelMessenger.js.map +1 -1
  17. package/dist/cjs/session/SessionManager.d.ts +10 -2
  18. package/dist/cjs/session/SessionManager.d.ts.map +1 -1
  19. package/dist/cjs/session/SessionManager.js +24 -8
  20. package/dist/cjs/session/SessionManager.js.map +1 -1
  21. package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
  22. package/dist/cjs/session/case/CaseClient.js.map +1 -1
  23. package/dist/cjs/session/case/CaseMessenger.js +1 -1
  24. package/dist/cjs/session/case/CaseMessenger.js.map +1 -1
  25. package/dist/esm/peer/ControllerCommissioner.d.ts.map +1 -1
  26. package/dist/esm/peer/ControllerCommissioner.js +4 -3
  27. package/dist/esm/peer/ControllerCommissioner.js.map +1 -1
  28. package/dist/esm/peer/ControllerCommissioningFlow.d.ts +34 -1
  29. package/dist/esm/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  30. package/dist/esm/peer/ControllerCommissioningFlow.js +81 -27
  31. package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
  32. package/dist/esm/peer/ControllerDiscovery.d.ts.map +1 -1
  33. package/dist/esm/peer/ControllerDiscovery.js +3 -3
  34. package/dist/esm/peer/ControllerDiscovery.js.map +1 -1
  35. package/dist/esm/peer/PeerSet.d.ts.map +1 -1
  36. package/dist/esm/peer/PeerSet.js +40 -27
  37. package/dist/esm/peer/PeerSet.js.map +1 -1
  38. package/dist/esm/securechannel/SecureChannelMessenger.d.ts.map +1 -1
  39. package/dist/esm/securechannel/SecureChannelMessenger.js +3 -1
  40. package/dist/esm/securechannel/SecureChannelMessenger.js.map +1 -1
  41. package/dist/esm/session/SessionManager.d.ts +10 -2
  42. package/dist/esm/session/SessionManager.d.ts.map +1 -1
  43. package/dist/esm/session/SessionManager.js +24 -8
  44. package/dist/esm/session/SessionManager.js.map +1 -1
  45. package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
  46. package/dist/esm/session/case/CaseClient.js.map +1 -1
  47. package/dist/esm/session/case/CaseMessenger.js +1 -1
  48. package/dist/esm/session/case/CaseMessenger.js.map +1 -1
  49. package/package.json +6 -6
  50. package/src/peer/ControllerCommissioner.ts +3 -2
  51. package/src/peer/ControllerCommissioningFlow.ts +87 -38
  52. package/src/peer/ControllerDiscovery.ts +3 -3
  53. package/src/peer/PeerSet.ts +56 -30
  54. package/src/securechannel/SecureChannelMessenger.ts +3 -1
  55. package/src/session/SessionManager.ts +24 -7
  56. package/src/session/case/CaseClient.ts +1 -0
  57. package/src/session/case/CaseMessenger.ts +1 -1
@@ -31,13 +31,14 @@ import {
31
31
  import { SubscriptionClient } from "#interaction/SubscriptionClient.js";
32
32
  import { MdnsScanner } from "#mdns/MdnsScanner.js";
33
33
  import { PeerAddress, PeerAddressMap } from "#peer/PeerAddress.js";
34
+ import { ChannelStatusResponseError } from "#securechannel/index.js";
34
35
  import { CaseClient, SecureSession, Session } from "#session/index.js";
35
36
  import { SessionManager } from "#session/SessionManager.js";
36
- import { SECURE_CHANNEL_PROTOCOL_ID } from "#types";
37
+ import { NodeId, ProtocolStatusCode, SECURE_CHANNEL_PROTOCOL_ID } from "#types";
37
38
  import { ChannelManager } from "../protocol/ChannelManager.js";
38
39
  import { ChannelNotConnectedError, ExchangeManager, MessageChannel } from "../protocol/ExchangeManager.js";
39
40
  import { DedicatedChannelExchangeProvider, ReconnectableExchangeProvider } from "../protocol/ExchangeProvider.js";
40
- import { RetransmissionLimitReachedError } from "../protocol/MessageExchange.js";
41
+ import { MessageExchange, RetransmissionLimitReachedError } from "../protocol/MessageExchange.js";
41
42
  import { ControllerDiscovery, DiscoveryError, PairRetransmissionLimitReachedError } from "./ControllerDiscovery.js";
42
43
  import { InteractionQueue } from "./InteractionQueue.js";
43
44
  import { OperationalPeer } from "./OperationalPeer.js";
@@ -654,42 +655,67 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
654
655
  },
655
656
  isInitiator: true,
656
657
  });
657
- const operationalUnsecureMessageExchange = new MessageChannel(operationalChannel, unsecureSession);
658
- let operationalSecureSession;
658
+
659
659
  try {
660
- const exchange = this.#exchanges.initiateExchangeWithChannel(
661
- operationalUnsecureMessageExchange,
662
- SECURE_CHANNEL_PROTOCOL_ID,
660
+ const operationalSecureSession = await this.#doCasePair(
661
+ new MessageChannel(operationalChannel, unsecureSession),
662
+ address,
663
+ expectedProcessingTimeMs,
663
664
  );
664
665
 
665
- try {
666
- const { session, resumed } = await this.#caseClient.pair(
667
- exchange,
668
- this.#sessions.fabricFor(address),
669
- address.nodeId,
670
- expectedProcessingTimeMs,
671
- );
672
- operationalSecureSession = session;
673
-
674
- if (!resumed) {
675
- // When the session was not resumed then most likely the device firmware got updated, so we clear the cache
676
- this.#nodeCachedData.delete(address);
677
- }
678
- } catch (e) {
679
- await exchange.close();
680
- throw e;
681
- }
682
- } catch (e) {
683
- NoResponseTimeoutError.accept(e);
666
+ const channel = new MessageChannel(operationalChannel, operationalSecureSession);
667
+ await this.#channels.setChannel(address, channel);
668
+ return channel;
669
+ } catch (error) {
670
+ NoResponseTimeoutError.accept(error);
684
671
 
685
672
  // Convert error
686
- throw new PairRetransmissionLimitReachedError(e.message);
673
+ throw new PairRetransmissionLimitReachedError(error.message);
687
674
  } finally {
688
675
  await unsecureSession.destroy();
689
676
  }
690
- const channel = new MessageChannel(operationalChannel, operationalSecureSession);
691
- await this.#channels.setChannel(address, channel);
692
- return channel;
677
+ }
678
+
679
+ async #doCasePair(
680
+ unsecureMessageChannel: MessageChannel,
681
+ address: PeerAddress,
682
+ expectedProcessingTimeMs?: number,
683
+ ): Promise<SecureSession> {
684
+ const fabric = this.#sessions.fabricFor(address);
685
+ let exchange: MessageExchange | undefined;
686
+ try {
687
+ exchange = this.#exchanges.initiateExchangeWithChannel(unsecureMessageChannel, SECURE_CHANNEL_PROTOCOL_ID);
688
+
689
+ const { session, resumed } = await this.#caseClient.pair(
690
+ exchange,
691
+ fabric,
692
+ address.nodeId,
693
+ expectedProcessingTimeMs,
694
+ );
695
+
696
+ if (!resumed) {
697
+ // When the session was not resumed then most likely the device firmware got updated, so we clear the cache
698
+ this.#nodeCachedData.delete(address);
699
+ }
700
+ return session;
701
+ } catch (error) {
702
+ await exchange?.close();
703
+
704
+ if (
705
+ error instanceof ChannelStatusResponseError &&
706
+ error.protocolStatusCode === ProtocolStatusCode.NoSharedTrustRoots
707
+ ) {
708
+ // It seems the stored resumption record is outdated; we need to retry pairing without resumption
709
+ if (await this.#sessions.deleteResumptionRecord(fabric.addressOf(address.nodeId))) {
710
+ logger.info(
711
+ `Case client: Resumption record seems outdated for Fabric ${NodeId.toHexString(fabric.nodeId)} (index ${fabric.fabricIndex}) and PeerNode ${NodeId.toHexString(address.nodeId)}. Retrying pairing without resumption...`,
712
+ );
713
+ // An endless loop should not happen here, as the resumption record is deleted in the next step
714
+ return await this.#doCasePair(unsecureMessageChannel, address, expectedProcessingTimeMs);
715
+ }
716
+ }
717
+ throw error;
718
+ }
693
719
  }
694
720
 
695
721
  /**
@@ -23,7 +23,9 @@ export class ChannelStatusResponseError extends MatterError {
23
23
  public readonly generalStatusCode: GeneralStatusCode,
24
24
  public readonly protocolStatusCode: ProtocolStatusCode,
25
25
  ) {
26
- super(`(${generalStatusCode}/${protocolStatusCode}) ${message}`);
26
+ super(
27
+ `(${GeneralStatusCode[generalStatusCode]} (${generalStatusCode}) / ${ProtocolStatusCode[protocolStatusCode]} (${protocolStatusCode})) ${message}`,
28
+ );
27
29
  }
28
30
  }
29
31
 
@@ -135,9 +135,9 @@ export class SessionManager {
135
135
  this.#sessionParameters = { ...DEFAULT_SESSION_PARAMETERS, ...context.parameters };
136
136
 
137
137
  // When fabric is removed, also remove the resumption record
138
- this.#observers.on(context.fabrics.events.deleted, async fabric =>
139
- this.deleteResumptionRecordsForFabric(fabric),
140
- );
138
+ this.#observers.on(context.fabrics.events.deleted, async fabric => {
139
+ await this.deleteResumptionRecordsForFabric(fabric);
140
+ });
141
141
 
142
142
  this.#construction = Construction(this, () => this.#initialize());
143
143
  }
@@ -308,23 +308,40 @@ export class SessionManager {
308
308
  return session;
309
309
  }
310
310
 
311
+ /**
312
+ * Deletes a resumption record for a given address. Returns true if the record was deleted, false if it did not
313
+ * exist.
314
+ */
311
315
  async deleteResumptionRecord(address: PeerAddress) {
312
316
  await this.#construction;
313
317
 
314
- this.#resumptionRecords.delete(address);
315
- await this.#storeResumptionRecords();
318
+ const result = this.#resumptionRecords.delete(address);
319
+ if (result) {
320
+ await this.#storeResumptionRecords();
321
+ }
322
+ return result;
316
323
  }
317
324
 
325
+ /**
326
+ * Deletes all resumption records for a given fabric. Returns true if any records were deleted, false if none
327
+ * existed.
328
+ */
318
329
  async deleteResumptionRecordsForFabric(fabric: Fabric) {
319
330
  await this.#construction;
320
331
 
332
+ let deletedCount = 0;
321
333
  for (const address of this.#resumptionRecords.keys()) {
322
334
  if (address.fabricIndex === fabric.fabricIndex) {
323
- this.#resumptionRecords.delete(address);
335
+ if (this.#resumptionRecords.delete(address)) {
336
+ deletedCount++;
337
+ }
324
338
  }
325
339
  }
326
340
 
327
- await this.#storeResumptionRecords();
341
+ if (deletedCount > 0) {
342
+ await this.#storeResumptionRecords();
343
+ }
344
+ return deletedCount > 0;
328
345
  }
329
346
 
330
347
  findOldestInactiveSession() {
@@ -37,6 +37,7 @@ export class CaseClient {
37
37
 
38
38
  async pair(exchange: MessageExchange, fabric: Fabric, peerNodeId: NodeId, expectedProcessingTimeMs?: number) {
39
39
  const messenger = new CaseClientMessenger(exchange, expectedProcessingTimeMs);
40
+
40
41
  try {
41
42
  return await this.#doPair(messenger, exchange, fabric, peerNodeId);
42
43
  } catch (error) {
@@ -46,7 +46,7 @@ export class CaseClientMessenger extends SecureChannelMessenger {
46
46
  return { sigma2Resume: TlvCaseSigma2Resume.decode(payload) };
47
47
  default:
48
48
  throw new MatterFlowError(
49
- `Received unexpected message type while expecting CASE Sigma2: ${messageType}, expected: ${SecureMessageType.Sigma2} or ${SecureMessageType.Sigma2Resume}`,
49
+ `Received unexpected message type while expecting CASE Sigma2(Resume): ${messageType}, expected: ${SecureMessageType.Sigma2} or ${SecureMessageType.Sigma2Resume}`,
50
50
  );
51
51
  }
52
52
  }