@matter/node 0.16.0-alpha.0-20250819-0a388db8b → 0.16.0-alpha.0-20250821-dd03e1003

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 (195) hide show
  1. package/dist/cjs/behavior/Events.d.ts +5 -0
  2. package/dist/cjs/behavior/Events.d.ts.map +1 -1
  3. package/dist/cjs/behavior/Events.js +7 -4
  4. package/dist/cjs/behavior/Events.js.map +1 -1
  5. package/dist/cjs/behavior/Transitions.d.ts.map +1 -1
  6. package/dist/cjs/behavior/Transitions.js +2 -2
  7. package/dist/cjs/behavior/Transitions.js.map +1 -1
  8. package/dist/cjs/behavior/context/ActionContext.d.ts +0 -7
  9. package/dist/cjs/behavior/context/ActionContext.d.ts.map +1 -1
  10. package/dist/cjs/behavior/context/server/ContextAgents.d.ts +4 -5
  11. package/dist/cjs/behavior/context/server/ContextAgents.d.ts.map +1 -1
  12. package/dist/cjs/behavior/context/server/ContextAgents.js +9 -0
  13. package/dist/cjs/behavior/context/server/ContextAgents.js.map +1 -1
  14. package/dist/cjs/behavior/context/server/OfflineContext.d.ts.map +1 -1
  15. package/dist/cjs/behavior/context/server/OfflineContext.js +0 -8
  16. package/dist/cjs/behavior/context/server/OfflineContext.js.map +1 -1
  17. package/dist/cjs/behavior/context/server/OnlineContext.d.ts.map +1 -1
  18. package/dist/cjs/behavior/context/server/OnlineContext.js +0 -8
  19. package/dist/cjs/behavior/context/server/OnlineContext.js.map +1 -1
  20. package/dist/cjs/behavior/internal/Reactors.js +1 -1
  21. package/dist/cjs/behavior/internal/Reactors.js.map +1 -1
  22. package/dist/cjs/behavior/system/commissioning/CommissioningClient.d.ts.map +1 -1
  23. package/dist/cjs/behavior/system/commissioning/CommissioningClient.js +58 -58
  24. package/dist/cjs/behavior/system/commissioning/CommissioningClient.js.map +1 -1
  25. package/dist/cjs/behavior/system/network/ClientNetworkRuntime.d.ts +1 -0
  26. package/dist/cjs/behavior/system/network/ClientNetworkRuntime.d.ts.map +1 -1
  27. package/dist/cjs/behavior/system/network/ClientNetworkRuntime.js +40 -4
  28. package/dist/cjs/behavior/system/network/ClientNetworkRuntime.js.map +2 -2
  29. package/dist/cjs/behavior/system/network/NetworkBehavior.d.ts +5 -0
  30. package/dist/cjs/behavior/system/network/NetworkBehavior.d.ts.map +1 -1
  31. package/dist/cjs/behavior/system/network/NetworkBehavior.js +5 -0
  32. package/dist/cjs/behavior/system/network/NetworkBehavior.js.map +1 -1
  33. package/dist/cjs/behavior/system/network/NetworkClient.d.ts +7 -4
  34. package/dist/cjs/behavior/system/network/NetworkClient.d.ts.map +1 -1
  35. package/dist/cjs/behavior/system/network/NetworkClient.js +14 -7
  36. package/dist/cjs/behavior/system/network/NetworkClient.js.map +1 -1
  37. package/dist/cjs/behavior/system/network/NetworkRuntime.d.ts.map +1 -1
  38. package/dist/cjs/behavior/system/network/NetworkRuntime.js +0 -1
  39. package/dist/cjs/behavior/system/network/NetworkRuntime.js.map +1 -1
  40. package/dist/cjs/behavior/system/network/ServerNetworkRuntime.d.ts.map +1 -1
  41. package/dist/cjs/behavior/system/network/ServerNetworkRuntime.js +1 -0
  42. package/dist/cjs/behavior/system/network/ServerNetworkRuntime.js.map +1 -1
  43. package/dist/cjs/behavior/system/parts/PartsBehavior.js +1 -1
  44. package/dist/cjs/behavior/system/parts/PartsBehavior.js.map +1 -1
  45. package/dist/cjs/behavior/system/product-description/ProductDescriptionServer.js +1 -1
  46. package/dist/cjs/behavior/system/product-description/ProductDescriptionServer.js.map +1 -1
  47. package/dist/cjs/behaviors/general-commissioning/ServerNodeFailsafeContext.js +1 -1
  48. package/dist/cjs/behaviors/general-commissioning/ServerNodeFailsafeContext.js.map +1 -1
  49. package/dist/cjs/behaviors/groups/GroupsServer.js +4 -4
  50. package/dist/cjs/behaviors/groups/GroupsServer.js.map +1 -1
  51. package/dist/cjs/endpoint/Agent.js +1 -1
  52. package/dist/cjs/endpoint/Agent.js.map +1 -1
  53. package/dist/cjs/endpoint/Endpoint.d.ts +9 -0
  54. package/dist/cjs/endpoint/Endpoint.d.ts.map +1 -1
  55. package/dist/cjs/endpoint/Endpoint.js +12 -1
  56. package/dist/cjs/endpoint/Endpoint.js.map +1 -1
  57. package/dist/cjs/endpoint/properties/Behaviors.js +3 -3
  58. package/dist/cjs/endpoint/properties/Behaviors.js.map +1 -1
  59. package/dist/cjs/endpoint/properties/Commands.js +1 -1
  60. package/dist/cjs/endpoint/properties/Commands.js.map +1 -1
  61. package/dist/cjs/node/ClientNode.d.ts +12 -0
  62. package/dist/cjs/node/ClientNode.d.ts.map +1 -1
  63. package/dist/cjs/node/ClientNode.js +28 -0
  64. package/dist/cjs/node/ClientNode.js.map +1 -1
  65. package/dist/cjs/node/Node.d.ts.map +1 -1
  66. package/dist/cjs/node/Node.js +2 -0
  67. package/dist/cjs/node/Node.js.map +1 -1
  68. package/dist/cjs/node/client/ClientBehavior.js +11 -4
  69. package/dist/cjs/node/client/ClientBehavior.js.map +1 -1
  70. package/dist/cjs/node/client/ClientEventEmitter.d.ts +19 -0
  71. package/dist/cjs/node/client/ClientEventEmitter.d.ts.map +1 -0
  72. package/dist/cjs/node/client/ClientEventEmitter.js +97 -0
  73. package/dist/cjs/node/client/ClientEventEmitter.js.map +6 -0
  74. package/dist/cjs/node/client/ClientStructure.d.ts +7 -3
  75. package/dist/cjs/node/client/ClientStructure.d.ts.map +1 -1
  76. package/dist/cjs/node/client/ClientStructure.js +42 -22
  77. package/dist/cjs/node/client/ClientStructure.js.map +1 -1
  78. package/dist/cjs/node/client/NodePeerAddressStore.d.ts +4 -1
  79. package/dist/cjs/node/client/NodePeerAddressStore.d.ts.map +1 -1
  80. package/dist/cjs/node/server/IdentityService.js +1 -1
  81. package/dist/cjs/node/server/IdentityService.js.map +1 -1
  82. package/dist/cjs/node/server/ProtocolService.js +1 -1
  83. package/dist/cjs/node/server/ProtocolService.js.map +1 -1
  84. package/dist/esm/behavior/Events.d.ts +5 -0
  85. package/dist/esm/behavior/Events.d.ts.map +1 -1
  86. package/dist/esm/behavior/Events.js +8 -4
  87. package/dist/esm/behavior/Events.js.map +1 -1
  88. package/dist/esm/behavior/Transitions.d.ts.map +1 -1
  89. package/dist/esm/behavior/Transitions.js +2 -2
  90. package/dist/esm/behavior/Transitions.js.map +1 -1
  91. package/dist/esm/behavior/context/ActionContext.d.ts +0 -7
  92. package/dist/esm/behavior/context/ActionContext.d.ts.map +1 -1
  93. package/dist/esm/behavior/context/server/ContextAgents.d.ts +4 -5
  94. package/dist/esm/behavior/context/server/ContextAgents.d.ts.map +1 -1
  95. package/dist/esm/behavior/context/server/ContextAgents.js +9 -0
  96. package/dist/esm/behavior/context/server/ContextAgents.js.map +1 -1
  97. package/dist/esm/behavior/context/server/OfflineContext.d.ts.map +1 -1
  98. package/dist/esm/behavior/context/server/OfflineContext.js +0 -8
  99. package/dist/esm/behavior/context/server/OfflineContext.js.map +1 -1
  100. package/dist/esm/behavior/context/server/OnlineContext.d.ts.map +1 -1
  101. package/dist/esm/behavior/context/server/OnlineContext.js +0 -8
  102. package/dist/esm/behavior/context/server/OnlineContext.js.map +1 -1
  103. package/dist/esm/behavior/internal/Reactors.js +1 -1
  104. package/dist/esm/behavior/internal/Reactors.js.map +1 -1
  105. package/dist/esm/behavior/system/commissioning/CommissioningClient.d.ts.map +1 -1
  106. package/dist/esm/behavior/system/commissioning/CommissioningClient.js +58 -58
  107. package/dist/esm/behavior/system/commissioning/CommissioningClient.js.map +1 -1
  108. package/dist/esm/behavior/system/network/ClientNetworkRuntime.d.ts +1 -0
  109. package/dist/esm/behavior/system/network/ClientNetworkRuntime.d.ts.map +1 -1
  110. package/dist/esm/behavior/system/network/ClientNetworkRuntime.js +42 -6
  111. package/dist/esm/behavior/system/network/ClientNetworkRuntime.js.map +2 -2
  112. package/dist/esm/behavior/system/network/NetworkBehavior.d.ts +5 -0
  113. package/dist/esm/behavior/system/network/NetworkBehavior.d.ts.map +1 -1
  114. package/dist/esm/behavior/system/network/NetworkBehavior.js +5 -0
  115. package/dist/esm/behavior/system/network/NetworkBehavior.js.map +1 -1
  116. package/dist/esm/behavior/system/network/NetworkClient.d.ts +7 -4
  117. package/dist/esm/behavior/system/network/NetworkClient.d.ts.map +1 -1
  118. package/dist/esm/behavior/system/network/NetworkClient.js +14 -7
  119. package/dist/esm/behavior/system/network/NetworkClient.js.map +1 -1
  120. package/dist/esm/behavior/system/network/NetworkRuntime.d.ts.map +1 -1
  121. package/dist/esm/behavior/system/network/NetworkRuntime.js +0 -1
  122. package/dist/esm/behavior/system/network/NetworkRuntime.js.map +1 -1
  123. package/dist/esm/behavior/system/network/ServerNetworkRuntime.d.ts.map +1 -1
  124. package/dist/esm/behavior/system/network/ServerNetworkRuntime.js +1 -0
  125. package/dist/esm/behavior/system/network/ServerNetworkRuntime.js.map +1 -1
  126. package/dist/esm/behavior/system/parts/PartsBehavior.js +1 -1
  127. package/dist/esm/behavior/system/parts/PartsBehavior.js.map +1 -1
  128. package/dist/esm/behavior/system/product-description/ProductDescriptionServer.js +1 -1
  129. package/dist/esm/behavior/system/product-description/ProductDescriptionServer.js.map +1 -1
  130. package/dist/esm/behaviors/general-commissioning/ServerNodeFailsafeContext.js +1 -1
  131. package/dist/esm/behaviors/general-commissioning/ServerNodeFailsafeContext.js.map +1 -1
  132. package/dist/esm/behaviors/groups/GroupsServer.js +4 -4
  133. package/dist/esm/behaviors/groups/GroupsServer.js.map +1 -1
  134. package/dist/esm/endpoint/Agent.js +1 -1
  135. package/dist/esm/endpoint/Agent.js.map +1 -1
  136. package/dist/esm/endpoint/Endpoint.d.ts +9 -0
  137. package/dist/esm/endpoint/Endpoint.d.ts.map +1 -1
  138. package/dist/esm/endpoint/Endpoint.js +12 -1
  139. package/dist/esm/endpoint/Endpoint.js.map +1 -1
  140. package/dist/esm/endpoint/properties/Behaviors.js +3 -3
  141. package/dist/esm/endpoint/properties/Behaviors.js.map +1 -1
  142. package/dist/esm/endpoint/properties/Commands.js +1 -1
  143. package/dist/esm/endpoint/properties/Commands.js.map +1 -1
  144. package/dist/esm/node/ClientNode.d.ts +12 -0
  145. package/dist/esm/node/ClientNode.d.ts.map +1 -1
  146. package/dist/esm/node/ClientNode.js +28 -0
  147. package/dist/esm/node/ClientNode.js.map +1 -1
  148. package/dist/esm/node/Node.d.ts.map +1 -1
  149. package/dist/esm/node/Node.js +2 -0
  150. package/dist/esm/node/Node.js.map +1 -1
  151. package/dist/esm/node/client/ClientBehavior.js +11 -4
  152. package/dist/esm/node/client/ClientBehavior.js.map +1 -1
  153. package/dist/esm/node/client/ClientEventEmitter.d.ts +19 -0
  154. package/dist/esm/node/client/ClientEventEmitter.d.ts.map +1 -0
  155. package/dist/esm/node/client/ClientEventEmitter.js +77 -0
  156. package/dist/esm/node/client/ClientEventEmitter.js.map +6 -0
  157. package/dist/esm/node/client/ClientStructure.d.ts +7 -3
  158. package/dist/esm/node/client/ClientStructure.d.ts.map +1 -1
  159. package/dist/esm/node/client/ClientStructure.js +42 -22
  160. package/dist/esm/node/client/ClientStructure.js.map +1 -1
  161. package/dist/esm/node/client/NodePeerAddressStore.d.ts +4 -1
  162. package/dist/esm/node/client/NodePeerAddressStore.d.ts.map +1 -1
  163. package/dist/esm/node/server/IdentityService.js +1 -1
  164. package/dist/esm/node/server/IdentityService.js.map +1 -1
  165. package/dist/esm/node/server/ProtocolService.js +1 -1
  166. package/dist/esm/node/server/ProtocolService.js.map +1 -1
  167. package/package.json +7 -7
  168. package/src/behavior/Events.ts +19 -6
  169. package/src/behavior/Transitions.ts +7 -6
  170. package/src/behavior/context/ActionContext.ts +0 -6
  171. package/src/behavior/context/server/ContextAgents.ts +17 -1
  172. package/src/behavior/context/server/OfflineContext.ts +0 -11
  173. package/src/behavior/context/server/OnlineContext.ts +0 -12
  174. package/src/behavior/internal/Reactors.ts +1 -1
  175. package/src/behavior/system/commissioning/CommissioningClient.ts +61 -59
  176. package/src/behavior/system/network/ClientNetworkRuntime.ts +59 -6
  177. package/src/behavior/system/network/NetworkBehavior.ts +6 -1
  178. package/src/behavior/system/network/NetworkClient.ts +17 -9
  179. package/src/behavior/system/network/NetworkRuntime.ts +0 -1
  180. package/src/behavior/system/network/ServerNetworkRuntime.ts +2 -0
  181. package/src/behavior/system/parts/PartsBehavior.ts +1 -1
  182. package/src/behavior/system/product-description/ProductDescriptionServer.ts +1 -1
  183. package/src/behaviors/general-commissioning/ServerNodeFailsafeContext.ts +1 -1
  184. package/src/behaviors/groups/GroupsServer.ts +4 -4
  185. package/src/endpoint/Agent.ts +1 -1
  186. package/src/endpoint/Endpoint.ts +14 -1
  187. package/src/endpoint/properties/Behaviors.ts +3 -3
  188. package/src/endpoint/properties/Commands.ts +1 -1
  189. package/src/node/ClientNode.ts +34 -1
  190. package/src/node/Node.ts +2 -0
  191. package/src/node/client/ClientBehavior.ts +12 -5
  192. package/src/node/client/ClientEventEmitter.ts +115 -0
  193. package/src/node/client/ClientStructure.ts +58 -34
  194. package/src/node/server/IdentityService.ts +1 -1
  195. package/src/node/server/ProtocolService.ts +1 -1
@@ -75,6 +75,7 @@ function generateType(analysis: ShapeAnalysis, baseType: Behavior.Type): Cluster
75
75
  }
76
76
 
77
77
  let { schema } = analysis;
78
+ let isCloned = false;
78
79
  const { extraAttrs, extraCommands } = analysis;
79
80
 
80
81
  // Obtain a ClusterType. This provides TLV for known elements
@@ -99,8 +100,7 @@ function generateType(analysis: ShapeAnalysis, baseType: Behavior.Type): Cluster
99
100
  .map(([k]) => k);
100
101
  if (featureNames.length) {
101
102
  // Update ClusterModel
102
- schema = schema.clone();
103
- schema.supportedFeatures = featureNames;
103
+ cloneSchema();
104
104
 
105
105
  // Update the cluster. Note that we do not validate feature combinations. What the device sends we work with
106
106
  cluster = new ClusterComposer(cluster, true).compose(featureNames.map(capitalize));
@@ -109,7 +109,7 @@ function generateType(analysis: ShapeAnalysis, baseType: Behavior.Type): Cluster
109
109
  // If the schema does not match what the device actually returned, further augment both the ClusterModel and
110
110
  // ClusterType with unknown attributes and/or commands
111
111
  if (schema.revision !== analysis.shape.revision || extraAttrs.size || extraCommands.size) {
112
- schema = schema.clone();
112
+ cloneSchema();
113
113
 
114
114
  cluster = {
115
115
  ...cluster,
@@ -118,8 +118,6 @@ function generateType(analysis: ShapeAnalysis, baseType: Behavior.Type): Cluster
118
118
  commands: { ...cluster.commands },
119
119
  };
120
120
 
121
- schema.supportedFeatures = supportedFeatures;
122
-
123
121
  for (const id of extraAttrs) {
124
122
  const name = createUnknownName("attr", id);
125
123
  cluster.attributes[camelize(name, false)] = Attribute(id, TlvAny);
@@ -145,6 +143,15 @@ function generateType(analysis: ShapeAnalysis, baseType: Behavior.Type): Cluster
145
143
 
146
144
  return type;
147
145
 
146
+ function cloneSchema() {
147
+ if (isCloned) {
148
+ return;
149
+ }
150
+ schema = schema.clone();
151
+ schema.supportedFeatures = featureNames;
152
+ isCloned = true;
153
+ }
154
+
148
155
  function implementCommand(command: ClusterType.Command) {
149
156
  return async function (this: ClusterBehavior, fields?: {}) {
150
157
  const node = this.env.get(Node) as ClientNode;
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { ElementEvent, Events } from "#behavior/Events.js";
8
+ import { camelize, Logger } from "#general";
9
+ import { ClusterModel, EventModel, MatterModel } from "#model";
10
+ import { ClientNode } from "#node/ClientNode.js";
11
+ import { ReadResult } from "#protocol";
12
+ import { ClusterId, EndpointNumber, EventId } from "#types";
13
+ import { ClientStructure } from "./ClientStructure.js";
14
+
15
+ const logger = Logger.get("ClientEventEmitter");
16
+
17
+ /**
18
+ * Event handler for Matter events transmitted by a peer.
19
+ *
20
+ * TODO - set priority on context when split for server vs. client
21
+ * TODO - record latest event number for each subscription shape (or just wildcard?)
22
+ */
23
+ export interface ClientEventEmitter {
24
+ (event: ReadResult.EventValue): void;
25
+ }
26
+
27
+ /**
28
+ * Cache of MatterModel + cluster + event ID -> event name.
29
+ */
30
+ const nameCache = new WeakMap<
31
+ MatterModel,
32
+ Record<`${ClusterId}-${EventId}`, undefined | { cluster: string; event: string }>
33
+ >();
34
+
35
+ /**
36
+ * We warn for each cluster or cluster+event that we don't support.
37
+ */
38
+ const warnedForUnknown = new Set<ClusterId | `${ClusterId}-${EventId}`>();
39
+
40
+ export function ClientEventEmitter(node: ClientNode, structure: ClientStructure) {
41
+ return emitClientEvent;
42
+
43
+ function emitClientEvent(occurrence: ReadResult.EventValue) {
44
+ const names = getNames(node.matter, occurrence);
45
+ if (!names) {
46
+ return;
47
+ }
48
+
49
+ const event = getEvent(occurrence.path.endpointId, names.cluster, names.event);
50
+ if (event) {
51
+ node.act(agent => {
52
+ // Current ActionContext is not writable, could skip act() but meh, see TODO above
53
+ //agent.context.priority = occurrence.priority;
54
+ event.emit(occurrence.value, agent.context);
55
+ });
56
+ }
57
+ }
58
+
59
+ function getEvent(endpointId: EndpointNumber, clusterName: string, eventName: string) {
60
+ const endpoint = structure.endpointFor(endpointId);
61
+ if (endpoint === undefined) {
62
+ logger.error(`Received event for unsupported endpoint #${endpointId}`);
63
+ return;
64
+ }
65
+
66
+ const events = (endpoint.events as Events.Generic<ElementEvent>)[clusterName];
67
+ if (events === undefined) {
68
+ logger.error(`Received event ${eventName} for unsupported cluster ${clusterName} on ${endpoint}`);
69
+ return;
70
+ }
71
+
72
+ const event = events[eventName];
73
+ if (event === undefined) {
74
+ logger.error(`Received unsupported event ${eventName} for cluster ${clusterName} on ${endpoint}`);
75
+ return;
76
+ }
77
+
78
+ return event;
79
+ }
80
+ }
81
+
82
+ function getNames(matter: MatterModel, { path: { clusterId, eventId } }: ReadResult.EventValue) {
83
+ let matterCache = nameCache.get(matter);
84
+ if (matterCache === undefined) {
85
+ matterCache = {};
86
+ nameCache.set(matter, matterCache);
87
+ }
88
+
89
+ const key = `${clusterId}-${eventId}` as const;
90
+ if (key in matterCache) {
91
+ return matterCache[key];
92
+ }
93
+
94
+ const cluster = matter.get(ClusterModel, clusterId);
95
+ if (cluster === undefined) {
96
+ if (!warnedForUnknown.has(clusterId)) {
97
+ logger.warn(`Ignoring events for unknown cluster #${clusterId}`);
98
+ warnedForUnknown.add(clusterId);
99
+ matterCache[key] = undefined;
100
+ }
101
+ return;
102
+ }
103
+
104
+ const event = cluster.get(EventModel, eventId);
105
+ if (event === undefined) {
106
+ if (!warnedForUnknown.has(key)) {
107
+ logger.warn(`Ignoring unknown event #${eventId} for ${cluster.name} cluster`);
108
+ warnedForUnknown.add(key);
109
+ matterCache[key] = undefined;
110
+ }
111
+ return;
112
+ }
113
+
114
+ return (matterCache[key] = { cluster: camelize(cluster.name), event: camelize(event.name) });
115
+ }
@@ -17,6 +17,7 @@ import { DatasourceCache } from "#storage/client/DatasourceCache.js";
17
17
  import { ClientNodeStore } from "#storage/index.js";
18
18
  import type { AttributeId, ClusterId, ClusterType, CommandId, DeviceTypeId, EndpointNumber } from "#types";
19
19
  import { ClientBehavior } from "./ClientBehavior.js";
20
+ import { ClientEventEmitter } from "./ClientEventEmitter.js";
20
21
 
21
22
  const DEVICE_TYPE_LIST_ATTR_ID = DescriptorCluster.attributes.deviceTypeList.id;
22
23
  const SERVER_LIST_ATTR_ID = DescriptorCluster.attributes.serverList.id;
@@ -28,6 +29,7 @@ const PARTS_LIST_ATTR_ID = DescriptorCluster.attributes.partsList.id;
28
29
  export class ClientStructure {
29
30
  #nodeStore: ClientNodeStore;
30
31
  #endpoints: Record<EndpointNumber, EndpointStructure> = {};
32
+ #emitEvent: ClientEventEmitter;
31
33
 
32
34
  constructor(node: ClientNode) {
33
35
  this.#nodeStore = node.env.get(ClientNodeStore);
@@ -35,6 +37,7 @@ export class ClientStructure {
35
37
  endpoint: node,
36
38
  clusters: {},
37
39
  };
40
+ this.#emitEvent = ClientEventEmitter(node, this);
38
41
  }
39
42
 
40
43
  /**
@@ -76,9 +79,9 @@ export class ClientStructure {
76
79
  }
77
80
 
78
81
  /**
82
+ * Obtain the store for a non-cluster behavior.
79
83
  *
80
- * @param request
81
- * @returns
84
+ * The data for these behaviors is managed locally and not synced from the peer.
82
85
  */
83
86
  storeForLocal(endpoint: Endpoint, type: Behavior.Type) {
84
87
  return this.#nodeStore.storeForEndpoint(endpoint).createStoreForLocalBehavior(type.id);
@@ -132,39 +135,17 @@ export class ClientStructure {
132
135
 
133
136
  for await (const chunk of changes) {
134
137
  for (const change of chunk) {
135
- if (change.kind !== "attr-value") {
136
- continue;
137
- }
138
-
139
- const { endpointId, clusterId, attributeId } = change.path;
138
+ switch (change.kind) {
139
+ case "attr-value":
140
+ currentUpdates = await this.#mutateAttribute(change, scope, currentUpdates);
141
+ break;
140
142
 
141
- // If we are building updates to a cluster and the cluster/endpoint changes, apply the current update
142
- // set
143
- if (
144
- currentUpdates &&
145
- (currentUpdates.endpointId !== endpointId || currentUpdates.clusterId !== clusterId)
146
- ) {
147
- await this.#updateCluster(currentUpdates);
148
- currentUpdates = undefined;
143
+ case "event-value":
144
+ this.#emitEvent(change);
145
+ break;
149
146
  }
150
-
151
- if (currentUpdates === undefined) {
152
- // Updating a new endpoint/cluster
153
- currentUpdates = {
154
- endpointId,
155
- clusterId,
156
- values: {
157
- [attributeId]: change.value,
158
- },
159
- };
160
-
161
- // Update version but only if this was a wildcard read
162
- if (scope.isWildcard(endpointId, clusterId)) {
163
- currentUpdates.values[DatasourceCache.VERSION_KEY] = change.version;
164
- }
165
- } else {
166
- // Add value to change set for current endpoint/cluster
167
- currentUpdates.values[attributeId] = change.value;
147
+ if (change.kind !== "attr-value") {
148
+ continue;
168
149
  }
169
150
  }
170
151
 
@@ -176,8 +157,44 @@ export class ClientStructure {
176
157
  }
177
158
  }
178
159
 
160
+ async #mutateAttribute(
161
+ change: ReadResult.AttributeValue,
162
+ scope: ReadScope,
163
+ currentUpdates: undefined | AttributeUpdates,
164
+ ) {
165
+ const { endpointId, clusterId, attributeId } = change.path;
166
+
167
+ // If we are building updates to a cluster and the cluster/endpoint changes, apply the current update
168
+ // set
169
+ if (currentUpdates && (currentUpdates.endpointId !== endpointId || currentUpdates.clusterId !== clusterId)) {
170
+ await this.#updateCluster(currentUpdates);
171
+ currentUpdates = undefined;
172
+ }
173
+
174
+ if (currentUpdates === undefined) {
175
+ // Updating a new endpoint/cluster
176
+ currentUpdates = {
177
+ endpointId,
178
+ clusterId,
179
+ values: {
180
+ [attributeId]: change.value,
181
+ },
182
+ };
183
+
184
+ // Update version but only if this was a wildcard read
185
+ if (scope.isWildcard(endpointId, clusterId)) {
186
+ currentUpdates.values[DatasourceCache.VERSION_KEY] = change.version;
187
+ }
188
+ } else {
189
+ // Add value to change set for current endpoint/cluster
190
+ currentUpdates.values[attributeId] = change.value;
191
+ }
192
+
193
+ return currentUpdates;
194
+ }
195
+
179
196
  /**
180
- * Obtain the {@link ClusterType} for an endpoint number and cluster ID.
197
+ * Obtain the {@link ClusterType} for an {@link EndpointNumber} and {@link ClusterId}.
181
198
  */
182
199
  clusterFor(endpoint: EndpointNumber, cluster: ClusterId) {
183
200
  const ep = this.#endpointFor(endpoint);
@@ -188,6 +205,13 @@ export class ClientStructure {
188
205
  return this.#clusterFor(ep, cluster)?.behavior?.cluster;
189
206
  }
190
207
 
208
+ /**
209
+ * Obtain the {@link Endpoint} for a {@link EndpointNumber}.
210
+ */
211
+ endpointFor(endpoint: EndpointNumber): Endpoint | undefined {
212
+ return this.#endpoints[endpoint]?.endpoint;
213
+ }
214
+
191
215
  /**
192
216
  * Apply new attribute values for specific endpoint/cluster.
193
217
  *
@@ -44,7 +44,7 @@ export class IdentityService {
44
44
  other = this.#node;
45
45
  } else {
46
46
  if (this.#partsById === undefined) {
47
- this.#partsById = OfflineContext.ReadOnly.agentFor(this.#node).get(IndexBehavior).partsById;
47
+ this.#partsById = this.#node.agentFor(OfflineContext.ReadOnly).get(IndexBehavior).partsById;
48
48
  }
49
49
  other = this.#partsById?.[number];
50
50
  }
@@ -602,7 +602,7 @@ function invokeCommand(
602
602
  requestDiagnostic,
603
603
  );
604
604
 
605
- const agent = context.agentFor(endpoint);
605
+ const agent = endpoint.agentFor(context);
606
606
  const behavior = agent.get(backing.type);
607
607
 
608
608
  let isAsync = false;