@matter/node 0.16.0-alpha.0-20251212-4dde71be3 → 0.16.0-alpha.0-20251216-71c21f901

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 (78) hide show
  1. package/LICENSE +1 -1
  2. package/dist/cjs/behavior/system/commissioning/CommissioningClient.d.ts +1 -1
  3. package/dist/cjs/behavior/system/commissioning/CommissioningClient.d.ts.map +1 -1
  4. package/dist/cjs/behavior/system/commissioning/CommissioningClient.js +31 -14
  5. package/dist/cjs/behavior/system/commissioning/CommissioningClient.js.map +2 -2
  6. package/dist/cjs/behavior/system/network/ClientNetworkRuntime.d.ts.map +1 -1
  7. package/dist/cjs/behavior/system/network/ClientNetworkRuntime.js +12 -1
  8. package/dist/cjs/behavior/system/network/ClientNetworkRuntime.js.map +1 -1
  9. package/dist/cjs/behavior/system/network/NetworkClient.d.ts +8 -4
  10. package/dist/cjs/behavior/system/network/NetworkClient.d.ts.map +1 -1
  11. package/dist/cjs/behavior/system/network/NetworkClient.js +32 -4
  12. package/dist/cjs/behavior/system/network/NetworkClient.js.map +1 -1
  13. package/dist/cjs/endpoint/properties/Behaviors.d.ts.map +1 -1
  14. package/dist/cjs/endpoint/properties/Behaviors.js +31 -1
  15. package/dist/cjs/endpoint/properties/Behaviors.js.map +1 -1
  16. package/dist/cjs/node/ClientNode.d.ts +3 -3
  17. package/dist/cjs/node/ClientNode.d.ts.map +1 -1
  18. package/dist/cjs/node/ClientNode.js +5 -4
  19. package/dist/cjs/node/ClientNode.js.map +1 -1
  20. package/dist/cjs/node/Node.d.ts.map +1 -1
  21. package/dist/cjs/node/Node.js +14 -0
  22. package/dist/cjs/node/Node.js.map +1 -1
  23. package/dist/cjs/node/client/ClientNodeInteraction.d.ts +25 -6
  24. package/dist/cjs/node/client/ClientNodeInteraction.d.ts.map +1 -1
  25. package/dist/cjs/node/client/ClientNodeInteraction.js +45 -9
  26. package/dist/cjs/node/client/ClientNodeInteraction.js.map +1 -1
  27. package/dist/cjs/node/client/ClientStructure.d.ts +1 -1
  28. package/dist/cjs/node/client/ClientStructure.d.ts.map +1 -1
  29. package/dist/cjs/node/client/ClientStructure.js +4 -3
  30. package/dist/cjs/node/client/ClientStructure.js.map +1 -1
  31. package/dist/cjs/node/client/Peers.d.ts +6 -3
  32. package/dist/cjs/node/client/Peers.d.ts.map +1 -1
  33. package/dist/cjs/node/client/Peers.js +40 -15
  34. package/dist/cjs/node/client/Peers.js.map +2 -2
  35. package/dist/esm/behavior/system/commissioning/CommissioningClient.d.ts +1 -1
  36. package/dist/esm/behavior/system/commissioning/CommissioningClient.d.ts.map +1 -1
  37. package/dist/esm/behavior/system/commissioning/CommissioningClient.js +32 -14
  38. package/dist/esm/behavior/system/commissioning/CommissioningClient.js.map +2 -2
  39. package/dist/esm/behavior/system/network/ClientNetworkRuntime.d.ts.map +1 -1
  40. package/dist/esm/behavior/system/network/ClientNetworkRuntime.js +21 -2
  41. package/dist/esm/behavior/system/network/ClientNetworkRuntime.js.map +1 -1
  42. package/dist/esm/behavior/system/network/NetworkClient.d.ts +8 -4
  43. package/dist/esm/behavior/system/network/NetworkClient.d.ts.map +1 -1
  44. package/dist/esm/behavior/system/network/NetworkClient.js +33 -5
  45. package/dist/esm/behavior/system/network/NetworkClient.js.map +1 -1
  46. package/dist/esm/endpoint/properties/Behaviors.d.ts.map +1 -1
  47. package/dist/esm/endpoint/properties/Behaviors.js +31 -1
  48. package/dist/esm/endpoint/properties/Behaviors.js.map +1 -1
  49. package/dist/esm/node/ClientNode.d.ts +3 -3
  50. package/dist/esm/node/ClientNode.d.ts.map +1 -1
  51. package/dist/esm/node/ClientNode.js +5 -4
  52. package/dist/esm/node/ClientNode.js.map +1 -1
  53. package/dist/esm/node/Node.d.ts.map +1 -1
  54. package/dist/esm/node/Node.js +16 -1
  55. package/dist/esm/node/Node.js.map +1 -1
  56. package/dist/esm/node/client/ClientNodeInteraction.d.ts +25 -6
  57. package/dist/esm/node/client/ClientNodeInteraction.d.ts.map +1 -1
  58. package/dist/esm/node/client/ClientNodeInteraction.js +47 -10
  59. package/dist/esm/node/client/ClientNodeInteraction.js.map +1 -1
  60. package/dist/esm/node/client/ClientStructure.d.ts +1 -1
  61. package/dist/esm/node/client/ClientStructure.d.ts.map +1 -1
  62. package/dist/esm/node/client/ClientStructure.js +4 -3
  63. package/dist/esm/node/client/ClientStructure.js.map +1 -1
  64. package/dist/esm/node/client/Peers.d.ts +6 -3
  65. package/dist/esm/node/client/Peers.d.ts.map +1 -1
  66. package/dist/esm/node/client/Peers.js +49 -16
  67. package/dist/esm/node/client/Peers.js.map +2 -2
  68. package/package.json +7 -7
  69. package/src/behavior/system/commissioning/CommissioningClient.ts +32 -10
  70. package/src/behavior/system/network/ClientNetworkRuntime.ts +20 -2
  71. package/src/behavior/system/network/NetworkClient.ts +39 -8
  72. package/src/endpoint/properties/Behaviors.ts +39 -1
  73. package/src/endpoint/properties/Commands.ts +1 -1
  74. package/src/node/ClientNode.ts +10 -4
  75. package/src/node/Node.ts +17 -0
  76. package/src/node/client/ClientNodeInteraction.ts +65 -16
  77. package/src/node/client/ClientStructure.ts +13 -5
  78. package/src/node/client/Peers.ts +56 -19
@@ -198,7 +198,7 @@ export class ClientStructure {
198
198
  logger.debug(
199
199
  "Received status for",
200
200
  change.kind === "attr-status" ? "attribute" : "event",
201
- Diagnostic.strong(change.path.toString()),
201
+ Diagnostic.strong(Diagnostic.dict(change.path)),
202
202
  `: ${Status[change.status]}#${change.status}${change.clusterStatus !== undefined ? `/${Status[change.clusterStatus]}#${change.clusterStatus}` : ""}`,
203
203
  );
204
204
  break;
@@ -237,10 +237,18 @@ export class ClientStructure {
237
237
  await this.#emitPendingEvents();
238
238
  }
239
239
 
240
- /** Reference to the default subscription used when the node was started. */
241
- protected get subscribedFabricFiltered() {
240
+ /** Determines if the subscription is fabric filtered */
241
+ protected get subscribedFabricFiltered(): boolean {
242
242
  if (this.#subscribedFabricFiltered === undefined) {
243
- this.#subscribedFabricFiltered = this.#node.state.network.defaultSubscription?.isFabricFiltered ?? true;
243
+ const defaultSubscription =
244
+ this.#node.state.network.defaultSubscription ??
245
+ ({} as { isFabricFiltered?: boolean; fabricFiltered?: boolean }); // Either Subscribe or Options
246
+ this.#subscribedFabricFiltered =
247
+ ("isFabricFiltered" in defaultSubscription
248
+ ? defaultSubscription.isFabricFiltered
249
+ : "fabricFiltered" in defaultSubscription
250
+ ? defaultSubscription.fabricFiltered
251
+ : true) ?? true;
244
252
  this.#node.events.network.defaultSubscription$Changed.on(newSubscription => {
245
253
  this.#subscribedFabricFiltered = newSubscription?.isFabricFiltered ?? true;
246
254
  });
@@ -293,7 +301,7 @@ export class ClientStructure {
293
301
  const { endpointId, clusterId } = occurrence.path;
294
302
 
295
303
  const endpoint = this.#endpoints.get(endpointId);
296
- // If we are building updates on current cluster or endpoint has pending changes, delay event emission
304
+ // If we are building updates on the current cluster or endpoint has pending changes, delay event emission
297
305
  if (
298
306
  (currentUpdates && (currentUpdates.endpointId === endpointId || currentUpdates.clusterId === clusterId)) ||
299
307
  (endpoint !== undefined && this.#pendingChanges?.has(endpoint))
@@ -33,7 +33,15 @@ import {
33
33
  } from "#general";
34
34
  import { ClientGroup } from "#node/ClientGroup.js";
35
35
  import { InteractionServer } from "#node/server/InteractionServer.js";
36
- import { ClientSubscriptionHandler, ClientSubscriptions, FabricManager, PeerAddress, PeerSet } from "#protocol";
36
+ import {
37
+ ClientSubscriptionHandler,
38
+ ClientSubscriptions,
39
+ FabricManager,
40
+ InteractionQueue,
41
+ PeerAddress,
42
+ PeerSet,
43
+ SessionManager,
44
+ } from "#protocol";
37
45
  import { ServerNodeStore } from "#storage/server/ServerNodeStore.js";
38
46
  import { FabricIndex } from "@matter/types";
39
47
  import { ClientNode } from "../ClientNode.js";
@@ -53,9 +61,10 @@ const EXPIRATION_INTERVAL = Minutes.one;
53
61
  */
54
62
  export class Peers extends EndpointContainer<ClientNode> {
55
63
  #expirationInterval?: CancelablePromise;
56
- #subscriptionHandler?: ClientSubscriptionHandler;
64
+ #installedSubscriptionHandler?: ClientSubscriptionHandler;
57
65
  #mutex = new Mutex(this);
58
66
  #closed = false;
67
+ #queue: InteractionQueue;
59
68
 
60
69
  constructor(owner: ServerNode) {
61
70
  super(owner);
@@ -66,6 +75,8 @@ export class Peers extends EndpointContainer<ClientNode> {
66
75
 
67
76
  owner.env.applyTo(InteractionServer, this.#configureInteractionServer.bind(this));
68
77
 
78
+ this.#queue = this.owner.env.get(InteractionQueue); // Queue is Node wide
79
+
69
80
  this.added.on(this.#handlePeerAdded.bind(this));
70
81
  this.deleted.on(this.#manageExpiration.bind(this));
71
82
 
@@ -117,16 +128,19 @@ export class Peers extends EndpointContainer<ClientNode> {
117
128
  }
118
129
 
119
130
  /**
120
- * Find a specific commissionable node.
131
+ * Find a specific commissionable node, or, if no discovery options are provided, returns the first discovered node.
132
+ * TODO: Allow to provide an array of options for multiple discoveries (e.g. from a Multi QR code).
121
133
  */
122
134
  locate(options?: Discovery.Options) {
123
135
  return new InstanceDiscovery(this.owner, options);
124
136
  }
125
137
 
126
138
  /**
127
- * Employ discovery to find a set of commissionable nodes.
139
+ * Employ discovery to find a set of commissionable nodes, the options can be used to limit the discovered devices
140
+ * (e.g. just a specific vendor).
141
+ * TODO: Allow to provide multiple identifiers for multiple discoveries (e.g. from a Multi QR code).
128
142
  *
129
- * If you do not provide a timeout value, will search until canceled and you need to add a listener to
143
+ * If you do not provide a timeout value, will search until canceled, and you need to add a listener to
130
144
  * {@link Discovery#discovered} or {@link added} to receive discovered nodes.
131
145
  */
132
146
  discover(options?: Discovery.Options) {
@@ -161,14 +175,15 @@ export class Peers extends EndpointContainer<ClientNode> {
161
175
  /**
162
176
  * Emits when fixed attributes
163
177
  */
164
-
165
178
  override get(id: number | string | PeerAddress) {
166
179
  if (typeof id !== "string" && typeof id !== "number") {
167
180
  const address = PeerAddress(id);
168
181
  for (const node of this) {
169
- const nodeAddress = node.state.commissioning.peerAddress;
170
- if (nodeAddress && PeerAddress.is(nodeAddress, address)) {
171
- return node;
182
+ if (node.behaviors.active.some(({ id }) => id === "commissioning")) {
183
+ const nodeAddress = node.maybeStateOf("commissioning")?.peerAddress as PeerAddress | undefined;
184
+ if (nodeAddress !== undefined && PeerAddress.is(nodeAddress, address)) {
185
+ return node;
186
+ }
172
187
  }
173
188
  }
174
189
  return undefined;
@@ -218,7 +233,8 @@ export class Peers extends EndpointContainer<ClientNode> {
218
233
 
219
234
  override async close() {
220
235
  this.#closed = true;
221
- await this.#subscriptionHandler?.close();
236
+ this.#queue.close();
237
+ await this.#installedSubscriptionHandler?.close();
222
238
  this.#cancelExpiration();
223
239
  await this.#mutex;
224
240
  await super.close();
@@ -242,18 +258,19 @@ export class Peers extends EndpointContainer<ClientNode> {
242
258
  * If required, installs a listener in the environment's {@link InteractionServer} to handle subscription responses.
243
259
  */
244
260
  #configureInteractionServer() {
245
- if (this.#closed || this.size > 0 || !this.owner.env.has(InteractionServer)) {
261
+ if (
262
+ this.#closed ||
263
+ this.#installedSubscriptionHandler !== undefined ||
264
+ !this.owner.env.has(InteractionServer)
265
+ ) {
246
266
  return;
247
267
  }
248
268
 
249
269
  const subscriptions = this.owner.env.get(ClientSubscriptions);
250
270
  const interactionServer = this.owner.env.get(InteractionServer);
251
271
 
252
- if (!this.#subscriptionHandler) {
253
- this.#subscriptionHandler = new ClientSubscriptionHandler(subscriptions);
254
- }
255
-
256
- interactionServer.clientHandler = this.#subscriptionHandler;
272
+ this.#installedSubscriptionHandler = new ClientSubscriptionHandler(subscriptions);
273
+ interactionServer.clientHandler = this.#installedSubscriptionHandler;
257
274
  }
258
275
 
259
276
  /**
@@ -281,6 +298,9 @@ export class Peers extends EndpointContainer<ClientNode> {
281
298
  }
282
299
 
283
300
  #onExpirationIntervalElapsed() {
301
+ if (this.#closed) {
302
+ return;
303
+ }
284
304
  this.#mutex.run(() =>
285
305
  this.#cullExpiredNodesAndAddresses()
286
306
  .catch(error => {
@@ -297,7 +317,13 @@ export class Peers extends EndpointContainer<ClientNode> {
297
317
  const now = Time.nowMs;
298
318
 
299
319
  for (const node of this) {
300
- const state = node.state.commissioning;
320
+ if (!node.lifecycle.isReady) {
321
+ continue;
322
+ }
323
+ const state = node.maybeStateOf(CommissioningClient);
324
+ if (state === undefined) {
325
+ continue;
326
+ }
301
327
  const { addresses } = state;
302
328
  const isCommissioned = state.peerAddress !== undefined;
303
329
 
@@ -358,6 +384,10 @@ export class Peers extends EndpointContainer<ClientNode> {
358
384
  node.eventsOf(type).capabilityMinima$Changed.on(setPeerLimits);
359
385
 
360
386
  function setPeerLimits() {
387
+ if (!node.env.has(PeerSet)) {
388
+ // Node is not yet online, delay setting limits
389
+ return;
390
+ }
361
391
  const peerAddress = node.maybeStateOf(CommissioningClient)?.peerAddress;
362
392
  if (peerAddress) {
363
393
  node.env.get(PeerSet).for(peerAddress).limits = node.stateOf(type).capabilityMinima;
@@ -398,8 +428,15 @@ export class Peers extends EndpointContainer<ClientNode> {
398
428
  });
399
429
  }
400
430
 
401
- #onShutdown(_node: ClientNode) {
402
- // TODO
431
+ async #onShutdown(node: ClientNode) {
432
+ if (!node.lifecycle.isReady || !node.lifecycle.isOnline) {
433
+ return;
434
+ }
435
+ const peerAddress = node.maybeStateOf(CommissioningClient)?.peerAddress;
436
+ if (peerAddress !== undefined) {
437
+ // Shutdown event means the device reboots, handle it like a peer loss and remove all sessions
438
+ await this.owner.env.get(SessionManager).handlePeerShutdown(peerAddress);
439
+ }
403
440
  }
404
441
  }
405
442