homebridge
Version:
HomeKit support for the impatient
126 lines • 4.16 kB
JavaScript
/**
* Matter Utility Functions
*
* Shared utility functions used across the Matter implementation to avoid code duplication.
*/
/**
* Type guard for Node.js error objects with code property
*/
const NON_HEX_RE = /[^A-F0-9]/gi;
const HEX_PAIR_RE = /.{1,2}/g;
/**
* Type guard to check if an error has a code property
*
* @param error - The error to check
* @returns True if error has a code property
*/
export function isNodeError(error) {
return error instanceof Error && 'code' in error;
}
/**
* Extract error code from an error object
*
* @param error - The error object
* @returns Error code string if present, undefined otherwise
*/
export function getErrorCode(error) {
return isNodeError(error) ? error.code : undefined;
}
/**
* Normalize bind configuration to array format
*
* Converts a single bind address or array of addresses to a consistent array format.
* Returns undefined if no bind config provided.
*
* @param bind - Single bind address, array of addresses, or undefined
* @returns Array of bind addresses or undefined
*
* @example
* ```typescript
* normalizeBindConfig('192.168.1.1') // ['192.168.1.1']
* normalizeBindConfig(['192.168.1.1', '10.0.0.1']) // ['192.168.1.1', '10.0.0.1']
* normalizeBindConfig(undefined) // undefined
* ```
*/
export function normalizeBindConfig(bind) {
if (!bind) {
return undefined;
}
return Array.isArray(bind) ? bind : [bind];
}
/**
* Create a Matter username from a unique identifier
*
* Formats a unique ID (like a serial number) into a MAC address format
* suitable for use as a Matter bridge username.
*
* @param uniqueId - Unique identifier (typically without colons)
* @returns MAC address formatted username
*
* @example
* ```typescript
* createMatterUsername('ABCDEF123456') // 'AB:CD:EF:12:34:56'
* ```
*/
export function createMatterUsername(uniqueId) {
const cleanId = uniqueId.replace(NON_HEX_RE, '');
const formatted = cleanId.match(HEX_PAIR_RE)?.slice(0, 6).join(':').toUpperCase() || uniqueId;
return formatted;
}
/**
* Append suffix to a MAC address for Matter port allocation
*
* @param baseUsername - Base MAC address
* @param suffix - Suffix to append (e.g., 'MATTER')
* @returns MAC address with suffix
*/
export function appendUsernameSuffix(baseUsername, suffix) {
return `${baseUsername}:${suffix}`;
}
/**
* Sanitise a Matter `productLabel` (or similar) so it does not contain the
* vendor name. The Matter spec requires that `productLabel` SHALL NOT include
* the `vendorName`, and matter.js logs a warning when it does. Many users
* name accessories with the manufacturer prefix (e.g. "Eufy Front Door"),
* which trips the check unless we strip the vendor first.
*
* Removes the first case-insensitive occurrence of `vendor` from `label`,
* collapses whitespace, and trims leading/trailing separators. Returns an
* empty string if stripping consumes the entire label — callers should
* provide a non-vendor fallback in that case.
*
* @param label - The candidate label (e.g. an accessory display name)
* @param vendor - The vendor name to strip
* @returns A label safe to send as `productLabel`, or `''` if fully consumed
*
* @example
* ```typescript
* stripVendorFromLabel('Eufy Front Door', 'Eufy') // 'Front Door'
* stripVendorFromLabel('Govee Light', 'govee') // 'Light'
* stripVendorFromLabel('Homebridge', 'Homebridge') // '' (caller supplies fallback)
* ```
*/
export function stripVendorFromLabel(label, vendor) {
if (!label) {
return '';
}
if (!vendor) {
return label;
}
const idx = label.toLowerCase().indexOf(vendor.toLowerCase());
if (idx === -1) {
return label;
}
return (label.slice(0, idx) + label.slice(idx + vendor.length))
.replace(/\s+/g, ' ')
.replace(/^[\s\-_:,]+|[\s\-_:,]+$/g, '');
}
/**
* Get the version of @matter/main from package.json dependencies.
*
* @returns The version string of @matter/main, or '0.0.0' if not found.
*/
export async function getMatterJsVersion() {
return '0.17.0-alpha.0-20260508-96d5c3a88';
}
//# sourceMappingURL=utils.js.map