zigbee-clusters 2.8.1 → 2.8.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zigbee-clusters",
3
- "version": "2.8.1",
3
+ "version": "2.8.2",
4
4
  "description": "Zigbee Cluster Library for Node.js",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -179,6 +179,8 @@ function generateClusterInterface(cluster) {
179
179
  lines.push(` readAttributes<K extends ${attrNames}>(attributeNames: K[], opts?: { timeout?: number }): Promise<Pick<${interfaceName}Attributes, K>>;`);
180
180
  lines.push(` readAttributes(attributeNames: Array<keyof ${interfaceName}Attributes | number>, opts?: { timeout?: number }): Promise<Partial<${interfaceName}Attributes> & Record<number, unknown>>;`);
181
181
  lines.push(` writeAttributes(attributes: Partial<${interfaceName}Attributes>, opts?: { timeout?: number }): Promise<unknown>;`);
182
+ lines.push(` on<K extends keyof ${interfaceName}Attributes & string>(eventName: \`attr.\${K}\`, listener: (value: ${interfaceName}Attributes[K]) => void): this;`);
183
+ lines.push(` once<K extends keyof ${interfaceName}Attributes & string>(eventName: \`attr.\${K}\`, listener: (value: ${interfaceName}Attributes[K]) => void): this;`);
182
184
  }
183
185
 
184
186
  // Add command methods
@@ -208,9 +210,14 @@ function generateClusterInterface(cluster) {
208
210
  /**
209
211
  * Generate the full index.d.ts file
210
212
  * @param {object[]} clusters - Array of parsed cluster definitions
213
+ * @param {Array<{
214
+ * constantName: string;
215
+ * clusterId: number;
216
+ * clusterName: string;
217
+ * }>} clusterDefinitions - Array of CLUSTER definitions used to generate typed CLUSTER exports
211
218
  * @returns {string} Complete TypeScript definitions file
212
219
  */
213
- function generateTypesFile(clusters) {
220
+ function generateTypesFile(clusters, clusterDefinitions) {
214
221
  const lines = [];
215
222
 
216
223
  // Header
@@ -309,6 +316,42 @@ type ZCLNodeConstructorInput = {
309
316
  lines.push('}');
310
317
  lines.push('');
311
318
 
319
+ // Generate cluster type lookup maps for inference helpers
320
+ lines.push('/** Cluster type lookup by cluster NAME */');
321
+ lines.push('export interface ClusterTypeByName {');
322
+ for (const cluster of clusters) {
323
+ const interfaceName = toInterfaceName(cluster);
324
+ lines.push(` ${cluster.clusterName}: ${interfaceName};`);
325
+ }
326
+ lines.push('}');
327
+ lines.push('');
328
+
329
+ // Generate cluster attribute lookup maps for inference helpers
330
+ lines.push('/** Cluster attributes lookup by cluster NAME */');
331
+ lines.push('export interface ClusterAttributesByName {');
332
+ for (const cluster of clusters) {
333
+ const interfaceName = toInterfaceName(cluster);
334
+ const attributesInterfaceName = `${interfaceName}Attributes`;
335
+ const attributesType = cluster.attributes.length > 0 ? attributesInterfaceName : 'Record<string, unknown>';
336
+ lines.push(` ${cluster.clusterName}: ${attributesType};`);
337
+ }
338
+ lines.push('}');
339
+ lines.push('');
340
+
341
+ lines.push('/** Infer a typed cluster interface from a CLUSTER definition object. */');
342
+ lines.push('export type ClusterTypeFromDefinition<TDef extends { NAME: string; ID: number }> =');
343
+ lines.push(" TDef['NAME'] extends keyof ClusterTypeByName");
344
+ lines.push(" ? ClusterTypeByName[TDef['NAME']]");
345
+ lines.push(' : ZCLNodeCluster;');
346
+ lines.push('');
347
+
348
+ lines.push('/** Infer typed cluster attribute map from a CLUSTER definition object. */');
349
+ lines.push('export type ClusterAttributesFromDefinition<TDef extends { NAME: string; ID: number }> =');
350
+ lines.push(" TDef['NAME'] extends keyof ClusterAttributesByName");
351
+ lines.push(" ? ClusterAttributesByName[TDef['NAME']]");
352
+ lines.push(' : Record<string, unknown>;');
353
+ lines.push('');
354
+
312
355
  // Generate endpoint type
313
356
  lines.push(`export type ZCLNodeEndpoint = {
314
357
  clusters: ClusterRegistry & {
@@ -327,30 +370,46 @@ export interface ZCLNode {
327
370
  }
328
371
  `);
329
372
 
330
- // Module declaration for CommonJS compatibility
331
- lines.push(`declare module "zigbee-clusters" {
332
- export const ZCLNode: {
333
- new (node: ZCLNodeConstructorInput): ZCLNode;
334
- };
335
- export const CLUSTER: {
336
- [key: string]: { ID: number; NAME: string; ATTRIBUTES: unknown; COMMANDS: unknown };
337
- };
338
- export { ZCLNodeCluster };`);
373
+ // Runtime value exports
374
+ lines.push(`export const ZCLNode: {
375
+ new (node: ZCLNodeConstructorInput): ZCLNode;
376
+ };
339
377
 
340
- // Export all cluster classes
341
- for (const cluster of clusters) {
342
- const interfaceName = toInterfaceName(cluster);
343
- const exportName = cluster.exportName || interfaceName;
344
- lines.push(` export const ${exportName}: {`);
345
- lines.push(` new (...args: any[]): ${interfaceName};`);
378
+ export const CLUSTER: {
379
+ `);
380
+ for (const def of clusterDefinitions) {
381
+ lines.push(` ${def.constantName}: {`);
346
382
  lines.push(' ID: number;');
347
- lines.push(' NAME: string;');
383
+ lines.push(` NAME: '${def.clusterName}';`);
348
384
  lines.push(' ATTRIBUTES: unknown;');
349
385
  lines.push(' COMMANDS: unknown;');
350
386
  lines.push(' };');
351
387
  }
388
+ lines.push('};');
352
389
 
353
- lines.push('}');
390
+ // Export all cluster classes
391
+ for (const cluster of clusters) {
392
+ const interfaceName = toInterfaceName(cluster);
393
+ const exportName = cluster.exportName || interfaceName;
394
+ lines.push(`export const ${exportName}: {`);
395
+ lines.push(` new (...args: any[]): ${interfaceName};`);
396
+ lines.push(` ID: ${cluster.clusterId};`);
397
+ lines.push(` NAME: '${cluster.clusterName}';`);
398
+ lines.push(' ATTRIBUTES: unknown;');
399
+ lines.push(' COMMANDS: unknown;');
400
+ lines.push('};');
401
+ }
402
+
403
+ lines.push('');
404
+ lines.push('declare const _default: {');
405
+ lines.push(' ZCLNode: typeof ZCLNode;');
406
+ lines.push(' CLUSTER: typeof CLUSTER;');
407
+ for (const cluster of clusters) {
408
+ const exportName = cluster.exportName || toInterfaceName(cluster);
409
+ lines.push(` ${exportName}: typeof ${exportName};`);
410
+ }
411
+ lines.push('};');
412
+ lines.push('export default _default;');
354
413
 
355
414
  return lines.join('\n');
356
415
  }
@@ -381,8 +440,16 @@ function main() {
381
440
  // Sort clusters alphabetically
382
441
  clusters.sort((a, b) => a.clusterName.localeCompare(b.clusterName));
383
442
 
443
+ const clusterDefinitions = Object.entries(clustersModule.CLUSTER)
444
+ .map(([constantName, value]) => ({
445
+ constantName,
446
+ clusterId: value.ID,
447
+ clusterName: value.NAME,
448
+ }))
449
+ .sort((a, b) => a.constantName.localeCompare(b.constantName));
450
+
384
451
  console.log(`\nGenerating ${OUTPUT_FILE}...`);
385
- const output = generateTypesFile(clusters);
452
+ const output = generateTypesFile(clusters, clusterDefinitions);
386
453
  fs.writeFileSync(OUTPUT_FILE, output);
387
454
 
388
455
  console.log(`Done! Generated types for ${clusters.length} clusters.`);