matterbridge 3.0.1-dev-20250503-aa33494 → 3.0.1-dev-20250504-6f217b4

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
@@ -29,10 +29,11 @@ It is also available the official Matterbridge Home Assistant plugin https://git
29
29
  - [package]: Updated dependencies.
30
30
  - [docker]: Updated the [Docker configurations](README-DOCKER.md).
31
31
  - [frontend]: Changing configuration for a plugin now only lock configuration on that plugin.
32
+ - [frontend]: Frontend v.2.6.4.
32
33
 
33
34
  ### Fixed
34
35
 
35
- - [BasicInformation]: Fixed vulnerability to BasicInformation and BridgedDeviceBasicInformation cluster initialization attributes.
36
+ - [BasicInformation]: Fixed vulnerability in BasicInformation and BridgedDeviceBasicInformation cluster initialization attributes.
36
37
 
37
38
  ## [3.0.0] - 2025-04-29
38
39
 
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![Docker Version](https://img.shields.io/docker/v/luligu/matterbridge?label=docker%20version&sort=semver)](https://hub.docker.com/r/luligu/matterbridge)
6
6
  [![Docker Pulls](https://img.shields.io/docker/pulls/luligu/matterbridge.svg)](https://hub.docker.com/r/luligu/matterbridge)
7
7
  ![Node.js CI](https://github.com/Luligu/matterbridge/actions/workflows/build.yml/badge.svg)
8
+ ![Coverage](https://img.shields.io/badge/Jest%20coverage-80%25-brightgreen)
8
9
 
9
10
  [![power by](https://img.shields.io/badge/powered%20by-matter--history-blue)](https://www.npmjs.com/package/matter-history)
10
11
  [![power by](https://img.shields.io/badge/powered%20by-node--ansi--logger-blue)](https://www.npmjs.com/package/node-ansi-logger)
package/dist/frontend.js CHANGED
@@ -810,13 +810,13 @@ export class Frontend {
810
810
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
811
811
  this.wssSendCloseSnackbarMessage(`Installing package ${data.params.packageName}...`);
812
812
  this.wssSendSnackbarMessage(`Installed package ${data.params.packageName}`, 5, 'success');
813
- if (data.params.restart === false) {
814
- data.params.packageName = data.params.packageName.replace(/@.*$/, '');
815
- this.matterbridge.plugins.add(data.params.packageName).then((plugin) => {
813
+ const packageName = data.params.packageName.replace(/@.*$/, '');
814
+ if (data.params.restart === false && packageName !== 'matterbridge') {
815
+ this.matterbridge.plugins.add(packageName).then((plugin) => {
816
816
  if (plugin) {
817
- this.wssSendSnackbarMessage(`Added plugin ${data.params.pluginNameOrPath}`, 5, 'success');
817
+ this.wssSendSnackbarMessage(`Added plugin ${packageName}`, 5, 'success');
818
818
  this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true).then(() => {
819
- this.wssSendSnackbarMessage(`Started plugin ${data.params.pluginNameOrPath}`, 5, 'success');
819
+ this.wssSendSnackbarMessage(`Started plugin ${packageName}`, 5, 'success');
820
820
  this.wssSendRefreshRequired('plugins');
821
821
  });
822
822
  }
@@ -964,7 +964,7 @@ export class Frontend {
964
964
  this.log.warn(`Plugin ${plg}${data.params.pluginName}${wr} not found in matterbridge`);
965
965
  }
966
966
  else {
967
- this.matterbridge.plugins.saveConfigFromJson(plugin, data.params.formData);
967
+ this.matterbridge.plugins.saveConfigFromJson(plugin, data.params.formData, true);
968
968
  this.wssSendSnackbarMessage(`Saved config for plugin ${data.params.pluginName}`);
969
969
  this.wssSendRefreshRequired('plugins');
970
970
  this.wssSendRestartRequired();
@@ -1428,7 +1428,6 @@ export class Frontend {
1428
1428
  }
1429
1429
  const config = plugin.configJson;
1430
1430
  const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
1431
- this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
1432
1431
  if (select === 'serial')
1433
1432
  this.log.info(`Selected device serial ${data.params.serial}`);
1434
1433
  if (select === 'name')
@@ -1455,9 +1454,17 @@ export class Frontend {
1455
1454
  }
1456
1455
  if (plugin.platform)
1457
1456
  plugin.platform.config = config;
1458
- await this.matterbridge.plugins.saveConfigFromPlugin(plugin);
1457
+ plugin.configJson = config;
1458
+ const restartRequired = plugin.restartRequired;
1459
+ await this.matterbridge.plugins.saveConfigFromPlugin(plugin, true);
1460
+ if (!restartRequired)
1461
+ this.wssSendRefreshRequired('plugins');
1459
1462
  this.wssSendRestartRequired(false);
1460
1463
  }
1464
+ else {
1465
+ this.log.error(`SelectDevice: select ${select} not supported`);
1466
+ client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: `SelectDevice: select ${select} not supported` }));
1467
+ }
1461
1468
  }
1462
1469
  else if (data.params.command === 'unselectdevice' && isValidString(data.params.plugin, 10) && isValidString(data.params.serial, 1) && isValidString(data.params.name, 1)) {
1463
1470
  const plugin = this.matterbridge.plugins.get(data.params.plugin);
@@ -1467,7 +1474,6 @@ export class Frontend {
1467
1474
  }
1468
1475
  const config = plugin.configJson;
1469
1476
  const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
1470
- this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
1471
1477
  if (select === 'serial')
1472
1478
  this.log.info(`Unselected device serial ${data.params.serial}`);
1473
1479
  if (select === 'name')
@@ -1494,9 +1500,17 @@ export class Frontend {
1494
1500
  }
1495
1501
  if (plugin.platform)
1496
1502
  plugin.platform.config = config;
1497
- await this.matterbridge.plugins.saveConfigFromPlugin(plugin);
1503
+ plugin.configJson = config;
1504
+ const restartRequired = plugin.restartRequired;
1505
+ await this.matterbridge.plugins.saveConfigFromPlugin(plugin, true);
1506
+ if (!restartRequired)
1507
+ this.wssSendRefreshRequired('plugins');
1498
1508
  this.wssSendRestartRequired(false);
1499
1509
  }
1510
+ else {
1511
+ this.log.error(`SelectDevice: select ${select} not supported`);
1512
+ client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: `SelectDevice: select ${select} not supported` }));
1513
+ }
1500
1514
  }
1501
1515
  }
1502
1516
  else {
@@ -1564,7 +1578,8 @@ export class Frontend {
1564
1578
  });
1565
1579
  }
1566
1580
  wssSendCpuUpdate(cpuUsage) {
1567
- this.log.debug('Sending a cpu update message to all connected clients');
1581
+ if (hasParameter('debug'))
1582
+ this.log.debug('Sending a cpu update message to all connected clients');
1568
1583
  this.webSocketServer?.clients.forEach((client) => {
1569
1584
  if (client.readyState === WebSocket.OPEN) {
1570
1585
  client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
@@ -1572,7 +1587,8 @@ export class Frontend {
1572
1587
  });
1573
1588
  }
1574
1589
  wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
1575
- this.log.debug('Sending a memory update message to all connected clients');
1590
+ if (hasParameter('debug'))
1591
+ this.log.debug('Sending a memory update message to all connected clients');
1576
1592
  this.webSocketServer?.clients.forEach((client) => {
1577
1593
  if (client.readyState === WebSocket.OPEN) {
1578
1594
  client.send(JSON.stringify({ id: WS_ID_MEMORY_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } }));
@@ -1580,7 +1596,8 @@ export class Frontend {
1580
1596
  });
1581
1597
  }
1582
1598
  wssSendUptimeUpdate(systemUptime, processUptime) {
1583
- this.log.debug('Sending a uptime update message to all connected clients');
1599
+ if (hasParameter('debug'))
1600
+ this.log.debug('Sending a uptime update message to all connected clients');
1584
1601
  this.webSocketServer?.clients.forEach((client) => {
1585
1602
  if (client.readyState === WebSocket.OPEN) {
1586
1603
  client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
@@ -7,6 +7,7 @@ import { Thermostat } from '@matter/main/clusters/thermostat';
7
7
  import { ValveConfigurationAndControl } from '@matter/main/clusters/valve-configuration-and-control';
8
8
  import { SmokeCoAlarm } from '@matter/main/clusters/smoke-co-alarm';
9
9
  import { BooleanStateConfigurationServer } from '@matter/main/behaviors/boolean-state-configuration';
10
+ import { OperationalState } from '@matter/main/clusters/operational-state';
10
11
  import { IdentifyServer } from '@matter/main/behaviors/identify';
11
12
  import { OnOffServer } from '@matter/main/behaviors/on-off';
12
13
  import { LevelControlServer } from '@matter/main/behaviors/level-control';
@@ -19,6 +20,7 @@ import { ValveConfigurationAndControlBehavior } from '@matter/main/behaviors/val
19
20
  import { ModeSelectServer } from '@matter/main/behaviors/mode-select';
20
21
  import { SmokeCoAlarmServer } from '@matter/main/behaviors/smoke-co-alarm';
21
22
  import { SwitchServer } from '@matter/main/behaviors/switch';
23
+ import { OperationalStateBehavior } from '@matter/main/behaviors/operational-state';
22
24
  export class MatterbridgeServerDevice {
23
25
  log;
24
26
  commandHandler;
@@ -140,6 +142,22 @@ export class MatterbridgeServerDevice {
140
142
  this.log.info(`Enabling/disabling alarm ${alarmsToEnableDisable}`);
141
143
  this.commandHandler.executeHandler('enableDisableAlarm', { request: { alarmsToEnableDisable }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
142
144
  }
145
+ pause() {
146
+ this.log.info(`Pause (endpoint ${this.endpointId}.${this.endpointNumber})`);
147
+ this.commandHandler.executeHandler('pause', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
148
+ }
149
+ stop() {
150
+ this.log.info(`Stop (endpoint ${this.endpointId}.${this.endpointNumber})`);
151
+ this.commandHandler.executeHandler('stop', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
152
+ }
153
+ start() {
154
+ this.log.info(`Start (endpoint ${this.endpointId}.${this.endpointNumber})`);
155
+ this.commandHandler.executeHandler('start', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
156
+ }
157
+ resume() {
158
+ this.log.info(`Resume (endpoint ${this.endpointId}.${this.endpointNumber})`);
159
+ this.commandHandler.executeHandler('resume', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
160
+ }
143
161
  }
144
162
  export class MatterbridgeServer extends Behavior {
145
163
  static id = 'matterbridge';
@@ -348,3 +366,51 @@ export class MatterbridgeSwitchServer extends SwitchServer {
348
366
  initialize() {
349
367
  }
350
368
  }
369
+ export class MatterbridgeOperationalStateServer extends OperationalStateBehavior {
370
+ initialize() {
371
+ const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
372
+ device.log.debug('MatterbridgeOperationalStateServer initialized: setting operational state to Stopped');
373
+ this.state.operationalState = OperationalState.OperationalStateEnum.Stopped;
374
+ this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
375
+ }
376
+ pause() {
377
+ const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
378
+ device.log.debug('MatterbridgeOperationalStateServer: pause called setting operational state to Paused');
379
+ device.pause();
380
+ this.state.operationalState = OperationalState.OperationalStateEnum.Paused;
381
+ this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
382
+ return {
383
+ commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
384
+ };
385
+ }
386
+ stop() {
387
+ const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
388
+ device.log.debug('MatterbridgeOperationalStateServer: stop called setting operational state to Stopped');
389
+ device.stop();
390
+ this.state.operationalState = OperationalState.OperationalStateEnum.Stopped;
391
+ this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
392
+ return {
393
+ commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
394
+ };
395
+ }
396
+ start() {
397
+ const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
398
+ device.log.debug('MatterbridgeOperationalStateServer: start called setting operational state to Running');
399
+ device.start();
400
+ this.state.operationalState = OperationalState.OperationalStateEnum.Running;
401
+ this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
402
+ return {
403
+ commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
404
+ };
405
+ }
406
+ resume() {
407
+ const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
408
+ device.log.debug('MatterbridgeOperationalStateServer: resume called setting operational state to Running');
409
+ device.resume();
410
+ this.state.operationalState = OperationalState.OperationalStateEnum.Running;
411
+ this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
412
+ return {
413
+ commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
414
+ };
415
+ }
416
+ }
@@ -1,7 +1,7 @@
1
1
  import { AnsiLogger, BLUE, CYAN, YELLOW, db, debugStringify, er, hk, or, zb } from './logger/export.js';
2
2
  import { bridgedNode } from './matterbridgeDeviceTypes.js';
3
3
  import { isValidNumber, isValidObject, isValidString } from './utils/export.js';
4
- import { MatterbridgeServer, MatterbridgeServerDevice, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeSwitchServer, } from './matterbridgeBehaviors.js';
4
+ import { MatterbridgeServer, MatterbridgeServerDevice, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeSwitchServer, MatterbridgeOperationalStateServer, } from './matterbridgeBehaviors.js';
5
5
  import { addClusterServers, addFixedLabel, addOptionalClusterServers, addRequiredClusterServers, addUserLabel, capitalizeFirstLetter, createUniqueId, getBehavior, getBehaviourTypesFromClusterClientIds, getBehaviourTypesFromClusterServerIds, getDefaultFlowMeasurementClusterServer, getDefaultIlluminanceMeasurementClusterServer, getDefaultPressureMeasurementClusterServer, getDefaultRelativeHumidityMeasurementClusterServer, getDefaultTemperatureMeasurementClusterServer, getDefaultOccupancySensingClusterServer, lowercaseFirstLetter, updateAttribute, getClusterId, getAttributeId, setAttribute, getAttribute, checkNotLatinCharacters, generateUniqueId, subscribeAttribute, } from './matterbridgeEndpointHelpers.js';
6
6
  import { Endpoint, Lifecycle, MutableEndpoint, NamedHandler, SupportedBehaviors, UINT16_MAX, UINT32_MAX, VendorId } from '@matter/main';
7
7
  import { getClusterNameById, MeasurementType } from '@matter/main/types';
@@ -28,6 +28,7 @@ import { AirQuality } from '@matter/main/clusters/air-quality';
28
28
  import { ConcentrationMeasurement } from '@matter/main/clusters/concentration-measurement';
29
29
  import { OccupancySensing } from '@matter/main/clusters/occupancy-sensing';
30
30
  import { ThermostatUserInterfaceConfiguration } from '@matter/main/clusters/thermostat-user-interface-configuration';
31
+ import { OperationalState } from '@matter/main/clusters/operational-state';
31
32
  import { DescriptorServer } from '@matter/main/behaviors/descriptor';
32
33
  import { PowerSourceServer } from '@matter/main/behaviors/power-source';
33
34
  import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
@@ -984,6 +985,21 @@ export class MatterbridgeEndpoint extends Endpoint {
984
985
  }
985
986
  return true;
986
987
  }
988
+ createDefaultOperationalStateClusterServer(operationalState = OperationalState.OperationalStateEnum.Stopped) {
989
+ this.behaviors.require(MatterbridgeOperationalStateServer, {
990
+ phaseList: [],
991
+ currentPhase: null,
992
+ operationalStateList: [
993
+ { operationalStateId: OperationalState.OperationalStateEnum.Stopped, operationalStateLabel: 'Stopped' },
994
+ { operationalStateId: OperationalState.OperationalStateEnum.Running, operationalStateLabel: 'Running' },
995
+ { operationalStateId: OperationalState.OperationalStateEnum.Paused, operationalStateLabel: 'Paused' },
996
+ { operationalStateId: OperationalState.OperationalStateEnum.Error, operationalStateLabel: 'Error' },
997
+ ],
998
+ operationalState,
999
+ operationalError: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
1000
+ });
1001
+ return this;
1002
+ }
987
1003
  createDefaultBooleanStateClusterServer(contact) {
988
1004
  this.behaviors.require(BooleanStateServer.enable({
989
1005
  events: { stateChange: true },
@@ -1,7 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { BLUE, CYAN, db, debugStringify, er, hk, or, YELLOW, zb } from './logger/export.js';
3
3
  import { deepCopy, deepEqual, isValidArray } from './utils/export.js';
4
- import { MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, } from './matterbridgeBehaviors.js';
4
+ import { MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeOperationalStateServer, } from './matterbridgeBehaviors.js';
5
5
  import { Lifecycle } from '@matter/main';
6
6
  import { getClusterNameById } from '@matter/main/types';
7
7
  import { PowerSource } from '@matter/main/clusters/power-source';
@@ -45,6 +45,7 @@ import { Pm25ConcentrationMeasurement } from '@matter/main/clusters/pm25-concent
45
45
  import { Pm10ConcentrationMeasurement } from '@matter/main/clusters/pm10-concentration-measurement';
46
46
  import { RadonConcentrationMeasurement } from '@matter/main/clusters/radon-concentration-measurement';
47
47
  import { TotalVolatileOrganicCompoundsConcentrationMeasurement } from '@matter/main/clusters/total-volatile-organic-compounds-concentration-measurement';
48
+ import { OperationalState } from '@matter/main/clusters/operational-state';
48
49
  import { PowerSourceServer } from '@matter/main/behaviors/power-source';
49
50
  import { UserLabelServer } from '@matter/main/behaviors/user-label';
50
51
  import { FixedLabelServer } from '@matter/main/behaviors/fixed-label';
@@ -157,6 +158,8 @@ export function getBehaviourTypeFromClusterServerId(clusterId) {
157
158
  return MatterbridgeSmokeCoAlarmServer.with('SmokeAlarm', 'CoAlarm');
158
159
  if (clusterId === Switch.Cluster.id)
159
160
  return SwitchServer.with('MomentarySwitch', 'MomentarySwitchRelease', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress');
161
+ if (clusterId === OperationalState.Cluster.id)
162
+ return MatterbridgeOperationalStateServer;
160
163
  if (clusterId === BooleanState.Cluster.id)
161
164
  return BooleanStateServer.enable({ events: { stateChange: true } });
162
165
  if (clusterId === BooleanStateConfiguration.Cluster.id)
@@ -278,6 +281,8 @@ export function addClusterServers(endpoint, serverList) {
278
281
  endpoint.createDefaultSmokeCOAlarmClusterServer();
279
282
  if (serverList.includes(Switch.Cluster.id))
280
283
  endpoint.createDefaultSwitchClusterServer();
284
+ if (serverList.includes(OperationalState.Cluster.id))
285
+ endpoint.createDefaultOperationalStateClusterServer();
281
286
  if (serverList.includes(BooleanState.Cluster.id))
282
287
  endpoint.createDefaultBooleanStateClusterServer();
283
288
  if (serverList.includes(BooleanStateConfiguration.Cluster.id))
@@ -693,7 +693,7 @@ export class PluginManager {
693
693
  }
694
694
  }
695
695
  }
696
- async saveConfigFromPlugin(plugin) {
696
+ async saveConfigFromPlugin(plugin, restartRequired = false) {
697
697
  const { default: path } = await import('node:path');
698
698
  const { promises } = await import('node:fs');
699
699
  if (!plugin.platform?.config) {
@@ -704,6 +704,8 @@ export class PluginManager {
704
704
  try {
705
705
  await promises.writeFile(configFile, JSON.stringify(plugin.platform.config, null, 2), 'utf8');
706
706
  plugin.configJson = plugin.platform.config;
707
+ if (restartRequired)
708
+ plugin.restartRequired = true;
707
709
  this.log.debug(`Saved config file ${configFile} for plugin ${plg}${plugin.name}${db}`);
708
710
  return Promise.resolve();
709
711
  }
@@ -712,7 +714,7 @@ export class PluginManager {
712
714
  return Promise.reject(err);
713
715
  }
714
716
  }
715
- async saveConfigFromJson(plugin, config) {
717
+ async saveConfigFromJson(plugin, config, restartRequired = false) {
716
718
  const { default: path } = await import('node:path');
717
719
  const { promises } = await import('node:fs');
718
720
  if (!config.name || !config.type || config.name !== plugin.name) {
@@ -723,7 +725,8 @@ export class PluginManager {
723
725
  try {
724
726
  await promises.writeFile(configFile, JSON.stringify(config, null, 2), 'utf8');
725
727
  plugin.configJson = config;
726
- plugin.restartRequired = true;
728
+ if (restartRequired)
729
+ plugin.restartRequired = true;
727
730
  if (plugin.platform) {
728
731
  plugin.platform.config = config;
729
732
  plugin.platform.onConfigChanged(config).catch((err) => this.log.error(`Error calling onConfigChanged for plugin ${plg}${plugin.name}${er}: ${err}`));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "./static/css/main.944b63c3.css",
4
- "main.js": "./static/js/main.53d64feb.js",
4
+ "main.js": "./static/js/main.5e6e4eb5.js",
5
5
  "static/js/453.d855a71b.chunk.js": "./static/js/453.d855a71b.chunk.js",
6
6
  "static/media/roboto-latin-700-normal.woff2": "./static/media/roboto-latin-700-normal.c4d6cab43bec89049809.woff2",
7
7
  "static/media/roboto-latin-500-normal.woff2": "./static/media/roboto-latin-500-normal.599f66a60bdf974e578e.woff2",
@@ -77,11 +77,11 @@
77
77
  "static/media/roboto-greek-ext-300-normal.woff": "./static/media/roboto-greek-ext-300-normal.60729cafbded24073dfb.woff",
78
78
  "index.html": "./index.html",
79
79
  "main.944b63c3.css.map": "./static/css/main.944b63c3.css.map",
80
- "main.53d64feb.js.map": "./static/js/main.53d64feb.js.map",
80
+ "main.5e6e4eb5.js.map": "./static/js/main.5e6e4eb5.js.map",
81
81
  "453.d855a71b.chunk.js.map": "./static/js/453.d855a71b.chunk.js.map"
82
82
  },
83
83
  "entrypoints": [
84
84
  "static/css/main.944b63c3.css",
85
- "static/js/main.53d64feb.js"
85
+ "static/js/main.5e6e4eb5.js"
86
86
  ]
87
87
  }
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.53d64feb.js"></script><link href="./static/css/main.944b63c3.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.5e6e4eb5.js"></script><link href="./static/css/main.944b63c3.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>