matterbridge 3.1.1-dev-20250703-80c685d → 3.1.1-dev-20250704-aff5fcb

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/CHANGELOG.md CHANGED
@@ -8,12 +8,12 @@ If you like this project and find it useful, please consider giving it a star on
8
8
  <img src="bmc-button.svg" alt="Buy me a coffee" width="120">
9
9
  </a>
10
10
 
11
- ## [3.1.1] - 2025-07-01
11
+ ## [3.1.1] - 2025-07-08
12
12
 
13
13
  ### Development Breaking Changes
14
14
 
15
- - [devices]: The single devices (i.e. Rvc, Evse etc...) are only exported from `matterbridge/devices`. Please update your imports to use the new export path. Refer to the [documentation](README-DEV.md) for details on imports.
16
- - [MatterbridgeEndpoint]: Added the mode property: `server` will make the device indipendent from its plugin. It has its own server node: QRCode, Fabrics and Sessions are visible in the Devices section of the Home page. This a workaround for the Rvc Apple issue. So the Rvc (like any other device) can be paired directly to the controller and is a native Matter device and is not bridged.
15
+ - [exports]: The single devices (i.e. Rvc, Evse etc...) are only exported from `matterbridge/devices`. Please update your imports to use the new export path. Refer to the [documentation](README-DEV.md) for details on imports.
16
+ - [MatterbridgeEndpoint]: Added the mode property: `server` will make the device indipendent from its plugin. It has its own server node: QRCode, Fabrics and Sessions are visible in the Devices section of the Home page. This is a workaround for the Rvc Apple issue. With mode=server the Rvc (like any other device) can be paired directly to the controller like a native not bridged Matter device.
17
17
 
18
18
  ### Added
19
19
 
@@ -27,8 +27,9 @@ If you like this project and find it useful, please consider giving it a star on
27
27
 
28
28
  - [package]: Updated dependencies.
29
29
  - [frontend]: Added all esa devices.
30
- - [frontend]: New default values: select on the home page and icon view on devices page.
30
+ - [frontend]: New default values: devices on the home page and icon view on the devices page.
31
31
  - [matter.js]: Bumped `matter.js` to 0.15.1 (https://github.com/project-chip/matter.js/discussions/2220). Great job matter.js!
32
+ - [imports]: Added more dynamic imports to Matterbridge and Frontend classes.
32
33
 
33
34
  <a href="https://www.buymeacoffee.com/luligugithub">
34
35
  <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
package/dist/frontend.js CHANGED
@@ -3,6 +3,7 @@ import https from 'node:https';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { promises as fs } from 'node:fs';
6
+ import EventEmitter from 'node:events';
6
7
  import express from 'express';
7
8
  import WebSocket, { WebSocketServer } from 'ws';
8
9
  import multer from 'multer';
@@ -12,7 +13,6 @@ import { BridgedDeviceBasicInformation, PowerSource } from '@matter/main/cluster
12
13
  import { createZip, isValidArray, isValidNumber, isValidObject, isValidString, isValidBoolean, withTimeout, hasParameter } from './utils/export.js';
13
14
  import { plg } from './matterbridgeTypes.js';
14
15
  import { capitalizeFirstLetter } from './matterbridgeEndpointHelpers.js';
15
- import spawn from './utils/spawn.js';
16
16
  export const WS_ID_LOG = 0;
17
17
  export const WS_ID_REFRESH_NEEDED = 1;
18
18
  export const WS_ID_RESTART_NEEDED = 2;
@@ -25,7 +25,7 @@ export const WS_ID_STATEUPDATE = 8;
25
25
  export const WS_ID_CLOSE_SNACKBAR = 9;
26
26
  export const WS_ID_SHELLY_SYS_UPDATE = 100;
27
27
  export const WS_ID_SHELLY_MAIN_UPDATE = 101;
28
- export class Frontend {
28
+ export class Frontend extends EventEmitter {
29
29
  matterbridge;
30
30
  log;
31
31
  port = 8283;
@@ -35,6 +35,7 @@ export class Frontend {
35
35
  httpsServer;
36
36
  webSocketServer;
37
37
  constructor(matterbridge) {
38
+ super();
38
39
  this.matterbridge = matterbridge;
39
40
  this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
40
41
  }
@@ -54,6 +55,7 @@ export class Frontend {
54
55
  if (hasParameter('ingress')) {
55
56
  this.httpServer.listen(this.port, '0.0.0.0', () => {
56
57
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
58
+ this.emit('server_listening', 'http', this.port, '0.0.0.0');
57
59
  });
58
60
  }
59
61
  else {
@@ -62,6 +64,7 @@ export class Frontend {
62
64
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://${this.matterbridge.systemInformation.ipv4Address}:${this.port}${UNDERLINEOFF}${rs}`);
63
65
  if (this.matterbridge.systemInformation.ipv6Address !== '')
64
66
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
67
+ this.emit('server_listening', 'http', this.port);
65
68
  });
66
69
  }
67
70
  this.httpServer.on('error', (error) => {
@@ -75,6 +78,7 @@ export class Frontend {
75
78
  break;
76
79
  }
77
80
  this.initializeError = true;
81
+ this.emit('server_error', error);
78
82
  return;
79
83
  });
80
84
  }
@@ -110,6 +114,7 @@ export class Frontend {
110
114
  if (hasParameter('ingress')) {
111
115
  this.httpsServer.listen(this.port, '0.0.0.0', () => {
112
116
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
117
+ this.emit('server_listening', 'https', this.port, '0.0.0.0');
113
118
  });
114
119
  }
115
120
  else {
@@ -118,6 +123,7 @@ export class Frontend {
118
123
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://${this.matterbridge.systemInformation.ipv4Address}:${this.port}${UNDERLINEOFF}${rs}`);
119
124
  if (this.matterbridge.systemInformation.ipv6Address !== '')
120
125
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
126
+ this.emit('server_listening', 'https', this.port);
121
127
  });
122
128
  }
123
129
  this.httpsServer.on('error', (error) => {
@@ -131,6 +137,7 @@ export class Frontend {
131
137
  break;
132
138
  }
133
139
  this.initializeError = true;
140
+ this.emit('server_error', error);
134
141
  return;
135
142
  });
136
143
  }
@@ -175,6 +182,7 @@ export class Frontend {
175
182
  });
176
183
  this.webSocketServer.on('listening', () => {
177
184
  this.log.info(`The WebSocketServer is listening on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
185
+ this.emit('websocket_server_listening', wssHost);
178
186
  });
179
187
  this.webSocketServer.on('error', (ws, error) => {
180
188
  this.log.error(`WebSocketServer error: ${error}`);
@@ -423,7 +431,8 @@ export class Frontend {
423
431
  await fs.rename(file.path, filePath);
424
432
  this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
425
433
  if (filename.endsWith('.tgz')) {
426
- await spawn.spawnCommand(this.matterbridge, 'npm', ['install', '-g', filePath, '--omit=dev', '--verbose']);
434
+ const { spawnCommand } = await import('./utils/spawn.js');
435
+ await spawnCommand(this.matterbridge, 'npm', ['install', '-g', filePath, '--omit=dev', '--verbose']);
427
436
  this.log.info(`Plugin package ${plg}${filename}${nf} installed successfully. Full restart required.`);
428
437
  this.wssSendCloseSnackbarMessage(`Installing package ${filename}. Please wait...`);
429
438
  this.wssSendSnackbarMessage(`Installed package ${filename}`, 10, 'success');
@@ -897,8 +906,8 @@ export class Frontend {
897
906
  return;
898
907
  }
899
908
  this.wssSendSnackbarMessage(`Installing package ${data.params.packageName}...`, 0);
900
- spawn
901
- .spawnCommand(this.matterbridge, 'npm', ['install', '-g', data.params.packageName, '--omit=dev', '--verbose'])
909
+ const { spawnCommand } = await import('./utils/spawn.js');
910
+ spawnCommand(this.matterbridge, 'npm', ['install', '-g', data.params.packageName, '--omit=dev', '--verbose'])
902
911
  .then((response) => {
903
912
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
904
913
  this.wssSendCloseSnackbarMessage(`Installing package ${data.params.packageName}...`);
@@ -962,8 +971,8 @@ export class Frontend {
962
971
  this.wssSendRefreshRequired('devices');
963
972
  }
964
973
  this.wssSendSnackbarMessage(`Uninstalling package ${data.params.packageName}...`, 0);
965
- spawn
966
- .spawnCommand(this.matterbridge, 'npm', ['uninstall', '-g', data.params.packageName, '--verbose'])
974
+ const { spawnCommand } = await import('./utils/spawn.js');
975
+ spawnCommand(this.matterbridge, 'npm', ['uninstall', '-g', data.params.packageName, '--verbose'])
967
976
  .then((response) => {
968
977
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
969
978
  this.wssSendCloseSnackbarMessage(`Uninstalling package ${data.params.packageName}...`);
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import { promises as fs } from 'node:fs';
4
4
  import EventEmitter from 'node:events';
5
5
  import { inspect } from 'node:util';
6
- import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN } from 'node-ansi-logger';
6
+ import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt } from 'node-ansi-logger';
7
7
  import { NodeStorageManager } from 'node-persist-manager';
8
8
  import { DeviceTypeId, Endpoint, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode, UINT32_MAX, UINT16_MAX, Crypto, } from '@matter/main';
9
9
  import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
@@ -11,7 +11,6 @@ import { AggregatorEndpoint } from '@matter/main/endpoints';
11
11
  import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
12
12
  import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
13
13
  import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout, waiter, isValidString, parseVersionString, isValidNumber, createDirectory } from './utils/export.js';
14
- import { logInterfaces, getGlobalNodeModules } from './utils/network.js';
15
14
  import { dev, plg, typ } from './matterbridgeTypes.js';
16
15
  import { PluginManager } from './pluginManager.js';
17
16
  import { DeviceManager } from './deviceManager.js';
@@ -19,7 +18,6 @@ import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
19
18
  import { bridge } from './matterbridgeDeviceTypes.js';
20
19
  import { Frontend } from './frontend.js';
21
20
  import { addVirtualDevices } from './helpers.js';
22
- import spawn from './utils/spawn.js';
23
21
  export class Matterbridge extends EventEmitter {
24
22
  systemInformation = {
25
23
  interfaceName: '',
@@ -385,15 +383,15 @@ export class Matterbridge extends EventEmitter {
385
383
  }
386
384
  Logger.format = MatterLogFormat.ANSI;
387
385
  Logger.setLogger('default', this.createMatterLogger());
388
- this.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
386
+ this.matterbridgeInformation.matterLoggerLevel = Logger.level;
389
387
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
390
388
  this.matterbridgeInformation.matterFileLogger = true;
391
389
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
392
- defaultLogLevel: Logger.defaultLogLevel,
390
+ defaultLogLevel: Logger.level,
393
391
  logFormat: MatterLogFormat.PLAIN,
394
392
  });
395
393
  }
396
- this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
394
+ this.log.debug(`Matter logLevel: ${Logger.level} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
397
395
  const networkInterfaces = os.networkInterfaces();
398
396
  const availableAddresses = Object.entries(networkInterfaces);
399
397
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -494,7 +492,8 @@ export class Matterbridge extends EventEmitter {
494
492
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
495
493
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
496
494
  try {
497
- await spawn.spawnCommand(this, 'npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
495
+ const { spawnCommand } = await import('./utils/spawn.js');
496
+ await spawnCommand(this, 'npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
498
497
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
499
498
  plugin.error = false;
500
499
  }
@@ -605,6 +604,7 @@ export class Matterbridge extends EventEmitter {
605
604
  return;
606
605
  }
607
606
  if (hasParameter('loginterfaces')) {
607
+ const { logInterfaces } = await import('./utils/network.js');
608
608
  this.log.info(`${plg}Matterbridge${nf} network interfaces log`);
609
609
  logInterfaces();
610
610
  this.shutdown = true;
@@ -667,7 +667,7 @@ export class Matterbridge extends EventEmitter {
667
667
  await matterStorageManager.createContext('root')?.clearAll();
668
668
  await matterStorageManager.createContext('sessions')?.clearAll();
669
669
  await matterStorageManager.createContext('persist')?.clearAll();
670
- this.log.info(`Reset commissionig for plugin ${plg}${plugin.name}${nf} done! Remove the device from the controller.`);
670
+ this.log.notice(`Reset commissioning for plugin ${plg}${plugin.name}${nt} done! Remove the device from the controller.`);
671
671
  }
672
672
  }
673
673
  else {
@@ -679,10 +679,12 @@ export class Matterbridge extends EventEmitter {
679
679
  }
680
680
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
681
681
  await this.frontend.start(getIntParameter('frontend'));
682
+ clearTimeout(this.checkUpdateTimeout);
682
683
  this.checkUpdateTimeout = setTimeout(async () => {
683
684
  const { checkUpdates } = await import('./update.js');
684
685
  checkUpdates(this);
685
686
  }, 30 * 1000).unref();
687
+ clearInterval(this.checkUpdateInterval);
686
688
  this.checkUpdateInterval = setInterval(async () => {
687
689
  const { checkUpdates } = await import('./update.js');
688
690
  checkUpdates(this);
@@ -853,6 +855,7 @@ export class Matterbridge extends EventEmitter {
853
855
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
854
856
  if (this.globalModulesDirectory === '') {
855
857
  try {
858
+ const { getGlobalNodeModules } = await import('./utils/network.js');
856
859
  this.execRunningCount++;
857
860
  this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory = await getGlobalNodeModules();
858
861
  this.execRunningCount--;
@@ -905,9 +908,6 @@ export class Matterbridge extends EventEmitter {
905
908
  case MatterLogLevel.FATAL:
906
909
  matterLogger.log("fatal", message);
907
910
  break;
908
- default:
909
- matterLogger.log("debug", message);
910
- break;
911
911
  }
912
912
  };
913
913
  }
@@ -922,11 +922,12 @@ export class Matterbridge extends EventEmitter {
922
922
  }
923
923
  }
924
924
  return async (level, formattedLog) => {
925
- if (fileSize > 100000000)
925
+ if (fileSize > 100000000) {
926
926
  return;
927
+ }
927
928
  fileSize += formattedLog.length;
928
929
  if (fileSize > 100000000) {
929
- await fs.appendFile(filePath, `Logging on file has been stoppped because the file size is greater then 100MB.` + os.EOL);
930
+ await fs.appendFile(filePath, `Logging on file has been stopped because the file size is greater than 100MB.` + os.EOL);
930
931
  return;
931
932
  }
932
933
  const now = new Date();
@@ -954,9 +955,6 @@ export class Matterbridge extends EventEmitter {
954
955
  case MatterLogLevel.FATAL:
955
956
  await fs.appendFile(filePath, `[${timestamp}] [${logger}] [fatal] ${finalMessage}`);
956
957
  break;
957
- default:
958
- await fs.appendFile(filePath, `[${timestamp}] [${logger}] ${finalMessage}`);
959
- break;
960
958
  }
961
959
  };
962
960
  }
@@ -969,11 +967,12 @@ export class Matterbridge extends EventEmitter {
969
967
  async updateProcess() {
970
968
  this.log.info('Updating matterbridge...');
971
969
  try {
972
- await spawn.spawnCommand(this, 'npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
970
+ const { spawnCommand } = await import('./utils/spawn.js');
971
+ await spawnCommand(this, 'npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
973
972
  this.log.info('Matterbridge has been updated. Full restart required.');
974
973
  }
975
974
  catch (error) {
976
- this.log.error('Error updating matterbridge:', error instanceof Error ? error.message : error);
975
+ this.log.error(`Error updating matterbridge: ${error instanceof Error ? error.message : error}`);
977
976
  }
978
977
  this.frontend.wssSendRestartRequired();
979
978
  await this.cleanup('updating...', false);
@@ -1,68 +1,66 @@
1
1
  import { hasParameter } from './commandLine.js';
2
- export default {
3
- async spawnCommand(matterbridge, command, args) {
4
- const { spawn } = await import('node:child_process');
5
- const cmdLine = command + ' ' + args.join(' ');
6
- if (process.platform === 'win32' && command === 'npm') {
7
- const argstring = 'npm ' + args.join(' ');
8
- args.splice(0, args.length, '/c', argstring);
9
- command = 'cmd.exe';
10
- }
11
- if (hasParameter('sudo') || (process.platform !== 'win32' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
12
- args.unshift(command);
13
- command = 'sudo';
14
- }
15
- matterbridge.log.debug(`Spawn command ${command} with ${args.join(' ')}`);
16
- return new Promise((resolve, reject) => {
17
- const childProcess = spawn(command, args, {
18
- stdio: ['inherit', 'pipe', 'pipe'],
19
- });
20
- childProcess.on('error', (err) => {
21
- matterbridge.log.error(`Failed to start child process "${cmdLine}": ${err.message}`);
22
- reject(err);
23
- });
24
- childProcess.on('close', (code, signal) => {
25
- matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', `child process closed with code ${code} and signal ${signal}`);
26
- if (code === 0) {
27
- if (cmdLine.startsWith('npm install -g'))
28
- matterbridge.log.notice(`Package ${cmdLine.replace('npm install -g ', '').replace('--verbose', '').replace('--omit=dev', '')} installed correctly`);
29
- matterbridge.log.debug(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
30
- resolve(true);
31
- }
32
- else {
33
- matterbridge.log.error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
34
- reject(new Error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`));
35
- }
36
- });
37
- childProcess.on('exit', (code, signal) => {
38
- matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', `child process exited with code ${code} and signal ${signal}`);
39
- if (code === 0) {
40
- matterbridge.log.debug(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
41
- resolve(true);
42
- }
43
- else {
44
- matterbridge.log.error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
45
- reject(new Error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`));
46
- }
47
- });
48
- childProcess.on('disconnect', () => {
49
- matterbridge.log.debug(`Child process "${cmdLine}" has been disconnected from the parent`);
2
+ export async function spawnCommand(matterbridge, command, args) {
3
+ const { spawn } = await import('node:child_process');
4
+ const cmdLine = command + ' ' + args.join(' ');
5
+ if (process.platform === 'win32' && command === 'npm') {
6
+ const argstring = 'npm ' + args.join(' ');
7
+ args.splice(0, args.length, '/c', argstring);
8
+ command = 'cmd.exe';
9
+ }
10
+ if (hasParameter('sudo') || (process.platform !== 'win32' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
11
+ args.unshift(command);
12
+ command = 'sudo';
13
+ }
14
+ matterbridge.log.debug(`Spawn command ${command} with ${args.join(' ')}`);
15
+ return new Promise((resolve, reject) => {
16
+ const childProcess = spawn(command, args, {
17
+ stdio: ['inherit', 'pipe', 'pipe'],
18
+ });
19
+ childProcess.on('error', (err) => {
20
+ matterbridge.log.error(`Failed to start child process "${cmdLine}": ${err.message}`);
21
+ reject(err);
22
+ });
23
+ childProcess.on('close', (code, signal) => {
24
+ matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', `child process closed with code ${code} and signal ${signal}`);
25
+ if (code === 0) {
26
+ if (cmdLine.startsWith('npm install -g'))
27
+ matterbridge.log.notice(`Package ${cmdLine.replace('npm install -g ', '').replace('--verbose', '').replace('--omit=dev', '')} installed correctly`);
28
+ matterbridge.log.debug(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
50
29
  resolve(true);
51
- });
52
- if (childProcess.stdout) {
53
- childProcess.stdout.on('data', (data) => {
54
- const message = data.toString().trim();
55
- matterbridge.log.debug(`Spawn output (stdout): ${message}`);
56
- matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', message);
57
- });
58
30
  }
59
- if (childProcess.stderr) {
60
- childProcess.stderr.on('data', (data) => {
61
- const message = data.toString().trim();
62
- matterbridge.log.debug(`Spawn verbose (stderr): ${message}`);
63
- matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', message);
64
- });
31
+ else {
32
+ matterbridge.log.error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
33
+ reject(new Error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`));
65
34
  }
66
35
  });
67
- },
68
- };
36
+ childProcess.on('exit', (code, signal) => {
37
+ matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', `child process exited with code ${code} and signal ${signal}`);
38
+ if (code === 0) {
39
+ matterbridge.log.debug(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
40
+ resolve(true);
41
+ }
42
+ else {
43
+ matterbridge.log.error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
44
+ reject(new Error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`));
45
+ }
46
+ });
47
+ childProcess.on('disconnect', () => {
48
+ matterbridge.log.debug(`Child process "${cmdLine}" has been disconnected from the parent`);
49
+ resolve(true);
50
+ });
51
+ if (childProcess.stdout) {
52
+ childProcess.stdout.on('data', (data) => {
53
+ const message = data.toString().trim();
54
+ matterbridge.log.debug(`Spawn output (stdout): ${message}`);
55
+ matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', message);
56
+ });
57
+ }
58
+ if (childProcess.stderr) {
59
+ childProcess.stderr.on('data', (data) => {
60
+ const message = data.toString().trim();
61
+ matterbridge.log.debug(`Spawn verbose (stderr): ${message}`);
62
+ matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', message);
63
+ });
64
+ }
65
+ });
66
+ }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.1.1-dev-20250703-80c685d",
3
+ "version": "3.1.1-dev-20250704-aff5fcb",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.1.1-dev-20250703-80c685d",
9
+ "version": "3.1.1-dev-20250704-aff5fcb",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.15.1",
@@ -16,7 +16,7 @@
16
16
  "multer": "2.0.1",
17
17
  "node-ansi-logger": "3.1.1",
18
18
  "node-persist-manager": "2.0.0",
19
- "ws": "8.18.2"
19
+ "ws": "8.18.3"
20
20
  },
21
21
  "bin": {
22
22
  "matterbridge": "bin/matterbridge"
@@ -2126,9 +2126,9 @@
2126
2126
  "license": "ISC"
2127
2127
  },
2128
2128
  "node_modules/ws": {
2129
- "version": "8.18.2",
2130
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
2131
- "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
2129
+ "version": "8.18.3",
2130
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
2131
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
2132
2132
  "license": "MIT",
2133
2133
  "engines": {
2134
2134
  "node": ">=10.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.1.1-dev-20250703-80c685d",
3
+ "version": "3.1.1-dev-20250704-aff5fcb",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",
@@ -105,6 +105,6 @@
105
105
  "multer": "2.0.1",
106
106
  "node-ansi-logger": "3.1.1",
107
107
  "node-persist-manager": "2.0.0",
108
- "ws": "8.18.2"
108
+ "ws": "8.18.3"
109
109
  }
110
110
  }