@matter/protocol 0.16.0-alpha.0-20251016-b56cf5683 → 0.16.0-alpha.0-20251020-3f6e46245

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 (201) hide show
  1. package/dist/cjs/action/client/ClientInteraction.d.ts +10 -5
  2. package/dist/cjs/action/client/ClientInteraction.d.ts.map +1 -1
  3. package/dist/cjs/action/client/ClientInteraction.js +129 -18
  4. package/dist/cjs/action/client/ClientInteraction.js.map +1 -1
  5. package/dist/cjs/action/request/Invoke.d.ts +36 -8
  6. package/dist/cjs/action/request/Invoke.d.ts.map +1 -1
  7. package/dist/cjs/action/request/Invoke.js +80 -15
  8. package/dist/cjs/action/request/Invoke.js.map +1 -1
  9. package/dist/cjs/action/request/Read.d.ts +1 -1
  10. package/dist/cjs/action/request/Read.d.ts.map +1 -1
  11. package/dist/cjs/action/request/Read.js +10 -2
  12. package/dist/cjs/action/request/Read.js.map +1 -1
  13. package/dist/cjs/action/request/Specifier.d.ts +16 -1
  14. package/dist/cjs/action/request/Specifier.d.ts.map +1 -1
  15. package/dist/cjs/action/request/Specifier.js +56 -1
  16. package/dist/cjs/action/request/Specifier.js.map +1 -1
  17. package/dist/cjs/action/request/Write.d.ts +5 -3
  18. package/dist/cjs/action/request/Write.d.ts.map +1 -1
  19. package/dist/cjs/action/request/Write.js +52 -12
  20. package/dist/cjs/action/request/Write.js.map +1 -1
  21. package/dist/cjs/action/response/InvokeResult.d.ts +6 -0
  22. package/dist/cjs/action/response/InvokeResult.d.ts.map +1 -1
  23. package/dist/cjs/common/FailsafeContext.d.ts +2 -1
  24. package/dist/cjs/common/FailsafeContext.d.ts.map +1 -1
  25. package/dist/cjs/common/FailsafeContext.js +10 -5
  26. package/dist/cjs/common/FailsafeContext.js.map +1 -1
  27. package/dist/cjs/common/FailsafeTimer.d.ts +2 -0
  28. package/dist/cjs/common/FailsafeTimer.d.ts.map +1 -1
  29. package/dist/cjs/common/FailsafeTimer.js +9 -0
  30. package/dist/cjs/common/FailsafeTimer.js.map +1 -1
  31. package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
  32. package/dist/cjs/interaction/InteractionClient.js +91 -74
  33. package/dist/cjs/interaction/InteractionClient.js.map +1 -1
  34. package/dist/cjs/interaction/InteractionMessenger.d.ts +3 -2
  35. package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
  36. package/dist/cjs/interaction/InteractionMessenger.js +10 -3
  37. package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
  38. package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
  39. package/dist/cjs/protocol/ExchangeManager.js +20 -17
  40. package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
  41. package/dist/cjs/protocol/MessageChannel.d.ts.map +1 -1
  42. package/dist/cjs/protocol/MessageChannel.js +1 -1
  43. package/dist/cjs/protocol/MessageChannel.js.map +1 -1
  44. package/dist/cjs/protocol/MessageExchange.d.ts +1 -0
  45. package/dist/cjs/protocol/MessageExchange.d.ts.map +1 -1
  46. package/dist/cjs/protocol/MessageExchange.js +14 -4
  47. package/dist/cjs/protocol/MessageExchange.js.map +1 -1
  48. package/dist/cjs/protocol/ProtocolHandler.d.ts +7 -2
  49. package/dist/cjs/protocol/ProtocolHandler.d.ts.map +1 -1
  50. package/dist/cjs/securechannel/SecureChannelProtocol.d.ts +1 -1
  51. package/dist/cjs/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  52. package/dist/cjs/securechannel/SecureChannelProtocol.js +5 -4
  53. package/dist/cjs/securechannel/SecureChannelProtocol.js.map +1 -1
  54. package/dist/cjs/session/GroupSession.d.ts +8 -1
  55. package/dist/cjs/session/GroupSession.d.ts.map +1 -1
  56. package/dist/cjs/session/GroupSession.js +10 -0
  57. package/dist/cjs/session/GroupSession.js.map +1 -1
  58. package/dist/cjs/session/NodeSession.d.ts +4 -1
  59. package/dist/cjs/session/NodeSession.d.ts.map +1 -1
  60. package/dist/cjs/session/NodeSession.js +17 -0
  61. package/dist/cjs/session/NodeSession.js.map +2 -2
  62. package/dist/cjs/session/SecureSession.d.ts +2 -0
  63. package/dist/cjs/session/SecureSession.d.ts.map +1 -1
  64. package/dist/cjs/session/SecureSession.js.map +1 -1
  65. package/dist/cjs/session/Session.d.ts +1 -0
  66. package/dist/cjs/session/Session.d.ts.map +1 -1
  67. package/dist/cjs/session/Session.js +4 -0
  68. package/dist/cjs/session/Session.js.map +1 -1
  69. package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
  70. package/dist/cjs/session/case/CaseClient.js +3 -15
  71. package/dist/cjs/session/case/CaseClient.js.map +1 -1
  72. package/dist/cjs/session/case/CaseMessenger.d.ts.map +1 -1
  73. package/dist/cjs/session/case/CaseMessenger.js.map +1 -1
  74. package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
  75. package/dist/cjs/session/case/CaseServer.js +10 -18
  76. package/dist/cjs/session/case/CaseServer.js.map +1 -1
  77. package/dist/cjs/session/index.d.ts +1 -0
  78. package/dist/cjs/session/index.d.ts.map +1 -1
  79. package/dist/cjs/session/index.js +1 -0
  80. package/dist/cjs/session/index.js.map +1 -1
  81. package/dist/cjs/session/pase/PaseClient.js +1 -1
  82. package/dist/cjs/session/pase/PaseClient.js.map +1 -1
  83. package/dist/cjs/session/pase/PaseMessenger.d.ts.map +1 -1
  84. package/dist/cjs/session/pase/PaseMessenger.js.map +1 -1
  85. package/dist/cjs/session/pase/PaseServer.d.ts.map +1 -1
  86. package/dist/cjs/session/pase/PaseServer.js +2 -2
  87. package/dist/cjs/session/pase/PaseServer.js.map +1 -1
  88. package/dist/esm/action/client/ClientInteraction.d.ts +10 -5
  89. package/dist/esm/action/client/ClientInteraction.d.ts.map +1 -1
  90. package/dist/esm/action/client/ClientInteraction.js +140 -20
  91. package/dist/esm/action/client/ClientInteraction.js.map +1 -1
  92. package/dist/esm/action/request/Invoke.d.ts +36 -8
  93. package/dist/esm/action/request/Invoke.d.ts.map +1 -1
  94. package/dist/esm/action/request/Invoke.js +81 -16
  95. package/dist/esm/action/request/Invoke.js.map +1 -1
  96. package/dist/esm/action/request/Read.d.ts +1 -1
  97. package/dist/esm/action/request/Read.d.ts.map +1 -1
  98. package/dist/esm/action/request/Read.js +12 -4
  99. package/dist/esm/action/request/Read.js.map +1 -1
  100. package/dist/esm/action/request/Specifier.d.ts +16 -1
  101. package/dist/esm/action/request/Specifier.d.ts.map +1 -1
  102. package/dist/esm/action/request/Specifier.js +56 -1
  103. package/dist/esm/action/request/Specifier.js.map +1 -1
  104. package/dist/esm/action/request/Write.d.ts +5 -3
  105. package/dist/esm/action/request/Write.d.ts.map +1 -1
  106. package/dist/esm/action/request/Write.js +53 -13
  107. package/dist/esm/action/request/Write.js.map +1 -1
  108. package/dist/esm/action/response/InvokeResult.d.ts +6 -0
  109. package/dist/esm/action/response/InvokeResult.d.ts.map +1 -1
  110. package/dist/esm/common/FailsafeContext.d.ts +2 -1
  111. package/dist/esm/common/FailsafeContext.d.ts.map +1 -1
  112. package/dist/esm/common/FailsafeContext.js +10 -5
  113. package/dist/esm/common/FailsafeContext.js.map +1 -1
  114. package/dist/esm/common/FailsafeTimer.d.ts +2 -0
  115. package/dist/esm/common/FailsafeTimer.d.ts.map +1 -1
  116. package/dist/esm/common/FailsafeTimer.js +9 -0
  117. package/dist/esm/common/FailsafeTimer.js.map +1 -1
  118. package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
  119. package/dist/esm/interaction/InteractionClient.js +92 -74
  120. package/dist/esm/interaction/InteractionClient.js.map +1 -1
  121. package/dist/esm/interaction/InteractionMessenger.d.ts +3 -2
  122. package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
  123. package/dist/esm/interaction/InteractionMessenger.js +10 -3
  124. package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
  125. package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
  126. package/dist/esm/protocol/ExchangeManager.js +20 -17
  127. package/dist/esm/protocol/ExchangeManager.js.map +1 -1
  128. package/dist/esm/protocol/MessageChannel.d.ts.map +1 -1
  129. package/dist/esm/protocol/MessageChannel.js +2 -2
  130. package/dist/esm/protocol/MessageChannel.js.map +1 -1
  131. package/dist/esm/protocol/MessageExchange.d.ts +1 -0
  132. package/dist/esm/protocol/MessageExchange.d.ts.map +1 -1
  133. package/dist/esm/protocol/MessageExchange.js +14 -4
  134. package/dist/esm/protocol/MessageExchange.js.map +1 -1
  135. package/dist/esm/protocol/ProtocolHandler.d.ts +7 -2
  136. package/dist/esm/protocol/ProtocolHandler.d.ts.map +1 -1
  137. package/dist/esm/securechannel/SecureChannelProtocol.d.ts +1 -1
  138. package/dist/esm/securechannel/SecureChannelProtocol.d.ts.map +1 -1
  139. package/dist/esm/securechannel/SecureChannelProtocol.js +5 -4
  140. package/dist/esm/securechannel/SecureChannelProtocol.js.map +1 -1
  141. package/dist/esm/session/GroupSession.d.ts +8 -1
  142. package/dist/esm/session/GroupSession.d.ts.map +1 -1
  143. package/dist/esm/session/GroupSession.js +11 -1
  144. package/dist/esm/session/GroupSession.js.map +1 -1
  145. package/dist/esm/session/NodeSession.d.ts +4 -1
  146. package/dist/esm/session/NodeSession.d.ts.map +1 -1
  147. package/dist/esm/session/NodeSession.js +17 -0
  148. package/dist/esm/session/NodeSession.js.map +2 -2
  149. package/dist/esm/session/SecureSession.d.ts +2 -0
  150. package/dist/esm/session/SecureSession.d.ts.map +1 -1
  151. package/dist/esm/session/SecureSession.js.map +1 -1
  152. package/dist/esm/session/Session.d.ts +1 -0
  153. package/dist/esm/session/Session.d.ts.map +1 -1
  154. package/dist/esm/session/Session.js +4 -0
  155. package/dist/esm/session/Session.js.map +1 -1
  156. package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
  157. package/dist/esm/session/case/CaseClient.js +5 -17
  158. package/dist/esm/session/case/CaseClient.js.map +1 -1
  159. package/dist/esm/session/case/CaseMessenger.d.ts.map +1 -1
  160. package/dist/esm/session/case/CaseMessenger.js.map +1 -1
  161. package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
  162. package/dist/esm/session/case/CaseServer.js +12 -20
  163. package/dist/esm/session/case/CaseServer.js.map +1 -1
  164. package/dist/esm/session/index.d.ts +1 -0
  165. package/dist/esm/session/index.d.ts.map +1 -1
  166. package/dist/esm/session/index.js +1 -0
  167. package/dist/esm/session/index.js.map +1 -1
  168. package/dist/esm/session/pase/PaseClient.js +1 -1
  169. package/dist/esm/session/pase/PaseClient.js.map +1 -1
  170. package/dist/esm/session/pase/PaseMessenger.d.ts.map +1 -1
  171. package/dist/esm/session/pase/PaseMessenger.js.map +1 -1
  172. package/dist/esm/session/pase/PaseServer.d.ts.map +1 -1
  173. package/dist/esm/session/pase/PaseServer.js +3 -2
  174. package/dist/esm/session/pase/PaseServer.js.map +1 -1
  175. package/package.json +6 -6
  176. package/src/action/client/ClientInteraction.ts +181 -27
  177. package/src/action/request/Invoke.ts +149 -27
  178. package/src/action/request/Read.ts +27 -7
  179. package/src/action/request/Specifier.ts +80 -1
  180. package/src/action/request/Write.ts +71 -19
  181. package/src/action/response/InvokeResult.ts +8 -0
  182. package/src/common/FailsafeContext.ts +15 -6
  183. package/src/common/FailsafeTimer.ts +11 -0
  184. package/src/interaction/InteractionClient.ts +135 -96
  185. package/src/interaction/InteractionMessenger.ts +15 -3
  186. package/src/protocol/ExchangeManager.ts +27 -29
  187. package/src/protocol/MessageChannel.ts +2 -2
  188. package/src/protocol/MessageExchange.ts +18 -4
  189. package/src/protocol/ProtocolHandler.ts +7 -2
  190. package/src/securechannel/SecureChannelProtocol.ts +8 -5
  191. package/src/session/GroupSession.ts +12 -1
  192. package/src/session/NodeSession.ts +26 -0
  193. package/src/session/SecureSession.ts +2 -0
  194. package/src/session/Session.ts +5 -0
  195. package/src/session/case/CaseClient.ts +3 -23
  196. package/src/session/case/CaseMessenger.ts +2 -0
  197. package/src/session/case/CaseServer.ts +15 -20
  198. package/src/session/index.ts +1 -0
  199. package/src/session/pase/PaseClient.ts +1 -1
  200. package/src/session/pase/PaseMessenger.ts +2 -0
  201. package/src/session/pase/PaseServer.ts +3 -2
@@ -41,7 +41,7 @@ export namespace Specifier {
41
41
  export type Command<C extends ClusterType = ClusterType> = ClusterType.Command | (string & keyof C["commands"]);
42
42
 
43
43
  /**
44
- * An event specifier may be the name of a cluser event or an event object.
44
+ * An event specifier may be the name of a cluster event or an event object.
45
45
  */
46
46
  export type Event<C extends ClusterType = ClusterType> = ClusterType.Event | (string & keyof C["events"]);
47
47
 
@@ -97,6 +97,26 @@ export namespace Specifier {
97
97
  ? CMD
98
98
  : never;
99
99
 
100
+ export function commandFor<const C extends ClusterType, const CMD extends Specifier.Command<C>>(
101
+ cluster: C | undefined,
102
+ specifier: CMD,
103
+ ): CommandFor<C, CMD> {
104
+ if (typeof specifier !== "string") {
105
+ return specifier as CommandFor<C, CMD>;
106
+ }
107
+
108
+ if (cluster === undefined) {
109
+ throw new MalformedRequestError(`Cannot designate command "${specifier}" without a cluster`);
110
+ }
111
+
112
+ const command = cluster.commands?.[specifier];
113
+ if (command === undefined) {
114
+ throw new MalformedRequestError(`Cluster ${cluster.name} does not define command ${specifier}`);
115
+ }
116
+
117
+ return command as CommandFor<C, CMD>;
118
+ }
119
+
100
120
  /**
101
121
  * Extract an event object from a cluster and event specifier.
102
122
  */
@@ -144,3 +164,62 @@ export namespace Specifier {
144
164
  return request.endpoint?.number;
145
165
  }
146
166
  }
167
+
168
+ export function toWildcardOrHexPath(name: string, value: number | bigint | undefined) {
169
+ if (value === undefined) {
170
+ return "*";
171
+ }
172
+ return `${name ? `${name}:` : ""}0x${value.toString(16)}`;
173
+ }
174
+
175
+ /**
176
+ * Resolve a path into a human readable textual form for logging
177
+ * TODO: Add a Diagnostic display formatter for this
178
+ */
179
+ export function resolvePathForSpecifier<const C extends ClusterType>(location: {
180
+ endpoint?: Specifier.Endpoint;
181
+ cluster?: Specifier.Cluster;
182
+ attribute?: Specifier.Attribute<Specifier.ClusterFor<C>>;
183
+ event?: Specifier.Event<Specifier.ClusterFor<C>>;
184
+ command?: Specifier.Command<Specifier.ClusterFor<C>>;
185
+ isUrgent?: boolean;
186
+ listIndex?: number | null;
187
+ }) {
188
+ const endpointId = Specifier.endpointIdOf(location);
189
+ const cluster = location.cluster ? Specifier.clusterFor(location.cluster) : undefined;
190
+ const attribute = location.attribute && cluster ? Specifier.attributeFor(cluster, location.attribute) : undefined;
191
+ const event = location.event && cluster ? Specifier.eventFor(cluster, location.event) : undefined;
192
+ const command = location.command && cluster ? Specifier.commandFor(cluster, location.command) : undefined;
193
+ const isUrgentString = "isUrgent" in location && location.isUrgent ? "!" : "";
194
+ const listIndexString = "listIndex" in location && location.listIndex === null ? "[ADD]" : "";
195
+ const postString = `${listIndexString}${isUrgentString}`;
196
+
197
+ const clusterId = cluster?.id;
198
+ const elementId = attribute ? attribute.id : event ? event.id : command ? command.requestId : undefined;
199
+
200
+ if (endpointId === undefined) {
201
+ return `*.${toWildcardOrHexPath("", clusterId)}.${toWildcardOrHexPath("", elementId)}${postString}`;
202
+ }
203
+
204
+ const endpointName = toWildcardOrHexPath("", endpointId);
205
+
206
+ if (cluster === undefined || clusterId === undefined) {
207
+ return `${endpointName}.*.${toWildcardOrHexPath("", elementId)}${postString}`;
208
+ }
209
+
210
+ const clusterName = toWildcardOrHexPath(cluster.name, clusterId);
211
+
212
+ if (elementId !== undefined) {
213
+ if (event) {
214
+ return `${endpointName}.${clusterName}.${toWildcardOrHexPath(typeof location.event === "string" ? location.event : "?", elementId)}${postString}`;
215
+ } else if (attribute) {
216
+ return `${endpointName}.${clusterName}.${toWildcardOrHexPath(typeof location.attribute === "string" ? location.attribute : "?", elementId)}${postString}`;
217
+ } else if (command) {
218
+ return `${endpointName}.${clusterName}.${toWildcardOrHexPath(typeof location.command === "string" ? location.command : "?", elementId)}${postString}`;
219
+ } else {
220
+ return "unknown";
221
+ }
222
+ } else {
223
+ return `${endpointName}.${clusterName}.*${postString}`;
224
+ }
225
+ }
@@ -4,14 +4,25 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import { FALLBACK_INTERACTIONMODEL_REVISION } from "#session/Session.js";
8
- import { AttributeData, ClusterType, WriteRequest } from "#types";
7
+ import { AccessControl } from "#clusters/access-control";
8
+ import { Diagnostic, Duration } from "#general";
9
+ import { Specification } from "#model";
10
+ import { ArraySchema, AttributeData, AttributeId, ClusterId, ClusterType, WriteRequest } from "#types";
9
11
  import { MalformedRequestError } from "./MalformedRequestError.js";
10
- import { Specifier } from "./Specifier.js";
12
+ import { resolvePathForSpecifier, Specifier } from "./Specifier.js";
13
+
14
+ const AclClusterId = AccessControl.Complete.id;
15
+ const AclAttributeId = AccessControl.Complete.attributes.acl.id;
16
+ const AclExtensionAttributeId = AccessControl.Complete.attributes.extension.id;
17
+
18
+ function isAclOrExtensionPath(path: { clusterId: ClusterId; attributeId: AttributeId }) {
19
+ const { clusterId, attributeId } = path;
20
+ return clusterId === AclClusterId && (attributeId === AclAttributeId || attributeId === AclExtensionAttributeId);
21
+ }
11
22
 
12
23
  export interface Write extends WriteRequest {
13
- /** Timeout only relevant for Client Interactions */
14
- timeout?: number;
24
+ /** Timeout only relevant for Client Interactions with a required TimedRequest flagging */
25
+ timeout?: Duration;
15
26
  }
16
27
 
17
28
  /**
@@ -41,13 +52,25 @@ export function Write(optionsOrData: Write.Options | Write.Attribute, ...data: W
41
52
  } else {
42
53
  options = optionsOrData;
43
54
  }
44
- const { writes: writeRequests = [] } = options;
55
+ const { writes: writeRequests = [], timed, timeout, chunkLists } = options;
45
56
 
46
- const result: Write = {
47
- timedRequest: !!options.timed || !!options.timeout,
57
+ const result = {
58
+ timedRequest: !!timed || !!timeout,
59
+ timeout,
48
60
  writeRequests,
49
- interactionModelRevision: options.interactionModelRevision ?? FALLBACK_INTERACTIONMODEL_REVISION,
50
- };
61
+ moreChunkedMessages: false,
62
+ interactionModelRevision: options.interactionModelRevision ?? Specification.INTERACTION_MODEL_REVISION,
63
+
64
+ [Diagnostic.value]: () =>
65
+ Diagnostic.list(
66
+ data.map(entry => {
67
+ const { version, value } = entry;
68
+ return `${resolvePathForSpecifier(entry)} = ${Diagnostic.json(
69
+ value,
70
+ )}${version !== undefined ? `(version=${version})` : ""}`;
71
+ }),
72
+ ),
73
+ } as Write;
51
74
 
52
75
  for (const entry of data) {
53
76
  reifyData(entry);
@@ -87,15 +110,43 @@ export function Write(optionsOrData: Write.Options | Write.Attribute, ...data: W
87
110
  };
88
111
 
89
112
  for (const specifier of attributes) {
113
+ const clusterId = cluster.id;
90
114
  const attribute = Specifier.attributeFor(cluster, specifier);
91
- writeRequests.push({
92
- ...prototype,
93
- path: {
94
- ...prototype.path,
95
- attributeId: attribute.id,
96
- },
97
- data: attribute.schema.encodeTlv(value, { forWriteInteraction: true }),
98
- });
115
+ const { schema, id: attributeId } = attribute;
116
+
117
+ if (
118
+ chunkLists &&
119
+ Array.isArray(value) &&
120
+ schema instanceof ArraySchema &&
121
+ // As implemented for Matter 1.4.2 in https://github.com/project-chip/connectedhomeip/pull/38263
122
+ // Acl writes will no longer be chunked by default, all others still
123
+ // Will be streamlined later ... see https://github.com/project-chip/connectedhomeip/issues/38270
124
+ !isAclOrExtensionPath({ clusterId, attributeId })
125
+ ) {
126
+ writeRequests.push(
127
+ ...schema
128
+ .encodeAsChunkedArray(value, { forWriteInteraction: true })
129
+ .map(({ element: data, listIndex }) => ({
130
+ path: {
131
+ ...prototype.path,
132
+ attributeId: attribute.id,
133
+ listIndex,
134
+ },
135
+ data,
136
+ dataVersion,
137
+ })),
138
+ );
139
+ } else {
140
+ writeRequests.push({
141
+ ...prototype,
142
+ path: {
143
+ ...prototype.path,
144
+ attributeId: attribute.id,
145
+ },
146
+ data: attribute.schema.encodeTlv(value, { forWriteInteraction: true }),
147
+ });
148
+ }
149
+ result.timedRequest ||= attribute.timed;
99
150
  }
100
151
  }
101
152
  }
@@ -104,8 +155,9 @@ export namespace Write {
104
155
  export interface Options {
105
156
  writes?: AttributeData[];
106
157
  timed?: boolean;
107
- timeout?: number;
158
+ timeout?: Duration;
108
159
  interactionModelRevision?: number;
160
+ chunkLists?: boolean;
109
161
  }
110
162
 
111
163
  /**
@@ -8,10 +8,14 @@ import type { ClusterId, CommandId, CommandPath, EndpointNumber, StatusCode, Tlv
8
8
 
9
9
  export type InvokeResult = AsyncIterable<InvokeResult.Chunk>;
10
10
 
11
+ export type DecodedInvokeResult = AsyncIterable<InvokeResult.DecodedChunk>;
12
+
11
13
  export namespace InvokeResult {
12
14
  export type Chunk = Iterable<Data>;
15
+ export type DecodedChunk = Iterable<DecodedData>;
13
16
 
14
17
  export type Data = CommandStatus | CommandResponse;
18
+ export type DecodedData = CommandStatus | DecodedCommandResponse;
15
19
 
16
20
  export interface ConcreteCommandPath extends CommandPath {
17
21
  endpointId: EndpointNumber;
@@ -33,4 +37,8 @@ export namespace InvokeResult {
33
37
  commandRef?: number;
34
38
  data: TlvStream;
35
39
  }
40
+
41
+ export interface DecodedCommandResponse extends Omit<CommandResponse, "data"> {
42
+ data: any;
43
+ }
36
44
  }
@@ -14,6 +14,7 @@ import {
14
14
  UnexpectedDataError,
15
15
  UninitializedDependencyError,
16
16
  } from "#general";
17
+ import { SecureSession } from "#session/SecureSession.js";
17
18
  import { CaseAuthenticatedTag, NodeId, ValidationError, VendorId } from "#types";
18
19
  import { Fabric, FabricBuilder } from "../fabric/Fabric.js";
19
20
  import { FabricManager } from "../fabric/FabricManager.js";
@@ -47,11 +48,11 @@ export abstract class FailsafeContext {
47
48
  #commissioned = AsyncObservable<[], void>();
48
49
 
49
50
  constructor(options: FailsafeContext.Options) {
50
- const { expiryLength, associatedFabric, maxCumulativeFailsafe } = options;
51
+ const { sessions, fabrics, expiryLength, session, maxCumulativeFailsafe } = options;
51
52
 
52
- this.#sessions = options.sessions;
53
- this.#fabrics = options.fabrics;
54
- this.#associatedFabric = options.associatedFabric;
53
+ this.#sessions = sessions;
54
+ this.#fabrics = fabrics;
55
+ this.#associatedFabric = session.fabric;
55
56
 
56
57
  this.#construction = Construction(this, async () => {
57
58
  this.#fabricBuilder = await FabricBuilder.create(this.#fabrics.crypto);
@@ -62,10 +63,18 @@ export abstract class FailsafeContext {
62
63
 
63
64
  // If ExpiryLengthSeconds is non-zero and the fail-safe timer was not currently armed, then the fail-safe
64
65
  // timer SHALL be armed for that duration.
65
- this.#failsafe = new FailsafeTimer(associatedFabric, expiryLength, maxCumulativeFailsafe, () =>
66
+ this.#failsafe = new FailsafeTimer(this.#associatedFabric, expiryLength, maxCumulativeFailsafe, () =>
66
67
  this.#failSafeExpired(),
67
68
  );
68
69
  logger.debug(`Arm failSafe timer for ${Duration.format(expiryLength)}`);
70
+
71
+ // When the PASE session used to arm the Fail-Safe timer is terminated by peer, the Fail-Safe timer SHALL
72
+ // be considered expired and do the relevant cleanup actions.
73
+ session.closedByPeer.on(() => {
74
+ if (!this.#failsafe?.completed) {
75
+ return this.#failSafeExpired();
76
+ }
77
+ });
69
78
  });
70
79
  }
71
80
 
@@ -341,6 +350,6 @@ export namespace FailsafeContext {
341
350
  fabrics: FabricManager;
342
351
  expiryLength: Duration;
343
352
  maxCumulativeFailsafe: Duration;
344
- associatedFabric: Fabric | undefined;
353
+ session: SecureSession;
345
354
  }
346
355
  }
@@ -19,6 +19,7 @@ export class FailsafeTimer {
19
19
  #expiryCallback: () => Promise<void>;
20
20
  #failsafeTimer: Timer;
21
21
  #maxCumulativeFailsafeTimer: Timer;
22
+ #completed = false;
22
23
 
23
24
  constructor(
24
25
  public associatedFabric: Fabric | undefined,
@@ -69,14 +70,24 @@ export class FailsafeTimer {
69
70
  }
70
71
  }
71
72
 
73
+ /** Returns whether the FailSafe context is currently armed. */
74
+ get completed() {
75
+ return this.#completed;
76
+ }
77
+
72
78
  /** Expire the FailSafe context. This is called by the timer and can also be called manually if needed. */
73
79
  async expire() {
80
+ if (this.#completed) {
81
+ // Completion was already triggered, so do nothing
82
+ return;
83
+ }
74
84
  this.complete();
75
85
  await this.#expiryCallback();
76
86
  }
77
87
 
78
88
  /** Complete the FailSafe context. This is called when the commissioning is completed. */
79
89
  complete() {
90
+ this.#completed = true;
80
91
  this.#failsafeTimer.stop();
81
92
  this.#maxCumulativeFailsafeTimer.stop();
82
93
  }