matterbridge 3.4.3-dev-20251209-e6cb85f → 3.4.3
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/README.md +2 -3
- package/dist/broadcastServer.d.ts +144 -0
- package/dist/broadcastServer.d.ts.map +1 -0
- package/dist/broadcastServer.js +119 -0
- package/dist/broadcastServer.js.map +1 -0
- package/dist/broadcastServerTypes.d.ts +841 -0
- package/dist/broadcastServerTypes.d.ts.map +1 -0
- package/dist/broadcastServerTypes.js +24 -0
- package/dist/broadcastServerTypes.js.map +1 -0
- package/dist/cli.d.ts +30 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +97 -1
- package/dist/cli.js.map +1 -0
- package/dist/cliEmitter.d.ts +50 -0
- package/dist/cliEmitter.d.ts.map +1 -0
- package/dist/cliEmitter.js +37 -0
- package/dist/cliEmitter.js.map +1 -0
- package/dist/cliHistory.d.ts +48 -0
- package/dist/cliHistory.d.ts.map +1 -0
- package/dist/cliHistory.js +38 -0
- package/dist/cliHistory.js.map +1 -0
- package/dist/clusters/export.d.ts +2 -0
- package/dist/clusters/export.d.ts.map +1 -0
- package/dist/clusters/export.js +2 -0
- package/dist/clusters/export.js.map +1 -0
- package/dist/deviceManager.d.ts +135 -0
- package/dist/deviceManager.d.ts.map +1 -0
- package/dist/deviceManager.js +113 -1
- package/dist/deviceManager.js.map +1 -0
- package/dist/devices/airConditioner.d.ts +98 -0
- package/dist/devices/airConditioner.d.ts.map +1 -0
- package/dist/devices/airConditioner.js +57 -0
- package/dist/devices/airConditioner.js.map +1 -0
- package/dist/devices/batteryStorage.d.ts +48 -0
- package/dist/devices/batteryStorage.d.ts.map +1 -0
- package/dist/devices/batteryStorage.js +48 -1
- package/dist/devices/batteryStorage.js.map +1 -0
- package/dist/devices/cooktop.d.ts +61 -0
- package/dist/devices/cooktop.d.ts.map +1 -0
- package/dist/devices/cooktop.js +56 -0
- package/dist/devices/cooktop.js.map +1 -0
- package/dist/devices/dishwasher.d.ts +71 -0
- package/dist/devices/dishwasher.d.ts.map +1 -0
- package/dist/devices/dishwasher.js +57 -0
- package/dist/devices/dishwasher.js.map +1 -0
- package/dist/devices/evse.d.ts +76 -0
- package/dist/devices/evse.d.ts.map +1 -0
- package/dist/devices/evse.js +74 -10
- package/dist/devices/evse.js.map +1 -0
- package/dist/devices/export.d.ts +17 -0
- package/dist/devices/export.d.ts.map +1 -0
- package/dist/devices/export.js +5 -0
- package/dist/devices/export.js.map +1 -0
- package/dist/devices/extractorHood.d.ts +46 -0
- package/dist/devices/extractorHood.d.ts.map +1 -0
- package/dist/devices/extractorHood.js +43 -0
- package/dist/devices/extractorHood.js.map +1 -0
- package/dist/devices/heatPump.d.ts +47 -0
- package/dist/devices/heatPump.d.ts.map +1 -0
- package/dist/devices/heatPump.js +50 -2
- package/dist/devices/heatPump.js.map +1 -0
- package/dist/devices/laundryDryer.d.ts +67 -0
- package/dist/devices/laundryDryer.d.ts.map +1 -0
- package/dist/devices/laundryDryer.js +62 -3
- package/dist/devices/laundryDryer.js.map +1 -0
- package/dist/devices/laundryWasher.d.ts +81 -0
- package/dist/devices/laundryWasher.d.ts.map +1 -0
- package/dist/devices/laundryWasher.js +70 -4
- package/dist/devices/laundryWasher.js.map +1 -0
- package/dist/devices/microwaveOven.d.ts +168 -0
- package/dist/devices/microwaveOven.d.ts.map +1 -0
- package/dist/devices/microwaveOven.js +88 -5
- package/dist/devices/microwaveOven.js.map +1 -0
- package/dist/devices/oven.d.ts +105 -0
- package/dist/devices/oven.d.ts.map +1 -0
- package/dist/devices/oven.js +85 -0
- package/dist/devices/oven.js.map +1 -0
- package/dist/devices/refrigerator.d.ts +118 -0
- package/dist/devices/refrigerator.d.ts.map +1 -0
- package/dist/devices/refrigerator.js +102 -0
- package/dist/devices/refrigerator.js.map +1 -0
- package/dist/devices/roboticVacuumCleaner.d.ts +112 -0
- package/dist/devices/roboticVacuumCleaner.d.ts.map +1 -0
- package/dist/devices/roboticVacuumCleaner.js +100 -9
- package/dist/devices/roboticVacuumCleaner.js.map +1 -0
- package/dist/devices/solarPower.d.ts +40 -0
- package/dist/devices/solarPower.d.ts.map +1 -0
- package/dist/devices/solarPower.js +38 -0
- package/dist/devices/solarPower.js.map +1 -0
- package/dist/devices/speaker.d.ts +87 -0
- package/dist/devices/speaker.d.ts.map +1 -0
- package/dist/devices/speaker.js +84 -0
- package/dist/devices/speaker.js.map +1 -0
- package/dist/devices/temperatureControl.d.ts +166 -0
- package/dist/devices/temperatureControl.d.ts.map +1 -0
- package/dist/devices/temperatureControl.js +24 -3
- package/dist/devices/temperatureControl.js.map +1 -0
- package/dist/devices/waterHeater.d.ts +111 -0
- package/dist/devices/waterHeater.d.ts.map +1 -0
- package/dist/devices/waterHeater.js +82 -2
- package/dist/devices/waterHeater.js.map +1 -0
- package/dist/dgram/coap.d.ts +205 -0
- package/dist/dgram/coap.d.ts.map +1 -0
- package/dist/dgram/coap.js +126 -13
- package/dist/dgram/coap.js.map +1 -0
- package/dist/dgram/dgram.d.ts +141 -0
- package/dist/dgram/dgram.d.ts.map +1 -0
- package/dist/dgram/dgram.js +114 -2
- package/dist/dgram/dgram.js.map +1 -0
- package/dist/dgram/mb_coap.d.ts +24 -0
- package/dist/dgram/mb_coap.d.ts.map +1 -0
- package/dist/dgram/mb_coap.js +41 -3
- package/dist/dgram/mb_coap.js.map +1 -0
- package/dist/dgram/mb_mdns.d.ts +24 -0
- package/dist/dgram/mb_mdns.d.ts.map +1 -0
- package/dist/dgram/mb_mdns.js +80 -15
- package/dist/dgram/mb_mdns.js.map +1 -0
- package/dist/dgram/mdns.d.ts +290 -0
- package/dist/dgram/mdns.d.ts.map +1 -0
- package/dist/dgram/mdns.js +299 -137
- package/dist/dgram/mdns.js.map +1 -0
- package/dist/dgram/multicast.d.ts +67 -0
- package/dist/dgram/multicast.d.ts.map +1 -0
- package/dist/dgram/multicast.js +62 -1
- package/dist/dgram/multicast.js.map +1 -0
- package/dist/dgram/unicast.d.ts +56 -0
- package/dist/dgram/unicast.d.ts.map +1 -0
- package/dist/dgram/unicast.js +54 -0
- package/dist/dgram/unicast.js.map +1 -0
- package/dist/frontend.d.ts +238 -0
- package/dist/frontend.d.ts.map +1 -0
- package/dist/frontend.js +455 -35
- package/dist/frontend.js.map +1 -0
- package/dist/frontendTypes.d.ts +529 -0
- package/dist/frontendTypes.d.ts.map +1 -0
- package/dist/frontendTypes.js +45 -0
- package/dist/frontendTypes.js.map +1 -0
- package/dist/helpers.d.ts +48 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +53 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/jestutils/export.d.ts +2 -0
- package/dist/jestutils/export.d.ts.map +1 -0
- package/dist/jestutils/export.js +1 -0
- package/dist/jestutils/export.js.map +1 -0
- package/dist/jestutils/jestHelpers.d.ts +345 -0
- package/dist/jestutils/jestHelpers.d.ts.map +1 -0
- package/dist/jestutils/jestHelpers.js +371 -14
- package/dist/jestutils/jestHelpers.js.map +1 -0
- package/dist/logger/export.d.ts +2 -0
- package/dist/logger/export.d.ts.map +1 -0
- package/dist/logger/export.js +1 -0
- package/dist/logger/export.js.map +1 -0
- package/dist/matter/behaviors.d.ts +2 -0
- package/dist/matter/behaviors.d.ts.map +1 -0
- package/dist/matter/behaviors.js +2 -0
- package/dist/matter/behaviors.js.map +1 -0
- package/dist/matter/clusters.d.ts +2 -0
- package/dist/matter/clusters.d.ts.map +1 -0
- package/dist/matter/clusters.js +2 -0
- package/dist/matter/clusters.js.map +1 -0
- package/dist/matter/devices.d.ts +2 -0
- package/dist/matter/devices.d.ts.map +1 -0
- package/dist/matter/devices.js +2 -0
- package/dist/matter/devices.js.map +1 -0
- package/dist/matter/endpoints.d.ts +2 -0
- package/dist/matter/endpoints.d.ts.map +1 -0
- package/dist/matter/endpoints.js +2 -0
- package/dist/matter/endpoints.js.map +1 -0
- package/dist/matter/export.d.ts +5 -0
- package/dist/matter/export.d.ts.map +1 -0
- package/dist/matter/export.js +3 -0
- package/dist/matter/export.js.map +1 -0
- package/dist/matter/types.d.ts +3 -0
- package/dist/matter/types.d.ts.map +1 -0
- package/dist/matter/types.js +3 -0
- package/dist/matter/types.js.map +1 -0
- package/dist/matterNode.d.ts +342 -0
- package/dist/matterNode.d.ts.map +1 -0
- package/dist/matterNode.js +369 -8
- package/dist/matterNode.js.map +1 -0
- package/dist/matterbridge.d.ts +492 -0
- package/dist/matterbridge.d.ts.map +1 -0
- package/dist/matterbridge.js +811 -46
- package/dist/matterbridge.js.map +1 -0
- package/dist/matterbridgeAccessoryPlatform.d.ts +41 -0
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +1 -0
- package/dist/matterbridgeAccessoryPlatform.js +38 -0
- package/dist/matterbridgeAccessoryPlatform.js.map +1 -0
- package/dist/matterbridgeBehaviors.d.ts +2404 -0
- package/dist/matterbridgeBehaviors.d.ts.map +1 -0
- package/dist/matterbridgeBehaviors.js +68 -5
- package/dist/matterbridgeBehaviors.js.map +1 -0
- package/dist/matterbridgeDeviceTypes.d.ts +698 -0
- package/dist/matterbridgeDeviceTypes.d.ts.map +1 -0
- package/dist/matterbridgeDeviceTypes.js +635 -14
- package/dist/matterbridgeDeviceTypes.js.map +1 -0
- package/dist/matterbridgeDynamicPlatform.d.ts +41 -0
- package/dist/matterbridgeDynamicPlatform.d.ts.map +1 -0
- package/dist/matterbridgeDynamicPlatform.js +38 -0
- package/dist/matterbridgeDynamicPlatform.js.map +1 -0
- package/dist/matterbridgeEndpoint.d.ts +1507 -0
- package/dist/matterbridgeEndpoint.d.ts.map +1 -0
- package/dist/matterbridgeEndpoint.js +1444 -53
- package/dist/matterbridgeEndpoint.js.map +1 -0
- package/dist/matterbridgeEndpointHelpers.d.ts +787 -0
- package/dist/matterbridgeEndpointHelpers.d.ts.map +1 -0
- package/dist/matterbridgeEndpointHelpers.js +483 -20
- package/dist/matterbridgeEndpointHelpers.js.map +1 -0
- package/dist/matterbridgeEndpointTypes.d.ts +166 -0
- package/dist/matterbridgeEndpointTypes.d.ts.map +1 -0
- package/dist/matterbridgeEndpointTypes.js +25 -0
- package/dist/matterbridgeEndpointTypes.js.map +1 -0
- package/dist/matterbridgePlatform.d.ts +539 -0
- package/dist/matterbridgePlatform.d.ts.map +1 -0
- package/dist/matterbridgePlatform.js +451 -1
- package/dist/matterbridgePlatform.js.map +1 -0
- package/dist/matterbridgeTypes.d.ts +251 -0
- package/dist/matterbridgeTypes.d.ts.map +1 -0
- package/dist/matterbridgeTypes.js +26 -0
- package/dist/matterbridgeTypes.js.map +1 -0
- package/dist/pluginManager.d.ts +372 -0
- package/dist/pluginManager.d.ts.map +1 -0
- package/dist/pluginManager.js +341 -5
- package/dist/pluginManager.js.map +1 -0
- package/dist/shelly.d.ts +181 -0
- package/dist/shelly.d.ts.map +1 -0
- package/dist/shelly.js +178 -7
- package/dist/shelly.js.map +1 -0
- package/dist/storage/export.d.ts +2 -0
- package/dist/storage/export.d.ts.map +1 -0
- package/dist/storage/export.js +1 -0
- package/dist/storage/export.js.map +1 -0
- package/dist/update.d.ts +84 -0
- package/dist/update.d.ts.map +1 -0
- package/dist/update.js +93 -1
- package/dist/update.js.map +1 -0
- package/dist/utils/colorUtils.d.ts +101 -0
- package/dist/utils/colorUtils.d.ts.map +1 -0
- package/dist/utils/colorUtils.js +97 -2
- package/dist/utils/colorUtils.js.map +1 -0
- package/dist/utils/commandLine.d.ts +66 -0
- package/dist/utils/commandLine.d.ts.map +1 -0
- package/dist/utils/commandLine.js +60 -0
- package/dist/utils/commandLine.js.map +1 -0
- package/dist/utils/copyDirectory.d.ts +35 -0
- package/dist/utils/copyDirectory.d.ts.map +1 -0
- package/dist/utils/copyDirectory.js +37 -0
- package/dist/utils/copyDirectory.js.map +1 -0
- package/dist/utils/createDirectory.d.ts +34 -0
- package/dist/utils/createDirectory.d.ts.map +1 -0
- package/dist/utils/createDirectory.js +33 -0
- package/dist/utils/createDirectory.js.map +1 -0
- package/dist/utils/createZip.d.ts +39 -0
- package/dist/utils/createZip.d.ts.map +1 -0
- package/dist/utils/createZip.js +47 -2
- package/dist/utils/createZip.js.map +1 -0
- package/dist/utils/deepCopy.d.ts +32 -0
- package/dist/utils/deepCopy.d.ts.map +1 -0
- package/dist/utils/deepCopy.js +39 -0
- package/dist/utils/deepCopy.js.map +1 -0
- package/dist/utils/deepEqual.d.ts +54 -0
- package/dist/utils/deepEqual.d.ts.map +1 -0
- package/dist/utils/deepEqual.js +72 -1
- package/dist/utils/deepEqual.js.map +1 -0
- package/dist/utils/error.d.ts +45 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +42 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/export.d.ts +13 -0
- package/dist/utils/export.d.ts.map +1 -0
- package/dist/utils/export.js +1 -0
- package/dist/utils/export.js.map +1 -0
- package/dist/utils/format.d.ts +53 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +49 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/hex.d.ts +89 -0
- package/dist/utils/hex.d.ts.map +1 -0
- package/dist/utils/hex.js +124 -0
- package/dist/utils/hex.js.map +1 -0
- package/dist/utils/inspector.d.ts +87 -0
- package/dist/utils/inspector.d.ts.map +1 -0
- package/dist/utils/inspector.js +69 -1
- package/dist/utils/inspector.js.map +1 -0
- package/dist/utils/isvalid.d.ts +103 -0
- package/dist/utils/isvalid.d.ts.map +1 -0
- package/dist/utils/isvalid.js +101 -0
- package/dist/utils/isvalid.js.map +1 -0
- package/dist/utils/network.d.ts +111 -0
- package/dist/utils/network.d.ts.map +1 -0
- package/dist/utils/network.js +96 -5
- package/dist/utils/network.js.map +1 -0
- package/dist/utils/spawn.d.ts +33 -0
- package/dist/utils/spawn.d.ts.map +1 -0
- package/dist/utils/spawn.js +71 -1
- package/dist/utils/spawn.js.map +1 -0
- package/dist/utils/tracker.d.ts +108 -0
- package/dist/utils/tracker.d.ts.map +1 -0
- package/dist/utils/tracker.js +64 -1
- package/dist/utils/tracker.js.map +1 -0
- package/dist/utils/wait.d.ts +54 -0
- package/dist/utils/wait.d.ts.map +1 -0
- package/dist/utils/wait.js +60 -8
- package/dist/utils/wait.js.map +1 -0
- package/dist/workerGlobalPrefix.d.ts +25 -0
- package/dist/workerGlobalPrefix.d.ts.map +1 -0
- package/dist/workerGlobalPrefix.js +37 -5
- package/dist/workerGlobalPrefix.js.map +1 -0
- package/dist/workerTypes.d.ts +52 -0
- package/dist/workerTypes.d.ts.map +1 -0
- package/dist/workerTypes.js +24 -0
- package/dist/workerTypes.js.map +1 -0
- package/dist/workers.d.ts +69 -0
- package/dist/workers.d.ts.map +1 -0
- package/dist/workers.js +68 -4
- package/dist/workers.js.map +1 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -1
- package/scripts/data_model.mjs +2058 -0
package/dist/pluginManager.js
CHANGED
|
@@ -1,9 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file contains the Plugins class.
|
|
3
|
+
*
|
|
4
|
+
* @file plugins.ts
|
|
5
|
+
* @author Luca Liguori
|
|
6
|
+
* @created 2024-07-14
|
|
7
|
+
* @version 1.3.5
|
|
8
|
+
* @license Apache-2.0
|
|
9
|
+
*
|
|
10
|
+
* Copyright 2024, 2025, 2026 Luca Liguori.
|
|
11
|
+
*
|
|
12
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
+
* you may not use this file except in compliance with the License.
|
|
14
|
+
* You may obtain a copy of the License at
|
|
15
|
+
*
|
|
16
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
*
|
|
18
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
* See the License for the specific language governing permissions and
|
|
22
|
+
* limitations under the License.
|
|
23
|
+
*/
|
|
24
|
+
// Node.js import
|
|
1
25
|
import EventEmitter from 'node:events';
|
|
26
|
+
// AnsiLogger module
|
|
2
27
|
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, BLUE, db, er, nf, nt, rs, wr, debugStringify, CYAN } from 'node-ansi-logger';
|
|
3
28
|
import { plg, typ } from './matterbridgeTypes.js';
|
|
4
29
|
import { inspectError, logError } from './utils/error.js';
|
|
5
30
|
import { hasParameter } from './utils/commandLine.js';
|
|
6
31
|
import { BroadcastServer } from './broadcastServer.js';
|
|
32
|
+
/**
|
|
33
|
+
* Manages Matterbridge plugins.
|
|
34
|
+
*/
|
|
7
35
|
export class PluginManager extends EventEmitter {
|
|
8
36
|
matterbridge;
|
|
9
37
|
_plugins = new Map();
|
|
@@ -11,10 +39,15 @@ export class PluginManager extends EventEmitter {
|
|
|
11
39
|
server;
|
|
12
40
|
debug = hasParameter('debug') || hasParameter('verbose');
|
|
13
41
|
verbose = hasParameter('verbose');
|
|
42
|
+
/**
|
|
43
|
+
* Creates an instance of PluginManager.
|
|
44
|
+
*
|
|
45
|
+
* @param {Matterbridge} matterbridge - The Matterbridge instance.
|
|
46
|
+
*/
|
|
14
47
|
constructor(matterbridge) {
|
|
15
48
|
super();
|
|
16
49
|
this.matterbridge = matterbridge;
|
|
17
|
-
this.log = new AnsiLogger({ logName: 'PluginManager', logTimestampFormat: 4
|
|
50
|
+
this.log = new AnsiLogger({ logName: 'PluginManager', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
|
|
18
51
|
this.log.debug('Matterbridge plugin manager starting...');
|
|
19
52
|
this.server = new BroadcastServer('plugins', this.log);
|
|
20
53
|
this.server.on('broadcast_message', this.msgHandler.bind(this));
|
|
@@ -187,7 +220,7 @@ export class PluginManager extends EventEmitter {
|
|
|
187
220
|
{
|
|
188
221
|
const plugin = this.get(msg.params.name);
|
|
189
222
|
if (plugin) {
|
|
190
|
-
this.saveConfigFromJson(plugin, msg.params.config, msg.params.restartRequired);
|
|
223
|
+
this.saveConfigFromJson(plugin, msg.params.config, msg.params.restartRequired); // No await as it's not necessary to wait
|
|
191
224
|
this.server.respond({ ...msg, result: { success: true } });
|
|
192
225
|
}
|
|
193
226
|
else {
|
|
@@ -225,25 +258,62 @@ export class PluginManager extends EventEmitter {
|
|
|
225
258
|
}
|
|
226
259
|
}
|
|
227
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Gets the number of plugins.
|
|
263
|
+
*
|
|
264
|
+
* @returns {number} The number of plugins.
|
|
265
|
+
*/
|
|
228
266
|
get length() {
|
|
229
267
|
return this._plugins.size;
|
|
230
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Gets the number of plugins.
|
|
271
|
+
*
|
|
272
|
+
* @returns {number} The number of plugins.
|
|
273
|
+
*/
|
|
231
274
|
get size() {
|
|
232
275
|
return this._plugins.size;
|
|
233
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Checks if a plugin with the specified name exists.
|
|
279
|
+
*
|
|
280
|
+
* @param {string} name - The name of the plugin.
|
|
281
|
+
* @returns {boolean} True if the plugin exists, false otherwise.
|
|
282
|
+
*/
|
|
234
283
|
has(name) {
|
|
235
284
|
return this._plugins.has(name);
|
|
236
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Gets a plugin by its name.
|
|
288
|
+
*
|
|
289
|
+
* @param {string} name - The name of the plugin.
|
|
290
|
+
* @returns {Plugin | undefined} The plugin, or undefined if not found.
|
|
291
|
+
*/
|
|
237
292
|
get(name) {
|
|
238
293
|
return this._plugins.get(name);
|
|
239
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Adds a plugin to the manager.
|
|
297
|
+
*
|
|
298
|
+
* @param {Plugin} plugin - The plugin to add.
|
|
299
|
+
* @returns {Plugin} The added plugin.
|
|
300
|
+
*/
|
|
240
301
|
set(plugin) {
|
|
241
302
|
this._plugins.set(plugin.name, plugin);
|
|
242
303
|
return plugin;
|
|
243
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Clears all plugins from the manager.
|
|
307
|
+
*/
|
|
244
308
|
clear() {
|
|
245
309
|
this._plugins.clear();
|
|
246
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Converts a plugin or API plugin to a storage plugin.
|
|
313
|
+
*
|
|
314
|
+
* @param {Plugin | ApiPlugin} plugin - The plugin or API plugin to convert.
|
|
315
|
+
* @returns {StoragePlugin} The converted storage plugin.
|
|
316
|
+
*/
|
|
247
317
|
toStoragePlugin(plugin) {
|
|
248
318
|
return {
|
|
249
319
|
name: plugin.name,
|
|
@@ -255,6 +325,12 @@ export class PluginManager extends EventEmitter {
|
|
|
255
325
|
enabled: plugin.enabled,
|
|
256
326
|
};
|
|
257
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* Converts a plugin to an API plugin.
|
|
330
|
+
*
|
|
331
|
+
* @param {Plugin} plugin - The plugin to convert.
|
|
332
|
+
* @returns {ApiPlugin} The converted API plugin.
|
|
333
|
+
*/
|
|
258
334
|
toApiPlugin(plugin) {
|
|
259
335
|
return {
|
|
260
336
|
name: plugin.name,
|
|
@@ -284,9 +360,19 @@ export class PluginManager extends EventEmitter {
|
|
|
284
360
|
matter: plugin.serverNode ? this.matterbridge.getServerNodeData(plugin.serverNode) : undefined,
|
|
285
361
|
};
|
|
286
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* Gets an array of all plugins.
|
|
365
|
+
*
|
|
366
|
+
* @returns {Plugin[]} An array of all plugins.
|
|
367
|
+
*/
|
|
287
368
|
array() {
|
|
288
369
|
return Array.from(this._plugins.values());
|
|
289
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* Gets a StoragePlugin array of all plugins suitable for serialization.
|
|
373
|
+
*
|
|
374
|
+
* @returns {StoragePlugin[]} An array of all plugins.
|
|
375
|
+
*/
|
|
290
376
|
storagePluginArray() {
|
|
291
377
|
const storagePlugins = [];
|
|
292
378
|
for (const plugin of this._plugins.values()) {
|
|
@@ -294,6 +380,11 @@ export class PluginManager extends EventEmitter {
|
|
|
294
380
|
}
|
|
295
381
|
return storagePlugins;
|
|
296
382
|
}
|
|
383
|
+
/**
|
|
384
|
+
* Gets an ApiPlugin array of all plugins suitable for serialization.
|
|
385
|
+
*
|
|
386
|
+
* @returns {ApiPlugin[]} An array of all plugins.
|
|
387
|
+
*/
|
|
297
388
|
apiPluginArray() {
|
|
298
389
|
const apiPlugins = [];
|
|
299
390
|
for (const plugin of this._plugins.values()) {
|
|
@@ -301,9 +392,20 @@ export class PluginManager extends EventEmitter {
|
|
|
301
392
|
}
|
|
302
393
|
return apiPlugins;
|
|
303
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Gets an iterator for the plugins.
|
|
397
|
+
*
|
|
398
|
+
* @returns {IterableIterator<Plugin>} An iterator for the plugins.
|
|
399
|
+
*/
|
|
304
400
|
[Symbol.iterator]() {
|
|
305
401
|
return this._plugins.values();
|
|
306
402
|
}
|
|
403
|
+
/**
|
|
404
|
+
* Executes a provided function once for each plugin.
|
|
405
|
+
*
|
|
406
|
+
* @param {Function} callback - The function to execute for each plugin.
|
|
407
|
+
* @returns {Promise<void>}
|
|
408
|
+
*/
|
|
307
409
|
async forEach(callback) {
|
|
308
410
|
if (this.size === 0)
|
|
309
411
|
return;
|
|
@@ -317,23 +419,40 @@ export class PluginManager extends EventEmitter {
|
|
|
317
419
|
});
|
|
318
420
|
await Promise.all(tasks);
|
|
319
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* Sets the log level for the plugin manager.
|
|
424
|
+
*
|
|
425
|
+
* @param {LogLevel} logLevel - The log level to set.
|
|
426
|
+
*/
|
|
320
427
|
set logLevel(logLevel) {
|
|
321
428
|
this.log.logLevel = logLevel;
|
|
322
429
|
}
|
|
430
|
+
/**
|
|
431
|
+
* Loads registered plugins from storage.
|
|
432
|
+
*
|
|
433
|
+
* @returns {Promise<StoragePlugin[]>} A promise that resolves to an array of registered plugins.
|
|
434
|
+
*/
|
|
323
435
|
async loadFromStorage() {
|
|
324
436
|
if (!this.matterbridge.nodeContext) {
|
|
325
437
|
throw new Error('loadFromStorage: node context is not available.');
|
|
326
438
|
}
|
|
439
|
+
// Load the array from storage and convert it to a map
|
|
327
440
|
const pluginsArray = await this.matterbridge.nodeContext.get('plugins', []);
|
|
328
441
|
for (const plugin of pluginsArray)
|
|
329
442
|
this._plugins.set(plugin.name, plugin);
|
|
330
443
|
this.log.debug(`Loaded ${BLUE}${pluginsArray.length}${db} plugins from storage`);
|
|
331
444
|
return pluginsArray;
|
|
332
445
|
}
|
|
446
|
+
/**
|
|
447
|
+
* Saves registered plugins to storage.
|
|
448
|
+
*
|
|
449
|
+
* @returns {Promise<number>} A promise that resolves to the number of registered plugins.
|
|
450
|
+
*/
|
|
333
451
|
async saveToStorage() {
|
|
334
452
|
if (!this.matterbridge.nodeContext) {
|
|
335
453
|
throw new Error('loadFromStorage: node context is not available.');
|
|
336
454
|
}
|
|
455
|
+
// Convert the map to an array
|
|
337
456
|
const plugins = [];
|
|
338
457
|
for (const plugin of this.array()) {
|
|
339
458
|
plugins.push({
|
|
@@ -350,13 +469,22 @@ export class PluginManager extends EventEmitter {
|
|
|
350
469
|
this.log.debug(`Saved ${BLUE}${plugins.length}${db} plugins to storage`);
|
|
351
470
|
return plugins.length;
|
|
352
471
|
}
|
|
472
|
+
/**
|
|
473
|
+
* Resolves the name of a plugin by loading and parsing its package.json file.
|
|
474
|
+
* It will first try to resolve the path as is, then in the global modules directory, and finally in the matterbridge plugin directory.
|
|
475
|
+
*
|
|
476
|
+
* @param {string} nameOrPath - The name of the plugin or the path to the plugin's package.json file.
|
|
477
|
+
* @returns {Promise<string | null>} A promise that resolves to the path of the plugin's package.json file or null if it could not be resolved.
|
|
478
|
+
*/
|
|
353
479
|
async resolve(nameOrPath) {
|
|
354
480
|
const { default: path } = await import('node:path');
|
|
355
481
|
const { promises } = await import('node:fs');
|
|
356
482
|
if (!nameOrPath.endsWith('package.json'))
|
|
357
483
|
nameOrPath = path.join(nameOrPath, 'package.json');
|
|
484
|
+
// Resolve the package.json of the plugin
|
|
358
485
|
let packageJsonPath = path.resolve(nameOrPath);
|
|
359
486
|
this.log.debug(`Resolving plugin path ${plg}${packageJsonPath}${db}`);
|
|
487
|
+
// Check if the package.json file exists at the specified path or next try in the global modules directory
|
|
360
488
|
try {
|
|
361
489
|
await promises.access(packageJsonPath);
|
|
362
490
|
}
|
|
@@ -365,6 +493,7 @@ export class PluginManager extends EventEmitter {
|
|
|
365
493
|
packageJsonPath = path.join(this.matterbridge.globalModulesDirectory, nameOrPath);
|
|
366
494
|
this.log.debug(`Trying at ${plg}${packageJsonPath}${db}`);
|
|
367
495
|
}
|
|
496
|
+
// Check if the package.json file exists at the global modules directory or next try in the matterbridge plugin directory
|
|
368
497
|
try {
|
|
369
498
|
await promises.access(packageJsonPath);
|
|
370
499
|
}
|
|
@@ -374,7 +503,9 @@ export class PluginManager extends EventEmitter {
|
|
|
374
503
|
this.log.debug(`Trying at ${plg}${packageJsonPath}${db}`);
|
|
375
504
|
}
|
|
376
505
|
try {
|
|
506
|
+
// Load the package.json of the plugin or fails if even not found in the matterbridge plugin directory
|
|
377
507
|
const packageJson = JSON.parse(await promises.readFile(packageJsonPath, 'utf8'));
|
|
508
|
+
// Check for main issues
|
|
378
509
|
if (!packageJson.name) {
|
|
379
510
|
this.log.error(`Package.json name not found at ${packageJsonPath}`);
|
|
380
511
|
return null;
|
|
@@ -387,6 +518,7 @@ export class PluginManager extends EventEmitter {
|
|
|
387
518
|
this.log.error(`Plugin at ${packageJsonPath} has no main entrypoint in package.json`);
|
|
388
519
|
return null;
|
|
389
520
|
}
|
|
521
|
+
// Check for @project-chip and @matter packages in dependencies and devDependencies
|
|
390
522
|
const checkForProjectChipPackages = (dependencies) => {
|
|
391
523
|
return Object.keys(dependencies).filter((pkg) => pkg.startsWith('@project-chip') || pkg.startsWith('@matter'));
|
|
392
524
|
};
|
|
@@ -408,6 +540,7 @@ export class PluginManager extends EventEmitter {
|
|
|
408
540
|
this.log.error(`Please open an issue on the plugin repository to remove them.`);
|
|
409
541
|
return null;
|
|
410
542
|
}
|
|
543
|
+
// Check for matterbridge package in dependencies and devDependencies
|
|
411
544
|
const checkForMatterbridgePackage = (dependencies) => {
|
|
412
545
|
return Object.keys(dependencies).filter((pkg) => pkg === 'matterbridge');
|
|
413
546
|
};
|
|
@@ -437,13 +570,19 @@ export class PluginManager extends EventEmitter {
|
|
|
437
570
|
return null;
|
|
438
571
|
}
|
|
439
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* Installs a package globally using npm.
|
|
575
|
+
*
|
|
576
|
+
* @param {string} packageName - The name of the package to install.
|
|
577
|
+
* @returns {Promise<boolean>} A promise that resolves to true if the installation was successful, false otherwise.
|
|
578
|
+
*/
|
|
440
579
|
async install(packageName) {
|
|
441
580
|
this.log.debug(`Installing plugin ${plg}${packageName}${db}...`);
|
|
442
581
|
const { spawnCommand } = await import('./utils/spawn.js');
|
|
443
582
|
if (await spawnCommand('npm', ['install', '-g', packageName, '--omit=dev', '--verbose'], 'install', packageName)) {
|
|
444
583
|
this.matterbridge.restartRequired = true;
|
|
445
584
|
this.matterbridge.fixedRestartRequired = true;
|
|
446
|
-
packageName = packageName.replace(/@.*$/, '');
|
|
585
|
+
packageName = packageName.replace(/@.*$/, ''); // Remove @version if present
|
|
447
586
|
if (packageName !== 'matterbridge') {
|
|
448
587
|
if (!this.has(packageName))
|
|
449
588
|
await this.add(packageName);
|
|
@@ -464,6 +603,12 @@ export class PluginManager extends EventEmitter {
|
|
|
464
603
|
return false;
|
|
465
604
|
}
|
|
466
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* Uninstalls a package globally using npm.
|
|
608
|
+
*
|
|
609
|
+
* @param {string} packageName - The name of the package to uninstall.
|
|
610
|
+
* @returns {Promise<boolean>} A promise that resolves to true if the uninstallation was successful, false otherwise.
|
|
611
|
+
*/
|
|
467
612
|
async uninstall(packageName) {
|
|
468
613
|
this.log.debug(`Uninstalling plugin ${plg}${packageName}${db}...`);
|
|
469
614
|
const { spawnCommand } = await import('./utils/spawn.js');
|
|
@@ -485,6 +630,12 @@ export class PluginManager extends EventEmitter {
|
|
|
485
630
|
return false;
|
|
486
631
|
}
|
|
487
632
|
}
|
|
633
|
+
/**
|
|
634
|
+
* Get the author of a plugin from its package.json.
|
|
635
|
+
*
|
|
636
|
+
* @param {Record<string, string | number | Record<string, string | number | object>>} packageJson - The package.json object of the plugin.
|
|
637
|
+
* @returns {string} The author of the plugin, or 'Unknown author' if not found.
|
|
638
|
+
*/
|
|
488
639
|
getAuthor(packageJson) {
|
|
489
640
|
if (packageJson.author && typeof packageJson.author === 'string')
|
|
490
641
|
return packageJson.author;
|
|
@@ -492,6 +643,12 @@ export class PluginManager extends EventEmitter {
|
|
|
492
643
|
return packageJson.author.name;
|
|
493
644
|
return 'Unknown author';
|
|
494
645
|
}
|
|
646
|
+
/**
|
|
647
|
+
* Get the homepage of a plugin from its package.json.
|
|
648
|
+
*
|
|
649
|
+
* @param {Record<string, string | number | Record<string, string | number | object>>} packageJson - The package.json object of the plugin.
|
|
650
|
+
* @returns {string | undefined} The homepage of the plugin, or undefined if not found.
|
|
651
|
+
*/
|
|
495
652
|
getHomepage(packageJson) {
|
|
496
653
|
if (packageJson.homepage && typeof packageJson.homepage === 'string' && packageJson.homepage.includes('http')) {
|
|
497
654
|
return packageJson.homepage.replace('git+', '').replace('.git', '');
|
|
@@ -500,7 +657,14 @@ export class PluginManager extends EventEmitter {
|
|
|
500
657
|
return packageJson.repository.url.replace('git+', '').replace('.git', '');
|
|
501
658
|
}
|
|
502
659
|
}
|
|
660
|
+
/**
|
|
661
|
+
* Get the help URL of a plugin from its package.json.
|
|
662
|
+
*
|
|
663
|
+
* @param {Record<string, string | number | Record<string, string | number | object>>} packageJson - The package.json object of the plugin.
|
|
664
|
+
* @returns {string | undefined} The URL to the help page or to the README file, or undefined if not found.
|
|
665
|
+
*/
|
|
503
666
|
getHelp(packageJson) {
|
|
667
|
+
// If there's a help field that looks like a URL, return it.
|
|
504
668
|
if (packageJson.help && typeof packageJson.help === 'string' && packageJson.help.startsWith('http')) {
|
|
505
669
|
return packageJson.help;
|
|
506
670
|
}
|
|
@@ -511,7 +675,14 @@ export class PluginManager extends EventEmitter {
|
|
|
511
675
|
return packageJson.homepage.replace('git+', '').replace('.git', '');
|
|
512
676
|
}
|
|
513
677
|
}
|
|
678
|
+
/**
|
|
679
|
+
* Get the changelog URL of a plugin from its package.json.
|
|
680
|
+
*
|
|
681
|
+
* @param {Record<string, string | number | Record<string, string | number | object>>} packageJson - The package.json object of the plugin.
|
|
682
|
+
* @returns {string | undefined} The URL to the CHANGELOG file, or undefined if not found.
|
|
683
|
+
*/
|
|
514
684
|
getChangelog(packageJson) {
|
|
685
|
+
// If there's a changelog field that looks like a URL, return it.
|
|
515
686
|
if (packageJson.changelog && typeof packageJson.changelog === 'string' && packageJson.changelog.startsWith('http')) {
|
|
516
687
|
return packageJson.changelog;
|
|
517
688
|
}
|
|
@@ -522,6 +693,13 @@ export class PluginManager extends EventEmitter {
|
|
|
522
693
|
return packageJson.homepage.replace('git+', '').replace('.git', '');
|
|
523
694
|
}
|
|
524
695
|
}
|
|
696
|
+
/**
|
|
697
|
+
* Get the first funding URL(s) of a plugin from its package.json.
|
|
698
|
+
*
|
|
699
|
+
* @param {Record<string, any>} packageJson - The package.json object of the plugin.
|
|
700
|
+
* @returns {string | undefined} The first funding URLs, or undefined if not found.
|
|
701
|
+
*/
|
|
702
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
525
703
|
getFunding(packageJson) {
|
|
526
704
|
const funding = packageJson.funding;
|
|
527
705
|
if (!funding)
|
|
@@ -530,16 +708,27 @@ export class PluginManager extends EventEmitter {
|
|
|
530
708
|
return;
|
|
531
709
|
if (typeof funding === 'string' && funding.startsWith('http'))
|
|
532
710
|
return funding;
|
|
711
|
+
// Normalize funding into an array.
|
|
533
712
|
const fundingEntries = Array.isArray(funding) ? funding : [funding];
|
|
534
713
|
for (const entry of fundingEntries) {
|
|
535
714
|
if (entry && typeof entry === 'string' && entry.startsWith('http')) {
|
|
715
|
+
// If the funding entry is a string, assume it is a URL.
|
|
536
716
|
return entry;
|
|
537
717
|
}
|
|
538
718
|
else if (entry && typeof entry === 'object' && typeof entry.url === 'string' && entry.url.startsWith('http')) {
|
|
719
|
+
// If it's an object with a 'url' property, use that.
|
|
539
720
|
return entry.url;
|
|
540
721
|
}
|
|
541
722
|
}
|
|
542
723
|
}
|
|
724
|
+
/**
|
|
725
|
+
* Parses the plugin package.json and returns it.
|
|
726
|
+
* It will also log warnings and errors for missing or invalid fields.
|
|
727
|
+
* It will return null if critical errors are found.
|
|
728
|
+
*
|
|
729
|
+
* @param {Plugin | PluginName} plugin - The plugin to load the package from.
|
|
730
|
+
* @returns {Promise<Record<string, string | number | object> | null>} A promise that resolves to the parsed package.json object or null if it could not be parsed.
|
|
731
|
+
*/
|
|
543
732
|
async parse(plugin) {
|
|
544
733
|
const { promises } = await import('node:fs');
|
|
545
734
|
if (typeof plugin === 'string') {
|
|
@@ -577,6 +766,7 @@ export class PluginManager extends EventEmitter {
|
|
|
577
766
|
plugin.funding = this.getFunding(packageJson);
|
|
578
767
|
if (!plugin.type)
|
|
579
768
|
this.log.warn(`Plugin ${plg}${plugin.name}${wr} has no type`);
|
|
769
|
+
// Check for @project-chip and @matter packages in dependencies and devDependencies
|
|
580
770
|
const checkForProjectChipPackages = (dependencies) => {
|
|
581
771
|
return Object.keys(dependencies).filter((pkg) => pkg.startsWith('@project-chip') || pkg.startsWith('@matter'));
|
|
582
772
|
};
|
|
@@ -598,6 +788,7 @@ export class PluginManager extends EventEmitter {
|
|
|
598
788
|
this.log.error(`Please open an issue on the plugin repository to remove them.`);
|
|
599
789
|
return null;
|
|
600
790
|
}
|
|
791
|
+
// Check for matterbridge package in dependencies and devDependencies
|
|
601
792
|
const checkForMatterbridgePackage = (dependencies) => {
|
|
602
793
|
return Object.keys(dependencies).filter((pkg) => pkg === 'matterbridge');
|
|
603
794
|
};
|
|
@@ -627,6 +818,16 @@ export class PluginManager extends EventEmitter {
|
|
|
627
818
|
return null;
|
|
628
819
|
}
|
|
629
820
|
}
|
|
821
|
+
/**
|
|
822
|
+
* Enables a plugin by its name or path.
|
|
823
|
+
*
|
|
824
|
+
* This method enables a plugin by setting its `enabled` property to `true` and saving the updated
|
|
825
|
+
* plugin information to storage. It first checks if the plugin is already registered in the `_plugins` map.
|
|
826
|
+
* If not, it attempts to resolve the plugin's `package.json` file to retrieve its name and enable it.
|
|
827
|
+
*
|
|
828
|
+
* @param {string} nameOrPath - The name or path of the plugin to enable.
|
|
829
|
+
* @returns {Promise<Plugin | null>} A promise that resolves to the enabled plugin object, or null if the plugin could not be enabled.
|
|
830
|
+
*/
|
|
630
831
|
async enable(nameOrPath) {
|
|
631
832
|
const { promises } = await import('node:fs');
|
|
632
833
|
if (!nameOrPath)
|
|
@@ -662,6 +863,16 @@ export class PluginManager extends EventEmitter {
|
|
|
662
863
|
return null;
|
|
663
864
|
}
|
|
664
865
|
}
|
|
866
|
+
/**
|
|
867
|
+
* Disables a plugin by its name or path.
|
|
868
|
+
*
|
|
869
|
+
* This method disables a plugin by setting its `enabled` property to `false` and saving the updated
|
|
870
|
+
* plugin information to storage. It first checks if the plugin is already registered in the `_plugins` map.
|
|
871
|
+
* If not, it attempts to resolve the plugin's `package.json` file to retrieve its name and disable it.
|
|
872
|
+
*
|
|
873
|
+
* @param {string} nameOrPath - The name or path of the plugin to enable.
|
|
874
|
+
* @returns {Promise<Plugin | null>} A promise that resolves to the disabled plugin object, or null if the plugin could not be disabled.
|
|
875
|
+
*/
|
|
665
876
|
async disable(nameOrPath) {
|
|
666
877
|
const { promises } = await import('node:fs');
|
|
667
878
|
if (!nameOrPath)
|
|
@@ -697,6 +908,16 @@ export class PluginManager extends EventEmitter {
|
|
|
697
908
|
return null;
|
|
698
909
|
}
|
|
699
910
|
}
|
|
911
|
+
/**
|
|
912
|
+
* Removes a plugin by its name or path.
|
|
913
|
+
*
|
|
914
|
+
* This method removes a plugin from the `_plugins` map and saves the updated plugin information to storage.
|
|
915
|
+
* It first checks if the plugin is already registered in the `_plugins` map. If not, it attempts to resolve
|
|
916
|
+
* the plugin's `package.json` file to retrieve its name and remove it.
|
|
917
|
+
*
|
|
918
|
+
* @param {string} nameOrPath - The name or path of the plugin to remove.
|
|
919
|
+
* @returns {Promise<Plugin | null>} A promise that resolves to the removed plugin object, or null if the plugin could not be removed.
|
|
920
|
+
*/
|
|
700
921
|
async remove(nameOrPath) {
|
|
701
922
|
const { promises } = await import('node:fs');
|
|
702
923
|
if (!nameOrPath)
|
|
@@ -732,6 +953,17 @@ export class PluginManager extends EventEmitter {
|
|
|
732
953
|
return null;
|
|
733
954
|
}
|
|
734
955
|
}
|
|
956
|
+
/**
|
|
957
|
+
* Adds a plugin by its name or path.
|
|
958
|
+
*
|
|
959
|
+
* This method adds a plugin to the plugins map and saves the updated plugin information to storage.
|
|
960
|
+
* It first resolves the plugin's `package.json` file to retrieve its details. If the plugin is already
|
|
961
|
+
* registered, it logs an info message and returns null. Otherwise, it registers the plugin, enables it,
|
|
962
|
+
* and saves the updated plugin information to storage.
|
|
963
|
+
*
|
|
964
|
+
* @param {string} nameOrPath - The name or path of the plugin to add.
|
|
965
|
+
* @returns {Promise<Plugin | null>} A promise that resolves to the added plugin object, or null if the plugin could not be added.
|
|
966
|
+
*/
|
|
735
967
|
async add(nameOrPath) {
|
|
736
968
|
const { promises } = await import('node:fs');
|
|
737
969
|
if (!nameOrPath)
|
|
@@ -771,6 +1003,15 @@ export class PluginManager extends EventEmitter {
|
|
|
771
1003
|
return null;
|
|
772
1004
|
}
|
|
773
1005
|
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Loads a plugin and returns the corresponding MatterbridgePlatform instance.
|
|
1008
|
+
*
|
|
1009
|
+
* @param {Plugin | PluginName} plugin - The plugin to load.
|
|
1010
|
+
* @param {boolean} start - Optional flag indicating whether to start the plugin after loading. Default is false.
|
|
1011
|
+
* @param {string} message - Optional message to pass to the plugin when starting.
|
|
1012
|
+
* @param {boolean} configure - Optional flag indicating whether to configure the plugin after loading. Default is false.
|
|
1013
|
+
* @returns {Promise<MatterbridgePlatform | undefined>} A Promise that resolves to the loaded MatterbridgePlatform instance or undefined.
|
|
1014
|
+
*/
|
|
774
1015
|
async load(plugin, start = false, message = '', configure = false) {
|
|
775
1016
|
const { promises } = await import('node:fs');
|
|
776
1017
|
const { default: path } = await import('node:path');
|
|
@@ -792,15 +1033,20 @@ export class PluginManager extends EventEmitter {
|
|
|
792
1033
|
}
|
|
793
1034
|
this.log.info(`Loading plugin ${plg}${plugin.name}${nf} type ${typ}${plugin.type}${nf}`);
|
|
794
1035
|
try {
|
|
1036
|
+
// Load the package.json of the plugin
|
|
795
1037
|
const packageJson = JSON.parse(await promises.readFile(plugin.path, 'utf8'));
|
|
1038
|
+
// Resolve the main module path relative to package.json
|
|
796
1039
|
const pluginEntry = path.resolve(path.dirname(plugin.path), packageJson.main);
|
|
1040
|
+
// Dynamically import the plugin
|
|
797
1041
|
const { pathToFileURL } = await import('node:url');
|
|
798
1042
|
const pluginUrl = pathToFileURL(pluginEntry);
|
|
799
1043
|
this.log.debug(`Importing plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
800
1044
|
const pluginInstance = (await import(pluginUrl.href));
|
|
801
1045
|
this.log.debug(`Imported plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
1046
|
+
// Call the default export function of the plugin, passing this MatterBridge instance, the log and the config
|
|
802
1047
|
if (pluginInstance.default) {
|
|
803
1048
|
const config = await this.loadConfig(plugin);
|
|
1049
|
+
// Preset the plugin properties here in case the plugin throws an error during loading. In this case the user can change the config and restart the plugin.
|
|
804
1050
|
plugin.name = packageJson.name;
|
|
805
1051
|
plugin.description = packageJson.description ?? 'No description';
|
|
806
1052
|
plugin.version = packageJson.version;
|
|
@@ -809,13 +1055,14 @@ export class PluginManager extends EventEmitter {
|
|
|
809
1055
|
plugin.schemaJson = await this.loadSchema(plugin);
|
|
810
1056
|
config.name = packageJson.name;
|
|
811
1057
|
config.version = packageJson.version;
|
|
812
|
-
const log = new AnsiLogger({ logName: plugin.description, logTimestampFormat: 4
|
|
1058
|
+
const log = new AnsiLogger({ logName: plugin.description, logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: config.debug ? "debug" /* LogLevel.DEBUG */ : this.matterbridge.logLevel });
|
|
813
1059
|
const platform = pluginInstance.default(this.matterbridge, log, config);
|
|
814
1060
|
config.type = platform.type;
|
|
815
1061
|
platform.name = packageJson.name;
|
|
816
1062
|
platform.config = config;
|
|
817
1063
|
platform.version = packageJson.version;
|
|
818
1064
|
platform.isLoaded = true;
|
|
1065
|
+
// @ts-expect-error - setMatterNode is intentionally private
|
|
819
1066
|
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));
|
|
820
1067
|
plugin.name = packageJson.name;
|
|
821
1068
|
plugin.description = packageJson.description ?? 'No description';
|
|
@@ -829,7 +1076,7 @@ export class PluginManager extends EventEmitter {
|
|
|
829
1076
|
plugin.platform = platform;
|
|
830
1077
|
plugin.loaded = true;
|
|
831
1078
|
plugin.registeredDevices = 0;
|
|
832
|
-
await this.saveToStorage();
|
|
1079
|
+
await this.saveToStorage(); // Save the plugin to storage
|
|
833
1080
|
this.log.notice(`Loaded plugin ${plg}${plugin.name}${nt} type ${typ}${platform.type}${nt} (entrypoint ${UNDERLINE}${pluginEntry}${UNDERLINEOFF})`);
|
|
834
1081
|
this.emit('loaded', plugin.name);
|
|
835
1082
|
if (start)
|
|
@@ -849,6 +1096,14 @@ export class PluginManager extends EventEmitter {
|
|
|
849
1096
|
}
|
|
850
1097
|
return undefined;
|
|
851
1098
|
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Starts a plugin.
|
|
1101
|
+
*
|
|
1102
|
+
* @param {Plugin | PluginName} plugin - The plugin to start.
|
|
1103
|
+
* @param {string} [message] - Optional message to pass to the plugin's onStart method.
|
|
1104
|
+
* @param {boolean} [configure] - Indicates whether to configure the plugin after starting (default false).
|
|
1105
|
+
* @returns {Promise<Plugin | undefined>} A promise that resolves when the plugin is started successfully, or rejects with an error if starting the plugin fails.
|
|
1106
|
+
*/
|
|
852
1107
|
async start(plugin, message, configure = false) {
|
|
853
1108
|
if (typeof plugin === 'string') {
|
|
854
1109
|
const p = this._plugins.get(plugin);
|
|
@@ -888,6 +1143,12 @@ export class PluginManager extends EventEmitter {
|
|
|
888
1143
|
}
|
|
889
1144
|
return undefined;
|
|
890
1145
|
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Configures a plugin.
|
|
1148
|
+
*
|
|
1149
|
+
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
1150
|
+
* @returns {Promise<Plugin | undefined>} A promise that resolves when the plugin is configured successfully, or rejects with an error if configuration fails.
|
|
1151
|
+
*/
|
|
891
1152
|
async configure(plugin) {
|
|
892
1153
|
if (typeof plugin === 'string') {
|
|
893
1154
|
const p = this._plugins.get(plugin);
|
|
@@ -928,6 +1189,18 @@ export class PluginManager extends EventEmitter {
|
|
|
928
1189
|
}
|
|
929
1190
|
return undefined;
|
|
930
1191
|
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Shuts down a plugin.
|
|
1194
|
+
*
|
|
1195
|
+
* This method shuts down a plugin by calling its `onShutdown` method and resetting its state.
|
|
1196
|
+
* It logs the shutdown process and optionally removes all devices associated with the plugin.
|
|
1197
|
+
*
|
|
1198
|
+
* @param {Plugin | PluginName} plugin - The plugin to shut down.
|
|
1199
|
+
* @param {string} [reason] - The reason for shutting down the plugin.
|
|
1200
|
+
* @param {boolean} [removeAllDevices] - Whether to remove all devices associated with the plugin.
|
|
1201
|
+
* @param {boolean} [force] - Whether to force the shutdown even if the plugin is not loaded or started.
|
|
1202
|
+
* @returns {Promise<Plugin | undefined>} A promise that resolves to the shut down plugin object, or undefined if the shutdown failed.
|
|
1203
|
+
*/
|
|
931
1204
|
async shutdown(plugin, reason, removeAllDevices = false, force = false) {
|
|
932
1205
|
if (typeof plugin === 'string') {
|
|
933
1206
|
const p = this._plugins.get(plugin);
|
|
@@ -984,6 +1257,15 @@ export class PluginManager extends EventEmitter {
|
|
|
984
1257
|
}
|
|
985
1258
|
return undefined;
|
|
986
1259
|
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Loads the configuration for a plugin.
|
|
1262
|
+
* If the configuration file exists, it reads the file and returns the parsed JSON data.
|
|
1263
|
+
* If the configuration file does not exist, it creates a new file with default configuration and returns it.
|
|
1264
|
+
* If any error occurs during file access or creation, it logs an error and return un empty config.
|
|
1265
|
+
*
|
|
1266
|
+
* @param {Plugin} plugin - The plugin for which to load the configuration.
|
|
1267
|
+
* @returns {Promise<PlatformConfig>} A promise that resolves to the loaded or created configuration.
|
|
1268
|
+
*/
|
|
987
1269
|
async loadConfig(plugin) {
|
|
988
1270
|
const { default: path } = await import('node:path');
|
|
989
1271
|
const { promises } = await import('node:fs');
|
|
@@ -994,6 +1276,8 @@ export class PluginManager extends EventEmitter {
|
|
|
994
1276
|
const data = await promises.readFile(configFile, 'utf8');
|
|
995
1277
|
const config = JSON.parse(data);
|
|
996
1278
|
this.log.debug(`Loaded config file ${configFile} for plugin ${plg}${plugin.name}${db}.`);
|
|
1279
|
+
// this.log.debug(`Loaded config file ${configFile} for plugin ${plg}${plugin.name}${db}.\nConfig:${rs}\n`, config);
|
|
1280
|
+
// The first time a plugin is added to the system, the config file is created with the plugin name and type "AnyPlatform".
|
|
997
1281
|
config.name = plugin.name;
|
|
998
1282
|
config.type = plugin.type;
|
|
999
1283
|
if (config.debug === undefined)
|
|
@@ -1020,6 +1304,7 @@ export class PluginManager extends EventEmitter {
|
|
|
1020
1304
|
try {
|
|
1021
1305
|
await promises.writeFile(configFile, JSON.stringify(config, null, 2), 'utf8');
|
|
1022
1306
|
this.log.debug(`Created config file ${configFile} for plugin ${plg}${plugin.name}${db}.`);
|
|
1307
|
+
// this.log.debug(`Created config file ${configFile} for plugin ${plg}${plugin.name}${db}.\nConfig:${rs}\n`, config);
|
|
1023
1308
|
return config;
|
|
1024
1309
|
}
|
|
1025
1310
|
catch (err) {
|
|
@@ -1033,6 +1318,19 @@ export class PluginManager extends EventEmitter {
|
|
|
1033
1318
|
}
|
|
1034
1319
|
}
|
|
1035
1320
|
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Saves the configuration of a plugin to a file.
|
|
1323
|
+
*
|
|
1324
|
+
* This method saves the configuration of the specified plugin to a JSON file in the matterbridge directory.
|
|
1325
|
+
* If the plugin's configuration is not found, it logs an error and rejects the promise. If the configuration
|
|
1326
|
+
* is successfully saved, it logs a debug message. If an error occurs during the file write operation, it logs
|
|
1327
|
+
* the error and rejects the promise.
|
|
1328
|
+
*
|
|
1329
|
+
* @param {Plugin} plugin - The plugin whose configuration is to be saved.
|
|
1330
|
+
* @param {boolean} [restartRequired] - Indicates whether a restart is required after saving the configuration.
|
|
1331
|
+
* @returns {Promise<void>} A promise that resolves when the configuration is successfully saved, or rejects if an error occurs.
|
|
1332
|
+
* @throws {Error} If the plugin's configuration is not found.
|
|
1333
|
+
*/
|
|
1036
1334
|
async saveConfigFromPlugin(plugin, restartRequired = false) {
|
|
1037
1335
|
const { default: path } = await import('node:path');
|
|
1038
1336
|
const { promises } = await import('node:fs');
|
|
@@ -1047,6 +1345,7 @@ export class PluginManager extends EventEmitter {
|
|
|
1047
1345
|
if (restartRequired)
|
|
1048
1346
|
plugin.restartRequired = true;
|
|
1049
1347
|
this.log.debug(`Saved config file ${configFile} for plugin ${plg}${plugin.name}${db}`);
|
|
1348
|
+
// this.log.debug(`Saved config file ${configFile} for plugin ${plg}${plugin.name}${db}.\nConfig:${rs}\n`, plugin.platform.config);
|
|
1050
1349
|
return Promise.resolve();
|
|
1051
1350
|
}
|
|
1052
1351
|
catch (err) {
|
|
@@ -1054,6 +1353,20 @@ export class PluginManager extends EventEmitter {
|
|
|
1054
1353
|
return Promise.reject(err);
|
|
1055
1354
|
}
|
|
1056
1355
|
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Saves the configuration of a plugin from a JSON object to a file.
|
|
1358
|
+
*
|
|
1359
|
+
* This method saves the provided configuration of the specified plugin to a JSON file in the matterbridge directory.
|
|
1360
|
+
* It first checks if the configuration data is valid by ensuring it contains the correct name and type, and matches
|
|
1361
|
+
* the plugin's name. If the configuration data is invalid, it logs an error and returns. If the configuration is
|
|
1362
|
+
* successfully saved, it updates the plugin's `configJson` property and logs a debug message. If an error occurs
|
|
1363
|
+
* during the file write operation, it logs the error and returns.
|
|
1364
|
+
*
|
|
1365
|
+
* @param {Plugin} plugin - The plugin whose configuration is to be saved.
|
|
1366
|
+
* @param {PlatformConfig} config - The configuration data to be saved.
|
|
1367
|
+
* @param {boolean} [restartRequired] - Indicates whether a restart is required after saving the configuration.
|
|
1368
|
+
* @returns {Promise<void>} A promise that resolves when the configuration is successfully saved, or returns if an error occurs.
|
|
1369
|
+
*/
|
|
1057
1370
|
async saveConfigFromJson(plugin, config, restartRequired = false) {
|
|
1058
1371
|
const { default: path } = await import('node:path');
|
|
1059
1372
|
const { promises } = await import('node:fs');
|
|
@@ -1072,12 +1385,23 @@ export class PluginManager extends EventEmitter {
|
|
|
1072
1385
|
plugin.platform.onConfigChanged(config).catch((err) => this.log.error(`Error calling onConfigChanged for plugin ${plg}${plugin.name}${er}: ${err}`));
|
|
1073
1386
|
}
|
|
1074
1387
|
this.log.debug(`Saved config file ${configFile} for plugin ${plg}${plugin.name}${db}`);
|
|
1388
|
+
// this.log.debug(`Saved config file ${configFile} for plugin ${plg}${plugin.name}${db}.\nConfig:${rs}\n`, config);
|
|
1075
1389
|
}
|
|
1076
1390
|
catch (err) {
|
|
1077
1391
|
logError(this.log, `Error saving config file ${configFile} for plugin ${plg}${plugin.name}${er}`, err);
|
|
1078
1392
|
return;
|
|
1079
1393
|
}
|
|
1080
1394
|
}
|
|
1395
|
+
/**
|
|
1396
|
+
* Loads the schema for a plugin.
|
|
1397
|
+
*
|
|
1398
|
+
* This method attempts to load the schema file for the specified plugin. If the schema file is found,
|
|
1399
|
+
* it reads and parses the file, updates the schema's title and description, and logs the process.
|
|
1400
|
+
* If the schema file is not found, it logs the event and loads a default schema for the plugin.
|
|
1401
|
+
*
|
|
1402
|
+
* @param {Plugin} plugin - The plugin whose schema is to be loaded.
|
|
1403
|
+
* @returns {Promise<PlatformSchema>} A promise that resolves to the loaded schema object, or the default schema if the schema file is not found.
|
|
1404
|
+
*/
|
|
1081
1405
|
async loadSchema(plugin) {
|
|
1082
1406
|
const { promises } = await import('node:fs');
|
|
1083
1407
|
const schemaFile = plugin.path.replace('package.json', `${plugin.name}.schema.json`);
|
|
@@ -1088,6 +1412,7 @@ export class PluginManager extends EventEmitter {
|
|
|
1088
1412
|
schema.title = plugin.description;
|
|
1089
1413
|
schema.description = plugin.name + ' v. ' + plugin.version + ' by ' + plugin.author;
|
|
1090
1414
|
this.log.debug(`Loaded schema file ${schemaFile} for plugin ${plg}${plugin.name}${db}.`);
|
|
1415
|
+
// this.log.debug(`Loaded schema file ${schemaFile} for plugin ${plg}${plugin.name}${db}.\nSchema:${rs}\n`, schema);
|
|
1091
1416
|
return schema;
|
|
1092
1417
|
}
|
|
1093
1418
|
catch (_err) {
|
|
@@ -1095,6 +1420,16 @@ export class PluginManager extends EventEmitter {
|
|
|
1095
1420
|
return this.getDefaultSchema(plugin);
|
|
1096
1421
|
}
|
|
1097
1422
|
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Returns the default schema for a plugin.
|
|
1425
|
+
*
|
|
1426
|
+
* This method generates a default schema object for the specified plugin. The schema includes
|
|
1427
|
+
* metadata such as the plugin's title, description, version, and author. It also defines the
|
|
1428
|
+
* properties of the schema, including the plugin's name, type, debug flag, and unregisterOnShutdown flag.
|
|
1429
|
+
*
|
|
1430
|
+
* @param {Plugin} plugin - The plugin for which the default schema is to be generated.
|
|
1431
|
+
* @returns {PlatformSchema} The default schema object for the plugin.
|
|
1432
|
+
*/
|
|
1098
1433
|
getDefaultSchema(plugin) {
|
|
1099
1434
|
return {
|
|
1100
1435
|
title: plugin.description,
|
|
@@ -1125,3 +1460,4 @@ export class PluginManager extends EventEmitter {
|
|
|
1125
1460
|
};
|
|
1126
1461
|
}
|
|
1127
1462
|
}
|
|
1463
|
+
//# sourceMappingURL=pluginManager.js.map
|