matterbridge 3.2.10-dev-20250928-30c21de → 3.3.0-dev-20250928-3d2b558

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,9 +8,74 @@ 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.2.10] - Not released
11
+ ## Project evolution
12
12
 
13
- ### Breaking Changes
13
+ The project will evolve to multi thread (the cli will become the threads manager) with these initial threads:
14
+
15
+ - matterbridge;
16
+ - frontend;
17
+ - all plugins in bridge mode;
18
+ - each plugin in childbridge mode;
19
+
20
+ Advantages:
21
+
22
+ - real concurrency outside the Node.js main loop;
23
+ - isolation between threads;
24
+ - single plugin isolation in childbridge mode;
25
+
26
+ ## [3.3.0] - Not released
27
+
28
+ ### Development Breaking Changes
29
+
30
+ - [platform]: Now, internal use only properties are private readonly and internal use only methods are private. This prepares the road to plugin isolation.
31
+ - [platform]: The signature of the matterbridge param in the platform constructor has changed from Matterbridge to `PlatformMatterbridge` that has only the approriate readonly properties from matterbridge. This prepares the road to plugin isolation.
32
+
33
+ This change will require to adapt all plugins in two steps.
34
+
35
+ 1. `After` matterbridge `3.3.0` will be published as latest:
36
+
37
+ - update the plugin platform constructor with the new signature:
38
+
39
+ ```typescript
40
+ constructor(matterbridge: PlatformMatterbridge, log: AnsiLogger, config: PlatformConfig)
41
+ ```
42
+
43
+ - require matterbridge 3.3.0:
44
+
45
+ ```typescript
46
+ if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.3.0')) {
47
+ throw new Error(
48
+ `This plugin requires Matterbridge version >= "3.3.0". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version."`,
49
+ );
50
+ }
51
+ ```
52
+
53
+ - check that you didn't used any matterbridge calls.
54
+
55
+ In this phase (matterbridge 3.3.x) all plugins will continue to build and run even without updates.
56
+
57
+ 2. `After` matterbridge `3.4.0` will be published as latest, the new signature `PlatformMatterbridge` with the plugin isolation will be effective.
58
+
59
+ ```typescript
60
+ export type PlatformMatterbridge = {
61
+ readonly homeDirectory: string;
62
+ readonly rootDirectory: string;
63
+ readonly matterbridgeDirectory: string;
64
+ readonly matterbridgePluginDirectory: string;
65
+ readonly globalModulesDirectory: string;
66
+ readonly matterbridgeVersion: string;
67
+ readonly matterbridgeLatestVersion: string;
68
+ readonly matterbridgeDevVersion: string;
69
+ readonly bridgeMode: 'bridge' | 'childbridge' | 'controller' | '';
70
+ readonly restartMode: 'service' | 'docker' | '';
71
+ readonly aggregatorVendorId: VendorId;
72
+ readonly aggregatorVendorName: string;
73
+ readonly aggregatorProductId: number;
74
+ readonly aggregatorProductName: string;
75
+ };
76
+ ```
77
+
78
+ In this phase (matterbridge 3.4.x) all plugins will not build and will not run without updates.
14
79
 
15
80
  ### Added
16
81
 
package/dist/frontend.js CHANGED
@@ -643,7 +643,7 @@ export class Frontend extends EventEmitter {
643
643
  this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
644
644
  this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
645
645
  this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
646
- this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
646
+ this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.level;
647
647
  this.matterbridge.matterbridgeInformation.matterMdnsInterface = this.matterbridge.mdnsInterface;
648
648
  this.matterbridge.matterbridgeInformation.matterIpv4Address = this.matterbridge.ipv4address;
649
649
  this.matterbridge.matterbridgeInformation.matterIpv6Address = this.matterbridge.ipv6address;
@@ -997,6 +997,7 @@ export class Frontend extends EventEmitter {
997
997
  .then(() => {
998
998
  this.wssSendSnackbarMessage(`Started plugin ${packageName}`, 5, 'success');
999
999
  this.wssSendRefreshRequired('plugins');
1000
+ this.wssSendRefreshRequired('devices');
1000
1001
  return;
1001
1002
  })
1002
1003
  .catch((_error) => {
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AnsiLogger } from 'node-ansi-logger';
2
2
  import { Matterbridge } from './matterbridge.js';
3
- import { hasParameter } from './utils/export.js';
3
+ import { hasParameter } from './utils/commandLine.js';
4
4
  export * from './matterbridge.js';
5
5
  export * from './matterbridgeTypes.js';
6
6
  export * from './matterbridgeEndpoint.js';
@@ -5,7 +5,7 @@ import { CYAN, db, er, nf, wr } from 'node-ansi-logger';
5
5
  import { NodeStorageManager } from 'node-persist-manager';
6
6
  import { checkNotLatinCharacters } from './matterbridgeEndpointHelpers.js';
7
7
  import { bridgedNode } from './matterbridgeDeviceTypes.js';
8
- import { isValidArray, isValidObject, isValidString } from './utils/export.js';
8
+ import { isValidArray, isValidObject, isValidString } from './utils/isvalid.js';
9
9
  export class MatterbridgePlatform {
10
10
  matterbridge;
11
11
  log;
@@ -17,12 +17,12 @@ export class MatterbridgePlatform {
17
17
  context;
18
18
  selectDevice = new Map();
19
19
  selectEntity = new Map();
20
- _contextReady;
21
- _selectDeviceContextReady;
22
- _selectEntityContextReady;
20
+ contextReady;
21
+ selectDeviceContextReady;
22
+ selectEntityContextReady;
23
23
  ready;
24
- _registeredEndpoints = new Map();
25
- _registeredEndpointsByName = new Map();
24
+ registeredEndpointsByUniqueId = new Map();
25
+ registeredEndpointsByName = new Map();
26
26
  constructor(matterbridge, log, config) {
27
27
  this.matterbridge = matterbridge;
28
28
  this.log = log;
@@ -38,13 +38,13 @@ export class MatterbridgePlatform {
38
38
  forgiveParseErrors: true,
39
39
  });
40
40
  this.log.debug(`Creating context for plugin ${this.config.name}`);
41
- this._contextReady = this.storage.createStorage('context').then((context) => {
41
+ this.contextReady = this.storage.createStorage('context').then((context) => {
42
42
  this.context = context;
43
43
  this.log.debug(`Created context for plugin ${this.config.name}`);
44
44
  return;
45
45
  });
46
46
  this.log.debug(`Loading selectDevice for plugin ${this.config.name}`);
47
- this._selectDeviceContextReady = this.storage.createStorage('selectDevice').then(async (context) => {
47
+ this.selectDeviceContextReady = this.storage.createStorage('selectDevice').then(async (context) => {
48
48
  const selectDevice = await context.get('selectDevice', []);
49
49
  for (const device of selectDevice)
50
50
  this.selectDevice.set(device.serial, device);
@@ -52,14 +52,14 @@ export class MatterbridgePlatform {
52
52
  return;
53
53
  });
54
54
  this.log.debug(`Loading selectEntity for plugin ${this.config.name}`);
55
- this._selectEntityContextReady = this.storage.createStorage('selectEntity').then(async (context) => {
55
+ this.selectEntityContextReady = this.storage.createStorage('selectEntity').then(async (context) => {
56
56
  const selectEntity = await context.get('selectEntity', []);
57
57
  for (const entity of selectEntity)
58
58
  this.selectEntity.set(entity.name, entity);
59
59
  this.log.debug(`Loaded ${this.selectEntity.size} selectEntity for plugin ${this.config.name}`);
60
60
  return;
61
61
  });
62
- this.ready = Promise.all([this._contextReady, this._selectDeviceContextReady, this._selectEntityContextReady]).then(() => {
62
+ this.ready = Promise.all([this.contextReady, this.selectDeviceContextReady, this.selectEntityContextReady]).then(() => {
63
63
  this.log.debug(`MatterbridgePlatform for plugin ${this.config.name} is fully initialized`);
64
64
  return;
65
65
  });
@@ -79,8 +79,8 @@ export class MatterbridgePlatform {
79
79
  await this.checkEndpointNumbers();
80
80
  this.selectDevice.clear();
81
81
  this.selectEntity.clear();
82
- this._registeredEndpoints.clear();
83
- this._registeredEndpointsByName.clear();
82
+ this.registeredEndpointsByUniqueId.clear();
83
+ this.registeredEndpointsByName.clear();
84
84
  await this.context?.close();
85
85
  this.context = undefined;
86
86
  await this.storage?.close();
@@ -94,11 +94,21 @@ export class MatterbridgePlatform {
94
94
  async onConfigChanged(config) {
95
95
  this.log.debug(`The plugin ${CYAN}${config.name}${db} doesn't override onConfigChanged. Received new config.`);
96
96
  }
97
+ saveConfig(config) {
98
+ const plugin = this.matterbridge.plugins.get(this.name);
99
+ if (!plugin) {
100
+ throw new Error(`Plugin ${this.name} not found`);
101
+ }
102
+ this.matterbridge.plugins.saveConfigFromJson(plugin, config);
103
+ }
104
+ wssSendRestartRequired(snackbar = true, fixed = false) {
105
+ this.matterbridge.frontend.wssSendRestartRequired(snackbar, fixed);
106
+ }
97
107
  getDevices() {
98
- return Array.from(this._registeredEndpoints.values());
108
+ return Array.from(this.registeredEndpointsByUniqueId.values());
99
109
  }
100
110
  hasDeviceName(deviceName) {
101
- return this._registeredEndpointsByName.has(deviceName);
111
+ return this.registeredEndpointsByName.has(deviceName);
102
112
  }
103
113
  async registerDevice(device) {
104
114
  device.plugin = this.name;
@@ -114,7 +124,7 @@ export class MatterbridgePlatform {
114
124
  this.log.error(`Device with uniqueId ${CYAN}${device.uniqueId}${er} has no serialNumber. The device will not be added.`);
115
125
  return;
116
126
  }
117
- if (this._registeredEndpointsByName.has(device.deviceName)) {
127
+ if (this.registeredEndpointsByName.has(device.deviceName)) {
118
128
  this.log.error(`Device with name ${CYAN}${device.deviceName}${er} is already registered. The device will not be added. Please change the device name.`);
119
129
  return;
120
130
  }
@@ -139,20 +149,20 @@ export class MatterbridgePlatform {
139
149
  }
140
150
  }
141
151
  await this.matterbridge.addBridgedEndpoint(this.name, device);
142
- this._registeredEndpoints.set(device.uniqueId, device);
143
- this._registeredEndpointsByName.set(device.deviceName, device);
152
+ this.registeredEndpointsByUniqueId.set(device.uniqueId, device);
153
+ this.registeredEndpointsByName.set(device.deviceName, device);
144
154
  }
145
155
  async unregisterDevice(device) {
146
156
  await this.matterbridge.removeBridgedEndpoint(this.name, device);
147
157
  if (device.uniqueId)
148
- this._registeredEndpoints.delete(device.uniqueId);
158
+ this.registeredEndpointsByUniqueId.delete(device.uniqueId);
149
159
  if (device.deviceName)
150
- this._registeredEndpointsByName.delete(device.deviceName);
160
+ this.registeredEndpointsByName.delete(device.deviceName);
151
161
  }
152
162
  async unregisterAllDevices(delay = 0) {
153
163
  await this.matterbridge.removeAllBridgedEndpoints(this.name, delay);
154
- this._registeredEndpoints.clear();
155
- this._registeredEndpointsByName.clear();
164
+ this.registeredEndpointsByUniqueId.clear();
165
+ this.registeredEndpointsByName.clear();
156
166
  }
157
167
  async saveSelects() {
158
168
  if (this.storage) {
@@ -299,7 +309,7 @@ export class MatterbridgePlatform {
299
309
  const context = await this.storage.createStorage('endpointNumbers');
300
310
  const separator = '|.|';
301
311
  const endpointMap = new Map(await context.get('endpointMap', []));
302
- for (const device of this.matterbridge.getDevices().filter((d) => d.plugin === this.name)) {
312
+ for (const device of this.getDevices()) {
303
313
  if (device.uniqueId === undefined || device.maybeNumber === undefined) {
304
314
  this.log.debug(`Not checking device ${device.deviceName} without uniqueId or maybeNumber`);
305
315
  continue;