@matterbridge/core 3.7.2-dev-20260331-ac050d8 → 3.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ import { MdnsService } from '@matter/protocol';
8
8
  import { ColorControl } from '@matter/types/clusters/color-control';
9
9
  import { DeviceTypeId, VendorId } from '@matter/types/datatype';
10
10
  import { BroadcastServer } from '@matterbridge/thread/server';
11
- import { MATTER_STORAGE_NAME, NODE_STORAGE_DIR } from '@matterbridge/types';
11
+ import { MATTER_STORAGE_DIR, NODE_STORAGE_DIR } from '@matterbridge/types';
12
12
  import { AnsiLogger, er, rs, UNDERLINE, UNDERLINEOFF } from 'node-ansi-logger';
13
13
  import { NodeStorageManager } from 'node-persist-manager';
14
14
  import { Frontend } from '../frontend.js';
@@ -162,7 +162,7 @@ export async function startMatterbridge(bridgeMode = 'bridge', frontendPort = 82
162
162
  process.env['MATTERBRIDGE_START_MATTER_INTERVAL_MS'] = '100';
163
163
  process.env['MATTERBRIDGE_PAUSE_MATTER_INTERVAL_MS'] = '100';
164
164
  process.argv.length = 0;
165
- process.argv.push(...originalProcessArgv, '-novirtual', '-debug', '-verbose', '-logger', 'debug', '-matterlogger', 'debug', bridgeMode === '' ? '-test' : '-' + bridgeMode, '-homedir', HOMEDIR, '-frontend', frontendPort.toString(), '-port', matterPort.toString(), '-passcode', passcode.toString(), '-discriminator', discriminator.toString());
165
+ process.argv.push(...originalProcessArgv, '--novirtual', '--debug', '--verbose', '--logger', 'debug', '--matterlogger', 'debug', bridgeMode === '' ? '--test' : '--' + bridgeMode, '--homedir', HOMEDIR, '--frontend', frontendPort.toString(), '--port', matterPort.toString(), '--passcode', passcode.toString(), '--discriminator', discriminator.toString());
166
166
  expect(Matterbridge.instance).toBeUndefined();
167
167
  matterbridge = await Matterbridge.loadInstance(true);
168
168
  expect(matterbridge.environment).toBeDefined();
@@ -198,7 +198,7 @@ export async function startMatterbridge(bridgeMode = 'bridge', frontendPort = 82
198
198
  expect(frontend.webSocketServer).toBeDefined();
199
199
  expect(matterbridge.nodeStorage).toBeDefined();
200
200
  expect(matterbridge.nodeContext).toBeDefined();
201
- expect(Environment.default.vars.get('path.root')).toBe(path.join(matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME));
201
+ expect(Environment.default.vars.get('path.root')).toBe(path.join(matterbridge.matterbridgeDirectory, MATTER_STORAGE_DIR));
202
202
  expect(matterbridge.matterStorageService).toBeDefined();
203
203
  expect(matterbridge.matterStorageManager).toBeDefined();
204
204
  expect(matterbridge.matterbridgeContext).toBeDefined();
@@ -391,7 +391,7 @@ export function createTestEnvironment(name, createOnly = false) {
391
391
  environment = Environment.default;
392
392
  environment.vars.set('log.level', MatterLogLevel.DEBUG);
393
393
  environment.vars.set('log.format', MatterLogFormat.ANSI);
394
- environment.vars.set('path.root', path.join(HOMEDIR, '.matterbridge', MATTER_STORAGE_NAME));
394
+ environment.vars.set('path.root', path.join(HOMEDIR, '.matterbridge', MATTER_STORAGE_DIR));
395
395
  environment.vars.set('runtime.signals', false);
396
396
  environment.vars.set('runtime.exitcode', false);
397
397
  if (createOnly)
@@ -442,13 +442,20 @@ export function logKeepAlives(log) {
442
442
  }
443
443
  return summary.handles.length + summary.requests.length;
444
444
  }
445
- export async function flushAllEndpointNumberPersistence(targetServer, rounds = 2) {
445
+ export async function flushAllEndpointNumberPersistence(targetServer, rounds = 3, pause = 10) {
446
446
  const nodeStore = targetServer.env.get(ServerNodeStore);
447
447
  for (let i = 0; i < rounds; i++) {
448
- await new Promise((resolve) => setImmediate(resolve));
448
+ await flushAsync(undefined, undefined, pause);
449
449
  await nodeStore.endpointStores.close();
450
450
  }
451
451
  }
452
+ function getOwningServerNode(owner) {
453
+ let current = owner;
454
+ while (current.owner) {
455
+ current = current.owner;
456
+ }
457
+ return current;
458
+ }
452
459
  function collectAllEndpoints(root) {
453
460
  const list = [];
454
461
  const walk = (ep) => {
@@ -569,7 +576,8 @@ export async function addDevice(owner, device, pause = 10) {
569
576
  expect(owner.lifecycle.isReady).toBeTruthy();
570
577
  expect(owner.construction.status).toBe(Lifecycle.Status.Active);
571
578
  expect(owner.lifecycle.isPartsReady).toBeTruthy();
572
- await flushAsync(undefined, undefined, pause);
579
+ const targetServer = getOwningServerNode(owner);
580
+ await flushAllEndpointNumberPersistence(targetServer, 3, pause);
573
581
  try {
574
582
  await owner.add(device);
575
583
  }
@@ -587,7 +595,7 @@ export async function addDevice(owner, device, pause = 10) {
587
595
  expect(device.lifecycle.hasId).toBeTruthy();
588
596
  expect(device.lifecycle.hasNumber).toBeTruthy();
589
597
  expect(device.construction.status).toBe(Lifecycle.Status.Active);
590
- await flushAsync(undefined, undefined, pause);
598
+ await flushAllEndpointNumberPersistence(targetServer, 3, pause);
591
599
  return true;
592
600
  }
593
601
  export async function deleteDevice(owner, device, pause = 10) {
@@ -596,6 +604,8 @@ export async function deleteDevice(owner, device, pause = 10) {
596
604
  expect(owner.lifecycle.isReady).toBeTruthy();
597
605
  expect(owner.construction.status).toBe(Lifecycle.Status.Active);
598
606
  expect(owner.lifecycle.isPartsReady).toBeTruthy();
607
+ const targetServer = getOwningServerNode(owner);
608
+ await flushAllEndpointNumberPersistence(targetServer, 3, pause);
599
609
  try {
600
610
  await device.delete();
601
611
  }
@@ -612,7 +622,7 @@ export async function deleteDevice(owner, device, pause = 10) {
612
622
  expect(device.lifecycle.hasId).toBeTruthy();
613
623
  expect(device.lifecycle.hasNumber).toBeTruthy();
614
624
  expect(device.construction.status).toBe(Lifecycle.Status.Destroyed);
615
- await flushAsync(undefined, undefined, pause);
625
+ await flushAllEndpointNumberPersistence(targetServer, 3, pause);
616
626
  return true;
617
627
  }
618
628
  export function getMoveToLevelRequest(level, transitionTime, executeIfOff) {
@@ -10,7 +10,7 @@ import { AggregatorEndpoint } from '@matter/node/endpoints/aggregator';
10
10
  import { MdnsService } from '@matter/protocol';
11
11
  import { DeviceTypeId, VendorId } from '@matter/types';
12
12
  import { BroadcastServer } from '@matterbridge/thread/server';
13
- import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_NAME, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg } from '@matterbridge/types';
13
+ import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_DIR, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg } from '@matterbridge/types';
14
14
  import { getIntParameter, getParameter, hasParameter } from '@matterbridge/utils/cli';
15
15
  import { copyDirectory } from '@matterbridge/utils/copy-dir';
16
16
  import { inspectError } from '@matterbridge/utils/error';
@@ -78,8 +78,8 @@ export class MatterNode extends EventEmitter {
78
78
  if (this.verbose)
79
79
  this.log.debug(`PluginManager is ready`);
80
80
  this.environment.vars.set('log.level', MatterLogLevel.DEBUG);
81
- this.environment.vars.set('log.format', MatterLogFormat.ANSI);
82
- this.environment.vars.set('path.root', path.join(matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME));
81
+ this.environment.vars.set('log.format', hasParameter('no-ansi') || process.env.NO_COLOR === '1' ? MatterLogFormat.PLAIN : MatterLogFormat.ANSI);
82
+ this.environment.vars.set('path.root', path.join(matterbridge.matterbridgeDirectory, MATTER_STORAGE_DIR));
83
83
  this.environment.vars.set('runtime.signals', false);
84
84
  this.environment.vars.set('runtime.exitcode', false);
85
85
  if (this.verbose)
@@ -280,25 +280,27 @@ export class MatterNode extends EventEmitter {
280
280
  this.matterLog.logFilePath = path.join(this.matterbridge.matterbridgeDirectory, MATTER_LOGGER_FILE);
281
281
  }
282
282
  return (text, message) => {
283
- let logger;
284
- let msg;
285
- if (!hasParameter('no-ansi') && process.env.NO_ANSI !== 'true') {
286
- logger = text.slice(44, 44 + 20).trim();
287
- msg = text.slice(65);
283
+ try {
284
+ let msg;
285
+ if (Logger.format === MatterLogFormat.ANSI) {
286
+ msg = text.slice(65);
287
+ }
288
+ else {
289
+ msg = text.split(message.facility)[1]?.trim();
290
+ }
291
+ this.matterLog.logName = message.facility;
292
+ this.matterLog.log(MatterLogLevel.names[message.level], msg);
288
293
  }
289
- else {
290
- logger = text.slice(30).trim().split(/\s+/, 1)[0];
291
- msg = text.slice(30).trim().slice(logger.length).trimStart();
294
+ catch (_error) {
295
+ this.log.debug(`Error parsing matter log message facility ${message.facility}`);
292
296
  }
293
- this.matterLog.logName = logger;
294
- this.matterLog.log(MatterLogLevel.names[message.level], msg);
295
297
  };
296
298
  }
297
299
  async startMatterStorage() {
298
300
  this.log.info(`Starting matter node storage...`);
299
301
  this.matterStorageService = this.environment.get(StorageService);
300
302
  this.log.info(`Started matter node storage in ${CYAN}${this.matterStorageService.location}${nf}`);
301
- await this.backupMatterStorage(path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
303
+ await this.backupMatterStorage(path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_DIR), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_DIR + '.backup'));
302
304
  }
303
305
  async backupMatterStorage(storageName, backupName) {
304
306
  this.log.info(`Creating matter node storage backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}...`);
@@ -59,13 +59,6 @@ export declare class Matterbridge extends EventEmitter<MatterbridgeEvents> {
59
59
  readonly matterLog: AnsiLogger;
60
60
  matterLogLevel: LogLevel;
61
61
  matterFileLogger: boolean;
62
- readonly readOnly: boolean;
63
- readonly shellyBoard: boolean;
64
- shellySysUpdate: boolean;
65
- shellyMainUpdate: boolean;
66
- restartRequired: boolean;
67
- fixedRestartRequired: boolean;
68
- updateRequired: boolean;
69
62
  readonly plugins: PluginManager;
70
63
  readonly devices: DeviceManager;
71
64
  readonly frontend: Frontend;
@@ -14,7 +14,7 @@ import { AggregatorEndpoint } from '@matter/node/endpoints/aggregator';
14
14
  import { PaseClient, Read, Subscribe } from '@matter/protocol';
15
15
  import { DeviceTypeId, VendorId } from '@matter/types/datatype';
16
16
  import { BroadcastServer } from '@matterbridge/thread/server';
17
- import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_NAME, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg, typ } from '@matterbridge/types';
17
+ import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_DIR, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg, typ } from '@matterbridge/types';
18
18
  import { wait } from '@matterbridge/utils';
19
19
  import { getIntParameter, getParameter, hasAnyParameter, hasParameter } from '@matterbridge/utils/cli';
20
20
  import { copyDirectory } from '@matterbridge/utils/copy-dir';
@@ -90,13 +90,6 @@ export class Matterbridge extends EventEmitter {
90
90
  });
91
91
  matterLogLevel = this.matterLog.logLevel;
92
92
  matterFileLogger = false;
93
- readOnly = hasParameter('readonly') || hasParameter('shelly');
94
- shellyBoard = hasParameter('shelly');
95
- shellySysUpdate = false;
96
- shellyMainUpdate = false;
97
- restartRequired = false;
98
- fixedRestartRequired = false;
99
- updateRequired = false;
100
93
  plugins = new PluginManager(this);
101
94
  devices = new DeviceManager();
102
95
  frontend = new Frontend(this);
@@ -207,8 +200,6 @@ export class Matterbridge extends EventEmitter {
207
200
  port: this.port,
208
201
  discriminator: this.discriminator,
209
202
  passcode: this.passcode,
210
- shellySysUpdate: this.shellySysUpdate,
211
- shellyMainUpdate: this.shellyMainUpdate,
212
203
  };
213
204
  }
214
205
  async msgHandler(msg) {
@@ -245,14 +236,6 @@ export class Matterbridge extends EventEmitter {
245
236
  await this.nodeContext?.set('globalModulesDirectory', msg.params.prefix);
246
237
  this.server.respond({ ...msg, result: { success: true } });
247
238
  break;
248
- case 'matterbridge_shelly_sys_update':
249
- this.shellySysUpdate = true;
250
- this.server.respond({ ...msg, result: { success: true } });
251
- break;
252
- case 'matterbridge_shelly_main_update':
253
- this.shellyMainUpdate = true;
254
- this.server.respond({ ...msg, result: { success: true } });
255
- break;
256
239
  case 'matterbridge_platform':
257
240
  this.server.respond({ ...msg, result: { data: this.getPlatformMatterbridge(), success: true } });
258
241
  break;
@@ -306,8 +289,6 @@ export class Matterbridge extends EventEmitter {
306
289
  switch (msg.type) {
307
290
  case 'manager_spawn_response':
308
291
  if (msg.result && msg.result.success && msg.result.packageCommand === 'install') {
309
- this.restartRequired = true;
310
- this.fixedRestartRequired = true;
311
292
  const packageName = msg.result.packageName.replace(/@.*$/, '');
312
293
  if (packageName === 'matterbridge') {
313
294
  this.log.info('Matterbridge has been updated. Full restart required.');
@@ -349,7 +330,7 @@ export class Matterbridge extends EventEmitter {
349
330
  this.rootDirectory = currentFileDirectory.includes(path.join('packages', 'core')) ? path.resolve(currentFileDirectory, '../', '../', '../') : path.resolve(currentFileDirectory, '../', '../', '..', '../');
350
331
  this.environment.vars.set('log.level', MatterLogLevel.DEBUG);
351
332
  this.environment.vars.set('log.format', hasParameter('no-ansi') || process.env.NO_COLOR === '1' ? MatterLogFormat.PLAIN : MatterLogFormat.ANSI);
352
- this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME));
333
+ this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR));
353
334
  this.environment.vars.set('runtime.signals', false);
354
335
  this.environment.vars.set('runtime.exitcode', false);
355
336
  this.registerProcessHandlers();
@@ -1053,36 +1034,19 @@ export class Matterbridge extends EventEmitter {
1053
1034
  this.matterLog.logFilePath = path.join(this.matterbridgeDirectory, MATTER_LOGGER_FILE);
1054
1035
  }
1055
1036
  return (text, message) => {
1056
- let logger;
1057
- let msg;
1058
- if (!hasParameter('no-ansi') && process.env.NO_ANSI !== 'true') {
1059
- logger = text.slice(44, 44 + 20).trim();
1060
- msg = text.slice(65);
1061
- }
1062
- else {
1063
- logger = text.slice(30).trim().split(/\s+/, 1)[0];
1064
- msg = text.slice(30).trim().slice(logger.length).trimStart();
1037
+ try {
1038
+ let msg;
1039
+ if (Logger.format === MatterLogFormat.ANSI) {
1040
+ msg = text.slice(65);
1041
+ }
1042
+ else {
1043
+ msg = text.split(message.facility)[1]?.trim();
1044
+ }
1045
+ this.matterLog.logName = message.facility;
1046
+ this.matterLog.log(MatterLogLevel.names[message.level], msg);
1065
1047
  }
1066
- this.matterLog.logName = logger;
1067
- switch (message.level) {
1068
- case MatterLogLevel.DEBUG:
1069
- this.matterLog.log("debug", msg);
1070
- break;
1071
- case MatterLogLevel.INFO:
1072
- this.matterLog.log("info", msg);
1073
- break;
1074
- case MatterLogLevel.NOTICE:
1075
- this.matterLog.log("notice", msg);
1076
- break;
1077
- case MatterLogLevel.WARN:
1078
- this.matterLog.log("warn", msg);
1079
- break;
1080
- case MatterLogLevel.ERROR:
1081
- this.matterLog.log("error", msg);
1082
- break;
1083
- case MatterLogLevel.FATAL:
1084
- this.matterLog.log("fatal", msg);
1085
- break;
1048
+ catch (_error) {
1049
+ this.log.debug(`Error parsing matter log message facility ${message.facility}`);
1086
1050
  }
1087
1051
  };
1088
1052
  }
@@ -1274,19 +1238,19 @@ export class Matterbridge extends EventEmitter {
1274
1238
  }
1275
1239
  if (hasParameter('reset-sessions')) {
1276
1240
  this.log.debug(`Cleaning matter storage context for ${GREEN}Matterbridge${db}...`);
1277
- unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, 'Matterbridge', 'sessions.resumptionRecords'), this.log);
1278
- unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, 'Matterbridge', 'root.subscriptions.subscriptions'), this.log);
1241
+ unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR, 'Matterbridge', 'sessions.resumptionRecords'), this.log);
1242
+ unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR, 'Matterbridge', 'root.subscriptions.subscriptions'), this.log);
1279
1243
  for (const plugin of this.plugins.array()) {
1280
1244
  this.log.debug(`Cleaning matter storage context for plugin ${plg}${plugin.name}${db}...`);
1281
- unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, plugin.name, 'sessions.resumptionRecords'), this.log);
1282
- unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, plugin.name, 'root.subscriptions.subscriptions'), this.log);
1245
+ unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR, plugin.name, 'sessions.resumptionRecords'), this.log);
1246
+ unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR, plugin.name, 'root.subscriptions.subscriptions'), this.log);
1283
1247
  }
1284
1248
  for (const device of this.devices.array().filter((d) => d.mode === 'server')) {
1285
1249
  if (!device.deviceName)
1286
1250
  continue;
1287
1251
  this.log.debug(`Cleaning matter storage context for server node device ${dev}${device.deviceName}${db}...`);
1288
- unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, device.deviceName.replace(/[ .]/g, ''), 'sessions.resumptionRecords'), this.log);
1289
- unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, device.deviceName.replace(/[ .]/g, ''), 'root.subscriptions.subscriptions'), this.log);
1252
+ unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR, device.deviceName.replace(/[ .]/g, ''), 'sessions.resumptionRecords'), this.log);
1253
+ unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR, device.deviceName.replace(/[ .]/g, ''), 'root.subscriptions.subscriptions'), this.log);
1290
1254
  }
1291
1255
  }
1292
1256
  await this.frontend.stop();
@@ -1316,10 +1280,10 @@ export class Matterbridge extends EventEmitter {
1316
1280
  this.devices.clear();
1317
1281
  if (message === 'shutting down with factory reset...') {
1318
1282
  try {
1319
- const dir = path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME);
1283
+ const dir = path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR);
1320
1284
  this.log.info(`Removing matter storage directory: ${dir}`);
1321
1285
  await fs.promises.rm(dir, { recursive: true });
1322
- const backup = path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup');
1286
+ const backup = path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR + '.backup');
1323
1287
  this.log.info(`Removing matter storage backup directory: ${backup}`);
1324
1288
  await fs.promises.rm(backup, { recursive: true });
1325
1289
  }
@@ -1839,7 +1803,7 @@ export class Matterbridge extends EventEmitter {
1839
1803
  this.log.info('Matter node storage manager "Matterbridge" created');
1840
1804
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
1841
1805
  this.log.info('Matter node storage started');
1842
- await this.backupMatterStorage(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
1806
+ await this.backupMatterStorage(path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR), path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR + '.backup'));
1843
1807
  }
1844
1808
  async backupMatterStorage(storageName, backupName) {
1845
1809
  this.log.info('Creating matter node storage backup...');
@@ -74,6 +74,7 @@ export declare class PluginManager extends EventEmitter<PluginManagerEvents> {
74
74
  install(packageName: string): void;
75
75
  uninstall(packageName: string): void;
76
76
  getAuthor(packageJson: Record<string, string | number | Record<string, string | number | object>>): string;
77
+ getDescription(packageJson: Record<string, string | number | Record<string, string | number | object>>): string;
77
78
  getHomepage(packageJson: Record<string, string | number | Record<string, string | number | object>>): string | undefined;
78
79
  getHelp(packageJson: Record<string, string | number | Record<string, string | number | object>>): string | undefined;
79
80
  getChangelog(packageJson: Record<string, string | number | Record<string, string | number | object>>): string | undefined;
@@ -537,6 +537,11 @@ export class PluginManager extends EventEmitter {
537
537
  return packageJson.author.name;
538
538
  return 'Unknown author';
539
539
  }
540
+ getDescription(packageJson) {
541
+ if (packageJson.description && typeof packageJson.description === 'string')
542
+ return packageJson.description;
543
+ return 'No description';
544
+ }
540
545
  getHomepage(packageJson) {
541
546
  if (packageJson.homepage && typeof packageJson.homepage === 'string' && packageJson.homepage.includes('http')) {
542
547
  return packageJson.homepage.replace('git+', '').replace('.git', '');
@@ -828,7 +833,7 @@ export class PluginManager extends EventEmitter {
828
833
  if (pluginInstance.default) {
829
834
  const config = await this.loadConfig(plugin);
830
835
  plugin.name = packageJson.name;
831
- plugin.description = packageJson.description ?? 'No description';
836
+ plugin.description = this.getDescription(packageJson);
832
837
  plugin.version = packageJson.version;
833
838
  plugin.author = this.getAuthor(packageJson);
834
839
  plugin.configJson = config;
@@ -853,7 +858,7 @@ export class PluginManager extends EventEmitter {
853
858
  platform.isLoaded = true;
854
859
  platform.setMatterNode?.(this.matterbridge.addBridgedEndpoint.bind(this.matterbridge), this.matterbridge.removeBridgedEndpoint.bind(this.matterbridge), this.matterbridge.removeAllBridgedEndpoints.bind(this.matterbridge), this.matterbridge.addVirtualEndpoint.bind(this.matterbridge));
855
860
  plugin.name = packageJson.name;
856
- plugin.description = packageJson.description ?? 'No description';
861
+ plugin.description = this.getDescription(packageJson);
857
862
  plugin.version = packageJson.version;
858
863
  plugin.author = this.getAuthor(packageJson);
859
864
  plugin.homepage = this.getHomepage(packageJson);
@@ -1150,6 +1155,13 @@ export class PluginManager extends EventEmitter {
1150
1155
  'readOnly': true,
1151
1156
  'ui:widget': 'hidden',
1152
1157
  },
1158
+ version: {
1159
+ 'title': 'Plugin Version',
1160
+ 'description': 'Plugin version',
1161
+ 'type': 'string',
1162
+ 'readOnly': true,
1163
+ 'ui:widget': 'hidden',
1164
+ },
1153
1165
  debug: {
1154
1166
  title: 'Enable Debug',
1155
1167
  description: 'Enable the debug for the plugin (development only)',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matterbridge/core",
3
- "version": "3.7.2-dev-20260331-ac050d8",
3
+ "version": "3.7.2",
4
4
  "description": "Matterbridge core library",
5
5
  "author": "https://github.com/Luligu",
6
6
  "homepage": "https://matterbridge.io/",
@@ -126,10 +126,10 @@
126
126
  ],
127
127
  "dependencies": {
128
128
  "@matter/main": "0.16.10",
129
- "@matterbridge/dgram": "3.7.2-dev-20260331-ac050d8",
130
- "@matterbridge/thread": "3.7.2-dev-20260331-ac050d8",
131
- "@matterbridge/types": "3.7.2-dev-20260331-ac050d8",
132
- "@matterbridge/utils": "3.7.2-dev-20260331-ac050d8",
129
+ "@matterbridge/dgram": "3.7.2",
130
+ "@matterbridge/thread": "3.7.2",
131
+ "@matterbridge/types": "3.7.2",
132
+ "@matterbridge/utils": "3.7.2",
133
133
  "express": "5.2.1",
134
134
  "multer": "2.1.1",
135
135
  "node-ansi-logger": "3.2.1-dev-20260327-7069fd7",