matterbridge 3.4.1-dev-20251127-826b2bf → 3.4.1-dev-20251128-441f8db

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
@@ -39,10 +39,12 @@ Advantages:
39
39
  - [frontend]: Updated dependencies.
40
40
  - [frontend]: Bumped `frontend` version to 3.3.2.
41
41
  - [platform]: Bumped MatterbridgePlatform v.1.5.0.
42
+ - [thread]: Bump BroadcastServer to v1.0.4.
42
43
 
43
44
  ### Fixed
44
45
 
45
46
  - [frontend]: Fixed when the user put special characters in password. Thanks Dabern (https://github.com/Luligu/matterbridge/issues/443).
47
+ - [frontend]: Fixed minimum size to 1300x1024 and add a max width to Url. Thanks Ricardo B. (https://github.com/Luligu/matterbridge-home-assistant-addon/issues/23).
46
48
 
47
49
  <a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
48
50
 
package/README-DEV.md CHANGED
@@ -251,9 +251,25 @@ It is called when the plugin config has been updated.
251
251
 
252
252
  Retrieves the devices registered with the platform.
253
253
 
254
+ ### getDeviceByName(deviceName: string): MatterbridgeEndpoint | undefined
255
+
256
+ ### getDeviceByUniqueId(uniqueId: string): MatterbridgeEndpoint | undefined
257
+
258
+ ### getDeviceBySerialNumber(serialNumber: string): MatterbridgeEndpoint | undefined
259
+
260
+ ### getDeviceById(id: string): MatterbridgeEndpoint | undefined
261
+
262
+ ### getDeviceByOriginalId(originalId: string): MatterbridgeEndpoint | undefined
263
+
264
+ ### getDeviceByNumber(number: EndpointNumber | number): MatterbridgeEndpoint | undefined
265
+
266
+ They all return MatterbridgeEndpoint or undefined if not found.
267
+
254
268
  ### hasDeviceName(deviceName: string): boolean
255
269
 
256
- Checks if a device with this name is already registered in the platform.
270
+ ### hasDeviceUniqueId(deviceUniqueId: string): boolean
271
+
272
+ Checks if a device with this name or uniqueId is already registered in the platform.
257
273
 
258
274
  ### async registerDevice(device: MatterbridgeEndpoint)
259
275
 
@@ -288,7 +304,7 @@ You create a Matter device with a new instance of MatterbridgeEndpoint(definitio
288
304
 
289
305
  In the above example we create a contact sensor device type with also a power source device type feature replaceble battery.
290
306
 
291
- All device types are defined in src\matterbridgeDeviceTypes.ts and taken from the 'Matter-1.4.1-Device-Library-Specification.pdf'.
307
+ All device types are defined in src\matterbridgeDeviceTypes.ts and taken from the 'Matter-1.4.2-Device-Library-Specification.pdf'.
292
308
 
293
309
  All default cluster helpers are available as methods of MatterbridgeEndpoint.
294
310
 
@@ -388,7 +404,7 @@ const heatPump = new HeatPump('Heat Pump', 'HP1234567890');
388
404
 
389
405
  ## Plugin config file
390
406
 
391
- Each plugin has a minimal default config file injected by Matterbridge when it is loaded:
407
+ Each plugin has a minimal default config file injected by Matterbridge when it is loaded and the plugin doesn't have its own default one:
392
408
 
393
409
  ```typescript
394
410
  {
@@ -408,7 +424,7 @@ In all subsequent loads the config file is loaded from the '.matterbridge' direc
408
424
 
409
425
  ## Plugin schema file
410
426
 
411
- Each plugin has a minimal default schema file injected by Matterbridge when it is loaded:
427
+ Each plugin has a minimal default schema file injected by Matterbridge when it is loaded and the plugin doesn't have its own default one:
412
428
 
413
429
  ```typescript
414
430
  {
package/README.md CHANGED
@@ -56,6 +56,8 @@ Join us in the Matterbridge [Discord group](https://discord.gg/QX58CDe6hd) creat
56
56
 
57
57
  https://www.youtube.com/watch?v=goNB9Cgh_Fk
58
58
 
59
+ https://www.youtube.com/watch?v=06zzl7o_IqQ
60
+
59
61
  ## Reviews
60
62
 
61
63
  https://www.matteralpha.com/how-to/how-to-configure-an-open-source-matter-bridge-at-home
@@ -2,8 +2,9 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
2
2
  console.log('\u001B[32mBroadcastServer loaded.\u001B[40;0m');
3
3
  import { EventEmitter } from 'node:events';
4
4
  import { BroadcastChannel } from 'node:worker_threads';
5
- import { CYAN, db, debugStringify } from 'node-ansi-logger';
5
+ import { CYAN, db, debugStringify, er } from 'node-ansi-logger';
6
6
  import { hasParameter } from './utils/commandLine.js';
7
+ import { logError } from './utils/error.js';
7
8
  export class BroadcastServer extends EventEmitter {
8
9
  name;
9
10
  log;
@@ -56,7 +57,12 @@ export class BroadcastServer extends EventEmitter {
56
57
  }
57
58
  if (this.verbose)
58
59
  this.log.debug(`Broadcasting request message: ${debugStringify(message)}`);
59
- this.broadcastChannel.postMessage(message);
60
+ try {
61
+ this.broadcastChannel.postMessage(message);
62
+ }
63
+ catch (error) {
64
+ logError(this.log, `Failed to broadcast request message ${debugStringify(message)}${er}`, error);
65
+ }
60
66
  }
61
67
  respond(message) {
62
68
  if (message.timestamp === undefined) {
@@ -68,7 +74,12 @@ export class BroadcastServer extends EventEmitter {
68
74
  }
69
75
  if (this.verbose)
70
76
  this.log.debug(`Broadcasting response message: ${debugStringify(message)}`);
71
- this.broadcastChannel.postMessage(message);
77
+ try {
78
+ this.broadcastChannel.postMessage(message);
79
+ }
80
+ catch (error) {
81
+ logError(this.log, `Failed to broadcast response message ${debugStringify(message)}${er}`, error);
82
+ }
72
83
  }
73
84
  async fetch(message, timeout = 250) {
74
85
  if (message.id === undefined) {
@@ -97,7 +108,7 @@ export class BroadcastServer extends EventEmitter {
97
108
  this.request(message);
98
109
  const timeoutId = setTimeout(() => {
99
110
  this.off('broadcast_message', responseHandler);
100
- reject(new Error(`Fetch timeout after ${timeout}ms for message id ${message.id}`));
111
+ reject(new Error(`Fetch timeout after ${timeout}ms for message type ${message.type} id ${message.id} from ${message.src} to ${message.dst}`));
101
112
  }, timeout);
102
113
  });
103
114
  }
package/dist/frontend.js CHANGED
@@ -66,7 +66,7 @@ export class Frontend extends EventEmitter {
66
66
  this.server.respond({ ...msg, response: { success: true } });
67
67
  break;
68
68
  case 'frontend_refreshrequired':
69
- this.wssSendRefreshRequired(msg.params.changed, { matter: msg.params.matter });
69
+ this.wssSendRefreshRequired(msg.params.changed, msg.params.matter ? { matter: msg.params.matter } : undefined);
70
70
  this.server.respond({ ...msg, response: { success: true } });
71
71
  break;
72
72
  case 'frontend_restartrequired':
@@ -93,6 +93,10 @@ export class Frontend extends EventEmitter {
93
93
  this.wssSendLogMessage(msg.params.level, msg.params.time, msg.params.name, msg.params.message);
94
94
  this.server.respond({ ...msg, response: { success: true } });
95
95
  break;
96
+ case 'frontend_broadcast_message':
97
+ this.wssBroadcastMessage(msg.params.msg);
98
+ this.server.respond({ ...msg, response: { success: true } });
99
+ break;
96
100
  default:
97
101
  if (this.verbose)
98
102
  this.log.debug(`Unknown broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
@@ -11,6 +11,9 @@ import { NodeStorageManager } from 'node-persist-manager';
11
11
  import { Matterbridge } from '../matterbridge.js';
12
12
  import { MATTER_STORAGE_NAME, NODE_STORAGE_DIR } from '../matterbridgeTypes.js';
13
13
  import { bridge } from '../matterbridgeDeviceTypes.js';
14
+ import { PluginManager } from '../pluginManager.js';
15
+ import { Frontend } from '../frontend.js';
16
+ import { BroadcastServer } from '../broadcastServer.js';
14
17
  export const originalProcessArgv = Object.freeze([...process.argv]);
15
18
  export const originalProcessEnv = Object.freeze({ ...process.env });
16
19
  export let loggerLogSpy;
@@ -28,6 +31,29 @@ export let consoleErrorSpy;
28
31
  export let addBridgedEndpointSpy;
29
32
  export let removeBridgedEndpointSpy;
30
33
  export let removeAllBridgedEndpointsSpy;
34
+ export let addVirtualEndpointSpy;
35
+ export let installPluginSpy;
36
+ export let uninstallPluginSpy;
37
+ export let addPluginSpy;
38
+ export let loadPluginSpy;
39
+ export let startPluginSpy;
40
+ export let configurePluginSpy;
41
+ export let shutdownPluginSpy;
42
+ export let removePluginSpy;
43
+ export let enablePluginSpy;
44
+ export let disablePluginSpy;
45
+ export let wssSendSnackbarMessageSpy;
46
+ export let wssSendCloseSnackbarMessageSpy;
47
+ export let wssSendUpdateRequiredSpy;
48
+ export let wssSendRefreshRequiredSpy;
49
+ export let wssSendRestartRequiredSpy;
50
+ export let wssSendRestartNotRequiredSpy;
51
+ export let broadcastServerIsWorkerRequestSpy;
52
+ export let broadcastServerIsWorkerResponseSpy;
53
+ export let broadcastServerRequestSpy;
54
+ export let broadcastServerRespondSpy;
55
+ export let broadcastServerFetchSpy;
56
+ export let broadcastMessageHandlerSpy;
31
57
  export let NAME;
32
58
  export let HOMEDIR;
33
59
  export let matterbridge;
@@ -71,6 +97,29 @@ export async function setupTest(name, debug = false) {
71
97
  addBridgedEndpointSpy = jest.spyOn(Matterbridge.prototype, 'addBridgedEndpoint');
72
98
  removeBridgedEndpointSpy = jest.spyOn(Matterbridge.prototype, 'removeBridgedEndpoint');
73
99
  removeAllBridgedEndpointsSpy = jest.spyOn(Matterbridge.prototype, 'removeAllBridgedEndpoints');
100
+ addVirtualEndpointSpy = jest.spyOn(Matterbridge.prototype, 'addVirtualEndpoint');
101
+ installPluginSpy = jest.spyOn(PluginManager.prototype, 'install');
102
+ uninstallPluginSpy = jest.spyOn(PluginManager.prototype, 'uninstall');
103
+ addPluginSpy = jest.spyOn(PluginManager.prototype, 'add');
104
+ loadPluginSpy = jest.spyOn(PluginManager.prototype, 'load');
105
+ startPluginSpy = jest.spyOn(PluginManager.prototype, 'start');
106
+ configurePluginSpy = jest.spyOn(PluginManager.prototype, 'configure');
107
+ shutdownPluginSpy = jest.spyOn(PluginManager.prototype, 'shutdown');
108
+ removePluginSpy = jest.spyOn(PluginManager.prototype, 'remove');
109
+ enablePluginSpy = jest.spyOn(PluginManager.prototype, 'enable');
110
+ disablePluginSpy = jest.spyOn(PluginManager.prototype, 'disable');
111
+ wssSendSnackbarMessageSpy = jest.spyOn(Frontend.prototype, 'wssSendSnackbarMessage');
112
+ wssSendCloseSnackbarMessageSpy = jest.spyOn(Frontend.prototype, 'wssSendCloseSnackbarMessage');
113
+ wssSendUpdateRequiredSpy = jest.spyOn(Frontend.prototype, 'wssSendUpdateRequired');
114
+ wssSendRefreshRequiredSpy = jest.spyOn(Frontend.prototype, 'wssSendRefreshRequired');
115
+ wssSendRestartRequiredSpy = jest.spyOn(Frontend.prototype, 'wssSendRestartRequired');
116
+ wssSendRestartNotRequiredSpy = jest.spyOn(Frontend.prototype, 'wssSendRestartNotRequired');
117
+ broadcastServerIsWorkerRequestSpy = jest.spyOn(BroadcastServer.prototype, 'isWorkerRequest');
118
+ broadcastServerIsWorkerResponseSpy = jest.spyOn(BroadcastServer.prototype, 'isWorkerResponse');
119
+ broadcastServerRequestSpy = jest.spyOn(BroadcastServer.prototype, 'request');
120
+ broadcastServerRespondSpy = jest.spyOn(BroadcastServer.prototype, 'respond');
121
+ broadcastServerFetchSpy = jest.spyOn(BroadcastServer.prototype, 'fetch');
122
+ broadcastMessageHandlerSpy = jest.spyOn(BroadcastServer.prototype, 'broadcastMessageHandler');
74
123
  }
75
124
  export async function setDebug(debug) {
76
125
  const { jest } = await import('@jest/globals');
@@ -144,6 +144,24 @@ export class Matterbridge extends EventEmitter {
144
144
  this.log.logLevel = msg.params.logLevel;
145
145
  this.server.respond({ ...msg, response: { success: true, logLevel: this.log.logLevel } });
146
146
  break;
147
+ case 'matterbridge_latest_version':
148
+ this.matterbridgeLatestVersion = msg.params.version;
149
+ await this.nodeContext?.set('matterbridgeLatestVersion', msg.params.version);
150
+ this.server.respond({ ...msg, response: { success: true } });
151
+ break;
152
+ case 'matterbridge_dev_version':
153
+ this.matterbridgeDevVersion = msg.params.version;
154
+ await this.nodeContext?.set('matterbridgeDevVersion', msg.params.version);
155
+ this.server.respond({ ...msg, response: { success: true } });
156
+ break;
157
+ case 'matterbridge_sys_update':
158
+ this.shellySysUpdate = true;
159
+ this.server.respond({ ...msg, response: { success: true } });
160
+ break;
161
+ case 'matterbridge_main_update':
162
+ this.shellyMainUpdate = true;
163
+ this.server.respond({ ...msg, response: { success: true } });
164
+ break;
147
165
  default:
148
166
  if (this.verbose)
149
167
  this.log.debug(`Unknown broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
@@ -194,6 +194,30 @@ export class PluginManager extends EventEmitter {
194
194
  }
195
195
  }
196
196
  break;
197
+ case 'plugins_set_latest_version':
198
+ {
199
+ const plugin = this.get(msg.params.plugin.name);
200
+ if (plugin) {
201
+ plugin.latestVersion = msg.params.version;
202
+ this.server.respond({ ...msg, response: { success: true } });
203
+ }
204
+ else {
205
+ this.server.respond({ ...msg, response: { success: false } });
206
+ }
207
+ }
208
+ break;
209
+ case 'plugins_set_dev_version':
210
+ {
211
+ const plugin = this.get(msg.params.plugin.name);
212
+ if (plugin) {
213
+ plugin.devVersion = msg.params.version;
214
+ this.server.respond({ ...msg, response: { success: true } });
215
+ }
216
+ else {
217
+ this.server.respond({ ...msg, response: { success: false } });
218
+ }
219
+ }
220
+ break;
197
221
  default:
198
222
  if (this.verbose)
199
223
  this.log.debug(`Unknown broadcast message ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
package/dist/shelly.js CHANGED
@@ -7,22 +7,22 @@ export function setVerifyIntervalSecs(seconds) {
7
7
  export function setVerifyTimeoutSecs(seconds) {
8
8
  verifyTimeoutSecs = seconds;
9
9
  }
10
- export async function getShellySysUpdate(matterbridge) {
10
+ export async function getShellySysUpdate(matterbridge, log, server) {
11
11
  try {
12
12
  const updates = (await getShelly('/api/updates/sys/check'));
13
13
  if (updates.length === 0)
14
14
  return;
15
- matterbridge.shellySysUpdate = true;
16
- matterbridge.frontend.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'shelly_sys_update', success: true, response: { available: true } });
15
+ server.request({ type: 'matterbridge_sys_update', src: server.name, dst: 'matterbridge' });
16
+ server.request({ type: 'frontend_broadcast_message', src: server.name, dst: 'frontend', params: { msg: { id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'shelly_sys_update', success: true, response: { available: true } } } });
17
17
  for (const { name } of updates) {
18
18
  if (!name)
19
19
  continue;
20
- matterbridge.log.notice(`Shelly system update available: ${name}`);
21
- matterbridge.frontend.wssSendSnackbarMessage(`Shelly system update available: ${name}`, 10);
20
+ log.notice(`Shelly system update available: ${name}`);
21
+ server.request({ type: 'frontend_snackbarmessage', src: server.name, dst: 'frontend', params: { message: `Shelly system update available: ${name}`, timeout: 10 } });
22
22
  }
23
23
  }
24
24
  catch (err) {
25
- matterbridge.log.error(`Error getting Shelly system updates: ${err instanceof Error ? err.message : String(err)}`);
25
+ log.error(`Error getting Shelly system updates: ${err instanceof Error ? err.message : String(err)}`);
26
26
  }
27
27
  }
28
28
  export async function triggerShellySysUpdate(matterbridge) {
@@ -38,22 +38,22 @@ export async function triggerShellySysUpdate(matterbridge) {
38
38
  matterbridge.log.error(`Error triggering Shelly system update: ${err instanceof Error ? err.message : String(err)}`);
39
39
  }
40
40
  }
41
- export async function getShellyMainUpdate(matterbridge) {
41
+ export async function getShellyMainUpdate(matterbridge, log, server) {
42
42
  try {
43
43
  const updates = (await getShelly('/api/updates/main/check'));
44
44
  if (updates.length === 0)
45
45
  return;
46
- matterbridge.shellyMainUpdate = true;
47
- matterbridge.frontend.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'shelly_main_update', success: true, response: { available: true } });
46
+ server.request({ type: 'matterbridge_main_update', src: server.name, dst: 'matterbridge' });
47
+ server.request({ type: 'frontend_broadcast_message', src: server.name, dst: 'frontend', params: { msg: { id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'shelly_main_update', success: true, response: { available: true } } } });
48
48
  for (const { name } of updates) {
49
49
  if (!name)
50
50
  continue;
51
- matterbridge.log.notice(`Shelly software update available: ${name}`);
52
- matterbridge.frontend.wssSendSnackbarMessage(`Shelly software update available: ${name}`, 10);
51
+ log.notice(`Shelly software update available: ${name}`);
52
+ server.request({ type: 'frontend_snackbarmessage', src: server.name, dst: 'frontend', params: { message: `Shelly software update available: ${name}`, timeout: 10 } });
53
53
  }
54
54
  }
55
55
  catch (err) {
56
- matterbridge.log.error(`Error getting Shelly main updates: ${err instanceof Error ? err.message : String(err)}`);
56
+ log.error(`Error getting Shelly main updates: ${err instanceof Error ? err.message : String(err)}`);
57
57
  }
58
58
  }
59
59
  export async function triggerShellyMainUpdate(matterbridge) {
package/dist/update.js CHANGED
@@ -1,121 +1,137 @@
1
- import { db, debugStringify, nt, wr } from 'node-ansi-logger';
1
+ import { AnsiLogger, db, debugStringify, nt, wr } from 'node-ansi-logger';
2
2
  import { plg } from './matterbridgeTypes.js';
3
+ import { BroadcastServer } from './broadcastServer.js';
4
+ import { hasParameter } from './utils/commandLine.js';
5
+ import { isValidString } from './utils/isvalid.js';
3
6
  export async function checkUpdates(matterbridge) {
4
- const { hasParameter } = await import('./utils/commandLine.js');
5
- const update = checkUpdatesAndLog(matterbridge);
6
- const latestVersion = getMatterbridgeLatestVersion(matterbridge);
7
- const devVersion = getMatterbridgeDevVersion(matterbridge);
8
- const pluginsVersions = [];
9
- const pluginsDevVersions = [];
10
- const shellyUpdates = [];
11
- for (const plugin of matterbridge.plugins) {
12
- const pluginVersion = getPluginLatestVersion(matterbridge, plugin);
13
- pluginsVersions.push(pluginVersion);
14
- const pluginDevVersion = getPluginDevVersion(matterbridge, plugin);
15
- pluginsDevVersions.push(pluginDevVersion);
7
+ const log = new AnsiLogger({ logName: 'MatterbridgeUpdates', logTimestampFormat: 4, logLevel: matterbridge.logLevel });
8
+ const server = new BroadcastServer('updates', log);
9
+ const checkUpdatePromise = checkUpdatesAndLog(matterbridge, log, server);
10
+ const latestVersionPromise = getMatterbridgeLatestVersion(matterbridge, log, server);
11
+ const devVersionPromise = getMatterbridgeDevVersion(matterbridge, log, server);
12
+ const pluginsVersionPromises = [];
13
+ const pluginsDevVersionPromises = [];
14
+ const shellyUpdatesPromises = [];
15
+ const plugins = (await server.fetch({ type: 'plugins_apipluginarray', src: server.name, dst: 'plugins', params: {} })).response.plugins;
16
+ for (const plugin of plugins) {
17
+ pluginsVersionPromises.push(getPluginLatestVersion(log, server, plugin));
18
+ pluginsDevVersionPromises.push(getPluginDevVersion(log, server, plugin));
16
19
  }
17
20
  if (hasParameter('shelly')) {
18
21
  const { getShellySysUpdate, getShellyMainUpdate } = await import('./shelly.js');
19
- const systemUpdate = getShellySysUpdate(matterbridge);
20
- shellyUpdates.push(systemUpdate);
21
- const mainUpdate = getShellyMainUpdate(matterbridge);
22
- shellyUpdates.push(mainUpdate);
22
+ shellyUpdatesPromises.push(getShellySysUpdate(matterbridge, log, server));
23
+ shellyUpdatesPromises.push(getShellyMainUpdate(matterbridge, log, server));
23
24
  }
24
- await Promise.all([update, latestVersion, devVersion, ...pluginsVersions, ...pluginsDevVersions, ...shellyUpdates]);
25
+ await Promise.all([checkUpdatePromise, latestVersionPromise, devVersionPromise, ...pluginsVersionPromises, ...pluginsDevVersionPromises, ...shellyUpdatesPromises]);
26
+ server.close();
25
27
  }
26
- export async function checkUpdatesAndLog(matterbridge) {
28
+ export async function checkUpdatesAndLog(matterbridge, log, server) {
27
29
  const { getGitHubUpdate } = await import('./utils/network.js');
28
- const { isValidString } = await import('./utils/isvalid.js');
29
30
  const branch = matterbridge.matterbridgeVersion.includes('-dev-') ? 'dev' : 'main';
30
31
  try {
31
32
  const updateJson = await getGitHubUpdate(branch, 'update.json', 5_000);
32
- matterbridge.log.debug(`GitHub ${branch} update status: ${debugStringify(updateJson)}.`);
33
+ log.debug(`GitHub ${branch} update status: ${debugStringify(updateJson)}.`);
33
34
  if (isValidString(branch === 'main' ? updateJson.latestMessage : updateJson.devMessage, 1) &&
34
35
  isValidString(branch === 'main' ? updateJson.latestMessageSeverity : updateJson.devMessageSeverity, 4) &&
35
36
  ['info', 'warning', 'error', 'success'].includes(branch === 'main' ? updateJson.latestMessageSeverity : updateJson.devMessageSeverity)) {
36
- matterbridge.log.notice(`GitHub ${branch} update message: ${branch === 'main' ? updateJson.latestMessage : updateJson.devMessage}`);
37
- matterbridge.frontend.wssSendSnackbarMessage(branch === 'main' ? updateJson.latestMessage : updateJson.devMessage, 0, branch === 'main' ? updateJson.latestMessageSeverity : updateJson.devMessageSeverity);
37
+ log.notice(`GitHub ${branch} update message: ${branch === 'main' ? updateJson.latestMessage : updateJson.devMessage}`);
38
+ server.request({
39
+ type: 'frontend_snackbarmessage',
40
+ src: server.name,
41
+ dst: 'frontend',
42
+ params: { message: branch === 'main' ? updateJson.latestMessage : updateJson.devMessage, timeout: 0, severity: branch === 'main' ? updateJson.latestMessageSeverity : updateJson.devMessageSeverity },
43
+ });
38
44
  }
39
45
  }
40
46
  catch (error) {
41
- matterbridge.log.debug(`Error checking GitHub ${branch} updates: ${error instanceof Error ? error.message : error}`);
47
+ log.debug(`Error checking GitHub ${branch} updates: ${error instanceof Error ? error.message : error}`);
42
48
  }
43
49
  }
44
- export async function getMatterbridgeLatestVersion(matterbridge) {
50
+ export async function getMatterbridgeLatestVersion(matterbridge, log, server) {
45
51
  const { getNpmPackageVersion } = await import('./utils/network.js');
46
52
  try {
47
53
  const version = await getNpmPackageVersion('matterbridge');
48
- matterbridge.matterbridgeLatestVersion = version;
49
- await matterbridge.nodeContext?.set('matterbridgeLatestVersion', matterbridge.matterbridgeLatestVersion);
50
- if (matterbridge.matterbridgeVersion !== matterbridge.matterbridgeLatestVersion) {
51
- matterbridge.log.notice(`Matterbridge is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${matterbridge.matterbridgeLatestVersion}.`);
52
- matterbridge.frontend.wssSendSnackbarMessage('Matterbridge latest update available', 0, 'info');
53
- matterbridge.frontend.wssSendUpdateRequired();
54
- matterbridge.frontend.wssSendRefreshRequired('settings');
54
+ server.request({ type: 'matterbridge_latest_version', src: server.name, dst: 'matterbridge', params: { version } });
55
+ if (matterbridge.matterbridgeVersion !== version) {
56
+ log.notice(`Matterbridge is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${version}.`);
57
+ server.request({
58
+ type: 'frontend_snackbarmessage',
59
+ src: server.name,
60
+ dst: 'frontend',
61
+ params: { message: 'Matterbridge latest update available', timeout: 0, severity: 'info' },
62
+ });
63
+ server.request({ type: 'frontend_updaterequired', src: server.name, dst: 'frontend', params: { devVersion: false } });
64
+ server.request({ type: 'frontend_refreshrequired', src: server.name, dst: 'frontend', params: { changed: 'settings' } });
55
65
  }
56
66
  else {
57
- matterbridge.log.debug(`Matterbridge is up to date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${matterbridge.matterbridgeLatestVersion}.`);
67
+ log.debug(`Matterbridge is up to date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${version}.`);
58
68
  }
59
69
  return version;
60
70
  }
61
71
  catch (error) {
62
- matterbridge.log.warn(`Error getting Matterbridge latest version: ${error instanceof Error ? error.message : error}`);
72
+ log.warn(`Error getting Matterbridge latest version: ${error instanceof Error ? error.message : error}`);
63
73
  }
64
74
  }
65
- export async function getMatterbridgeDevVersion(matterbridge) {
75
+ export async function getMatterbridgeDevVersion(matterbridge, log, server) {
66
76
  const { getNpmPackageVersion } = await import('./utils/network.js');
67
77
  try {
68
78
  const version = await getNpmPackageVersion('matterbridge', 'dev');
69
- matterbridge.matterbridgeDevVersion = version;
70
- await matterbridge.nodeContext?.set('matterbridgeDevVersion', version);
79
+ server.request({ type: 'matterbridge_dev_version', src: server.name, dst: 'matterbridge', params: { version } });
71
80
  if (matterbridge.matterbridgeVersion.includes('-dev-') && matterbridge.matterbridgeVersion !== version) {
72
- matterbridge.log.notice(`Matterbridge@dev is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${matterbridge.matterbridgeDevVersion}.`);
73
- matterbridge.frontend.wssSendSnackbarMessage('Matterbridge dev update available', 0, 'info');
74
- matterbridge.frontend.wssSendUpdateRequired(true);
75
- matterbridge.frontend.wssSendRefreshRequired('settings');
81
+ log.notice(`Matterbridge@dev is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${version}.`);
82
+ server.request({
83
+ type: 'frontend_snackbarmessage',
84
+ src: server.name,
85
+ dst: 'frontend',
86
+ params: { message: 'Matterbridge dev update available', timeout: 0, severity: 'info' },
87
+ });
88
+ server.request({ type: 'frontend_updaterequired', src: server.name, dst: 'frontend', params: { devVersion: true } });
89
+ server.request({ type: 'frontend_refreshrequired', src: server.name, dst: 'frontend', params: { changed: 'settings' } });
76
90
  }
77
91
  else if (matterbridge.matterbridgeVersion.includes('-dev-') && matterbridge.matterbridgeVersion === version) {
78
- matterbridge.log.debug(`Matterbridge@dev is up to date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${matterbridge.matterbridgeDevVersion}.`);
92
+ log.debug(`Matterbridge@dev is up to date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${version}.`);
79
93
  }
80
94
  return version;
81
95
  }
82
96
  catch (error) {
83
- matterbridge.log.warn(`Error getting Matterbridge latest dev version: ${error instanceof Error ? error.message : error}`);
97
+ log.warn(`Error getting Matterbridge latest dev version: ${error instanceof Error ? error.message : error}`);
84
98
  }
85
99
  }
86
- export async function getPluginLatestVersion(matterbridge, plugin) {
100
+ export async function getPluginLatestVersion(log, server, plugin) {
87
101
  const { getNpmPackageVersion } = await import('./utils/network.js');
88
102
  try {
89
103
  const version = await getNpmPackageVersion(plugin.name);
90
104
  plugin.latestVersion = version;
105
+ server.request({ type: 'plugins_set_latest_version', src: server.name, dst: 'plugins', params: { plugin, version } });
91
106
  if (plugin.version !== plugin.latestVersion) {
92
- matterbridge.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
93
- matterbridge.frontend.wssSendRefreshRequired('plugins');
107
+ log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
108
+ server.request({ type: 'frontend_refreshrequired', src: server.name, dst: 'frontend', params: { changed: 'plugins' } });
94
109
  }
95
110
  else {
96
- matterbridge.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
111
+ log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
97
112
  }
98
113
  return version;
99
114
  }
100
115
  catch (error) {
101
- matterbridge.log.warn(`Error getting plugin ${plg}${plugin.name}${wr} latest version: ${error instanceof Error ? error.message : error}`);
116
+ log.warn(`Error getting plugin ${plg}${plugin.name}${wr} latest version: ${error instanceof Error ? error.message : error}`);
102
117
  }
103
118
  }
104
- export async function getPluginDevVersion(matterbridge, plugin) {
119
+ export async function getPluginDevVersion(log, server, plugin) {
105
120
  const { getNpmPackageVersion } = await import('./utils/network.js');
106
121
  try {
107
122
  const version = await getNpmPackageVersion(plugin.name, 'dev');
108
123
  plugin.devVersion = version;
124
+ server.request({ type: 'plugins_set_dev_version', src: server.name, dst: 'plugins', params: { plugin, version } });
109
125
  if (plugin.version.includes('-dev-') && plugin.version !== plugin.devVersion) {
110
- matterbridge.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest dev version: ${plugin.devVersion}.`);
111
- matterbridge.frontend.wssSendRefreshRequired('plugins');
126
+ log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest dev version: ${plugin.devVersion}.`);
127
+ server.request({ type: 'frontend_refreshrequired', src: server.name, dst: 'frontend', params: { changed: 'plugins' } });
112
128
  }
113
129
  else if (plugin.version.includes('-dev-') && plugin.version === plugin.devVersion) {
114
- matterbridge.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest dev version: ${plugin.devVersion}.`);
130
+ log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest dev version: ${plugin.devVersion}.`);
115
131
  }
116
132
  return version;
117
133
  }
118
134
  catch (error) {
119
- matterbridge.log.debug(`Error getting plugin ${plg}${plugin.name}${db} latest dev version: ${error instanceof Error ? error.message : error}`);
135
+ log.debug(`Error getting plugin ${plg}${plugin.name}${db} latest dev version: ${error instanceof Error ? error.message : error}`);
120
136
  }
121
137
  }
@@ -1 +1 @@
1
- body{font-family:Roboto,sans-serif}[frontend-theme=classic]{--main-bg-color: #c4c2c2;--main-text-color: black;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: #4d4d4d;--main-log-color: var(--main-text-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: #26292d;--main-menu-bg-color: #e2e2e2;--main-menu-hover-color: #959595;--main-label-color: var(--main-grey-color);--primary-color: #009a00;--secondary-color: #92771f;--header-bg-color: var(--primary-color);--header-text-color: white;--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: #ddd;--table-text-color: black;--table-even-bg-color: #bdbdbd;--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #5f8c9e;--table-selected-bg-color: #5f8c9e;--div-bg-color: #adadad;--div-text-color: black;--div-shadow-color: #888;--div-border-color: rgb(139, 139, 139);--div-border-radius: 0px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: black;background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=dark]{--main-bg-color: #26292d;--main-text-color: #ffffff;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: var(--main-light-color);--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-light-color);--main-menu-bg-color: var(--main-bg-color);--main-menu-hover-color: var(--div-bg-color);--main-label-color: var(--main-grey-color);--primary-color: #1976d2;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--primary-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: var(--main-bg-color);--table-selected-bg-color: var(--main-bg-color);--div-bg-color: #1b1d21;--div-text-color: var(--main-light-color);--div-shadow-color: #34373d;--div-border-color: #1b1d21;--div-border-radius: 5px;--div-title-bg-color: #1b1d21;--div-title-text-color: var(--primary-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=light]{--main-bg-color: #f0f0f0;--main-text-color: #212121;--main-grey-color: #616161;--main-light-color: #363636;--main-icon-color: #7a7a7a;--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-text-color);--main-menu-bg-color: var(--div-bg-color);--main-menu-hover-color: #85c0d8;--main-label-color: var(--main-grey-color);--primary-color: #2196f3;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--div-text-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #85c0d8;--table-selected-bg-color: #85c0d8;--div-bg-color: #ffffff;--div-text-color: #212121;--div-shadow-color: #bfbfbf;--div-border-color: var(--div-bg-color);--div-border-radius: 5px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: var(--div-text-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-track{background:"inherit"}html,.thin-scroll{scrollbar-width:thin;scrollbar-color:var(--primary-color) var(--div-bg-color)}.thin-scroll::-webkit-scrollbar{width:5px;height:5px}.thin-scroll::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}.tooltip-container{position:relative;display:inline-block;z-index:10}.tooltip-text{visibility:hidden;background-color:var(--ttip-bg-color);color:var(--ttip-text-color);text-align:center;padding:5px;border-radius:6px;position:absolute;z-index:10;bottom:calc(100% + 10px);left:50%;margin-left:-60px;opacity:0;transition:opacity .3s;font-size:12px}.tooltip-container:hover{cursor:pointer;z-index:10}.tooltip-container:hover .tooltip-text{visibility:visible;opacity:1;z-index:10}.status-enabled{background-color:green;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-disabled{background-color:red;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-information{background-color:#9e9e9e;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-warning{background-color:#e9db18;color:#000;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-sponsor{background-color:#b6409c;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-blue{background-color:#5f8c9e;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.header{display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:20px;margin:0;padding:0;height:40px}.sub-header{flex:0 0 auto;display:flex;flex-direction:row;align-items:center;gap:20px;margin:0;padding:0;height:40px}nav{display:flex;align-items:center;gap:10px}.nav-link{margin:0;font-size:20px;text-decoration:none;color:var(--main-icon-color);transition:color .3s ease}.nav-link:hover{color:var(--primary-color)}table{border-collapse:collapse;width:100%;table-layout:auto}thead{position:sticky;top:0;border:1px solid var(--table-border-color);z-index:10}thead th{border:1px solid var(--table-border-color);padding:5px 10px;color:var(--header-text-color);background:var(--header-bg-color);text-align:left;z-index:10}tbody td{border:1px solid var(--table-border-color);margin:0;padding:5px 10px;text-align:left;font-size:14px}tbody tr:hover{color:var(--table-text-color);background-color:var(--table-hover-bg-color)}.table-content-even{color:var(--table-text-color);background-color:var(--table-even-bg-color)}.table-content-odd{color:var(--table-text-color);background-color:var(--table-odd-bg-color)}.table-content-selected{color:var(--table-text-color);background-color:var(--table-selected-bg-color)}h3{margin:0}.MbfScreen{display:flex;flex-direction:column;width:calc(100vw - 40px);height:calc(100vh - 40px);gap:20px;margin:0;padding:20px;background-color:var(--main-bg-color)}.MbfPageDiv{display:flex;flex-direction:column;height:100%;width:100%;margin:0;padding:0;gap:20px}.MbfWindowDiv{display:flex;flex-direction:column;box-shadow:5px 5px 10px var(--div-shadow-color);border:1px solid var(--table-border-color);border-radius:var(--div-border-radius);box-sizing:border-box;background-color:var(--div-bg-color)}.MbfWindowDivTable{display:block;flex:1 1 auto;overflow:auto;margin:-1px;padding:0;gap:0}.MbfWindowHeaderFooterIcons{display:flex;flex-direction:row;margin:0;padding:0 10px;gap:10px}.MbfWindowHeader{display:flex;flex-direction:row;align-items:center;width:100%;border-bottom:1px solid var(--table-border-color);color:var(--header-text-color);background-color:var(--header-bg-color);margin:0;padding:0;box-sizing:border-box}.MbfWindowHeaderText{color:var(--header-text-color);font-weight:700;margin:0;padding:5px 10px}.MbfWindowFooter{display:flex;flex-direction:row;align-items:center;justify-content:center;color:var(--footer-text-color);background-color:var(--footer-bg-color);margin:0;padding:0}.MbfWindowFooterText{color:var(--footer-text-color);background-color:var(--footer-bg-color);font-weight:700;text-align:center;margin:0;padding:5px 10px}.MbfWindowBody{display:flex;flex:1 1 auto;margin:0;padding:10px;gap:10px}.MbfWindowBodyColumn{display:flex;flex-direction:column;flex:1 1 auto;width:100%;margin:0;padding:10px 0;gap:0px;overflow:auto}.MbfWindowBodyRow{display:flex;flex-direction:row;flex:1 1 auto;height:100%;margin:0;padding:0 10px;gap:0px;overflow:auto}.configSubmitButton{display:flex;flex-direction:row;justify-content:center;width:auto;margin:20px}.configSubmitButton button{width:auto}@media(max-width:1300px){.MbfScreen{width:1300px;height:1024px}.xxxheader{flex-direction:column;align-items:start;justify-content:start}.xxxsub-header{align-items:start;justify-content:start}}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
1
+ body{font-family:Roboto,sans-serif}[frontend-theme=classic]{--main-bg-color: #c4c2c2;--main-text-color: black;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: #4d4d4d;--main-log-color: var(--main-text-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: #26292d;--main-menu-bg-color: #e2e2e2;--main-menu-hover-color: #959595;--main-label-color: var(--main-grey-color);--primary-color: #009a00;--secondary-color: #92771f;--header-bg-color: var(--primary-color);--header-text-color: white;--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: #ddd;--table-text-color: black;--table-even-bg-color: #bdbdbd;--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #5f8c9e;--table-selected-bg-color: #5f8c9e;--div-bg-color: #adadad;--div-text-color: black;--div-shadow-color: #888;--div-border-color: rgb(139, 139, 139);--div-border-radius: 0px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: black;background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=dark]{--main-bg-color: #26292d;--main-text-color: #ffffff;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: var(--main-light-color);--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-light-color);--main-menu-bg-color: var(--main-bg-color);--main-menu-hover-color: var(--div-bg-color);--main-label-color: var(--main-grey-color);--primary-color: #1976d2;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--primary-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: var(--main-bg-color);--table-selected-bg-color: var(--main-bg-color);--div-bg-color: #1b1d21;--div-text-color: var(--main-light-color);--div-shadow-color: #34373d;--div-border-color: #1b1d21;--div-border-radius: 5px;--div-title-bg-color: #1b1d21;--div-title-text-color: var(--primary-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=light]{--main-bg-color: #f0f0f0;--main-text-color: #212121;--main-grey-color: #616161;--main-light-color: #363636;--main-icon-color: #7a7a7a;--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-text-color);--main-menu-bg-color: var(--div-bg-color);--main-menu-hover-color: #85c0d8;--main-label-color: var(--main-grey-color);--primary-color: #2196f3;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--div-text-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #85c0d8;--table-selected-bg-color: #85c0d8;--div-bg-color: #ffffff;--div-text-color: #212121;--div-shadow-color: #bfbfbf;--div-border-color: var(--div-bg-color);--div-border-radius: 5px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: var(--div-text-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-track{background:"inherit"}html,.thin-scroll{scrollbar-width:thin;scrollbar-color:var(--primary-color) var(--div-bg-color)}.thin-scroll::-webkit-scrollbar{width:5px;height:5px}.thin-scroll::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}.tooltip-container{position:relative;display:inline-block;z-index:10}.tooltip-text{visibility:hidden;background-color:var(--ttip-bg-color);color:var(--ttip-text-color);text-align:center;padding:5px;border-radius:6px;position:absolute;z-index:10;bottom:calc(100% + 10px);left:50%;margin-left:-60px;opacity:0;transition:opacity .3s;font-size:12px}.tooltip-container:hover{cursor:pointer;z-index:10}.tooltip-container:hover .tooltip-text{visibility:visible;opacity:1;z-index:10}.status-enabled{background-color:green;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-disabled{background-color:red;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-information{background-color:#9e9e9e;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-warning{background-color:#e9db18;color:#000;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-sponsor{background-color:#b6409c;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-blue{background-color:#5f8c9e;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.header{display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:20px;margin:0;padding:0;height:40px}.sub-header{flex:0 0 auto;display:flex;flex-direction:row;align-items:center;gap:20px;margin:0;padding:0;height:40px}nav{display:flex;align-items:center;gap:10px}.nav-link{margin:0;font-size:20px;text-decoration:none;color:var(--main-icon-color);transition:color .3s ease}.nav-link:hover{color:var(--primary-color)}table{border-collapse:collapse;width:100%;table-layout:auto}thead{position:sticky;top:0;border:1px solid var(--table-border-color);z-index:10}thead th{border:1px solid var(--table-border-color);padding:5px 10px;color:var(--header-text-color);background:var(--header-bg-color);text-align:left;z-index:10}tbody td{border:1px solid var(--table-border-color);margin:0;padding:5px 10px;text-align:left;font-size:14px}tbody tr:hover{color:var(--table-text-color);background-color:var(--table-hover-bg-color)}.table-content-even{color:var(--table-text-color);background-color:var(--table-even-bg-color)}.table-content-odd{color:var(--table-text-color);background-color:var(--table-odd-bg-color)}.table-content-selected{color:var(--table-text-color);background-color:var(--table-selected-bg-color)}h3{margin:0}.MbfScreen{display:flex;flex-direction:column;width:calc(100vw - 40px);height:calc(100vh - 40px);gap:20px;margin:0;padding:20px;background-color:var(--main-bg-color)}.MbfPageDiv{display:flex;flex-direction:column;height:100%;width:100%;margin:0;padding:0;gap:20px}.MbfWindowDiv{display:flex;flex-direction:column;box-shadow:5px 5px 10px var(--div-shadow-color);border:1px solid var(--table-border-color);border-radius:var(--div-border-radius);box-sizing:border-box;background-color:var(--div-bg-color)}.MbfWindowDivTable{display:block;flex:1 1 auto;overflow:auto;margin:-1px;padding:0;gap:0}.MbfWindowHeaderFooterIcons{display:flex;flex-direction:row;margin:0;padding:0 10px;gap:10px}.MbfWindowHeader{display:flex;flex-direction:row;align-items:center;width:100%;border-bottom:1px solid var(--table-border-color);color:var(--header-text-color);background-color:var(--header-bg-color);margin:0;padding:0;box-sizing:border-box}.MbfWindowHeaderText{color:var(--header-text-color);font-weight:700;margin:0;padding:5px 10px}.MbfWindowFooter{display:flex;flex-direction:row;align-items:center;justify-content:center;color:var(--footer-text-color);background-color:var(--footer-bg-color);margin:0;padding:0}.MbfWindowFooterText{color:var(--footer-text-color);background-color:var(--footer-bg-color);font-weight:700;text-align:center;margin:0;padding:5px 10px}.MbfWindowBody{display:flex;flex:1 1 auto;margin:0;padding:10px;gap:10px}.MbfWindowBodyColumn{display:flex;flex-direction:column;flex:1 1 auto;width:100%;margin:0;padding:10px 0;gap:0px;overflow:auto}.MbfWindowBodyRow{display:flex;flex-direction:row;flex:1 1 auto;height:100%;margin:0;padding:0 10px;gap:0px;overflow:auto}.configSubmitButton{display:flex;flex-direction:row;justify-content:center;width:auto;margin:20px}.configSubmitButton button{width:auto}@media(max-width:1300px){.MbfScreen{width:1300px;height:1024px}}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}