@matterbridge/core 3.9.1-dev-20260614-18d1a2e → 3.9.1-dev-20260617-8de71e5

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 (80) hide show
  1. package/README.md +5 -3
  2. package/dist/backend.js +17 -6
  3. package/dist/backendExpress.d.ts +1 -1
  4. package/dist/backendExpress.js +12 -12
  5. package/dist/backendWsServer.d.ts +1 -1
  6. package/dist/backendWsServer.js +3 -3
  7. package/dist/behaviors/activatedCarbonFilterMonitoringServer.d.ts +1 -1
  8. package/dist/behaviors/bindingServer.d.ts +4 -4
  9. package/dist/behaviors/bindingServer.js +2 -2
  10. package/dist/behaviors/booleanStateConfigurationServer.js +2 -1
  11. package/dist/behaviors/doorLockServer.d.ts +1 -1
  12. package/dist/behaviors/doorLockServer.js +2 -2
  13. package/dist/behaviors/hepaFilterMonitoringServer.d.ts +1 -1
  14. package/dist/behaviors/identifyServer.d.ts +1 -1
  15. package/dist/behaviors/levelControlServer.d.ts +1 -1
  16. package/dist/behaviors/matterbridgeServer.d.ts +2 -2
  17. package/dist/behaviors/modeSelectServer.d.ts +1 -1
  18. package/dist/behaviors/operationalStateServer.d.ts +1 -1
  19. package/dist/behaviors/serviceAreaServer.d.ts +1 -1
  20. package/dist/behaviors/windowCoveringServer.d.ts +2 -2
  21. package/dist/behaviors/windowCoveringServer.js +3 -3
  22. package/dist/cli.js +9 -9
  23. package/dist/cliEmitter.js +2 -2
  24. package/dist/cliHistory.js +2 -2
  25. package/dist/clusters/export.d.ts +1 -1
  26. package/dist/clusters/export.js +1 -1
  27. package/dist/deviceManager.d.ts +1 -1
  28. package/dist/deviceManager.js +3 -4
  29. package/dist/devices/batteryStorage.js +2 -1
  30. package/dist/devices/cooktop.d.ts +1 -1
  31. package/dist/devices/cooktop.js +2 -1
  32. package/dist/devices/dishwasher.d.ts +1 -1
  33. package/dist/devices/evse.d.ts +1 -1
  34. package/dist/devices/evse.js +4 -2
  35. package/dist/devices/extractorHood.js +2 -1
  36. package/dist/devices/heatPump.js +7 -8
  37. package/dist/devices/irrigationSystem.d.ts +1 -1
  38. package/dist/devices/laundryDryer.d.ts +1 -1
  39. package/dist/devices/laundryWasher.d.ts +1 -1
  40. package/dist/devices/oven.d.ts +2 -2
  41. package/dist/devices/oven.js +4 -3
  42. package/dist/devices/refrigerator.d.ts +2 -2
  43. package/dist/devices/refrigerator.js +2 -1
  44. package/dist/devices/solarPower.d.ts +1 -1
  45. package/dist/devices/solarPower.js +2 -1
  46. package/dist/devices/temperatureControl.d.ts +1 -1
  47. package/dist/devices/waterHeater.js +2 -1
  48. package/dist/export.js +2 -2
  49. package/dist/frontend.js +39 -39
  50. package/dist/helpers.d.ts +1 -1
  51. package/dist/helpers.js +6 -4
  52. package/dist/jestutils/jestMatterTest.js +1 -1
  53. package/dist/jestutils/jestMatterbridgeTest.d.ts +2 -2
  54. package/dist/jestutils/jestMatterbridgeTest.js +1 -1
  55. package/dist/jestutils/jestSetupTest.js +13 -12
  56. package/dist/jestutils/matterRequest.d.ts +1 -1
  57. package/dist/matterNode.js +8 -6
  58. package/dist/matterbridge.js +11 -21
  59. package/dist/matterbridgeAccessoryPlatform.d.ts +1 -1
  60. package/dist/matterbridgeAccessoryPlatform.js +2 -2
  61. package/dist/matterbridgeDeviceTypes.js +2 -2
  62. package/dist/matterbridgeDynamicPlatform.d.ts +1 -1
  63. package/dist/matterbridgeDynamicPlatform.js +2 -2
  64. package/dist/matterbridgeEndpoint.d.ts +9 -9
  65. package/dist/matterbridgeEndpoint.js +9 -8
  66. package/dist/matterbridgeEndpointCommandHandler.d.ts +40 -40
  67. package/dist/matterbridgeEndpointCommandHandler.js +2 -2
  68. package/dist/matterbridgeEndpointHelpers.d.ts +2 -2
  69. package/dist/matterbridgeEndpointHelpers.js +2 -2
  70. package/dist/matterbridgeEndpointTypes.js +2 -3
  71. package/dist/matterbridgeFactory.d.ts +1 -1
  72. package/dist/matterbridgeFactory.js +2 -2
  73. package/dist/matterbridgePlatform.d.ts +1 -1
  74. package/dist/matterbridgePlatform.js +2 -2
  75. package/dist/mb_coap.js +3 -1
  76. package/dist/mb_health.js +3 -1
  77. package/dist/mb_mdns.js +10 -7
  78. package/dist/pluginManager.d.ts +1 -1
  79. package/dist/pluginManager.js +11 -6
  80. package/package.json +9 -9
@@ -1,4 +1,4 @@
1
- import { type MaybePromise } from '@matter/general';
1
+ import type { MaybePromise } from '@matter/general';
2
2
  import { EnergyEvseServer } from '@matter/node/behaviors/energy-evse';
3
3
  import { EnergyEvseModeServer } from '@matter/node/behaviors/energy-evse-mode';
4
4
  import { EnergyEvse } from '@matter/types/clusters/energy-evse';
@@ -4,6 +4,8 @@ import { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-man
4
4
  import { EnergyEvse } from '@matter/types/clusters/energy-evse';
5
5
  import { EnergyEvseMode } from '@matter/types/clusters/energy-evse-mode';
6
6
  import { ModeBase } from '@matter/types/clusters/mode-base';
7
+ import { fireAndForget } from '@matterbridge/utils/wait';
8
+ import { debugStringify } from 'node-ansi-logger';
7
9
  import { MatterbridgeServer } from '../behaviors/matterbridgeServer.js';
8
10
  import { deviceEnergyManagement, electricalSensor, evse, powerSource } from '../matterbridgeDeviceTypes.js';
9
11
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
@@ -16,7 +18,7 @@ export class Evse extends MatterbridgeEndpoint {
16
18
  .createDefaultEnergyEvseModeClusterServer(currentMode, supportedModes)
17
19
  .createDefaultTemperatureMeasurementClusterServer(24_00)
18
20
  .addRequiredClusterServers();
19
- void this.addFixedLabel('composed', 'EVSE').catch(() => { });
21
+ fireAndForget(this.addFixedLabel('composed', 'EVSE'), this.log, 'Error adding composed label to EVSE');
20
22
  this.addChildDeviceType('PowerSource', powerSource).createDefaultPowerSourceWiredClusterServer().addRequiredClusterServers();
21
23
  this.addChildDeviceType('ElectricalSensor', electricalSensor)
22
24
  .createDefaultPowerTopologyClusterServer()
@@ -94,7 +96,7 @@ export class MatterbridgeEnergyEvseServer extends EnergyEvseServer.with(EnergyEv
94
96
  }
95
97
  setTargets(request) {
96
98
  const device = this.endpoint.stateOf(MatterbridgeServer);
97
- device.log.info(`SetTargets request ${request.chargingTargetSchedules} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
99
+ device.log.info(`SetTargets request ${debugStringify(request.chargingTargetSchedules)} (endpoint ${this.endpoint.maybeId}.${this.endpoint.maybeNumber})`);
98
100
  return;
99
101
  }
100
102
  getTargets() {
@@ -1,4 +1,5 @@
1
1
  import { ResourceMonitoring } from '@matter/types/clusters/resource-monitoring';
2
+ import { fireAndForget } from '@matterbridge/utils/wait';
2
3
  import { extractorHood, powerSource } from '../matterbridgeDeviceTypes.js';
3
4
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
4
5
  export class ExtractorHood extends MatterbridgeEndpoint {
@@ -19,7 +20,7 @@ export class ExtractorHood extends MatterbridgeEndpoint {
19
20
  if (context.fabric === undefined)
20
21
  return;
21
22
  this.log.info(`Fan control percentSetting attribute changed: ${newValue}`);
22
- void this.setAttribute('fanControl', 'percentCurrent', newValue, this.log).catch(() => { });
23
+ fireAndForget(this.setAttribute('fanControl', 'percentCurrent', newValue, this.log), this.log, 'ExtractorHood setAttribute');
23
24
  });
24
25
  this.subscribeAttribute('hepaFilterMonitoring', 'lastChangedTime', (newValue, oldValue, context) => {
25
26
  if (context.fabric === undefined)
@@ -1,5 +1,6 @@
1
1
  import { CommonAreaNamespaceTag, CommonNumberTag, PowerSourceTag } from '@matter/node';
2
2
  import { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-management';
3
+ import { fireAndForget } from '@matterbridge/utils/wait';
3
4
  import { deviceEnergyManagement, electricalSensor, heatPump, powerSource, temperatureSensor, thermostat } from '../matterbridgeDeviceTypes.js';
4
5
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
6
  import { getSemtag } from '../matterbridgeEndpointHelpers.js';
@@ -28,19 +29,17 @@ export class HeatPump extends MatterbridgeEndpoint {
28
29
  })
29
30
  .createDefaultTemperatureMeasurementClusterServer(3500)
30
31
  .addRequiredClusterServers();
31
- this.addChildDeviceType('LivingThermostat', thermostat, {
32
+ const livingThermostat = this.addChildDeviceType('LivingThermostat', thermostat, {
32
33
  tagList: [getSemtag(CommonNumberTag.One, 'LivingThermostat'), getSemtag(CommonAreaNamespaceTag.LivingRoom)],
33
34
  })
34
35
  .createDefaultThermostatClusterServer()
35
- .addRequiredClusterServers()
36
- .addUserLabel('room', 'Living Room')
37
- .catch(() => { });
38
- this.addChildDeviceType('BedroomThermostat', thermostat, {
36
+ .addRequiredClusterServers();
37
+ fireAndForget(livingThermostat.addUserLabel('room', 'Living Room'), this.log, 'HeatPump addUserLabel LivingRoom');
38
+ const bedroomThermostat = this.addChildDeviceType('BedroomThermostat', thermostat, {
39
39
  tagList: [getSemtag(CommonNumberTag.Two, 'BedroomThermostat'), getSemtag(CommonAreaNamespaceTag.Bedroom)],
40
40
  })
41
41
  .createDefaultThermostatClusterServer()
42
- .addRequiredClusterServers()
43
- .addUserLabel('room', 'Bedroom')
44
- .catch(() => { });
42
+ .addRequiredClusterServers();
43
+ fireAndForget(bedroomThermostat.addUserLabel('room', 'Bedroom'), this.log, 'HeatPump addUserLabel Bedroom');
45
44
  }
46
45
  }
@@ -1,5 +1,5 @@
1
1
  import { OperationalState } from '@matter/types/clusters/operational-state';
2
- import { type Semtag } from '@matter/types/globals';
2
+ import type { Semtag } from '@matter/types/globals';
3
3
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
4
4
  export interface IrrigationSystemOptions {
5
5
  singleZone?: boolean;
@@ -1,6 +1,6 @@
1
1
  import { LaundryDryerControls } from '@matter/types/clusters/laundry-dryer-controls';
2
2
  import { LaundryWasherMode } from '@matter/types/clusters/laundry-washer-mode';
3
- import { type OperationalState } from '@matter/types/clusters/operational-state';
3
+ import type { OperationalState } from '@matter/types/clusters/operational-state';
4
4
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
5
  export declare class LaundryDryer extends MatterbridgeEndpoint {
6
6
  constructor(name: string, serial: string, currentMode?: number, supportedModes?: LaundryWasherMode.ModeOption[], selectedTemperatureLevel?: number, supportedTemperatureLevels?: string[], temperatureSetpoint?: number, minTemperature?: number, maxTemperature?: number, step?: number, operationalState?: OperationalState.OperationalStateEnum);
@@ -2,7 +2,7 @@ import { LaundryWasherModeServer } from '@matter/node/behaviors/laundry-washer-m
2
2
  import { LaundryWasherControls } from '@matter/types/clusters/laundry-washer-controls';
3
3
  import { LaundryWasherMode } from '@matter/types/clusters/laundry-washer-mode';
4
4
  import { ModeBase } from '@matter/types/clusters/mode-base';
5
- import { type OperationalState } from '@matter/types/clusters/operational-state';
5
+ import type { OperationalState } from '@matter/types/clusters/operational-state';
6
6
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
7
7
  export declare class LaundryWasher extends MatterbridgeEndpoint {
8
8
  constructor(name: string, serial: string, currentMode?: number, supportedModes?: LaundryWasherMode.ModeOption[], spinSpeedCurrent?: number, spinSpeeds?: string[], numberOfRinses?: LaundryWasherControls.NumberOfRinses, supportedRinses?: LaundryWasherControls.NumberOfRinses[], selectedTemperatureLevel?: number, supportedTemperatureLevels?: string[], temperatureSetpoint?: number, minTemperature?: number, maxTemperature?: number, step?: number, operationalState?: OperationalState.OperationalStateEnum);
@@ -1,7 +1,7 @@
1
- import { type MaybePromise } from '@matter/general';
1
+ import type { MaybePromise } from '@matter/general';
2
2
  import { OvenCavityOperationalStateServer } from '@matter/node/behaviors/oven-cavity-operational-state';
3
3
  import { OvenModeServer } from '@matter/node/behaviors/oven-mode';
4
- import { type Semtag } from '@matter/types';
4
+ import type { Semtag } from '@matter/types';
5
5
  import { ModeBase } from '@matter/types/clusters/mode-base';
6
6
  import { OperationalState } from '@matter/types/clusters/operational-state';
7
7
  import { OvenMode } from '@matter/types/clusters/oven-mode';
@@ -3,6 +3,7 @@ import { OvenModeServer } from '@matter/node/behaviors/oven-mode';
3
3
  import { ModeBase } from '@matter/types/clusters/mode-base';
4
4
  import { OperationalState } from '@matter/types/clusters/operational-state';
5
5
  import { OvenMode } from '@matter/types/clusters/oven-mode';
6
+ import { fireAndForget } from '@matterbridge/utils/wait';
6
7
  import { MatterbridgeServer } from '../behaviors/matterbridgeServer.js';
7
8
  import { oven, powerSource, temperatureControlledCabinetHeater } from '../matterbridgeDeviceTypes.js';
8
9
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
@@ -13,7 +14,7 @@ export class Oven extends MatterbridgeEndpoint {
13
14
  this.createDefaultIdentifyClusterServer();
14
15
  this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Oven');
15
16
  this.createDefaultPowerSourceWiredClusterServer();
16
- void this.addFixedLabel('composed', 'Oven').catch(() => { });
17
+ fireAndForget(this.addFixedLabel('composed', 'Oven'), this.log, 'Oven addFixedLabel');
17
18
  }
18
19
  addCabinet(name, tagList, currentMode = 2, supportedModes = [
19
20
  { label: 'Bake', mode: 1, modeTags: [{ value: OvenMode.ModeTag.Bake }] },
@@ -44,8 +45,8 @@ export class Oven extends MatterbridgeEndpoint {
44
45
  }
45
46
  createDefaultOvenCavityOperationalStateClusterServer(endpoint, operationalState = OperationalState.OperationalStateEnum.Stopped, currentPhase, phaseList) {
46
47
  endpoint.behaviors.require(MatterbridgeOvenCavityOperationalStateServer, {
47
- phaseList: phaseList || null,
48
- currentPhase: currentPhase || null,
48
+ phaseList: phaseList ?? null,
49
+ currentPhase: currentPhase ?? null,
49
50
  operationalStateList: [
50
51
  { operationalStateId: OperationalState.OperationalStateEnum.Stopped },
51
52
  { operationalStateId: OperationalState.OperationalStateEnum.Running },
@@ -1,6 +1,6 @@
1
- import { type MaybePromise } from '@matter/general';
1
+ import type { MaybePromise } from '@matter/general';
2
2
  import { RefrigeratorAndTemperatureControlledCabinetModeServer } from '@matter/node/behaviors/refrigerator-and-temperature-controlled-cabinet-mode';
3
- import { type Semtag } from '@matter/types';
3
+ import type { Semtag } from '@matter/types';
4
4
  import { ModeBase } from '@matter/types/clusters/mode-base';
5
5
  import { RefrigeratorAndTemperatureControlledCabinetMode } from '@matter/types/clusters/refrigerator-and-temperature-controlled-cabinet-mode';
6
6
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
@@ -2,6 +2,7 @@ import { RefrigeratorAlarmServer } from '@matter/node/behaviors/refrigerator-ala
2
2
  import { RefrigeratorAndTemperatureControlledCabinetModeServer } from '@matter/node/behaviors/refrigerator-and-temperature-controlled-cabinet-mode';
3
3
  import { ModeBase } from '@matter/types/clusters/mode-base';
4
4
  import { RefrigeratorAndTemperatureControlledCabinetMode } from '@matter/types/clusters/refrigerator-and-temperature-controlled-cabinet-mode';
5
+ import { fireAndForget } from '@matterbridge/utils/wait';
5
6
  import { MatterbridgeServer } from '../behaviors/matterbridgeServer.js';
6
7
  import { powerSource, refrigerator, temperatureControlledCabinetCooler } from '../matterbridgeDeviceTypes.js';
7
8
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
@@ -16,7 +17,7 @@ export class Refrigerator extends MatterbridgeEndpoint {
16
17
  this.createDefaultIdentifyClusterServer();
17
18
  this.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Refrigerator');
18
19
  this.createDefaultPowerSourceWiredClusterServer();
19
- void this.addFixedLabel('composed', 'Refrigerator').catch(() => { });
20
+ fireAndForget(this.addFixedLabel('composed', 'Refrigerator'), this.log, 'Error adding composed label to Refrigerator');
20
21
  this.createDefaultRefrigeratorAndTemperatureControlledCabinetModeClusterServer(this, currentMode, supportedModes);
21
22
  this.createDefaultRefrigeratorAlarmClusterServer(this, false);
22
23
  }
@@ -1,4 +1,4 @@
1
- import { type Semtag } from '@matter/types/globals';
1
+ import type { Semtag } from '@matter/types/globals';
2
2
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
3
3
  export declare class SolarPower extends MatterbridgeEndpoint {
4
4
  constructor(name: string, serial: string, voltage?: number | bigint | null, current?: number | bigint | null, power?: number | bigint | null, energyExported?: number | bigint, absMinPower?: number, absMaxPower?: number);
@@ -1,5 +1,6 @@
1
1
  import { PowerSourceTag } from '@matter/node';
2
2
  import { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-management';
3
+ import { fireAndForget } from '@matterbridge/utils/wait';
3
4
  import { deviceEnergyManagement, electricalSensor, powerSource, solarPower } from '../matterbridgeDeviceTypes.js';
4
5
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
5
6
  import { getSemtag } from '../matterbridgeEndpointHelpers.js';
@@ -27,7 +28,7 @@ export class SolarPower extends MatterbridgeEndpoint {
27
28
  .createDefaultElectricalPowerMeasurementClusterServer(voltage, current, power)
28
29
  .createDefaultElectricalEnergyMeasurementClusterServer(0, energyExported)
29
30
  .addRequiredClusterServers();
30
- void panel.addUserLabel('panel', name.slice(0, 16)).catch(() => { });
31
+ fireAndForget(panel.addUserLabel('panel', name.slice(0, 16)), this.log, 'SolarPower addUserLabel');
31
32
  return panel;
32
33
  }
33
34
  }
@@ -1,6 +1,6 @@
1
1
  import { TemperatureControlServer } from '@matter/node/behaviors/temperature-control';
2
2
  import { TemperatureControl } from '@matter/types/clusters/temperature-control';
3
- import { type MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
3
+ import type { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
4
4
  export declare function createLevelTemperatureControlClusterServer(endpoint: MatterbridgeEndpoint, selectedTemperatureLevel?: number, supportedTemperatureLevels?: string[]): MatterbridgeEndpoint;
5
5
  export declare function createNumberTemperatureControlClusterServer(endpoint: MatterbridgeEndpoint, temperatureSetpoint?: number, minTemperature?: number, maxTemperature?: number, step?: number): MatterbridgeEndpoint;
6
6
  declare const MatterbridgeLevelTemperatureControlServer_base: import("@matter/node").ClusterBehavior.Type<typeof TemperatureControlServer, import("@matter/types").ClusterType.WithSupportedFeatures<TemperatureControl, {
@@ -4,6 +4,7 @@ import { DeviceEnergyManagement } from '@matter/types/clusters/device-energy-man
4
4
  import { ModeBase } from '@matter/types/clusters/mode-base';
5
5
  import { WaterHeaterManagement } from '@matter/types/clusters/water-heater-management';
6
6
  import { WaterHeaterMode } from '@matter/types/clusters/water-heater-mode';
7
+ import { fireAndForget } from '@matterbridge/utils/wait';
7
8
  import { MatterbridgeServer } from '../behaviors/matterbridgeServer.js';
8
9
  import { deviceEnergyManagement, electricalSensor, powerSource, waterHeater } from '../matterbridgeDeviceTypes.js';
9
10
  import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
@@ -15,7 +16,7 @@ export class WaterHeater extends MatterbridgeEndpoint {
15
16
  .createDefaultHeatingThermostatClusterServer(waterTemperature, targetWaterTemperature, minHeatSetpointLimit, maxHeatSetpointLimit)
16
17
  .createDefaultWaterHeaterManagementClusterServer(heaterTypes, {}, tankPercentage)
17
18
  .createDefaultWaterHeaterModeClusterServer();
18
- void this.addFixedLabel('composed', 'Water Heater').catch(() => { });
19
+ fireAndForget(this.addFixedLabel('composed', 'Water Heater'), this.log, 'WaterHeater addFixedLabel');
19
20
  this.addChildDeviceType('PowerSource', powerSource).createDefaultPowerSourceWiredClusterServer().addRequiredClusterServers();
20
21
  this.addChildDeviceType('ElectricalSensor', electricalSensor)
21
22
  .createDefaultPowerTopologyClusterServer()
package/dist/export.js CHANGED
@@ -1,5 +1,5 @@
1
- if (process.argv.includes('--loader'))
2
- console.log('\u001B[32m[' + new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit', fractionalSecondDigits: 3 }) + '] Index loaded.\u001B[40;0m');
1
+ import { logModuleLoaded } from '@matterbridge/utils/loader';
2
+ logModuleLoaded('Index');
3
3
  export * from './behaviors/activatedCarbonFilterMonitoringServer.js';
4
4
  export * from './behaviors/bindingServer.js';
5
5
  export * from './behaviors/booleanStateConfigurationServer.js';
package/dist/frontend.js CHANGED
@@ -10,17 +10,16 @@ import { FabricIndex } from '@matter/types/datatype';
10
10
  import { BroadcastServer } from '@matterbridge/thread/server';
11
11
  import { MATTER_LOGGER_FILE, MATTER_STORAGE_DIR, MATTERBRIDGE_DIAGNOSTIC_FILE, MATTERBRIDGE_HISTORY_FILE, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg, } from '@matterbridge/types';
12
12
  import { getParameter, hasParameter } from '@matterbridge/utils/cli';
13
- import { inspectError } from '@matterbridge/utils/error';
14
- import { logError } from '@matterbridge/utils/error';
13
+ import { getErrorMessage, inspectError, logError } from '@matterbridge/utils/error';
15
14
  import { formatBytes, formatPercent, formatUptime } from '@matterbridge/utils/format';
15
+ import { logModuleLoaded } from '@matterbridge/utils/loader';
16
16
  import { isValidArray, isValidBoolean, isValidNumber, isValidObject, isValidString } from '@matterbridge/utils/validate';
17
17
  import { fireAndForget, wait, withTimeout } from '@matterbridge/utils/wait';
18
18
  import { AnsiLogger, bgHex, CYAN, db, debugStringify, er, GREEN, nf, nt, rs, stringify, UNDERLINE, UNDERLINEOFF, wr, YELLOW } from 'node-ansi-logger';
19
19
  import { cliEmitter, lastOsCpuUsage, lastProcessCpuUsage } from './cliEmitter.js';
20
20
  import { generateHistoryPage } from './cliHistory.js';
21
21
  import { capitalizeFirstLetter, getAttribute } from './matterbridgeEndpointHelpers.js';
22
- if (hasParameter('loader'))
23
- console.log('\u001B[32m[' + new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit', fractionalSecondDigits: 3 }) + '] Frontend loaded.\u001B[40;0m');
22
+ logModuleLoaded('Frontend');
24
23
  export class Frontend extends EventEmitter {
25
24
  matterbridge;
26
25
  log;
@@ -59,7 +58,6 @@ export class Frontend extends EventEmitter {
59
58
  destroy() {
60
59
  clearTimeout(this.authClientsTimeout);
61
60
  this.authClientsTimeout = undefined;
62
- this.server.off('broadcast_message', this.broadcastMsgHandler.bind(this));
63
61
  this.server.close();
64
62
  }
65
63
  async broadcastMsgHandler(msg) {
@@ -252,7 +250,7 @@ export class Frontend extends EventEmitter {
252
250
  this.httpServer = http.createServer(this.expressApp);
253
251
  }
254
252
  catch (error) {
255
- this.log.error(`Failed to create HTTP server: ${error}`);
253
+ logError(this.log, `Failed to create HTTP server`, error);
256
254
  this.emit('server_error', error);
257
255
  return;
258
256
  }
@@ -326,7 +324,7 @@ export class Frontend extends EventEmitter {
326
324
  this.log.info(`Loaded p12 certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.p12')}`);
327
325
  }
328
326
  catch (error) {
329
- this.log.error(`Error reading p12 certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.p12')}: ${error}`);
327
+ logError(this.log, `Error reading p12 certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.p12')}`, error);
330
328
  this.emit('server_error', error);
331
329
  return;
332
330
  }
@@ -336,7 +334,7 @@ export class Frontend extends EventEmitter {
336
334
  this.log.info(`Loaded p12 passphrase file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.pass')}`);
337
335
  }
338
336
  catch (error) {
339
- this.log.error(`Error reading p12 passphrase file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.pass')}: ${error}`);
337
+ logError(this.log, `Error reading p12 passphrase file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.pass')}`, error);
340
338
  this.emit('server_error', error);
341
339
  return;
342
340
  }
@@ -348,7 +346,7 @@ export class Frontend extends EventEmitter {
348
346
  this.log.info(`Loaded certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.pem')}`);
349
347
  }
350
348
  catch (error) {
351
- this.log.error(`Error reading certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.pem')}: ${error}`);
349
+ logError(this.log, `Error reading certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'cert.pem')}`, error);
352
350
  this.emit('server_error', error);
353
351
  return;
354
352
  }
@@ -357,7 +355,7 @@ export class Frontend extends EventEmitter {
357
355
  this.log.info(`Loaded key file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'key.pem')}`);
358
356
  }
359
357
  catch (error) {
360
- this.log.error(`Error reading key file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'key.pem')}: ${error}`);
358
+ logError(this.log, `Error reading key file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'key.pem')}`, error);
361
359
  this.emit('server_error', error);
362
360
  return;
363
361
  }
@@ -367,7 +365,7 @@ export class Frontend extends EventEmitter {
367
365
  this.log.info(`Loaded CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'ca.pem')}`);
368
366
  }
369
367
  catch (error) {
370
- this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'ca.pem')} not loaded: ${error}`);
368
+ this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs', 'ca.pem')} not loaded: ${getErrorMessage(error)}`);
371
369
  }
372
370
  httpsServerOptions = { cert: fullChain ?? cert, key, ca };
373
371
  }
@@ -381,7 +379,7 @@ export class Frontend extends EventEmitter {
381
379
  this.httpsServer = https.createServer(httpsServerOptions, this.expressApp);
382
380
  }
383
381
  catch (error) {
384
- this.log.error(`Failed to create HTTPS server: ${error}`);
382
+ logError(this.log, `Failed to create HTTPS server`, error);
385
383
  this.emit('server_error', error);
386
384
  return;
387
385
  }
@@ -449,7 +447,7 @@ export class Frontend extends EventEmitter {
449
447
  cliEmitter.on('cpu', (cpuUsage, processCpuUsage) => {
450
448
  this.wssSendCpuUpdate(cpuUsage, processCpuUsage);
451
449
  });
452
- this.expressApp.post('/api/login', express.json(), async (req, res) => {
450
+ this.expressApp.post('/api/login', express.json(), (req, res) => {
453
451
  const { password } = req.body;
454
452
  this.log.debug(`The frontend sent /api/login with password ${password ? '[redacted]' : '(empty)'}`);
455
453
  if (this.storedPassword === '' || password === this.storedPassword) {
@@ -504,19 +502,19 @@ export class Frontend extends EventEmitter {
504
502
  };
505
503
  res.status(200).json(memoryReport);
506
504
  });
507
- this.expressApp.get('/api/settings', async (req, res) => {
505
+ this.expressApp.get('/api/settings', (req, res) => {
508
506
  this.log.debug('The frontend sent /api/settings');
509
507
  if (!this.validateReq(req, res))
510
508
  return;
511
509
  res.json(this.getApiSettings());
512
510
  });
513
- this.expressApp.get('/api/plugins', async (req, res) => {
511
+ this.expressApp.get('/api/plugins', (req, res) => {
514
512
  this.log.debug('The frontend sent /api/plugins');
515
513
  if (!this.validateReq(req, res))
516
514
  return;
517
515
  res.json(this.getApiPlugins());
518
516
  });
519
- this.expressApp.get('/api/devices', async (req, res) => {
517
+ this.expressApp.get('/api/devices', (req, res) => {
520
518
  this.log.debug('The frontend sent /api/devices');
521
519
  if (!this.validateReq(req, res))
522
520
  return;
@@ -549,12 +547,12 @@ export class Frontend extends EventEmitter {
549
547
  }
550
548
  catch (error) {
551
549
  await fs.promises.writeFile(path.join(os.tmpdir(), MATTERBRIDGE_LOGGER_FILE), 'Enable the matterbridge log on file in the settings to download the matterbridge log.', 'utf-8');
552
- this.log.debug(`Error in /api/download-mblog: ${error instanceof Error ? error.message : error}`);
550
+ this.log.debug(`Error in /api/download-mblog: ${getErrorMessage(error)}`);
553
551
  }
554
552
  res.type('text/plain; charset=utf-8');
555
553
  res.download(path.join(os.tmpdir(), MATTERBRIDGE_LOGGER_FILE), 'matterbridge.log', (error) => {
556
554
  if (error) {
557
- this.log.error(`Error downloading log file ${MATTERBRIDGE_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
555
+ logError(this.log, `Error downloading log file ${MATTERBRIDGE_LOGGER_FILE}`, error);
558
556
  res.status(500).send('Error downloading the matterbridge log file');
559
557
  }
560
558
  else {
@@ -573,7 +571,7 @@ export class Frontend extends EventEmitter {
573
571
  res.send(data);
574
572
  }
575
573
  catch (error) {
576
- this.log.error(`Error reading matter log file ${MATTER_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
574
+ logError(this.log, `Error reading matter log file ${MATTER_LOGGER_FILE}`, error);
577
575
  res.status(500).send('Error reading matter log file. Please enable the matter log on file in the settings.');
578
576
  }
579
577
  });
@@ -589,12 +587,12 @@ export class Frontend extends EventEmitter {
589
587
  }
590
588
  catch (error) {
591
589
  await fs.promises.writeFile(path.join(os.tmpdir(), MATTER_LOGGER_FILE), 'Enable the matter log on file in the settings to download the matter log.', 'utf-8');
592
- this.log.debug(`Error in /api/download-mjlog: ${error instanceof Error ? error.message : error}`);
590
+ this.log.debug(`Error in /api/download-mjlog: ${getErrorMessage(error)}`);
593
591
  }
594
592
  res.type('text/plain; charset=utf-8');
595
593
  res.download(path.join(os.tmpdir(), MATTER_LOGGER_FILE), 'matter.log', (error) => {
596
594
  if (error) {
597
- this.log.error(`Error downloading log file ${MATTER_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
595
+ logError(this.log, `Error downloading log file ${MATTER_LOGGER_FILE}`, error);
598
596
  res.status(500).send('Error downloading the matter log file');
599
597
  }
600
598
  else {
@@ -614,7 +612,7 @@ export class Frontend extends EventEmitter {
614
612
  res.send(data.slice(29));
615
613
  }
616
614
  catch (error) {
617
- this.log.error(`Error reading diagnostic log file ${MATTERBRIDGE_DIAGNOSTIC_FILE}: ${error instanceof Error ? error.message : error}`);
615
+ logError(this.log, `Error reading diagnostic log file ${MATTERBRIDGE_DIAGNOSTIC_FILE}`, error);
618
616
  res.status(500).send('Error reading diagnostic log file.');
619
617
  }
620
618
  });
@@ -630,7 +628,7 @@ export class Frontend extends EventEmitter {
630
628
  await fs.promises.writeFile(path.join(os.tmpdir(), MATTERBRIDGE_DIAGNOSTIC_FILE), data, 'utf-8');
631
629
  }
632
630
  catch (error) {
633
- this.log.debug(`Error in /api/download-diagnostic: ${error instanceof Error ? error.message : error}`);
631
+ this.log.debug(`Error in /api/download-diagnostic: ${getErrorMessage(error)}`);
634
632
  }
635
633
  res.type('text/plain; charset=utf-8');
636
634
  res.download(path.join(os.tmpdir(), MATTERBRIDGE_DIAGNOSTIC_FILE), MATTERBRIDGE_DIAGNOSTIC_FILE, (error) => {
@@ -654,7 +652,7 @@ export class Frontend extends EventEmitter {
654
652
  res.send(data);
655
653
  }
656
654
  catch (error) {
657
- this.log.error(`Error in /api/viewhistory reading history file ${MATTERBRIDGE_HISTORY_FILE}: ${error instanceof Error ? error.message : error}`);
655
+ logError(this.log, `Error in /api/viewhistory reading history file ${MATTERBRIDGE_HISTORY_FILE}`, error);
658
656
  res.status(500).send('Error reading history file.');
659
657
  }
660
658
  });
@@ -670,7 +668,7 @@ export class Frontend extends EventEmitter {
670
668
  res.type('text/html; charset=utf-8');
671
669
  res.download(path.join(os.tmpdir(), MATTERBRIDGE_HISTORY_FILE), MATTERBRIDGE_HISTORY_FILE, (error) => {
672
670
  if (error) {
673
- this.log.error(`Error in /api/downloadhistory downloading history file ${MATTERBRIDGE_HISTORY_FILE}: ${error instanceof Error ? error.message : error}`);
671
+ logError(this.log, `Error in /api/downloadhistory downloading history file ${MATTERBRIDGE_HISTORY_FILE}`, error);
674
672
  res.status(500).send('Error downloading history file');
675
673
  }
676
674
  else {
@@ -679,26 +677,26 @@ export class Frontend extends EventEmitter {
679
677
  });
680
678
  }
681
679
  catch (error) {
682
- this.log.error(`Error in /api/downloadhistory reading history file ${MATTERBRIDGE_HISTORY_FILE}: ${error instanceof Error ? error.message : error}`);
680
+ logError(this.log, `Error in /api/downloadhistory reading history file ${MATTERBRIDGE_HISTORY_FILE}`, error);
683
681
  res.status(500).send('Error reading history file.');
684
682
  }
685
683
  });
686
- this.expressApp.get('/api/download-backup', async (req, res) => {
684
+ this.expressApp.get('/api/download-backup', (req, res) => {
687
685
  this.log.debug('The frontend sent /api/download-backup');
688
686
  if (!this.validateReq(req, res))
689
687
  return;
690
688
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
691
689
  this.wssSendCloseSnackbarMessage('Creating matterbridge backup...');
692
690
  if (error) {
693
- this.log.error(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
694
- res.status(500).send(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
691
+ logError(this.log, `Error downloading file matterbridge.backup.zip`, error);
692
+ res.status(500).send(`Error downloading file matterbridge.backup.zip: ${getErrorMessage(error)}`);
695
693
  }
696
694
  else {
697
695
  this.log.debug('Backup matterbridge.backup.zip downloaded successfully');
698
696
  }
699
697
  });
700
698
  });
701
- this.expressApp.get('/api/download-mbstorage', async (req, res) => {
699
+ this.expressApp.get('/api/download-mbstorage', (req, res) => {
702
700
  this.log.debug('The frontend sent /api/download-mbstorage');
703
701
  if (!this.validateReq(req, res))
704
702
  return;
@@ -713,14 +711,14 @@ export class Frontend extends EventEmitter {
713
711
  }
714
712
  });
715
713
  });
716
- this.expressApp.get('/api/download-mjstorage', async (req, res) => {
714
+ this.expressApp.get('/api/download-mjstorage', (req, res) => {
717
715
  this.log.debug('The frontend sent /api/download-mjstorage');
718
716
  if (!this.validateReq(req, res))
719
717
  return;
720
718
  res.download(path.join(os.tmpdir(), `matterbridge.${MATTER_STORAGE_DIR}.zip`), `matterbridge.${MATTER_STORAGE_DIR}.zip`, (error) => {
721
719
  this.wssSendCloseSnackbarMessage('Creating matter storage backup...');
722
720
  if (error) {
723
- this.log.error(`Error downloading the matter storage matterbridge.${MATTER_STORAGE_DIR}.zip: ${error instanceof Error ? error.message : error}`);
721
+ logError(this.log, `Error downloading the matter storage matterbridge.${MATTER_STORAGE_DIR}.zip`, error);
724
722
  res.status(500).send('Error downloading the matter storage zip file');
725
723
  }
726
724
  else {
@@ -728,14 +726,14 @@ export class Frontend extends EventEmitter {
728
726
  }
729
727
  });
730
728
  });
731
- this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
729
+ this.expressApp.get('/api/download-pluginstorage', (req, res) => {
732
730
  this.log.debug('The frontend sent /api/download-pluginstorage');
733
731
  if (!this.validateReq(req, res))
734
732
  return;
735
733
  res.download(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), `matterbridge.pluginstorage.zip`, (error) => {
736
734
  this.wssSendCloseSnackbarMessage('Creating plugin backup...');
737
735
  if (error) {
738
- this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
736
+ logError(this.log, `Error downloading file matterbridge.pluginstorage.zip`, error);
739
737
  res.status(500).send('Error downloading the matterbridge plugin storage file');
740
738
  }
741
739
  else {
@@ -743,14 +741,14 @@ export class Frontend extends EventEmitter {
743
741
  }
744
742
  });
745
743
  });
746
- this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
744
+ this.expressApp.get('/api/download-pluginconfig', (req, res) => {
747
745
  this.log.debug('The frontend sent /api/download-pluginconfig');
748
746
  if (!this.validateReq(req, res))
749
747
  return;
750
748
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
751
749
  this.wssSendCloseSnackbarMessage('Creating config backup...');
752
750
  if (error) {
753
- this.log.error(`Error downloading file matterbridge.pluginconfig.zip: ${error instanceof Error ? error.message : error}`);
751
+ logError(this.log, `Error downloading file matterbridge.pluginconfig.zip`, error);
754
752
  res.status(500).send('Error downloading the matterbridge plugin config file');
755
753
  }
756
754
  else {
@@ -960,7 +958,7 @@ export class Frontend extends EventEmitter {
960
958
  if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
961
959
  return false;
962
960
  if (device.hasClusterServer(BridgedDeviceBasicInformation.id))
963
- return device.getAttribute(BridgedDeviceBasicInformation.id, 'reachable');
961
+ return device.getAttribute(BridgedDeviceBasicInformation, 'reachable');
964
962
  if (device.mode === 'server' && device.serverNode?.state.basicInformation.reachable !== undefined)
965
963
  return device.serverNode.state.basicInformation.reachable;
966
964
  if (this.matterbridge.bridgeMode === 'childbridge')
@@ -982,7 +980,7 @@ export class Frontend extends EventEmitter {
982
980
  const batChargeLevel = device.getAttribute(PowerSource.id, 'batChargeLevel');
983
981
  return ['ok', 'warning', 'critical'][batChargeLevel];
984
982
  }
985
- return;
983
+ return undefined;
986
984
  };
987
985
  if (endpoint.hasClusterServer(PowerSource.id))
988
986
  return powerSource(endpoint);
@@ -990,6 +988,7 @@ export class Frontend extends EventEmitter {
990
988
  if (child.hasClusterServer(PowerSource.id))
991
989
  return powerSource(child);
992
990
  }
991
+ return undefined;
993
992
  }
994
993
  getBatteryLevel(endpoint) {
995
994
  if (this.matterbridge.hasCleanupStarted)
@@ -1002,7 +1001,7 @@ export class Frontend extends EventEmitter {
1002
1001
  const batChargeLevel = device.getAttribute(PowerSource.id, 'batPercentRemaining');
1003
1002
  return isValidNumber(batChargeLevel) ? batChargeLevel / 2 : undefined;
1004
1003
  }
1005
- return;
1004
+ return undefined;
1006
1005
  };
1007
1006
  if (endpoint.hasClusterServer(PowerSource.id))
1008
1007
  return batteryLevel(endpoint);
@@ -1010,6 +1009,7 @@ export class Frontend extends EventEmitter {
1010
1009
  if (child.hasClusterServer(PowerSource.id))
1011
1010
  return batteryLevel(child);
1012
1011
  }
1012
+ return undefined;
1013
1013
  }
1014
1014
  getClusterTextFromDevice(device) {
1015
1015
  if (this.matterbridge.hasCleanupStarted)
package/dist/helpers.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Endpoint } from '@matter/node';
2
- import { type AggregatorEndpoint } from '@matter/node/endpoints/aggregator';
2
+ import type { AggregatorEndpoint } from '@matter/node/endpoints/aggregator';
3
3
  import type { Matterbridge } from './matterbridge.js';
4
4
  export declare function addVirtualDevice(aggregatorEndpoint: Endpoint<AggregatorEndpoint>, name: string, type: 'light' | 'outlet' | 'switch' | 'mounted_switch', callback: () => Promise<void>): Promise<Endpoint>;
5
5
  export declare function addVirtualDevices(matterbridge: Matterbridge, aggregatorEndpoint: Endpoint<AggregatorEndpoint>): Promise<void>;
package/dist/helpers.js CHANGED
@@ -1,5 +1,3 @@
1
- if (process.argv.includes('--loader'))
2
- console.log('\u001B[32m[' + new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit', fractionalSecondDigits: 3 }) + '] MatterbridgeHelpers loaded.\u001B[40;0m');
3
1
  import { Endpoint } from '@matter/node';
4
2
  import { BindingServer } from '@matter/node/behaviors/binding';
5
3
  import { BridgedDeviceBasicInformationServer } from '@matter/node/behaviors/bridged-device-basic-information';
@@ -10,6 +8,8 @@ import { OnOffLightDevice } from '@matter/node/devices/on-off-light';
10
8
  import { OnOffLightSwitchDevice } from '@matter/node/devices/on-off-light-switch';
11
9
  import { OnOffPlugInUnitDevice } from '@matter/node/devices/on-off-plug-in-unit';
12
10
  import { VendorId } from '@matter/types/datatype';
11
+ import { logModuleLoaded } from '@matterbridge/utils/loader';
12
+ logModuleLoaded('MatterbridgeHelpers');
13
13
  export async function addVirtualDevice(aggregatorEndpoint, name, type, callback) {
14
14
  let deviceType;
15
15
  switch (type) {
@@ -40,8 +40,10 @@ export async function addVirtualDevice(aggregatorEndpoint, name, type, callback)
40
40
  });
41
41
  device.events.onOff.onOff$Changed.on((value) => {
42
42
  if (value) {
43
- void callback().catch(() => { });
44
- void device.setStateOf(OnOffServer, { onOff: false }).catch(() => { });
43
+ void callback().catch(() => {
44
+ });
45
+ void device.setStateOf(OnOffServer, { onOff: false }).catch(() => {
46
+ });
45
47
  }
46
48
  });
47
49
  await aggregatorEndpoint.add(device);
@@ -183,7 +183,7 @@ export async function startServerNode(ticks = 1, microTurns = 1, pause = 10) {
183
183
  throw new Error('Server node and aggregator must be created before starting the server. Call createServerNode() first.');
184
184
  }
185
185
  await new Promise((resolve, reject) => {
186
- server.lifecycle.online.on(async () => {
186
+ server.lifecycle.online.on(() => {
187
187
  resolve();
188
188
  });
189
189
  server.start().catch((err) => reject(err));
@@ -1,5 +1,5 @@
1
- import { type Endpoint, type ServerNode } from '@matter/node';
2
- import { type AggregatorEndpoint } from '@matter/node/endpoints';
1
+ import type { Endpoint, ServerNode } from '@matter/node';
2
+ import type { AggregatorEndpoint } from '@matter/node/endpoints';
3
3
  import type { DeviceManager } from '../deviceManager.js';
4
4
  import type { Frontend } from '../frontend.js';
5
5
  import { Matterbridge } from '../matterbridge.js';