matterbridge 2.1.6-dev.4 → 2.1.6-dev.6

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.
@@ -1,13 +1,11 @@
1
- import { fileURLToPath } from 'url';
2
- import { promises as fs } from 'fs';
3
- import { exec, spawn } from 'child_process';
4
- import EventEmitter from 'events';
5
- import os from 'os';
6
- import path from 'path';
7
- import { randomBytes } from 'crypto';
8
- import { NodeStorageManager } from './storage/export.js';
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { promises as fs } from 'node:fs';
4
+ import EventEmitter from 'node:events';
9
5
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt } from './logger/export.js';
10
- import { logInterfaces, copyDirectory, getParameter, getIntParameter, hasParameter, getNpmPackageVersion } from './utils/utils.js';
6
+ import { NodeStorageManager } from './storage/export.js';
7
+ import { getParameter, getIntParameter, hasParameter } from './utils/export.js';
8
+ import { logInterfaces, copyDirectory, getNpmPackageVersion, getGlobalNodeModules } from './utils/utils.js';
11
9
  import { PluginManager } from './pluginManager.js';
12
10
  import { DeviceManager } from './deviceManager.js';
13
11
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
@@ -54,6 +52,7 @@ export class Matterbridge extends EventEmitter {
54
52
  matterbridgeFabricInformations: [],
55
53
  matterbridgeSessionInformations: [],
56
54
  matterbridgePaired: false,
55
+ matterbridgeAdvertise: false,
57
56
  bridgeMode: '',
58
57
  restartMode: '',
59
58
  readOnly: hasParameter('readonly'),
@@ -86,6 +85,7 @@ export class Matterbridge extends EventEmitter {
86
85
  bridgeMode = '';
87
86
  restartMode = '';
88
87
  profile = getParameter('profile');
88
+ shutdown = false;
89
89
  edge = true;
90
90
  log;
91
91
  matterbrideLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
@@ -174,6 +174,7 @@ export class Matterbridge extends EventEmitter {
174
174
  return Matterbridge.instance;
175
175
  }
176
176
  async destroyInstance() {
177
+ this.log.info(`Destroy instance...`);
177
178
  const servers = [];
178
179
  if (this.bridgeMode === 'bridge') {
179
180
  if (this.serverNode)
@@ -186,6 +187,7 @@ export class Matterbridge extends EventEmitter {
186
187
  }
187
188
  }
188
189
  await this.cleanup('destroying instance...', false);
190
+ this.log.info(`Dispose ${servers.length} MdnsService...`);
189
191
  for (const server of servers) {
190
192
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
191
193
  this.log.info(`Closed ${server.id} MdnsService`);
@@ -250,7 +252,7 @@ export class Matterbridge extends EventEmitter {
250
252
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
251
253
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode();
252
254
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator();
253
- this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
255
+ this.log.debug(`Initializing server node for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
254
256
  if (hasParameter('logger')) {
255
257
  const level = getParameter('logger');
256
258
  if (level === 'debug') {
@@ -288,6 +290,8 @@ export class Matterbridge extends EventEmitter {
288
290
  }
289
291
  this.log.notice('Matterbridge is starting...');
290
292
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
293
+ if (this.profile !== undefined)
294
+ this.log.debug(`Matterbridge profile: ${this.profile}.`);
291
295
  if (hasParameter('matterlogger')) {
292
296
  const level = getParameter('matterlogger');
293
297
  if (level === 'debug') {
@@ -443,7 +447,7 @@ export class Matterbridge extends EventEmitter {
443
447
  - disable [plugin name]: disable the globally installed plugin with the given name
444
448
  - reset [plugin path]: remove the commissioning for the plugin from the given absolute or relative path (childbridge mode). Shutdown Matterbridge before using it!
445
449
  - reset [plugin name]: remove the commissioning for the globally installed plugin (childbridge mode). Shutdown Matterbridge before using it!${rs}`);
446
- this.emit('shutdown');
450
+ this.shutdown = true;
447
451
  return;
448
452
  }
449
453
  if (hasParameter('list')) {
@@ -472,7 +476,7 @@ export class Matterbridge extends EventEmitter {
472
476
  this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
473
477
  }
474
478
  });
475
- this.emit('shutdown');
479
+ this.shutdown = true;
476
480
  return;
477
481
  }
478
482
  if (hasParameter('logstorage')) {
@@ -482,41 +486,43 @@ export class Matterbridge extends EventEmitter {
482
486
  this.log.info(`${plg}${plugin.name}${nf} storage log`);
483
487
  await plugin.nodeContext?.logStorage();
484
488
  }
485
- this.emit('shutdown');
489
+ this.shutdown = true;
486
490
  return;
487
491
  }
488
492
  if (hasParameter('loginterfaces')) {
489
493
  this.log.info(`${plg}Matterbridge${nf} network interfaces log`);
490
494
  logInterfaces();
491
- this.emit('shutdown');
495
+ this.shutdown = true;
492
496
  return;
493
497
  }
494
498
  if (getParameter('add')) {
495
499
  this.log.debug(`Adding plugin ${getParameter('add')}`);
496
500
  await this.plugins.add(getParameter('add'));
497
- this.emit('shutdown');
501
+ this.shutdown = true;
498
502
  return;
499
503
  }
500
504
  if (getParameter('remove')) {
501
505
  this.log.debug(`Removing plugin ${getParameter('remove')}`);
502
506
  await this.plugins.remove(getParameter('remove'));
503
- this.emit('shutdown');
507
+ this.shutdown = true;
504
508
  return;
505
509
  }
506
510
  if (getParameter('enable')) {
507
511
  this.log.debug(`Enabling plugin ${getParameter('enable')}`);
508
512
  await this.plugins.enable(getParameter('enable'));
509
- this.emit('shutdown');
513
+ this.shutdown = true;
510
514
  return;
511
515
  }
512
516
  if (getParameter('disable')) {
513
517
  this.log.debug(`Disabling plugin ${getParameter('disable')}`);
514
518
  await this.plugins.disable(getParameter('disable'));
515
- this.emit('shutdown');
519
+ this.shutdown = true;
516
520
  return;
517
521
  }
518
522
  if (hasParameter('factoryreset')) {
523
+ this.initialized = true;
519
524
  await this.shutdownProcessAndFactoryReset();
525
+ this.shutdown = true;
520
526
  return;
521
527
  }
522
528
  try {
@@ -527,7 +533,9 @@ export class Matterbridge extends EventEmitter {
527
533
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
528
534
  }
529
535
  if (hasParameter('reset') && getParameter('reset') === undefined) {
536
+ this.initialized = true;
530
537
  await this.shutdownProcessAndReset();
538
+ this.shutdown = true;
531
539
  return;
532
540
  }
533
541
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
@@ -535,20 +543,23 @@ export class Matterbridge extends EventEmitter {
535
543
  const plugin = this.plugins.get(getParameter('reset'));
536
544
  if (plugin) {
537
545
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
538
- if (!matterStorageManager)
546
+ if (!matterStorageManager) {
539
547
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
540
- await matterStorageManager?.createContext('events')?.clearAll();
541
- await matterStorageManager?.createContext('fabrics')?.clearAll();
542
- await matterStorageManager?.createContext('root')?.clearAll();
543
- await matterStorageManager?.createContext('sessions')?.clearAll();
544
- await matterStorageManager?.createContext('persist')?.clearAll();
545
- this.log.info(`Reset commissionig for plugin ${plg}${plugin.name}${nf} done! Remove the device from the controller.`);
548
+ }
549
+ else {
550
+ await matterStorageManager?.createContext('events')?.clearAll();
551
+ await matterStorageManager?.createContext('fabrics')?.clearAll();
552
+ await matterStorageManager?.createContext('root')?.clearAll();
553
+ await matterStorageManager?.createContext('sessions')?.clearAll();
554
+ await matterStorageManager?.createContext('persist')?.clearAll();
555
+ this.log.info(`Reset commissionig for plugin ${plg}${plugin.name}${nf} done! Remove the device from the controller.`);
556
+ }
546
557
  }
547
558
  else {
548
559
  this.log.warn(`Plugin ${plg}${getParameter('reset')}${wr} not registerd in matterbridge`);
549
560
  }
550
561
  await this.stopMatterStorage();
551
- this.emit('shutdown');
562
+ this.shutdown = true;
552
563
  return;
553
564
  }
554
565
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
@@ -720,6 +731,7 @@ export class Matterbridge extends EventEmitter {
720
731
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
721
732
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
722
733
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
734
+ const { fileURLToPath } = await import('node:url');
723
735
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
724
736
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
725
737
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
@@ -728,7 +740,9 @@ export class Matterbridge extends EventEmitter {
728
740
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
729
741
  if (this.globalModulesDirectory === '') {
730
742
  try {
731
- this.globalModulesDirectory = await this.getGlobalNodeModules();
743
+ this.execRunningCount++;
744
+ this.globalModulesDirectory = await getGlobalNodeModules();
745
+ this.execRunningCount--;
732
746
  this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
733
747
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
734
748
  await this.nodeContext?.set('globalModulesDirectory', this.globalModulesDirectory);
@@ -797,20 +811,6 @@ export class Matterbridge extends EventEmitter {
797
811
  const cmdArgs = process.argv.slice(2).join(' ');
798
812
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
799
813
  }
800
- async getGlobalNodeModules() {
801
- return new Promise((resolve, reject) => {
802
- this.execRunningCount++;
803
- exec('npm root -g', (error, stdout) => {
804
- this.execRunningCount--;
805
- if (error) {
806
- reject(error);
807
- }
808
- else {
809
- resolve(stdout.trim());
810
- }
811
- });
812
- });
813
- }
814
814
  async getMatterbridgeLatestVersion() {
815
815
  getNpmPackageVersion('matterbridge')
816
816
  .then(async (version) => {
@@ -1202,11 +1202,7 @@ export class Matterbridge extends EventEmitter {
1202
1202
  if (!plugin.enabled)
1203
1203
  continue;
1204
1204
  if (plugin.type === 'DynamicPlatform') {
1205
- plugin.locked = true;
1206
- plugin.storageContext = await this.createServerNodeContext(plugin.name, 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, plugin.description);
1207
- plugin.serverNode = await this.createServerNode(plugin.storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
1208
- plugin.aggregatorNode = await this.createAggregatorNode(plugin.storageContext);
1209
- await plugin.serverNode.add(plugin.aggregatorNode);
1205
+ await this.createDynamicPlugin(plugin);
1210
1206
  }
1211
1207
  }
1212
1208
  await this.startPlugins();
@@ -1259,7 +1255,7 @@ export class Matterbridge extends EventEmitter {
1259
1255
  for (const plugin of this.plugins) {
1260
1256
  if (!plugin.enabled || plugin.error)
1261
1257
  continue;
1262
- if (!plugin.addedDevices || plugin.addedDevices === 0) {
1258
+ if (plugin.type !== 'DynamicPlatform' && (!plugin.addedDevices || plugin.addedDevices === 0)) {
1263
1259
  this.log.error(`Plugin ${plg}${plugin.name}${er} didn't add any devices to Matterbridge. Verify the plugin configuration.`);
1264
1260
  continue;
1265
1261
  }
@@ -1315,6 +1311,7 @@ export class Matterbridge extends EventEmitter {
1315
1311
  this.log.info('Matter node storage closed');
1316
1312
  }
1317
1313
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
1314
+ const { randomBytes } = await import('node:crypto');
1318
1315
  if (!this.matterStorageService)
1319
1316
  throw new Error('No storage service initialized');
1320
1317
  this.log.info(`Creating server node storage context "${pluginName}.persist" for ${pluginName}...`);
@@ -1557,13 +1554,18 @@ export class Matterbridge extends EventEmitter {
1557
1554
  }
1558
1555
  }
1559
1556
  async advertiseServerNode(matterServerNode) {
1560
- if (matterServerNode && matterServerNode.lifecycle.isCommissioned) {
1557
+ if (matterServerNode) {
1561
1558
  await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
1562
1559
  const { qrPairingCode, manualPairingCode } = matterServerNode.state.commissioning.pairingCodes;
1563
- this.log.notice(`Advertising for ${matterServerNode.id} is now started with the following pairing codes: qrPairingCode ${qrPairingCode}, manualPairingCode ${manualPairingCode}`);
1560
+ this.log.notice(`Started advertising for ${matterServerNode.id} with the following pairing codes: qrPairingCode ${qrPairingCode}, manualPairingCode ${manualPairingCode}`);
1564
1561
  return { qrPairingCode, manualPairingCode };
1565
1562
  }
1566
- return undefined;
1563
+ }
1564
+ async stopAdvertiseServerNode(matterServerNode) {
1565
+ if (matterServerNode && matterServerNode.lifecycle.isOnline) {
1566
+ await matterServerNode.env.get(DeviceCommissioner)?.endCommissioning();
1567
+ this.log.notice(`Stopped advertising for ${matterServerNode.id}`);
1568
+ }
1567
1569
  }
1568
1570
  async createAggregatorNode(storageContext) {
1569
1571
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
@@ -1635,15 +1637,6 @@ export class Matterbridge extends EventEmitter {
1635
1637
  plugin.registeredDevices--;
1636
1638
  if (plugin.addedDevices !== undefined)
1637
1639
  plugin.addedDevices--;
1638
- if (plugin.registeredDevices === 0 && plugin.addedDevices === 0) {
1639
- if (plugin.serverNode) {
1640
- await this.stopServerNode(plugin.serverNode);
1641
- plugin.locked = false;
1642
- plugin.aggregatorNode = undefined;
1643
- plugin.serverNode = undefined;
1644
- this.log.info(`Stopped server node for plugin ${plg}${pluginName}${nf}`);
1645
- }
1646
- }
1647
1640
  }
1648
1641
  this.devices.remove(device);
1649
1642
  }
@@ -1702,7 +1695,7 @@ export class Matterbridge extends EventEmitter {
1702
1695
  getVendorIdName = (vendorId) => {
1703
1696
  if (!vendorId)
1704
1697
  return '';
1705
- let vendorName = '';
1698
+ let vendorName = '(Unknown vendorId)';
1706
1699
  switch (vendorId) {
1707
1700
  case 4937:
1708
1701
  vendorName = '(AppleHome)';
@@ -1732,15 +1725,13 @@ export class Matterbridge extends EventEmitter {
1732
1725
  vendorName = '(eWeLink)';
1733
1726
  break;
1734
1727
  case 65521:
1735
- vendorName = '(PythonMatterServer)';
1736
- break;
1737
- default:
1738
- vendorName = '(unknown)';
1728
+ vendorName = '(MatterServer)';
1739
1729
  break;
1740
1730
  }
1741
1731
  return vendorName;
1742
1732
  };
1743
1733
  async spawnCommand(command, args = []) {
1734
+ const { spawn } = await import('node:child_process');
1744
1735
  const cmdLine = command + ' ' + args.join(' ');
1745
1736
  if (process.platform === 'win32' && command === 'npm') {
1746
1737
  const argstring = 'npm ' + args.join(' ');
@@ -1,6 +1,6 @@
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
- import { isValidNumber, isValidObject } from './utils/utils.js';
3
+ import { isValidNumber, isValidObject } from './utils/export.js';
4
4
  import { MatterbridgeBehavior, MatterbridgeBehaviorDevice, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeSwitchServer, } 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, VendorId } from '@matter/main';
@@ -1,5 +1,6 @@
1
- import { createHash } from 'crypto';
1
+ import { createHash } from 'node:crypto';
2
2
  import { BLUE, CYAN, db, debugStringify, er, hk, or, YELLOW, zb } from './logger/export.js';
3
+ import { deepCopy, deepEqual, isValidArray } from './utils/export.js';
3
4
  import { MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, } from './matterbridgeBehaviors.js';
4
5
  import { Lifecycle } from '@matter/main';
5
6
  import { getClusterNameById } from '@matter/main/types';
@@ -73,7 +74,6 @@ import { Pm25ConcentrationMeasurementServer } from '@matter/main/behaviors/pm25-
73
74
  import { Pm10ConcentrationMeasurementServer } from '@matter/main/behaviors/pm10-concentration-measurement';
74
75
  import { RadonConcentrationMeasurementServer } from '@matter/main/behaviors/radon-concentration-measurement';
75
76
  import { TotalVolatileOrganicCompoundsConcentrationMeasurementServer } from '@matter/main/behaviors/total-volatile-organic-compounds-concentration-measurement';
76
- import { deepCopy, deepEqual, isValidArray } from './utils/utils.js';
77
77
  export function capitalizeFirstLetter(name) {
78
78
  if (!name)
79
79
  return name;
@@ -1,8 +1,8 @@
1
1
  import { checkNotLatinCharacters } from './matterbridgeEndpointHelpers.js';
2
- import { isValidArray, isValidObject, isValidString } from './utils/utils.js';
2
+ import { isValidArray, isValidObject, isValidString } from './utils/export.js';
3
3
  import { CYAN, db, er, nf, wr } from './logger/export.js';
4
4
  import { NodeStorageManager } from './storage/export.js';
5
- import path from 'path';
5
+ import path from 'node:path';
6
6
  export class MatterbridgePlatform {
7
7
  matterbridge;
8
8
  log;
@@ -1,4 +1,4 @@
1
- import { assert } from 'console';
1
+ import { assert } from 'node:console';
2
2
  export function hslColorToRgbColor(hue, saturation, luminance) {
3
3
  if (hue === 360) {
4
4
  hue = 0;
@@ -1,2 +1,4 @@
1
1
  export * from './utils.js';
2
+ export * from './parameter.js';
3
+ export * from './isvalid.js';
2
4
  export * from './colorUtils.js';
@@ -0,0 +1,50 @@
1
+ export function isValidIpv4Address(ipv4Address) {
2
+ const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
3
+ return ipv4Regex.test(ipv4Address);
4
+ }
5
+ export function isValidNumber(value, min, max) {
6
+ if (value === undefined || value === null || typeof value !== 'number' || Number.isNaN(value))
7
+ return false;
8
+ if (min !== undefined && value < min)
9
+ return false;
10
+ if (max !== undefined && value > max)
11
+ return false;
12
+ return true;
13
+ }
14
+ export function isValidBoolean(value) {
15
+ return value !== undefined && value !== null && typeof value === 'boolean';
16
+ }
17
+ export function isValidString(value, minLength, maxLength) {
18
+ if (value === undefined || value === null || typeof value !== 'string')
19
+ return false;
20
+ if (minLength !== undefined && value.length < minLength)
21
+ return false;
22
+ if (maxLength !== undefined && value.length > maxLength)
23
+ return false;
24
+ return true;
25
+ }
26
+ export function isValidObject(value, minLength, maxLength) {
27
+ if (value === undefined || value === null || typeof value !== 'object' || Array.isArray(value))
28
+ return false;
29
+ const keys = Object.keys(value);
30
+ if (minLength !== undefined && keys.length < minLength)
31
+ return false;
32
+ if (maxLength !== undefined && keys.length > maxLength)
33
+ return false;
34
+ return true;
35
+ }
36
+ export function isValidArray(value, minLength, maxLength) {
37
+ if (value === undefined || value === null || !Array.isArray(value))
38
+ return false;
39
+ if (minLength !== undefined && value.length < minLength)
40
+ return false;
41
+ if (maxLength !== undefined && value.length > maxLength)
42
+ return false;
43
+ return true;
44
+ }
45
+ export function isValidNull(value) {
46
+ return value === null;
47
+ }
48
+ export function isValidUndefined(value) {
49
+ return value === undefined;
50
+ }
@@ -0,0 +1,26 @@
1
+ import { isValidNumber } from './export.js';
2
+ export function getParameter(name) {
3
+ const commandArguments = process.argv.slice(2);
4
+ let markerIndex = commandArguments.indexOf(`-${name}`);
5
+ if (markerIndex === -1)
6
+ markerIndex = commandArguments.indexOf(`--${name}`);
7
+ if (markerIndex === -1 || markerIndex + 1 === commandArguments.length)
8
+ return undefined;
9
+ return commandArguments[markerIndex + 1];
10
+ }
11
+ export function hasParameter(name) {
12
+ const commandArguments = process.argv.slice(2);
13
+ let markerIncluded = commandArguments.includes(`-${name}`);
14
+ if (!markerIncluded)
15
+ markerIncluded = commandArguments.includes(`--${name}`);
16
+ return markerIncluded;
17
+ }
18
+ export function getIntParameter(name) {
19
+ const value = getParameter(name);
20
+ if (value === undefined)
21
+ return undefined;
22
+ const intValue = parseInt(value, 10);
23
+ if (!isValidNumber(intValue))
24
+ return undefined;
25
+ return intValue;
26
+ }
@@ -1,6 +1,6 @@
1
- import os from 'os';
2
- import path from 'path';
3
- import { AnsiLogger, idn, rs } from 'node-ansi-logger';
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { AnsiLogger, idn, rs } from '../logger/export.js';
4
4
  const log = new AnsiLogger({ logName: 'MatterbridgeUtils', logTimestampFormat: 4, logLevel: "info" });
5
5
  export function deepEqual(a, b, excludeProperties = []) {
6
6
  const debug = false;
@@ -147,56 +147,6 @@ export function getMacAddress() {
147
147
  }
148
148
  return macAddress;
149
149
  }
150
- export function isValidIpv4Address(ipv4Address) {
151
- const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
152
- return ipv4Regex.test(ipv4Address);
153
- }
154
- export function isValidNumber(value, min, max) {
155
- if (value === undefined || value === null || typeof value !== 'number' || Number.isNaN(value))
156
- return false;
157
- if (min !== undefined && value < min)
158
- return false;
159
- if (max !== undefined && value > max)
160
- return false;
161
- return true;
162
- }
163
- export function isValidBoolean(value) {
164
- return value !== undefined && value !== null && typeof value === 'boolean';
165
- }
166
- export function isValidString(value, minLength, maxLength) {
167
- if (value === undefined || value === null || typeof value !== 'string')
168
- return false;
169
- if (minLength !== undefined && value.length < minLength)
170
- return false;
171
- if (maxLength !== undefined && value.length > maxLength)
172
- return false;
173
- return true;
174
- }
175
- export function isValidObject(value, minLength, maxLength) {
176
- if (value === undefined || value === null || typeof value !== 'object' || Array.isArray(value))
177
- return false;
178
- const keys = Object.keys(value);
179
- if (minLength !== undefined && keys.length < minLength)
180
- return false;
181
- if (maxLength !== undefined && keys.length > maxLength)
182
- return false;
183
- return true;
184
- }
185
- export function isValidArray(value, minLength, maxLength) {
186
- if (value === undefined || value === null || !Array.isArray(value))
187
- return false;
188
- if (minLength !== undefined && value.length < minLength)
189
- return false;
190
- if (maxLength !== undefined && value.length > maxLength)
191
- return false;
192
- return true;
193
- }
194
- export function isValidNull(value) {
195
- return value === null;
196
- }
197
- export function isValidUndefined(value) {
198
- return value === undefined;
199
- }
200
150
  export function logInterfaces(debug = true) {
201
151
  log.logLevel = "info";
202
152
  log.logName = 'LogInterfaces';
@@ -260,7 +210,7 @@ export async function wait(timeout = 1000, name, debug = false) {
260
210
  export async function createZip(outputPath, ...sourcePaths) {
261
211
  const { default: archiver } = await import('archiver');
262
212
  const { glob } = await import('glob');
263
- const { createWriteStream, statSync } = await import('fs');
213
+ const { createWriteStream, statSync } = await import('node:fs');
264
214
  log.logLevel = "info";
265
215
  log.logName = 'Archive';
266
216
  log.debug(`creating archive ${outputPath} from ${sourcePaths.join(', ')} ...`);
@@ -326,7 +276,7 @@ export async function createZip(outputPath, ...sourcePaths) {
326
276
  });
327
277
  }
328
278
  export async function copyDirectory(srcDir, destDir) {
329
- const fs = await import('fs').then((mod) => mod.promises);
279
+ const fs = await import('node:fs').then((mod) => mod.promises);
330
280
  log.debug(`copyDirectory: copying directory from ${srcDir} to ${destDir}`);
331
281
  try {
332
282
  await fs.mkdir(destDir, { recursive: true });
@@ -349,7 +299,7 @@ export async function copyDirectory(srcDir, destDir) {
349
299
  }
350
300
  }
351
301
  export async function resolveHostname(hostname, family = 4) {
352
- const dns = await import('dns');
302
+ const dns = await import('node:dns');
353
303
  try {
354
304
  const addresses = await dns.promises.lookup(hostname.toLowerCase(), { family });
355
305
  return addresses.address;
@@ -358,31 +308,6 @@ export async function resolveHostname(hostname, family = 4) {
358
308
  return null;
359
309
  }
360
310
  }
361
- export function getParameter(name) {
362
- const commandArguments = process.argv.slice(2);
363
- let markerIndex = commandArguments.indexOf(`-${name}`);
364
- if (markerIndex === -1)
365
- markerIndex = commandArguments.indexOf(`--${name}`);
366
- if (markerIndex === -1 || markerIndex + 1 === commandArguments.length)
367
- return undefined;
368
- return commandArguments[markerIndex + 1];
369
- }
370
- export function hasParameter(name) {
371
- const commandArguments = process.argv.slice(2);
372
- let markerIncluded = commandArguments.includes(`-${name}`);
373
- if (!markerIncluded)
374
- markerIncluded = commandArguments.includes(`--${name}`);
375
- return markerIncluded;
376
- }
377
- export function getIntParameter(name) {
378
- const value = getParameter(name);
379
- if (value === undefined)
380
- return undefined;
381
- const intValue = parseInt(value, 10);
382
- if (!isValidNumber(intValue))
383
- return undefined;
384
- return intValue;
385
- }
386
311
  export async function getNpmPackageVersion(packageName, tag = 'latest', timeout = 5000) {
387
312
  const https = await import('https');
388
313
  return new Promise((resolve, reject) => {
@@ -427,3 +352,16 @@ export async function getNpmPackageVersion(packageName, tag = 'latest', timeout
427
352
  });
428
353
  });
429
354
  }
355
+ export async function getGlobalNodeModules() {
356
+ const { exec } = await import('node:child_process');
357
+ return new Promise((resolve, reject) => {
358
+ exec('npm root -g', (error, stdout) => {
359
+ if (error) {
360
+ reject(error);
361
+ }
362
+ else {
363
+ resolve(stdout.trim());
364
+ }
365
+ });
366
+ });
367
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "./static/css/main.cf25d33e.css",
4
- "main.js": "./static/js/main.257513e8.js",
4
+ "main.js": "./static/js/main.438c6c47.js",
5
5
  "static/js/453.abd36b29.chunk.js": "./static/js/453.abd36b29.chunk.js",
6
6
  "static/media/roboto-latin-700-normal.woff2": "./static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2",
7
7
  "static/media/roboto-latin-500-normal.woff2": "./static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2",
@@ -61,11 +61,11 @@
61
61
  "static/media/roboto-greek-ext-400-normal.woff": "./static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff",
62
62
  "index.html": "./index.html",
63
63
  "main.cf25d33e.css.map": "./static/css/main.cf25d33e.css.map",
64
- "main.257513e8.js.map": "./static/js/main.257513e8.js.map",
64
+ "main.438c6c47.js.map": "./static/js/main.438c6c47.js.map",
65
65
  "453.abd36b29.chunk.js.map": "./static/js/453.abd36b29.chunk.js.map"
66
66
  },
67
67
  "entrypoints": [
68
68
  "static/css/main.cf25d33e.css",
69
- "static/js/main.257513e8.js"
69
+ "static/js/main.438c6c47.js"
70
70
  ]
71
71
  }
@@ -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.257513e8.js"></script><link href="./static/css/main.cf25d33e.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.438c6c47.js"></script><link href="./static/css/main.cf25d33e.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>