matterbridge 3.3.9-dev-20251119-ea13a99 → 3.4.0-dev-20251120-21b4f48

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
@@ -28,7 +28,7 @@ Advantages:
28
28
  - individual plugin isolation in childbridge mode;
29
29
  - ability to update the plugin in childbridge mode without restarting matterbridge;
30
30
 
31
- ## [3.3.9] - Not published
31
+ ## [3.4.0] - Not published
32
32
 
33
33
  ### Development Breaking Changes
34
34
 
@@ -38,9 +38,20 @@ Removed the following long deprecated elements:
38
38
  - [endpoint]: uniqueStorageKey instead of id in MatterbridgeEndpointOptions (deprecated since months).
39
39
  - [endpoint]: endpointId instead of number in MatterbridgeEndpointOptions (deprecated since months).
40
40
 
41
+ ### Added
42
+
43
+ - [endpoint]: Added getChildEndpointById() and getChildEndpointByOriginalId().
44
+ - [endpoint]: Deprecated getChildEndpointByName(). Use getChildEndpointById() or getChildEndpointByOriginalId().
45
+ - [platform]: Added wssSendSnackbarMessage method to MatterbridgePlatform for sending snackbar notifications to the frontend.
46
+
41
47
  ### Changed
42
48
 
43
49
  - [package]: Updated dependencies.
50
+ - [deviceManager]: Bumped DeviceManager v.1.1.1.
51
+ - [pluginManager]: Bumped PluginManager v.1.3.1.
52
+ - [broadcastServer]: Bumped BroadcastServer v.1.0.3.
53
+ - [jest]: Bumped jestHelpers v.1.0.13.
54
+ - [spawn]: Bumped spawn module v.1.2.0.
44
55
 
45
56
  <a href="https://www.buymeacoffee.com/luligugithub">
46
57
  <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
@@ -70,7 +70,7 @@ export class BroadcastServer extends EventEmitter {
70
70
  this.log.debug(`Broadcasting response message: ${debugStringify(message)}`);
71
71
  this.broadcastChannel.postMessage(message);
72
72
  }
73
- async fetch(message, timeout = 100) {
73
+ async fetch(message, timeout = 250) {
74
74
  if (message.id === undefined) {
75
75
  message.id = this.getUniqueId();
76
76
  }
@@ -2,6 +2,31 @@ import { AnsiLogger, BLUE, CYAN, db, debugStringify, er } from 'node-ansi-logger
2
2
  import { dev } from './matterbridgeTypes.js';
3
3
  import { BroadcastServer } from './broadcastServer.js';
4
4
  import { hasParameter } from './utils/commandLine.js';
5
+ export function toBaseDevice(device) {
6
+ return {
7
+ mode: device.mode,
8
+ plugin: device.plugin,
9
+ configUrl: device.configUrl,
10
+ deviceName: device.deviceName,
11
+ serialNumber: device.serialNumber,
12
+ uniqueId: device.uniqueId,
13
+ vendorId: device.vendorId,
14
+ vendorName: device.vendorName,
15
+ productId: device.productId,
16
+ productName: device.productName,
17
+ softwareVersion: device.softwareVersion,
18
+ softwareVersionString: device.softwareVersionString,
19
+ hardwareVersion: device.hardwareVersion,
20
+ hardwareVersionString: device.hardwareVersionString,
21
+ productUrl: device.productUrl,
22
+ tagList: device.tagList,
23
+ originalId: device.originalId,
24
+ name: device.name,
25
+ deviceType: device.deviceType,
26
+ number: device.number,
27
+ id: device.id,
28
+ };
29
+ }
5
30
  export class DeviceManager {
6
31
  _devices = new Map();
7
32
  log;
@@ -40,13 +65,16 @@ export class DeviceManager {
40
65
  this.server.respond({ ...msg, response: { has: this.has(msg.params.uniqueId) } });
41
66
  break;
42
67
  case 'devices_get':
43
- this.server.respond({ ...msg, response: { device: this.get(msg.params.uniqueId) } });
68
+ {
69
+ const endpoint = this.get(msg.params.uniqueId);
70
+ this.server.respond({ ...msg, response: { device: endpoint ? toBaseDevice(endpoint) : undefined } });
71
+ }
44
72
  break;
45
73
  case 'devices_set':
46
- this.server.respond({ ...msg, response: { device: this.set(msg.params.device) } });
74
+ this.server.respond({ ...msg, response: { device: this.set(toBaseDevice(msg.params.device)) } });
47
75
  break;
48
76
  case 'devices_remove':
49
- this.server.respond({ ...msg, response: { success: this.remove(msg.params.device) } });
77
+ this.server.respond({ ...msg, response: { success: this.remove(toBaseDevice(msg.params.device)) } });
50
78
  break;
51
79
  case 'devices_clear':
52
80
  this.clear();
@@ -92,24 +120,14 @@ export class DeviceManager {
92
120
  this._devices.clear();
93
121
  }
94
122
  toBaseDevice(device) {
95
- return {
96
- pluginName: device.plugin,
97
- deviceType: device.deviceType,
98
- number: device.maybeNumber,
99
- id: device.maybeId,
100
- deviceName: device.deviceName,
101
- serialNumber: device.serialNumber,
102
- uniqueId: device.uniqueId,
103
- productUrl: device.productUrl,
104
- configUrl: device.configUrl,
105
- };
123
+ return toBaseDevice(device);
106
124
  }
107
125
  array() {
108
126
  return Array.from(this._devices.values());
109
127
  }
110
128
  baseArray(pluginName) {
111
129
  const devices = [];
112
- for (const device of this._devices.values()) {
130
+ for (const device of Array.from(this._devices.values())) {
113
131
  if (pluginName && pluginName !== device.plugin)
114
132
  continue;
115
133
  devices.push(this.toBaseDevice(device));
package/dist/frontend.js CHANGED
@@ -89,6 +89,10 @@ export class Frontend extends EventEmitter {
89
89
  this.wssSendAttributeChangedMessage(msg.params.plugin, msg.params.serialNumber, msg.params.uniqueId, msg.params.number, msg.params.id, msg.params.cluster, msg.params.attribute, msg.params.value);
90
90
  this.server.respond({ ...msg, response: { success: true } });
91
91
  break;
92
+ case 'frontend_logmessage':
93
+ this.wssSendLogMessage(msg.params.level, msg.params.time, msg.params.name, msg.params.message);
94
+ this.server.respond({ ...msg, response: { success: true } });
95
+ break;
92
96
  default:
93
97
  if (this.verbose)
94
98
  this.log.debug(`Unknown broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
@@ -689,15 +693,23 @@ export class Frontend extends EventEmitter {
689
693
  this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
690
694
  if (filename.endsWith('.tgz')) {
691
695
  const { spawnCommand } = await import('./utils/spawn.js');
692
- await spawnCommand(this.matterbridge, 'npm', ['install', '-g', filePath, '--omit=dev', '--verbose'], 'install', filename);
693
- this.log.info(`Plugin package ${plg}${filename}${nf} installed successfully. Full restart required.`);
694
- this.wssSendCloseSnackbarMessage(`Installing package ${filename}. Please wait...`);
695
- this.wssSendSnackbarMessage(`Installed package ${filename}`, 10, 'success');
696
- this.wssSendRestartRequired();
697
- res.send(`Plugin package ${filename} uploaded and installed successfully`);
696
+ if (await spawnCommand('npm', ['install', '-g', filePath, '--omit=dev', '--verbose'], 'install', filename)) {
697
+ this.log.info(`Plugin package ${plg}${filename}${nf} installed successfully. Full restart required.`);
698
+ this.wssSendCloseSnackbarMessage(`Installing package ${filename}. Please wait...`);
699
+ this.wssSendSnackbarMessage(`Installed package ${filename}`, 10, 'success');
700
+ this.wssSendRestartRequired();
701
+ res.send(`Plugin package ${filename} uploaded and installed successfully`);
702
+ }
703
+ else {
704
+ this.log.error(`Error uploading or installing plugin package file ${plg}${filename}${er}`);
705
+ this.wssSendCloseSnackbarMessage(`Installing package ${filename}. Please wait...`);
706
+ this.wssSendSnackbarMessage(`Error uploading or installing plugin package ${filename}`, 10, 'error');
707
+ res.status(500).send(`Error uploading or installing plugin package ${filename}`);
708
+ }
698
709
  }
699
- else
710
+ else {
700
711
  res.send(`File ${filename} uploaded successfully`);
712
+ }
701
713
  }
702
714
  catch (err) {
703
715
  this.log.error(`Error uploading or installing plugin package file ${plg}${filename}${er}:`, err);
@@ -28,7 +28,6 @@ import { bridge } from './matterbridgeDeviceTypes.js';
28
28
  import { Frontend } from './frontend.js';
29
29
  import { addVirtualDevices } from './helpers.js';
30
30
  import { BroadcastServer } from './broadcastServer.js';
31
- import { inspectError } from './utils/error.js';
32
31
  export class Matterbridge extends EventEmitter {
33
32
  systemInformation = {
34
33
  interfaceName: '',
@@ -462,14 +461,13 @@ export class Matterbridge extends EventEmitter {
462
461
  for (const plugin of this.plugins) {
463
462
  if (!fs.existsSync(plugin.path) && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
464
463
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm...`);
465
- try {
466
- const { spawnCommand } = await import('./utils/spawn.js');
467
- await spawnCommand(this, 'npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose'], 'install', plugin.name);
464
+ const { spawnCommand } = await import('./utils/spawn.js');
465
+ if (await spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose'], 'install', plugin.name)) {
468
466
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
469
467
  plugin.error = false;
470
468
  }
471
- catch (error) {
472
- inspectError(this.log, `Error installing plugin ${plg}${plugin.name}${er}. The plugin is disabled.`, error);
469
+ else {
470
+ this.log.error(`Error reinstalling plugin ${plg}${plugin.name}${nf}. The plugin is disabled.`);
473
471
  plugin.error = true;
474
472
  plugin.enabled = false;
475
473
  continue;
@@ -905,13 +903,12 @@ export class Matterbridge extends EventEmitter {
905
903
  }
906
904
  async updateProcess() {
907
905
  this.log.info('Updating matterbridge...');
908
- try {
909
- const { spawnCommand } = await import('./utils/spawn.js');
910
- await spawnCommand(this, 'npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose'], 'install', 'matterbridge');
906
+ const { spawnCommand } = await import('./utils/spawn.js');
907
+ if (await spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose'], 'install', 'matterbridge')) {
911
908
  this.log.info('Matterbridge has been updated. Full restart required.');
912
909
  }
913
- catch (error) {
914
- this.log.error(`Error updating matterbridge: ${error instanceof Error ? error.message : error}`);
910
+ else {
911
+ this.log.error('Error updating matterbridge.');
915
912
  }
916
913
  this.frontend.wssSendRestartRequired();
917
914
  await this.cleanup('updating...', false);
@@ -368,6 +368,12 @@ export class MatterbridgeEndpoint extends Endpoint {
368
368
  getChildEndpointByName(endpointName) {
369
369
  return this.parts.find((part) => part.id === endpointName);
370
370
  }
371
+ getChildEndpointById(id) {
372
+ return this.parts.find((part) => part.id === id);
373
+ }
374
+ getChildEndpointByOriginalId(originalId) {
375
+ return this.parts.find((part) => part.originalId === originalId);
376
+ }
371
377
  getChildEndpoint(endpointNumber) {
372
378
  return this.parts.find((part) => part.number === endpointNumber);
373
379
  }
@@ -266,6 +266,7 @@ export class PluginManager extends EventEmitter {
266
266
  const pluginsArray = await this.matterbridge.nodeContext.get('plugins', []);
267
267
  for (const plugin of pluginsArray)
268
268
  this._plugins.set(plugin.name, plugin);
269
+ this.log.debug(`Loaded ${BLUE}${pluginsArray.length}${db} plugins from storage`);
269
270
  return pluginsArray;
270
271
  }
271
272
  async saveToStorage() {
@@ -370,8 +371,7 @@ export class PluginManager extends EventEmitter {
370
371
  async install(packageName) {
371
372
  this.log.debug(`Installing plugin ${plg}${packageName}${db}...`);
372
373
  const { spawnCommand } = await import('./utils/spawn.js');
373
- try {
374
- await spawnCommand(this.matterbridge, 'npm', ['install', '-g', packageName, '--omit=dev', '--verbose'], 'install', packageName);
374
+ if (await spawnCommand('npm', ['install', '-g', packageName, '--omit=dev', '--verbose'], 'install', packageName)) {
375
375
  this.matterbridge.restartRequired = true;
376
376
  this.matterbridge.fixedRestartRequired = true;
377
377
  packageName = packageName.replace(/@.*$/, '');
@@ -387,12 +387,11 @@ export class PluginManager extends EventEmitter {
387
387
  await this.matterbridge.shutdownProcess();
388
388
  }
389
389
  }
390
- this.log.debug(`Installed plugin ${plg}${packageName}${db} successfully`);
390
+ this.log.info(`Installed plugin ${plg}${packageName}${db} successfully`);
391
391
  return true;
392
392
  }
393
- catch (error) {
394
- inspectError(this.log, `Failed to install package ${plg}${packageName}${er}`, error);
395
- this.log.debug(`Failed to install plugin ${plg}${packageName}${db}`);
393
+ else {
394
+ this.log.error(`Failed to install plugin ${plg}${packageName}${er}`);
396
395
  return false;
397
396
  }
398
397
  }
@@ -402,20 +401,18 @@ export class PluginManager extends EventEmitter {
402
401
  packageName = packageName.replace(/@.*$/, '');
403
402
  if (packageName === 'matterbridge')
404
403
  return false;
405
- try {
406
- if (this.has(packageName)) {
407
- const plugin = this.get(packageName);
408
- if (plugin && plugin.loaded)
409
- await this.shutdown(plugin, 'Matterbridge is uninstalling the plugin');
410
- await this.remove(packageName);
411
- }
412
- await spawnCommand(this.matterbridge, 'npm', ['uninstall', '-g', packageName, '--verbose'], 'uninstall', packageName);
413
- this.log.debug(`Uninstalled plugin ${plg}${packageName}${db} successfully`);
404
+ if (this.has(packageName)) {
405
+ const plugin = this.get(packageName);
406
+ if (plugin && plugin.loaded)
407
+ await this.shutdown(plugin, 'Matterbridge is uninstalling the plugin');
408
+ await this.remove(packageName);
409
+ }
410
+ if (await spawnCommand('npm', ['uninstall', '-g', packageName, '--verbose'], 'uninstall', packageName)) {
411
+ this.log.info(`Uninstalled plugin ${plg}${packageName}${db} successfully`);
414
412
  return true;
415
413
  }
416
- catch (error) {
417
- inspectError(this.log, `Failed to uninstall package ${plg}${packageName}${er}`, error);
418
- this.log.debug(`Failed to uninstall plugin ${plg}${packageName}${db}`);
414
+ else {
415
+ this.log.error(`Failed to uninstall plugin ${plg}${packageName}${er}`);
419
416
  return false;
420
417
  }
421
418
  }
@@ -741,7 +738,7 @@ export class PluginManager extends EventEmitter {
741
738
  plugin.author = this.getAuthor(packageJson);
742
739
  plugin.configJson = config;
743
740
  plugin.schemaJson = await this.loadSchema(plugin);
744
- config.name = plugin.name;
741
+ config.name = packageJson.name;
745
742
  config.version = packageJson.version;
746
743
  const log = new AnsiLogger({ logName: plugin.description, logTimestampFormat: 4, logLevel: config.debug ? "debug" : this.matterbridge.log.logLevel });
747
744
  const platform = pluginInstance.default(this.matterbridge, log, config);
@@ -1,5 +1,4 @@
1
- import { AnsiLogger } from '../logger/export.js';
2
- export async function copyDirectory(srcDir, destDir) {
1
+ export async function copyDirectory(srcDir, destDir, log) {
3
2
  if (srcDir === '') {
4
3
  throw new Error('Source directory must be specified.');
5
4
  }
@@ -15,10 +14,9 @@ export async function copyDirectory(srcDir, destDir) {
15
14
  if (srcDir === destDir) {
16
15
  throw new Error('Source and destination directories must be different.');
17
16
  }
18
- const log = new AnsiLogger({ logName: 'CopyDirectory', logTimestampFormat: 4, logLevel: "info" });
19
17
  const fs = await import('node:fs').then((mod) => mod.promises);
20
18
  const path = await import('node:path');
21
- log.debug(`copyDirectory: copying directory from ${srcDir} to ${destDir}`);
19
+ log?.debug(`copyDirectory: copying directory from ${srcDir} to ${destDir}`);
22
20
  try {
23
21
  await fs.mkdir(destDir, { recursive: true });
24
22
  const entries = await fs.readdir(srcDir, { withFileTypes: true });
@@ -35,7 +33,7 @@ export async function copyDirectory(srcDir, destDir) {
35
33
  return true;
36
34
  }
37
35
  catch (error) {
38
- log.error(`copyDirectory error copying from ${srcDir} to ${destDir}: ${error instanceof Error ? error.message : error}`);
36
+ log?.error(`copyDirectory error copying from ${srcDir} to ${destDir}: ${error instanceof Error ? error.message : error}`);
39
37
  return false;
40
38
  }
41
39
  }
@@ -1,6 +1,22 @@
1
+ import { AnsiLogger } from 'node-ansi-logger';
2
+ import { BroadcastServer } from '../broadcastServer.js';
1
3
  import { hasParameter } from './commandLine.js';
2
- export async function spawnCommand(matterbridge, command, args, packageCommand, packageName) {
4
+ export async function spawnCommand(command, args, packageCommand, packageName) {
3
5
  const { spawn } = await import('node:child_process');
6
+ const debug = hasParameter('debug') || hasParameter('verbose');
7
+ const verbose = hasParameter('verbose');
8
+ const log = new AnsiLogger({ logName: 'Spawn', logTimestampFormat: 4, logLevel: debug ? "debug" : "info" });
9
+ const server = new BroadcastServer('spawn', log);
10
+ const sendLog = (name, message) => {
11
+ try {
12
+ server.request({ type: 'frontend_logmessage', src: 'spawn', dst: 'frontend', params: { level: 'spawn', time: log.now(), name, message } });
13
+ }
14
+ catch (err) {
15
+ log.debug(`Failed to send log message to frontend: ${err instanceof Error ? err.message : String(err)}`);
16
+ }
17
+ };
18
+ if (verbose)
19
+ log.debug(`Spawning command: ${command} with ${args.join(' ')} ${packageCommand} ${packageName}`);
4
20
  const cmdLine = command + ' ' + args.join(' ');
5
21
  if (process.platform === 'win32' && command === 'npm') {
6
22
  const argstring = 'npm ' + args.join(' ');
@@ -11,46 +27,46 @@ export async function spawnCommand(matterbridge, command, args, packageCommand,
11
27
  args.unshift(command);
12
28
  command = 'sudo';
13
29
  }
14
- matterbridge.log.debug(`Spawn command ${command} with ${args.join(' ')}`);
15
- return new Promise((resolve, reject) => {
30
+ log.debug(`Spawn command ${command} with ${args.join(' ')}`);
31
+ const success = await new Promise((resolve) => {
16
32
  if (packageCommand === 'install')
17
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn-init', `Installing ${packageName}`);
33
+ sendLog('Matterbridge:spawn-init', `Installing ${packageName}`);
18
34
  else if (packageCommand === 'uninstall')
19
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn-init', `Uninstalling ${packageName}`);
35
+ sendLog('Matterbridge:spawn-init', `Uninstalling ${packageName}`);
20
36
  const childProcess = spawn(command, args, {
21
37
  stdio: ['inherit', 'pipe', 'pipe'],
22
38
  });
23
39
  childProcess.on('error', (err) => {
24
- matterbridge.log.error(`Failed to start child process "${cmdLine}": ${err.message}`);
25
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn-exit-error', 'Spawn process error');
26
- reject(err);
40
+ log.error(`Failed to start child process "${cmdLine}": ${err.message}`);
41
+ sendLog('Matterbridge:spawn-exit-error', 'Spawn process error');
42
+ resolve(false);
27
43
  });
28
44
  childProcess.on('close', (code, signal) => {
29
45
  if (code === 0) {
30
- matterbridge.log.debug(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
31
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn-exit-success', 'Child process closed');
46
+ log.debug(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
47
+ sendLog('Matterbridge:spawn-exit-success', 'Child process closed');
32
48
  resolve(true);
33
49
  }
34
50
  else {
35
- matterbridge.log.error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
36
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn-exit-error', 'Child process closed');
37
- reject(new Error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`));
51
+ log.error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
52
+ sendLog('Matterbridge:spawn-exit-error', 'Child process closed');
53
+ resolve(false);
38
54
  }
39
55
  });
40
56
  childProcess.on('exit', (code, signal) => {
41
57
  if (code === 0) {
42
- matterbridge.log.debug(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
43
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn-exit-success', 'Child process exited');
58
+ log.debug(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
59
+ sendLog('Matterbridge:spawn-exit-success', 'Child process exited');
44
60
  resolve(true);
45
61
  }
46
62
  else {
47
- matterbridge.log.error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
48
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn-exit-error', 'Child process exited');
49
- reject(new Error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`));
63
+ log.error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
64
+ sendLog('Matterbridge:spawn-exit-error', 'Child process exited');
65
+ resolve(false);
50
66
  }
51
67
  });
52
68
  childProcess.on('disconnect', () => {
53
- matterbridge.log.debug(`Child process "${cmdLine}" has been disconnected from the parent`);
69
+ log.debug(`Child process "${cmdLine}" has been disconnected from the parent`);
54
70
  resolve(true);
55
71
  });
56
72
  if (childProcess.stdout) {
@@ -58,8 +74,8 @@ export async function spawnCommand(matterbridge, command, args, packageCommand,
58
74
  const message = data.toString().trim();
59
75
  const lines = message.split('\n');
60
76
  for (const line of lines) {
61
- matterbridge.log.debug(`Spawn output (stdout): ${line}`);
62
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', line);
77
+ log.debug(`Spawn output (stdout): ${line}`);
78
+ sendLog('Matterbridge:spawn', line);
63
79
  }
64
80
  });
65
81
  }
@@ -68,10 +84,12 @@ export async function spawnCommand(matterbridge, command, args, packageCommand,
68
84
  const message = data.toString().trim();
69
85
  const lines = message.split('\n');
70
86
  for (const line of lines) {
71
- matterbridge.log.debug(`Spawn verbose (stderr): ${line}`);
72
- matterbridge.frontend.wssSendLogMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', line);
87
+ log.debug(`Spawn verbose (stderr): ${line}`);
88
+ sendLog('Matterbridge:spawn', line);
73
89
  }
74
90
  });
75
91
  }
76
92
  });
93
+ server.close();
94
+ return success;
77
95
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.3.9-dev-20251119-ea13a99",
3
+ "version": "3.4.0-dev-20251120-21b4f48",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.3.9-dev-20251119-ea13a99",
9
+ "version": "3.4.0-dev-20251120-21b4f48",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.15.6",
@@ -284,9 +284,9 @@
284
284
  }
285
285
  },
286
286
  "node_modules/archiver-utils/node_modules/glob": {
287
- "version": "10.4.5",
288
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
289
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
287
+ "version": "10.5.0",
288
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
289
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
290
290
  "license": "ISC",
291
291
  "dependencies": {
292
292
  "foreground-child": "^3.1.0",
@@ -581,15 +581,16 @@
581
581
  }
582
582
  },
583
583
  "node_modules/content-disposition": {
584
- "version": "1.0.0",
585
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
586
- "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
584
+ "version": "1.0.1",
585
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
586
+ "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
587
587
  "license": "MIT",
588
- "dependencies": {
589
- "safe-buffer": "5.2.1"
590
- },
591
588
  "engines": {
592
- "node": ">= 0.6"
589
+ "node": ">=18"
590
+ },
591
+ "funding": {
592
+ "type": "opencollective",
593
+ "url": "https://opencollective.com/express"
593
594
  }
594
595
  },
595
596
  "node_modules/content-type": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.3.9-dev-20251119-ea13a99",
3
+ "version": "3.4.0-dev-20251120-21b4f48",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",