@matter/types 0.16.0-alpha.0-20251004-92135c7df → 0.16.0-alpha.0-20251011-d8942d7d5

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 (46) hide show
  1. package/dist/cjs/common/ModelBounds.d.ts +74 -0
  2. package/dist/cjs/common/ModelBounds.d.ts.map +1 -0
  3. package/dist/cjs/common/ModelBounds.js +102 -0
  4. package/dist/cjs/common/ModelBounds.js.map +6 -0
  5. package/dist/cjs/common/StatusResponseError.d.ts +1 -0
  6. package/dist/cjs/common/StatusResponseError.d.ts.map +1 -1
  7. package/dist/cjs/common/StatusResponseError.js +4 -1
  8. package/dist/cjs/common/StatusResponseError.js.map +1 -1
  9. package/dist/cjs/common/index.d.ts +1 -0
  10. package/dist/cjs/common/index.d.ts.map +1 -1
  11. package/dist/cjs/common/index.js +1 -0
  12. package/dist/cjs/common/index.js.map +1 -1
  13. package/dist/cjs/tlv/TlvOfModel.d.ts +9 -0
  14. package/dist/cjs/tlv/TlvOfModel.d.ts.map +1 -0
  15. package/dist/cjs/tlv/TlvOfModel.js +227 -0
  16. package/dist/cjs/tlv/TlvOfModel.js.map +6 -0
  17. package/dist/cjs/tlv/index.d.ts +1 -0
  18. package/dist/cjs/tlv/index.d.ts.map +1 -1
  19. package/dist/cjs/tlv/index.js +1 -0
  20. package/dist/cjs/tlv/index.js.map +1 -1
  21. package/dist/esm/common/ModelBounds.d.ts +74 -0
  22. package/dist/esm/common/ModelBounds.d.ts.map +1 -0
  23. package/dist/esm/common/ModelBounds.js +99 -0
  24. package/dist/esm/common/ModelBounds.js.map +6 -0
  25. package/dist/esm/common/StatusResponseError.d.ts +1 -0
  26. package/dist/esm/common/StatusResponseError.d.ts.map +1 -1
  27. package/dist/esm/common/StatusResponseError.js +4 -1
  28. package/dist/esm/common/StatusResponseError.js.map +1 -1
  29. package/dist/esm/common/index.d.ts +1 -0
  30. package/dist/esm/common/index.d.ts.map +1 -1
  31. package/dist/esm/common/index.js +1 -0
  32. package/dist/esm/common/index.js.map +1 -1
  33. package/dist/esm/tlv/TlvOfModel.d.ts +9 -0
  34. package/dist/esm/tlv/TlvOfModel.d.ts.map +1 -0
  35. package/dist/esm/tlv/TlvOfModel.js +260 -0
  36. package/dist/esm/tlv/TlvOfModel.js.map +6 -0
  37. package/dist/esm/tlv/index.d.ts +1 -0
  38. package/dist/esm/tlv/index.d.ts.map +1 -1
  39. package/dist/esm/tlv/index.js +1 -0
  40. package/dist/esm/tlv/index.js.map +1 -1
  41. package/package.json +5 -5
  42. package/src/common/ModelBounds.ts +118 -0
  43. package/src/common/StatusResponseError.ts +5 -1
  44. package/src/common/index.ts +1 -0
  45. package/src/tlv/TlvOfModel.ts +312 -0
  46. package/src/tlv/index.ts +1 -0
@@ -21,6 +21,10 @@ export class StatusResponseError extends MatterError {
21
21
  super(message);
22
22
  }
23
23
 
24
+ get bareMessage() {
25
+ return this.message.replace(/ \(code .+\)$/, "");
26
+ }
27
+
24
28
  static is(error: unknown, ...codes: Status[]): error is StatusResponseError {
25
29
  return error instanceof StatusResponseError && (!codes.length || codes.includes(error.code));
26
30
  }
@@ -77,7 +81,7 @@ export const StatusResponse = Object.fromEntries(
77
81
  codeStr = `${codeStr}; cluster code ${clusterCode}`;
78
82
  }
79
83
 
80
- this.message = `message (${codeStr})`;
84
+ this.message = `${message} (${codeStr})`;
81
85
  }
82
86
  },
83
87
  } as const;
@@ -4,6 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ export * from "./ModelBounds.js";
7
8
  export * from "./ProductDescription.js";
8
9
  export * from "./StatusCode.js";
9
10
  export * from "./StatusResponseError.js";
@@ -0,0 +1,312 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { ModelBounds } from "#common/ModelBounds.js";
8
+ import { TlvAttributeId } from "#datatype/AttributeId.js";
9
+ import { TlvClusterId } from "#datatype/ClusterId.js";
10
+ import { TlvCommandId } from "#datatype/CommandId.js";
11
+ import { TlvDeviceTypeId } from "#datatype/DeviceTypeId.js";
12
+ import { TlvEndpointNumber } from "#datatype/EndpointNumber.js";
13
+ import { TlvEventId } from "#datatype/EventId.js";
14
+ import { TlvFabricId } from "#datatype/FabricId.js";
15
+ import { TlvFabricIndex } from "#datatype/FabricIndex.js";
16
+ import { TlvGroupId } from "#datatype/GroupId.js";
17
+ import { TlvNodeId } from "#datatype/NodeId.js";
18
+ import { TlvSubjectId } from "#datatype/SubjectId.js";
19
+ import { TlvVendorId } from "#datatype/VendorId.js";
20
+ import { camelize, ImplementationError, InternalError } from "#general";
21
+ import {
22
+ attribId,
23
+ clusterId,
24
+ ClusterModel,
25
+ commandId,
26
+ devtypeId,
27
+ endpointNo,
28
+ epochS,
29
+ epochUs,
30
+ eventId,
31
+ fabricId,
32
+ fabricIdx,
33
+ groupId,
34
+ int16,
35
+ int32,
36
+ int64,
37
+ int8,
38
+ map16,
39
+ map32,
40
+ map8,
41
+ Metatype,
42
+ nodeId,
43
+ percent,
44
+ percent100ths,
45
+ posixMs,
46
+ subjectId,
47
+ systimeMs,
48
+ systimeUs,
49
+ uint16,
50
+ uint32,
51
+ uint64,
52
+ uint8,
53
+ ValueModel,
54
+ vendorId,
55
+ } from "#model";
56
+ import { BitField, BitFlag } from "#schema/BitmapSchema.js";
57
+ import { TlvAny } from "./TlvAny.js";
58
+ import { TlvArray } from "./TlvArray.js";
59
+ import { TlvBoolean } from "./TlvBoolean.js";
60
+ import { TlvNullable } from "./TlvNullable.js";
61
+ import {
62
+ TlvBitmap,
63
+ TlvDouble,
64
+ TlvEnum,
65
+ TlvEpochS,
66
+ TlvEpochUs,
67
+ TlvFloat,
68
+ TlvInt16,
69
+ TlvInt32,
70
+ TlvInt64,
71
+ TlvInt8,
72
+ TlvNumberSchema,
73
+ TlvPercent,
74
+ TlvPercent100ths,
75
+ TlvPosixMs,
76
+ TlvSysTimeMS,
77
+ TlvSysTimeUs,
78
+ TlvUInt16,
79
+ TlvUInt32,
80
+ TlvUInt64,
81
+ TlvUInt8,
82
+ } from "./TlvNumber.js";
83
+ import { TlvObject } from "./TlvObject.js";
84
+ import { TlvSchema } from "./TlvSchema.js";
85
+ import { TlvByteString, TlvString } from "./TlvString.js";
86
+
87
+ const cache = new WeakMap<ClusterModel | ValueModel, TlvSchema<unknown>>();
88
+
89
+ export function TlvOfModel(model: ClusterModel | ValueModel) {
90
+ let tlv = cache.get(model);
91
+ if (tlv === undefined) {
92
+ tlv = generateTlv(model);
93
+ cache.set(model, tlv);
94
+ }
95
+ return tlv;
96
+ }
97
+
98
+ const NumberMapping: Record<string, TlvSchema<unknown>> = {
99
+ // Signed int
100
+ [int8.name]: TlvInt8,
101
+ [int16.name]: TlvInt16,
102
+ [int32.name]: TlvInt32,
103
+ [int64.name]: TlvInt64,
104
+
105
+ // Unsigned int
106
+ [uint8.name]: TlvUInt8,
107
+ [uint16.name]: TlvUInt16,
108
+ [uint32.name]: TlvUInt32,
109
+ [uint64.name]: TlvUInt64,
110
+
111
+ // Bitmap
112
+ [map8.name]: TlvUInt8,
113
+ [map16.name]: TlvUInt16,
114
+ [map32.name]: TlvUInt32,
115
+
116
+ // ID
117
+ [attribId.name]: TlvAttributeId,
118
+ [clusterId.name]: TlvClusterId,
119
+ [commandId.name]: TlvCommandId,
120
+ [devtypeId.name]: TlvDeviceTypeId,
121
+ [endpointNo.name]: TlvEndpointNumber,
122
+ [eventId.name]: TlvEventId,
123
+ [fabricId.name]: TlvFabricId,
124
+ [fabricIdx.name]: TlvFabricIndex,
125
+ [groupId.name]: TlvGroupId,
126
+ [nodeId.name]: TlvNodeId,
127
+ [subjectId.name]: TlvSubjectId,
128
+ [vendorId.name]: TlvVendorId,
129
+
130
+ // Percent
131
+ [percent.name]: TlvPercent,
132
+ [percent100ths.name]: TlvPercent100ths,
133
+
134
+ // Time
135
+ [epochUs.name]: TlvEpochUs,
136
+ [epochS.name]: TlvEpochS,
137
+ [posixMs.name]: TlvPosixMs,
138
+ [systimeUs.name]: TlvSysTimeUs,
139
+ [systimeMs.name]: TlvSysTimeMS,
140
+
141
+ // The following are defined in the specification but we don't support them so they're apparently unused
142
+ //[int24.name]: TlvInt24,
143
+ //[int40.name]: TlvInt40,
144
+ //[int48.name]: TlvInt48,
145
+ //[uint24.name]: TlvInt24,
146
+ //[uint40.name]: TlvInt40,
147
+ //[uint48.name]: TlvInt48,
148
+ //[map64.name]: TlvUInt64,
149
+ };
150
+
151
+ function generateTlv(model: ClusterModel | ValueModel): TlvSchema<unknown> {
152
+ const metatype = model.effectiveMetatype;
153
+
154
+ // Handle structs first because then we can exclude ClusterModel as type
155
+ if (metatype === Metatype.object) {
156
+ return generateStruct(model);
157
+ }
158
+
159
+ if (!(model instanceof ValueModel)) {
160
+ throw new InternalError(`Inappropriate use of ${model.tag} model as datatype`);
161
+ }
162
+
163
+ let tlv: TlvSchema<unknown>;
164
+
165
+ const metabase = model.metabase;
166
+ if (metabase === undefined) {
167
+ throw new InternalError(`No metabase for model ${model.name}`);
168
+ }
169
+
170
+ switch (metatype) {
171
+ case Metatype.any:
172
+ tlv = TlvAny;
173
+ break;
174
+
175
+ case Metatype.boolean:
176
+ tlv = TlvBoolean;
177
+ break;
178
+
179
+ case Metatype.bitmap:
180
+ tlv = generateBitmap(model);
181
+ break;
182
+
183
+ case Metatype.array:
184
+ tlv = generateList(model);
185
+ break;
186
+
187
+ case Metatype.bytes:
188
+ tlv = generateString(TlvByteString, model);
189
+ break;
190
+
191
+ case Metatype.string:
192
+ tlv = generateString(TlvString, model);
193
+ break;
194
+
195
+ case Metatype.enum:
196
+ // Enum enforcement at TLV level is apparently type-only
197
+ tlv = TlvEnum();
198
+ break;
199
+
200
+ case Metatype.float:
201
+ if (metabase.name === "single") {
202
+ tlv = TlvFloat;
203
+ } else {
204
+ tlv = TlvDouble;
205
+ }
206
+ break;
207
+
208
+ case Metatype.integer:
209
+ tlv = generateInteger(model);
210
+ break;
211
+
212
+ default:
213
+ throw new InternalError(`No TLV mapping for model ${model.name}`);
214
+ }
215
+
216
+ if (model.quality.nullable) {
217
+ tlv = TlvNullable(tlv);
218
+ }
219
+
220
+ return tlv;
221
+ }
222
+
223
+ function generateStruct(model: ClusterModel | ValueModel) {
224
+ const entries = model.conformant.properties.map(p => [camelize(p.name), TlvOfModel(model)]);
225
+ const fields = Object.fromEntries(entries);
226
+ return TlvObject(fields);
227
+ }
228
+
229
+ function generateBitmap(model: ValueModel) {
230
+ const { fields } = model.conformant;
231
+ if (!fields.length) {
232
+ return primitiveFallbackOf(model);
233
+ }
234
+
235
+ const entries = fields.map(field => {
236
+ const name = camelize(field.name);
237
+ const { constraint } = field;
238
+
239
+ if (typeof constraint.value === "number") {
240
+ return [name, BitFlag(constraint.value)];
241
+ }
242
+
243
+ if (typeof constraint.min === "number" && typeof constraint.max === "number") {
244
+ return [name, BitField(constraint.min, constraint.max - constraint.min + 1)];
245
+ }
246
+
247
+ throw new ImplementationError(`Bit field ${field.path} is not properly constrained`);
248
+ });
249
+
250
+ const metabaseName = model.metabase?.name;
251
+ const num = metabaseName ? NumberMapping[metabaseName] : undefined;
252
+ if (!num) {
253
+ throw new ImplementationError(`Could not determine numeric type for bitmap ${model.path} type "${model.type}"`);
254
+ }
255
+
256
+ return TlvBitmap(num as TlvNumberSchema, Object.fromEntries(entries));
257
+ }
258
+
259
+ function generateList(model: ValueModel) {
260
+ const entry = model.conformant.fields.for("entry");
261
+
262
+ const bounds = ModelBounds.createLengthBounds(model);
263
+
264
+ if (entry === undefined) {
265
+ return TlvArray(TlvAny, bounds);
266
+ }
267
+
268
+ return TlvArray(TlvOfModel(model), bounds);
269
+ }
270
+
271
+ function generateString(base: typeof TlvByteString | typeof TlvString, model: ValueModel) {
272
+ const bounds = ModelBounds.createLengthBounds(model);
273
+ if (bounds) {
274
+ return base.bound(bounds);
275
+ }
276
+ return base;
277
+ }
278
+
279
+ function generateInteger(model: ValueModel): TlvSchema<unknown> {
280
+ const base = model.metabase;
281
+ if (base === undefined) {
282
+ throw new InternalError(`No metabase for model ${model.path} type ${model.type}`);
283
+ }
284
+
285
+ const tlv = NumberMapping[base.name];
286
+ if (tlv === undefined) {
287
+ throw new InternalError(`No mapping for model ${model.path} metabase ${base.name}`);
288
+ }
289
+
290
+ if ("bound" in tlv) {
291
+ const bounds = ModelBounds.createNumberBounds(model);
292
+ if (bounds) {
293
+ return (tlv as TlvNumberSchema).bound(bounds);
294
+ }
295
+ }
296
+
297
+ return tlv;
298
+ }
299
+
300
+ /**
301
+ * For bitmaps, if we have no fields defined, the element would be useless from matter.js if so constrained. So instead
302
+ * revert to the primitive type.
303
+ */
304
+ function primitiveFallbackOf(model: ValueModel) {
305
+ const primitive = model.metabase?.primitiveBase;
306
+
307
+ if (primitive === undefined) {
308
+ throw new ImplementationError(`Could not determine primitive base for ${model.path}`);
309
+ }
310
+
311
+ return TlvOfModel(primitive);
312
+ }
package/src/tlv/index.ts CHANGED
@@ -12,6 +12,7 @@ export * from "./TlvNoArguments.js";
12
12
  export * from "./TlvNullable.js";
13
13
  export * from "./TlvNumber.js";
14
14
  export * from "./TlvObject.js";
15
+ export * from "./TlvOfModel.js";
15
16
  export * from "./TlvSchema.js";
16
17
  export * from "./TlvString.js";
17
18
  export * from "./TlvVoid.js";