From 60ad0f9b761bb2d658d4110262b0d74d25e3d56d Mon Sep 17 00:00:00 2001 From: foxriver76 Date: Thu, 29 Aug 2024 19:19:19 +0200 Subject: [PATCH] fixed issue if hostname contains '.' - closes #24 --- .github/workflows/test-and-release.yml | 2 +- README.md | 4 + build/main.js | 11 +- build/main.js.map | 4 +- package-lock.json | 421 ++++++++++++++++--------- package.json | 12 +- src/main.ts | 21 +- 7 files changed, 311 insertions(+), 164 deletions(-) diff --git a/.github/workflows/test-and-release.yml b/.github/workflows/test-and-release.yml index 644f6bd..fde2c75 100644 --- a/.github/workflows/test-and-release.yml +++ b/.github/workflows/test-and-release.yml @@ -41,7 +41,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - node-version: [18.x, 20.x] + node-version: [18.x, 20.x, 22.x] os: [ubuntu-latest, windows-latest, macos-latest] steps: diff --git a/README.md b/README.md index d592b65..efda879 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,10 @@ if the messaging adapter was able to deliver the notification, else it should re Placeholder for the next version (at the beginning of the line): ### **WORK IN PROGRESS** --> + +### **WORK IN PROGRESS** +* (@foxriver76) fixed issue if host name contains `.` + ### 1.2.0 (2024-08-05) * (@klein0r) Added Blockly blocks diff --git a/build/main.js b/build/main.js index ba7bc18..8dc9943 100644 --- a/build/main.js +++ b/build/main.js @@ -119,9 +119,14 @@ class NotificationManager extends utils.Adapter { callback(); } async onStateChange(id, _state) { - const hostName = id.split(".")[2]; - this.log.debug(`Notification update on "${hostName}" detected`); - await this.handleNotifications([`system.host.${hostName}`]); + const hostId = this.extractHostFromId(id); + this.log.debug(`Notification update on "${hostId}" detected`); + await this.handleNotifications([hostId]); + } + extractHostFromId(id) { + const notificationsId = id.substring(0, id.lastIndexOf(".")); + const hostId = id.substring(0, notificationsId.lastIndexOf(".")); + return hostId; } async handleNotifications(hosts) { hosts = hosts || await this.getAllHosts(); diff --git a/build/main.js.map b/build/main.js.map index 2ebf20d..de9949d 100644 --- a/build/main.js.map +++ b/build/main.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/main.ts"], - "sourcesContent": ["import * as utils from '@iobroker/adapter-core';\nimport fs from 'fs';\n\ninterface GetNotificationsResponse {\n result: NotificationsObject;\n}\n\ntype HostId = `system.host.${string}`;\n\ntype Severity = 'alert' | 'info' | 'notify';\n\ninterface NotificationCategory {\n instances: {\n [adapterInstance: string]: {\n messages: NotificationInstanceMessage[];\n };\n };\n /** i18n description of category */\n description: Record;\n /** i18n name of category */\n name: Record;\n severity: Severity;\n}\n\n/** Notifications category where i18n objects are already translated */\ninterface LocalizedNotificationCategory extends Omit {\n description: string;\n name: string;\n}\n\ninterface NotificationScope {\n /** i18n description of scope */\n description: Record;\n /** i18n name of scope */\n name: Record;\n categories: {\n [category: string]: NotificationCategory;\n };\n}\n\n/** Notifications scope where i18n objects are already translated */\ninterface LocalizedNotificationScope extends Omit {\n description: string;\n name: string;\n}\n\ninterface NotificationsObject {\n [scope: string]: NotificationScope;\n}\n\ninterface NotificationInstanceMessage {\n message: string;\n ts: number;\n}\n\ninterface SendNotificationsOptions {\n /** hostname system.host.xy */\n host: string;\n /** the received notifications from controller */\n notifications: NotificationsObject;\n}\n\ninterface FindInstanceOptions {\n /** id of the scope */\n scopeId: string;\n /** id of the category */\n categoryId: string;\n /** Severity of this category */\n severity: Severity;\n}\n\ninterface CategoryActiveCheckOptions {\n /** id of the scope */\n scopeId: string;\n /** id of the category */\n categoryId: string;\n}\n\ninterface ResponsibleInstances {\n firstAdapter: {\n /** highest priority adapter instance */\n main?: string;\n /** second priority adapter instance */\n fallback: string;\n };\n secondAdapter: {\n /** Fallback instance for the first instance */\n main?: string;\n /** Fallback instance for the second instance */\n fallback: string;\n };\n}\n\ninterface LocalizedNotification {\n /** host where the notification belongs too */\n host: string;\n /** The localized scope of the notification */\n scope: Omit;\n /** The localized category of the notification */\n category: LocalizedNotificationCategory;\n}\n\nclass NotificationManager extends utils.Adapter {\n /** Timeout to wait for response by instances on sendTo */\n private readonly SEND_TO_TIMEOUT = 5_000;\n /** The supported categories for messages sent by the user */\n private readonly SUPPORTED_USER_CATEGORIES = ['notify', 'info', 'alert'] as const;\n /** The scope used for messages sent by the user */\n private readonly USER_SCOPE = 'user';\n\n public constructor(options: Partial = {}) {\n super({\n ...options,\n name: 'notification-manager'\n });\n this.on('ready', this.onReady.bind(this));\n this.on('stateChange', this.onStateChange.bind(this));\n this.on('unload', this.onUnload.bind(this));\n this.on('message', this.onMessage.bind(this));\n }\n\n /**\n * Listen to messages from frontend\n */\n private async onMessage(obj: ioBroker.Message): Promise {\n switch (obj.command) {\n case 'getCategories':\n await this.handleGetCategoriesMessage(obj);\n break;\n case 'getSupportedMessengers':\n await this.handleGetSupportedMessengersMessage(obj);\n break;\n case 'sendTestMessage':\n await this.handleSendTestMessageMessage(obj);\n break;\n case 'registerUserNotification':\n await this.handleRegisterUserNotificationMessage(obj);\n break;\n default:\n this.log.warn(`Unsupported message received \"${obj.command}\"`);\n }\n }\n\n /**\n * Handle a `registerUserNotification` message, which is used to register a notification by the user itself\n *\n * @param obj the ioBroker message\n */\n private async handleRegisterUserNotificationMessage(obj: ioBroker.Message): Promise {\n if (typeof obj.message !== 'object') {\n return;\n }\n\n const { category, message } = obj.message;\n\n if (!this.SUPPORTED_USER_CATEGORIES.includes(category)) {\n this.sendTo(\n obj.from,\n obj.command,\n {\n success: false,\n error: `Unsupported category \"${category}\", please use one of \"${this.SUPPORTED_USER_CATEGORIES.join(\n ', '\n )}\"`\n },\n obj.callback\n );\n }\n\n // @ts-expect-error js-controller types are restricted to \"system\" here, should be fixed soon\n await this.registerNotification(this.USER_SCOPE, category, message);\n this.sendTo(obj.from, obj.command, { success: true }, obj.callback);\n }\n\n /**\n * Handle a `sendTestMessage` message used to send a test message by registering a notification\n *\n * @param obj the ioBroker message\n */\n private async handleSendTestMessageMessage(obj: ioBroker.Message): Promise {\n if (typeof obj.message !== 'object') {\n return;\n }\n\n const { scopeId, category } = obj.message;\n this.log.info(`Send test message for scope \"${scopeId}\" and category \"${category}\"`);\n await this.registerNotification(scopeId, category, 'Test notification from notification-manager');\n this.sendTo(obj.from, obj.command, { ack: true }, obj.callback);\n }\n\n /**\n * Handle a `getSupportedMessengers` message used to determine all supported messaging adapters\n *\n * @param obj the ioBroker message\n */\n private async handleGetSupportedMessengersMessage(obj: ioBroker.Message): Promise {\n const res = await this.getObjectViewAsync('system', 'instance', {\n startkey: 'system.adapter.',\n endkey: 'system.adapter.\\u9999'\n });\n\n const instances = res.rows\n .filter(row => row.value?.common.supportedMessages?.notifications)\n .map(obj => obj.id.substring('system.adapter.'.length));\n\n this.sendTo(obj.from, obj.command, { instances }, obj.callback);\n }\n\n /**\n * Handle a `getCategories` message used to determine all supported notification categories\n *\n * @param obj the ioBroker message\n */\n private async handleGetCategoriesMessage(obj: ioBroker.Message): Promise {\n const ioPackPath = require.resolve('iobroker.js-controller/io-package.json');\n\n const content = await fs.promises.readFile(ioPackPath, {\n encoding: 'utf-8'\n });\n\n const ioPack = JSON.parse(content);\n const notifications = ioPack.notifications || [];\n\n const res = await this.getObjectViewAsync('system', 'adapter', {\n startkey: 'system.adapter.',\n endkey: 'system.adapter.\\u9999'\n });\n\n for (const entry of res.rows) {\n if (entry.value.notifications) {\n notifications.push(...entry.value.notifications);\n }\n }\n\n this.sendTo(obj.from, obj.command, { notifications }, obj.callback);\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise {\n this.log.info('Starting notification manager ...');\n await this.subscribeForeignStatesAsync('system.host.*.notifications.*');\n await this.handleNotifications();\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n private onUnload(callback: () => void): void {\n callback();\n }\n\n /**\n * Is called if a subscribed state changes\n */\n private async onStateChange(id: string, _state: ioBroker.State | null | undefined): Promise {\n const hostName = id.split('.')[2];\n this.log.debug(`Notification update on \"${hostName}\" detected`);\n await this.handleNotifications([`system.host.${hostName}`]);\n }\n\n /**\n * Checks for existing notifications and handles them according to the configuration\n *\n * @param hosts names of the hosts to handle notifications for, if omitted all hosts are used\n */\n private async handleNotifications(hosts?: HostId[]): Promise {\n hosts = hosts || (await this.getAllHosts());\n\n for (const host of hosts) {\n this.log.debug(`Request notifications from \"${host}\"`);\n\n const { result: notifications } = (await this.sendToHostAsync(\n host,\n 'getNotifications',\n {}\n )) as unknown as GetNotificationsResponse;\n\n this.log.debug(`Received notifications from \"${host}\": ${JSON.stringify(notifications)}`);\n\n await this.sendNotifications({ host, notifications });\n }\n }\n\n /**\n * Get all existing hosts of this installation\n */\n private async getAllHosts(): Promise {\n const res = await this.getObjectViewAsync('system', 'host', {\n startkey: 'system.host.',\n endkey: 'system.host.\\u9999'\n });\n\n return res.rows.map(host => host.id as HostId);\n }\n\n /**\n * Find the adapter instances configured for the scope and category\n *\n * @param options scope and category for the instances\n */\n private findResponsibleInstances(options: FindInstanceOptions): ResponsibleInstances {\n const { scopeId, categoryId, severity } = options;\n\n return {\n firstAdapter: {\n main: this.config.categories[scopeId]?.[categoryId]?.firstAdapter,\n fallback: this.config.fallback[severity].firstAdapter\n },\n secondAdapter: {\n main: this.config.categories[scopeId]?.[categoryId]?.secondAdapter,\n fallback: this.config.fallback[severity].secondAdapter\n }\n };\n }\n\n /**\n * Sends notifications if configured\n *\n * @param options configure hostname and corresponding notifications object\n */\n private async sendNotifications(options: SendNotificationsOptions): Promise {\n const { notifications, host } = options;\n\n for (const [scopeId, scope] of Object.entries(notifications)) {\n for (const [categoryId, category] of Object.entries(scope.categories)) {\n const isActive = this.isCategoryActive({ scopeId, categoryId });\n\n if (!isActive) {\n this.log.debug(`Skip notification \"${scopeId}.${categoryId}\" because user opted-out`);\n continue;\n }\n\n const isSuppressed = this.isCategorySuppressed({ scopeId, categoryId });\n\n if (isSuppressed) {\n this.log.debug(`Suppress notification \"${scopeId}.${categoryId}\"`);\n\n await this.sendToHostAsync(host, 'clearNotifications', {\n scope: scopeId,\n category: categoryId\n });\n\n continue;\n }\n\n const { firstAdapter, secondAdapter } = this.findResponsibleInstances({\n scopeId,\n categoryId,\n severity: category.severity\n });\n\n for (const configuredAdapter of [firstAdapter, secondAdapter]) {\n const adapterInstance = configuredAdapter.main || configuredAdapter.fallback;\n if (!adapterInstance) {\n continue;\n }\n\n const bareScope: Omit = {\n name: scope.name,\n description: scope.description\n };\n\n this.log.info(`Send notification \"${scopeId}.${categoryId}\" to \"${adapterInstance}\"`);\n\n const localizedNotification: LocalizedNotification = {\n host,\n scope: await this.localize(bareScope),\n category: await this.localize(category)\n };\n\n try {\n const res = await this.sendToAsync(adapterInstance, 'sendNotification', localizedNotification, {\n timeout: this.SEND_TO_TIMEOUT\n });\n\n // @ts-expect-error types are wrong, this is a callback not a new message\n if (typeof res === 'object' && res.sent) {\n this.log.info(\n `Instance ${adapterInstance} successfully handled the notification for \"${scopeId}.${categoryId}\"`\n );\n\n await this.sendToHostAsync(host, 'clearNotifications', {\n scope: scopeId,\n category: categoryId\n });\n return;\n }\n } catch (e: any) {\n this.log.error(\n `Error appeared while sending notification \"${scopeId}.${categoryId}\" to \"${adapterInstance}\": ${e.message}`\n );\n }\n\n this.log.error(\n `Instance ${adapterInstance} could not handle the notification for \"${scopeId}.${categoryId}\"`\n );\n }\n }\n }\n }\n\n /**\n * Check if the category is active or opted out by the user\n *\n * @param options scope and category information\n */\n private isCategoryActive(options: CategoryActiveCheckOptions): boolean {\n const { scopeId, categoryId } = options;\n return this.config.categories[scopeId]?.[categoryId]?.active !== false;\n }\n\n /**\n * Check if the category is suppressed and should be cleared\n *\n * @param options scope and category information\n */\n private isCategorySuppressed(options: CategoryActiveCheckOptions): boolean {\n const { scopeId, categoryId } = options;\n return !!this.config.categories[scopeId]?.[categoryId]?.suppress;\n }\n\n /**\n * Transform scope or category to the localized version\n *\n * @param scopeOrCategory a notifications scope or category\n */\n private async localize | NotificationCategory>(\n scopeOrCategory: T\n ): Promise {\n const config = await this.getForeignObjectAsync('system.config');\n\n const lang = config?.common.language || 'en';\n\n const description = scopeOrCategory.description[lang];\n const name = scopeOrCategory.name[lang];\n\n return { ...scopeOrCategory, description, name };\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial | undefined) => new NotificationManager(options);\n} else {\n // otherwise start the instance directly\n (() => new NotificationManager())();\n}\n"], - "mappings": "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", + "sourcesContent": ["import * as utils from '@iobroker/adapter-core';\nimport fs from 'fs';\n\ninterface GetNotificationsResponse {\n result: NotificationsObject;\n}\n\ntype HostId = ioBroker.ObjectIDs.Host;\n\ntype Severity = 'alert' | 'info' | 'notify';\n\ninterface NotificationCategory {\n instances: {\n [adapterInstance: string]: {\n messages: NotificationInstanceMessage[];\n };\n };\n /** i18n description of category */\n description: Record;\n /** i18n name of category */\n name: Record;\n severity: Severity;\n}\n\n/** Notifications category where i18n objects are already translated */\ninterface LocalizedNotificationCategory extends Omit {\n description: string;\n name: string;\n}\n\ninterface NotificationScope {\n /** i18n description of scope */\n description: Record;\n /** i18n name of scope */\n name: Record;\n categories: {\n [category: string]: NotificationCategory;\n };\n}\n\n/** Notifications scope where i18n objects are already translated */\ninterface LocalizedNotificationScope extends Omit {\n description: string;\n name: string;\n}\n\ninterface NotificationsObject {\n [scope: string]: NotificationScope;\n}\n\ninterface NotificationInstanceMessage {\n message: string;\n ts: number;\n}\n\ninterface SendNotificationsOptions {\n /** hostname system.host.xy */\n host: string;\n /** the received notifications from controller */\n notifications: NotificationsObject;\n}\n\ninterface FindInstanceOptions {\n /** id of the scope */\n scopeId: string;\n /** id of the category */\n categoryId: string;\n /** Severity of this category */\n severity: Severity;\n}\n\ninterface CategoryActiveCheckOptions {\n /** id of the scope */\n scopeId: string;\n /** id of the category */\n categoryId: string;\n}\n\ninterface ResponsibleInstances {\n firstAdapter: {\n /** highest priority adapter instance */\n main?: string;\n /** second priority adapter instance */\n fallback: string;\n };\n secondAdapter: {\n /** Fallback instance for the first instance */\n main?: string;\n /** Fallback instance for the second instance */\n fallback: string;\n };\n}\n\ninterface LocalizedNotification {\n /** host where the notification belongs too */\n host: string;\n /** The localized scope of the notification */\n scope: Omit;\n /** The localized category of the notification */\n category: LocalizedNotificationCategory;\n}\n\nclass NotificationManager extends utils.Adapter {\n /** Timeout to wait for response by instances on sendTo */\n private readonly SEND_TO_TIMEOUT = 5_000;\n /** The supported categories for messages sent by the user */\n private readonly SUPPORTED_USER_CATEGORIES = ['notify', 'info', 'alert'] as const;\n /** The scope used for messages sent by the user */\n private readonly USER_SCOPE = 'user';\n\n public constructor(options: Partial = {}) {\n super({\n ...options,\n name: 'notification-manager'\n });\n this.on('ready', this.onReady.bind(this));\n this.on('stateChange', this.onStateChange.bind(this));\n this.on('unload', this.onUnload.bind(this));\n this.on('message', this.onMessage.bind(this));\n }\n\n /**\n * Listen to messages from frontend\n */\n private async onMessage(obj: ioBroker.Message): Promise {\n switch (obj.command) {\n case 'getCategories':\n await this.handleGetCategoriesMessage(obj);\n break;\n case 'getSupportedMessengers':\n await this.handleGetSupportedMessengersMessage(obj);\n break;\n case 'sendTestMessage':\n await this.handleSendTestMessageMessage(obj);\n break;\n case 'registerUserNotification':\n await this.handleRegisterUserNotificationMessage(obj);\n break;\n default:\n this.log.warn(`Unsupported message received \"${obj.command}\"`);\n }\n }\n\n /**\n * Handle a `registerUserNotification` message, which is used to register a notification by the user itself\n *\n * @param obj the ioBroker message\n */\n private async handleRegisterUserNotificationMessage(obj: ioBroker.Message): Promise {\n if (typeof obj.message !== 'object') {\n return;\n }\n\n const { category, message } = obj.message;\n\n if (!this.SUPPORTED_USER_CATEGORIES.includes(category)) {\n this.sendTo(\n obj.from,\n obj.command,\n {\n success: false,\n error: `Unsupported category \"${category}\", please use one of \"${this.SUPPORTED_USER_CATEGORIES.join(\n ', '\n )}\"`\n },\n obj.callback\n );\n }\n\n await this.registerNotification(this.USER_SCOPE, category, message);\n this.sendTo(obj.from, obj.command, { success: true }, obj.callback);\n }\n\n /**\n * Handle a `sendTestMessage` message used to send a test message by registering a notification\n *\n * @param obj the ioBroker message\n */\n private async handleSendTestMessageMessage(obj: ioBroker.Message): Promise {\n if (typeof obj.message !== 'object') {\n return;\n }\n\n const { scopeId, category } = obj.message;\n this.log.info(`Send test message for scope \"${scopeId}\" and category \"${category}\"`);\n await this.registerNotification(scopeId, category, 'Test notification from notification-manager');\n this.sendTo(obj.from, obj.command, { ack: true }, obj.callback);\n }\n\n /**\n * Handle a `getSupportedMessengers` message used to determine all supported messaging adapters\n *\n * @param obj the ioBroker message\n */\n private async handleGetSupportedMessengersMessage(obj: ioBroker.Message): Promise {\n const res = await this.getObjectViewAsync('system', 'instance', {\n startkey: 'system.adapter.',\n endkey: 'system.adapter.\\u9999'\n });\n\n const instances = res.rows\n .filter(row => row.value?.common.supportedMessages?.notifications)\n .map(obj => obj.id.substring('system.adapter.'.length));\n\n this.sendTo(obj.from, obj.command, { instances }, obj.callback);\n }\n\n /**\n * Handle a `getCategories` message used to determine all supported notification categories\n *\n * @param obj the ioBroker message\n */\n private async handleGetCategoriesMessage(obj: ioBroker.Message): Promise {\n const ioPackPath = require.resolve('iobroker.js-controller/io-package.json');\n\n const content = await fs.promises.readFile(ioPackPath, {\n encoding: 'utf-8'\n });\n\n const ioPack = JSON.parse(content);\n const notifications = ioPack.notifications || [];\n\n const res = await this.getObjectViewAsync('system', 'adapter', {\n startkey: 'system.adapter.',\n endkey: 'system.adapter.\\u9999'\n });\n\n for (const entry of res.rows) {\n if (entry.value.notifications) {\n notifications.push(...entry.value.notifications);\n }\n }\n\n this.sendTo(obj.from, obj.command, { notifications }, obj.callback);\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise {\n this.log.info('Starting notification manager ...');\n await this.subscribeForeignStatesAsync('system.host.*.notifications.*');\n await this.handleNotifications();\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n private onUnload(callback: () => void): void {\n callback();\n }\n\n /**\n * Is called if a subscribed state changes\n */\n private async onStateChange(id: string, _state: ioBroker.State | null | undefined): Promise {\n const hostId = this.extractHostFromId(id);\n this.log.debug(`Notification update on \"${hostId}\" detected`);\n await this.handleNotifications([hostId]);\n }\n\n /**\n * Extract the hostname from a `system.host.hostPart1.maybeHostPart2.maybeHostPartX.notifications.category` id\n *\n * @param id id with structure `system.host.hostPart1.maybeHostPart2.maybeHostPartX.notifications.category`\n */\n private extractHostFromId(id: string): HostId {\n const notificationsId = id.substring(0, id.lastIndexOf('.'))\n const hostId = id.substring(0, notificationsId.lastIndexOf('.'))\n\n return hostId as HostId\n }\n\n /**\n * Checks for existing notifications and handles them according to the configuration\n *\n * @param hosts names of the hosts to handle notifications for, if omitted all hosts are used\n */\n private async handleNotifications(hosts?: HostId[]): Promise {\n hosts = hosts || (await this.getAllHosts());\n\n for (const host of hosts) {\n this.log.debug(`Request notifications from \"${host}\"`);\n\n const { result: notifications } = (await this.sendToHostAsync(\n host,\n 'getNotifications',\n {}\n )) as unknown as GetNotificationsResponse;\n\n this.log.debug(`Received notifications from \"${host}\": ${JSON.stringify(notifications)}`);\n\n await this.sendNotifications({ host, notifications });\n }\n }\n\n /**\n * Get all existing hosts of this installation\n */\n private async getAllHosts(): Promise {\n const res = await this.getObjectViewAsync('system', 'host', {\n startkey: 'system.host.',\n endkey: 'system.host.\\u9999'\n });\n\n return res.rows.map(host => host.id as HostId);\n }\n\n /**\n * Find the adapter instances configured for the scope and category\n *\n * @param options scope and category for the instances\n */\n private findResponsibleInstances(options: FindInstanceOptions): ResponsibleInstances {\n const { scopeId, categoryId, severity } = options;\n\n return {\n firstAdapter: {\n main: this.config.categories[scopeId]?.[categoryId]?.firstAdapter,\n fallback: this.config.fallback[severity].firstAdapter\n },\n secondAdapter: {\n main: this.config.categories[scopeId]?.[categoryId]?.secondAdapter,\n fallback: this.config.fallback[severity].secondAdapter\n }\n };\n }\n\n /**\n * Sends notifications if configured\n *\n * @param options configure hostname and corresponding notifications object\n */\n private async sendNotifications(options: SendNotificationsOptions): Promise {\n const { notifications, host } = options;\n\n for (const [scopeId, scope] of Object.entries(notifications)) {\n for (const [categoryId, category] of Object.entries(scope.categories)) {\n const isActive = this.isCategoryActive({ scopeId, categoryId });\n\n if (!isActive) {\n this.log.debug(`Skip notification \"${scopeId}.${categoryId}\" because user opted-out`);\n continue;\n }\n\n const isSuppressed = this.isCategorySuppressed({ scopeId, categoryId });\n\n if (isSuppressed) {\n this.log.debug(`Suppress notification \"${scopeId}.${categoryId}\"`);\n\n await this.sendToHostAsync(host, 'clearNotifications', {\n scope: scopeId,\n category: categoryId\n });\n\n continue;\n }\n\n const { firstAdapter, secondAdapter } = this.findResponsibleInstances({\n scopeId,\n categoryId,\n severity: category.severity\n });\n\n for (const configuredAdapter of [firstAdapter, secondAdapter]) {\n const adapterInstance = configuredAdapter.main || configuredAdapter.fallback;\n if (!adapterInstance) {\n continue;\n }\n\n const bareScope: Omit = {\n name: scope.name,\n description: scope.description\n };\n\n this.log.info(`Send notification \"${scopeId}.${categoryId}\" to \"${adapterInstance}\"`);\n\n const localizedNotification: LocalizedNotification = {\n host,\n scope: await this.localize(bareScope),\n category: await this.localize(category)\n };\n\n try {\n const res = await this.sendToAsync(adapterInstance, 'sendNotification', localizedNotification, {\n timeout: this.SEND_TO_TIMEOUT\n });\n\n // @ts-expect-error types are wrong, this is a callback not a new message\n if (typeof res === 'object' && res.sent) {\n this.log.info(\n `Instance ${adapterInstance} successfully handled the notification for \"${scopeId}.${categoryId}\"`\n );\n\n await this.sendToHostAsync(host, 'clearNotifications', {\n scope: scopeId,\n category: categoryId\n });\n return;\n }\n } catch (e: any) {\n this.log.error(\n `Error appeared while sending notification \"${scopeId}.${categoryId}\" to \"${adapterInstance}\": ${e.message}`\n );\n }\n\n this.log.error(\n `Instance ${adapterInstance} could not handle the notification for \"${scopeId}.${categoryId}\"`\n );\n }\n }\n }\n }\n\n /**\n * Check if the category is active or opted out by the user\n *\n * @param options scope and category information\n */\n private isCategoryActive(options: CategoryActiveCheckOptions): boolean {\n const { scopeId, categoryId } = options;\n return this.config.categories[scopeId]?.[categoryId]?.active !== false;\n }\n\n /**\n * Check if the category is suppressed and should be cleared\n *\n * @param options scope and category information\n */\n private isCategorySuppressed(options: CategoryActiveCheckOptions): boolean {\n const { scopeId, categoryId } = options;\n return !!this.config.categories[scopeId]?.[categoryId]?.suppress;\n }\n\n /**\n * Transform scope or category to the localized version\n *\n * @param scopeOrCategory a notifications scope or category\n */\n private async localize | NotificationCategory>(\n scopeOrCategory: T\n ): Promise {\n const config = await this.getForeignObjectAsync('system.config');\n\n const lang = config?.common.language || 'en';\n\n const description = scopeOrCategory.description[lang];\n const name = scopeOrCategory.name[lang];\n\n return { ...scopeOrCategory, description, name };\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial | undefined) => new NotificationManager(options);\n} else {\n // otherwise start the instance directly\n (() => new NotificationManager())();\n}\n"], + "mappings": "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", "names": ["obj", "fs"] } diff --git a/package-lock.json b/package-lock.json index 94549ea..7ca39f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,13 @@ "version": "1.2.0", "license": "MIT", "dependencies": { - "@iobroker/adapter-core": "^3.1.4" + "@iobroker/adapter-core": "^3.1.6" }, "devDependencies": { - "@alcalzone/release-script": "^3.5.9", - "@alcalzone/release-script-plugin-iobroker": "^3.5.9", - "@alcalzone/release-script-plugin-license": "^3.5.9", - "@alcalzone/release-script-plugin-manual-review": "^3.5.9", + "@alcalzone/release-script": "^3.8.0", + "@alcalzone/release-script-plugin-iobroker": "^3.7.2", + "@alcalzone/release-script-plugin-license": "^3.7.0", + "@alcalzone/release-script-plugin-manual-review": "^3.7.0", "@fortawesome/fontawesome-svg-core": "^6.4.0", "@fortawesome/free-regular-svg-icons": "^6.4.0", "@fortawesome/free-solid-svg-icons": "^6.4.0", @@ -52,7 +52,7 @@ "typescript": "~4.6.4" }, "engines": { - "node": ">= 16" + "node": ">=18" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -66,43 +66,74 @@ } }, "node_modules/@alcalzone/pak": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.8.1.tgz", - "integrity": "sha512-sPdxNxdXLH96kbyWLdIljVSIY2N6/qnPqkq5AlWvuizjGQUwHIUtWZHLss9XNDV/hY7YkgdIb9ILHbMTnRBxVQ==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.10.2.tgz", + "integrity": "sha512-v+kM7HlfIVNLDlGBcbZvrG3yVK3rPLH5kIoGRJbCcoHwpUqQbfEMzXAy1ZrfP+zbI5phHw2PhgrXZr3z6nh7Ow==", "dev": true, + "license": "MIT", "dependencies": { - "axios": "^0.26.0", - "execa": "^5.0.0", - "fs-extra": "^10.0.1" + "axios": "^1.6.2", + "execa": "~5.0.1", + "fs-extra": "^10.1.0", + "semver": "^7.3.7", + "tiny-glob": "^0.2.9" } }, "node_modules/@alcalzone/pak/node_modules/axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "dev": true, + "license": "MIT", "dependencies": { - "follow-redirects": "^1.14.8" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/@alcalzone/pak/node_modules/execa": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.1.tgz", + "integrity": "sha512-4hFTjFbFzQa3aCLobpbPJR/U+VoL1wdV5ozOWjeet0AWDeYr9UFGM1eUFWHX+VtOWFq4p0xXUXfW1YxUaP4fpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, "node_modules/@alcalzone/release-script": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script/-/release-script-3.5.9.tgz", - "integrity": "sha512-2qBUyh+wd/7KToZGXrJDp8v1nos1jm+xsDiSvI2jv5Co+105N415DCJNtgOvR6s2+/G2lbIZ08oYopl+evHgkw==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script/-/release-script-3.8.0.tgz", + "integrity": "sha512-9H3imn8o9n3Ekpkie9TMgPeJfgT6WmklCMtOZ1wuwvMw/obNA0Ao1ZZ8CJfHk1YNjiLGmWn0kQFEGTqz4DoD7w==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/release-script-core": "3.5.9", - "@alcalzone/release-script-plugin-changelog": "3.5.9", - "@alcalzone/release-script-plugin-exec": "3.5.9", - "@alcalzone/release-script-plugin-git": "3.5.9", - "@alcalzone/release-script-plugin-package": "3.5.9", - "@alcalzone/release-script-plugin-version": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", + "@alcalzone/release-script-plugin-changelog": "3.7.0", + "@alcalzone/release-script-plugin-exec": "3.7.0", + "@alcalzone/release-script-plugin-git": "3.8.0", + "@alcalzone/release-script-plugin-package": "3.7.3", + "@alcalzone/release-script-plugin-version": "3.7.0", "alcalzone-shared": "^4.0.1", - "axios": "^0.27.1", + "axios": "^1.6.2", "enquirer": "^2.3.6", "fs-extra": "^10.1.0", "picocolors": "1.0.0", - "semver": "^7.3.7", + "semver": "^7.5.2", "source-map-support": "^0.5.21", "yargs": "^17.4.1" }, @@ -114,10 +145,11 @@ } }, "node_modules/@alcalzone/release-script-core": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-core/-/release-script-core-3.5.9.tgz", - "integrity": "sha512-rRxosfZMtpDcIm+sPTdwP5oVRBLX1WLYImrp0nUhqOPNN/UD5l9TxNVXDhGUsstXhaRXXBYS2BnOQwR308OfyA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-core/-/release-script-core-3.7.0.tgz", + "integrity": "sha512-4np4dBziwX/aNRhS/gpK8bwa0wpLe7oomzJ7YTUXf5bUtV/UTpN2a9tm5Bp7ElnisKj6N3AqHl4lVXRo4L9hYg==", "dev": true, + "license": "MIT", "dependencies": { "execa": "^5.1.1" }, @@ -126,12 +158,13 @@ } }, "node_modules/@alcalzone/release-script-plugin-changelog": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-changelog/-/release-script-plugin-changelog-3.5.9.tgz", - "integrity": "sha512-KmOMbjd7ta/Wl2OWQUxMpNza6Sr5/sB7AfV7BC0uCl839StnoivSjqywDfNcgJq97fxMs7hnGT/uYaz7oTUm7A==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-changelog/-/release-script-plugin-changelog-3.7.0.tgz", + "integrity": "sha512-AlLOIjIPP42uBmvcdYkfijYDzolyY6JmfbTmdxQDBLyrgYXnuUr2GaKxbpeWSbvcAuUhNvHCAyI6LI90X3OTEg==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1", "fs-extra": "^10.1.0" }, @@ -140,12 +173,13 @@ } }, "node_modules/@alcalzone/release-script-plugin-exec": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-exec/-/release-script-plugin-exec-3.5.9.tgz", - "integrity": "sha512-Y6OM+gEpfYYoDvHdzNUtgVZiBAgOzGWZk9yRPF5l8UWE3+tQAyMWavk2m08ExbEICfGV1lb8lRBzAdQaf7/0HA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-exec/-/release-script-plugin-exec-3.7.0.tgz", + "integrity": "sha512-ZhlKGhxa71mLyYB1/ojzik2RKcSAeIjuwKzlWRd6oUvKoZPe7eAjLYneXx5viQC6tvDJE4dvN1NlkFGWsSlZYA==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1" }, "engines": { @@ -153,12 +187,13 @@ } }, "node_modules/@alcalzone/release-script-plugin-git": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-git/-/release-script-plugin-git-3.5.9.tgz", - "integrity": "sha512-LT8YSevyLqZFI4rx4ET1qRnqTNnU5rVmQvGFCnC+d375zU5/U2cu19s/WVLChMHkvmUbAwBld+xhqqos2hQrKw==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-git/-/release-script-plugin-git-3.8.0.tgz", + "integrity": "sha512-rI9EqSmvMWaNZ5xxOUBZjD4WOv1Enl+/ZxhUoTROq+K/9RYYHQaAXilGWNvnz2DYr14Q+Yx/fs54GXgAVf0scg==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "fs-extra": "^10.1.0" }, "engines": { @@ -166,28 +201,42 @@ } }, "node_modules/@alcalzone/release-script-plugin-iobroker": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-iobroker/-/release-script-plugin-iobroker-3.5.9.tgz", - "integrity": "sha512-0z0wU0HCLEe94JAtDPtarOc0AcqudefRlhA7RddZ6+FRwPOyAg8i37hcDKTo+C7rrk31TwgY2xiPIDjkfBKhyQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-iobroker/-/release-script-plugin-iobroker-3.7.2.tgz", + "integrity": "sha512-ezXFyxx2irq7my3BmlBUrzT+QHNsldR9MQYkXs7uyH6lXSkudmqq5EiDW9WckT0Cj9YqIUzoOJhhnZA9M+XTvQ==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1", - "axios": "^0.27.1", + "axios": "^1.6.2", "fs-extra": "^10.1.0", - "semver": "^7.3.7" + "semver": "^7.5.2" }, "engines": { "node": ">=12.20" } }, + "node_modules/@alcalzone/release-script-plugin-iobroker/node_modules/axios": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/@alcalzone/release-script-plugin-license": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-license/-/release-script-plugin-license-3.5.9.tgz", - "integrity": "sha512-Wa+RN968zYK0ZNkkaIRfD3Ru2ndWLD5e+VNbah4krtoeHqvQDiOPlfcWM0McU8q3ud+AMPwhYEwR1mh2lwi0gg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-license/-/release-script-plugin-license-3.7.0.tgz", + "integrity": "sha512-HLnKHr3pc6NJJ7zAa8S/SdC305oEurnkRa9XNP5F6rgrixsxUiynBVh0tpPsVsOTdndm7fNIBRfR66IGnw0cag==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "fs-extra": "^10.1.0", "tiny-glob": "^0.2.9" }, @@ -196,49 +245,64 @@ } }, "node_modules/@alcalzone/release-script-plugin-manual-review": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-manual-review/-/release-script-plugin-manual-review-3.5.9.tgz", - "integrity": "sha512-W/7T6lXfnfGo822g2LLU122SDYOk5V7GgPSL4+yr+mRvgAVwiUf4YBnv8C6fyO0/7cSGNYebmuIlRJcGc6sZCw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-manual-review/-/release-script-plugin-manual-review-3.7.0.tgz", + "integrity": "sha512-lU/KJHQpYhdDcYPxiR3X5BsP9O+bNYfyP8VPE5dF9fwLgTFklbGMOhF9VjdQMiZ8Cyr7fCH7ptw+oHw+UuQutQ==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/release-script-core": "3.5.9" + "@alcalzone/release-script-core": "3.7.0" }, "engines": { "node": ">=12.20" } }, "node_modules/@alcalzone/release-script-plugin-package": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-package/-/release-script-plugin-package-3.5.9.tgz", - "integrity": "sha512-jYmWzm9Dvnnc6RWTrZApQbeXzaFYSrHqkEHViAtx5NvBztfH3ANwVl6jS4UEaMm2NbIIq6toWGznVvNtnVzEjg==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-package/-/release-script-plugin-package-3.7.3.tgz", + "integrity": "sha512-5oKSwbvHs9jRhARJ04eQ7xqig3a7NmPJlhtBxAqUM8+0cjs2g/V1xTxM6o8aZ09uRSdq80YGVxJm871SyszAWQ==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/pak": "^0.8.1", - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/pak": "^0.10.1", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1", "fs-extra": "^10.1.0", - "semver": "^7.3.7" + "semver": "^7.5.2" }, "engines": { "node": ">=12.20" } }, "node_modules/@alcalzone/release-script-plugin-version": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-version/-/release-script-plugin-version-3.5.9.tgz", - "integrity": "sha512-CYN49aXx4QSFRWQN11wCC13SK1ZygILlohYlUFkRiA0g6u2G7z1rjW8QZSLXrR6C6gxzR4zL12VJ/xFZqYeuZA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-version/-/release-script-plugin-version-3.7.0.tgz", + "integrity": "sha512-030NGQeB+mglVz/58cx0WO4QiFChaSd/pz35mnOrUc9PbKWRpzisTVOt4IhCV/++YiAVibJO31NMNzvipPdx4Q==", "dev": true, + "license": "MIT", "dependencies": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1", "fs-extra": "^10.1.0", - "semver": "^7.3.7", + "semver": "^7.5.2", "tiny-glob": "^0.2.9" }, "engines": { "node": ">=12.20" } }, + "node_modules/@alcalzone/release-script/node_modules/axios": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.21.4", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", @@ -1111,14 +1175,15 @@ } }, "node_modules/@iobroker/adapter-core": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@iobroker/adapter-core/-/adapter-core-3.1.4.tgz", - "integrity": "sha512-RYDGB8Vk/MEKvMMwo4fLgxY8kjHrCeQmqROo/JxQYiLBEA4/gwFCTpxdD6s7RQ+dh4yZoH16/yTWqdgyR6NAxQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@iobroker/adapter-core/-/adapter-core-3.1.6.tgz", + "integrity": "sha512-cArv8IzVsP3r8HivsYwO02e5WueboIH9v66PkHSGtadeUQQKUyxV32dzirM6YArWcI6+Iw5USQgVR9E+ryP3xg==", + "license": "MIT", "engines": { "npm": ">=7.0.0" }, "peerDependencies": { - "@iobroker/types": "^5.0.11" + "@iobroker/types": "^6.0.0" } }, "node_modules/@iobroker/adapter-dev": { @@ -1192,9 +1257,10 @@ } }, "node_modules/@iobroker/types": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/@iobroker/types/-/types-5.0.13.tgz", - "integrity": "sha512-QfGN+P1ixBtbeevgDkTDa1/lC5C89oCrlCwu1/MoRpFn1ryHMfCYpTuQVIMcty2KJNtlh/H2ocAu7TFui4kB1Q==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/@iobroker/types/-/types-6.0.11.tgz", + "integrity": "sha512-RNDURjtL5Cm9wt6ocCqdRi86Qx1350zBIvvrJ9+Fjgasoi6cWCdoOghkwEeb95TH2j//q/uLqWwL8SZ0vxx6Kw==", + "license": "MIT", "peer": true, "engines": { "node": ">=12.0.0" @@ -4771,9 +4837,9 @@ "peer": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -4781,6 +4847,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -7149,6 +7216,13 @@ "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", "dev": true }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, "node_modules/proxyquire": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", @@ -8563,145 +8637,192 @@ "peer": true }, "@alcalzone/pak": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.8.1.tgz", - "integrity": "sha512-sPdxNxdXLH96kbyWLdIljVSIY2N6/qnPqkq5AlWvuizjGQUwHIUtWZHLss9XNDV/hY7YkgdIb9ILHbMTnRBxVQ==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.10.2.tgz", + "integrity": "sha512-v+kM7HlfIVNLDlGBcbZvrG3yVK3rPLH5kIoGRJbCcoHwpUqQbfEMzXAy1ZrfP+zbI5phHw2PhgrXZr3z6nh7Ow==", "dev": true, "requires": { - "axios": "^0.26.0", - "execa": "^5.0.0", - "fs-extra": "^10.0.1" + "axios": "^1.6.2", + "execa": "~5.0.1", + "fs-extra": "^10.1.0", + "semver": "^7.3.7", + "tiny-glob": "^0.2.9" }, "dependencies": { "axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "dev": true, "requires": { - "follow-redirects": "^1.14.8" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "execa": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.1.tgz", + "integrity": "sha512-4hFTjFbFzQa3aCLobpbPJR/U+VoL1wdV5ozOWjeet0AWDeYr9UFGM1eUFWHX+VtOWFq4p0xXUXfW1YxUaP4fpw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" } } } }, "@alcalzone/release-script": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script/-/release-script-3.5.9.tgz", - "integrity": "sha512-2qBUyh+wd/7KToZGXrJDp8v1nos1jm+xsDiSvI2jv5Co+105N415DCJNtgOvR6s2+/G2lbIZ08oYopl+evHgkw==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script/-/release-script-3.8.0.tgz", + "integrity": "sha512-9H3imn8o9n3Ekpkie9TMgPeJfgT6WmklCMtOZ1wuwvMw/obNA0Ao1ZZ8CJfHk1YNjiLGmWn0kQFEGTqz4DoD7w==", "dev": true, "requires": { - "@alcalzone/release-script-core": "3.5.9", - "@alcalzone/release-script-plugin-changelog": "3.5.9", - "@alcalzone/release-script-plugin-exec": "3.5.9", - "@alcalzone/release-script-plugin-git": "3.5.9", - "@alcalzone/release-script-plugin-package": "3.5.9", - "@alcalzone/release-script-plugin-version": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", + "@alcalzone/release-script-plugin-changelog": "3.7.0", + "@alcalzone/release-script-plugin-exec": "3.7.0", + "@alcalzone/release-script-plugin-git": "3.8.0", + "@alcalzone/release-script-plugin-package": "3.7.3", + "@alcalzone/release-script-plugin-version": "3.7.0", "alcalzone-shared": "^4.0.1", - "axios": "^0.27.1", + "axios": "^1.6.2", "enquirer": "^2.3.6", "fs-extra": "^10.1.0", "picocolors": "1.0.0", - "semver": "^7.3.7", + "semver": "^7.5.2", "source-map-support": "^0.5.21", "yargs": "^17.4.1" + }, + "dependencies": { + "axios": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "dev": true, + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + } } }, "@alcalzone/release-script-core": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-core/-/release-script-core-3.5.9.tgz", - "integrity": "sha512-rRxosfZMtpDcIm+sPTdwP5oVRBLX1WLYImrp0nUhqOPNN/UD5l9TxNVXDhGUsstXhaRXXBYS2BnOQwR308OfyA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-core/-/release-script-core-3.7.0.tgz", + "integrity": "sha512-4np4dBziwX/aNRhS/gpK8bwa0wpLe7oomzJ7YTUXf5bUtV/UTpN2a9tm5Bp7ElnisKj6N3AqHl4lVXRo4L9hYg==", "dev": true, "requires": { "execa": "^5.1.1" } }, "@alcalzone/release-script-plugin-changelog": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-changelog/-/release-script-plugin-changelog-3.5.9.tgz", - "integrity": "sha512-KmOMbjd7ta/Wl2OWQUxMpNza6Sr5/sB7AfV7BC0uCl839StnoivSjqywDfNcgJq97fxMs7hnGT/uYaz7oTUm7A==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-changelog/-/release-script-plugin-changelog-3.7.0.tgz", + "integrity": "sha512-AlLOIjIPP42uBmvcdYkfijYDzolyY6JmfbTmdxQDBLyrgYXnuUr2GaKxbpeWSbvcAuUhNvHCAyI6LI90X3OTEg==", "dev": true, "requires": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1", "fs-extra": "^10.1.0" } }, "@alcalzone/release-script-plugin-exec": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-exec/-/release-script-plugin-exec-3.5.9.tgz", - "integrity": "sha512-Y6OM+gEpfYYoDvHdzNUtgVZiBAgOzGWZk9yRPF5l8UWE3+tQAyMWavk2m08ExbEICfGV1lb8lRBzAdQaf7/0HA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-exec/-/release-script-plugin-exec-3.7.0.tgz", + "integrity": "sha512-ZhlKGhxa71mLyYB1/ojzik2RKcSAeIjuwKzlWRd6oUvKoZPe7eAjLYneXx5viQC6tvDJE4dvN1NlkFGWsSlZYA==", "dev": true, "requires": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1" } }, "@alcalzone/release-script-plugin-git": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-git/-/release-script-plugin-git-3.5.9.tgz", - "integrity": "sha512-LT8YSevyLqZFI4rx4ET1qRnqTNnU5rVmQvGFCnC+d375zU5/U2cu19s/WVLChMHkvmUbAwBld+xhqqos2hQrKw==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-git/-/release-script-plugin-git-3.8.0.tgz", + "integrity": "sha512-rI9EqSmvMWaNZ5xxOUBZjD4WOv1Enl+/ZxhUoTROq+K/9RYYHQaAXilGWNvnz2DYr14Q+Yx/fs54GXgAVf0scg==", "dev": true, "requires": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "fs-extra": "^10.1.0" } }, "@alcalzone/release-script-plugin-iobroker": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-iobroker/-/release-script-plugin-iobroker-3.5.9.tgz", - "integrity": "sha512-0z0wU0HCLEe94JAtDPtarOc0AcqudefRlhA7RddZ6+FRwPOyAg8i37hcDKTo+C7rrk31TwgY2xiPIDjkfBKhyQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-iobroker/-/release-script-plugin-iobroker-3.7.2.tgz", + "integrity": "sha512-ezXFyxx2irq7my3BmlBUrzT+QHNsldR9MQYkXs7uyH6lXSkudmqq5EiDW9WckT0Cj9YqIUzoOJhhnZA9M+XTvQ==", "dev": true, "requires": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1", - "axios": "^0.27.1", + "axios": "^1.6.2", "fs-extra": "^10.1.0", - "semver": "^7.3.7" + "semver": "^7.5.2" + }, + "dependencies": { + "axios": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "dev": true, + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + } } }, "@alcalzone/release-script-plugin-license": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-license/-/release-script-plugin-license-3.5.9.tgz", - "integrity": "sha512-Wa+RN968zYK0ZNkkaIRfD3Ru2ndWLD5e+VNbah4krtoeHqvQDiOPlfcWM0McU8q3ud+AMPwhYEwR1mh2lwi0gg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-license/-/release-script-plugin-license-3.7.0.tgz", + "integrity": "sha512-HLnKHr3pc6NJJ7zAa8S/SdC305oEurnkRa9XNP5F6rgrixsxUiynBVh0tpPsVsOTdndm7fNIBRfR66IGnw0cag==", "dev": true, "requires": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "fs-extra": "^10.1.0", "tiny-glob": "^0.2.9" } }, "@alcalzone/release-script-plugin-manual-review": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-manual-review/-/release-script-plugin-manual-review-3.5.9.tgz", - "integrity": "sha512-W/7T6lXfnfGo822g2LLU122SDYOk5V7GgPSL4+yr+mRvgAVwiUf4YBnv8C6fyO0/7cSGNYebmuIlRJcGc6sZCw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-manual-review/-/release-script-plugin-manual-review-3.7.0.tgz", + "integrity": "sha512-lU/KJHQpYhdDcYPxiR3X5BsP9O+bNYfyP8VPE5dF9fwLgTFklbGMOhF9VjdQMiZ8Cyr7fCH7ptw+oHw+UuQutQ==", "dev": true, "requires": { - "@alcalzone/release-script-core": "3.5.9" + "@alcalzone/release-script-core": "3.7.0" } }, "@alcalzone/release-script-plugin-package": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-package/-/release-script-plugin-package-3.5.9.tgz", - "integrity": "sha512-jYmWzm9Dvnnc6RWTrZApQbeXzaFYSrHqkEHViAtx5NvBztfH3ANwVl6jS4UEaMm2NbIIq6toWGznVvNtnVzEjg==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-package/-/release-script-plugin-package-3.7.3.tgz", + "integrity": "sha512-5oKSwbvHs9jRhARJ04eQ7xqig3a7NmPJlhtBxAqUM8+0cjs2g/V1xTxM6o8aZ09uRSdq80YGVxJm871SyszAWQ==", "dev": true, "requires": { - "@alcalzone/pak": "^0.8.1", - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/pak": "^0.10.1", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1", "fs-extra": "^10.1.0", - "semver": "^7.3.7" + "semver": "^7.5.2" } }, "@alcalzone/release-script-plugin-version": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-version/-/release-script-plugin-version-3.5.9.tgz", - "integrity": "sha512-CYN49aXx4QSFRWQN11wCC13SK1ZygILlohYlUFkRiA0g6u2G7z1rjW8QZSLXrR6C6gxzR4zL12VJ/xFZqYeuZA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-version/-/release-script-plugin-version-3.7.0.tgz", + "integrity": "sha512-030NGQeB+mglVz/58cx0WO4QiFChaSd/pz35mnOrUc9PbKWRpzisTVOt4IhCV/++YiAVibJO31NMNzvipPdx4Q==", "dev": true, "requires": { - "@alcalzone/release-script-core": "3.5.9", + "@alcalzone/release-script-core": "3.7.0", "alcalzone-shared": "^4.0.1", "fs-extra": "^10.1.0", - "semver": "^7.3.7", + "semver": "^7.5.2", "tiny-glob": "^0.2.9" } }, @@ -9324,9 +9445,9 @@ "requires": {} }, "@iobroker/adapter-core": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@iobroker/adapter-core/-/adapter-core-3.1.4.tgz", - "integrity": "sha512-RYDGB8Vk/MEKvMMwo4fLgxY8kjHrCeQmqROo/JxQYiLBEA4/gwFCTpxdD6s7RQ+dh4yZoH16/yTWqdgyR6NAxQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@iobroker/adapter-core/-/adapter-core-3.1.6.tgz", + "integrity": "sha512-cArv8IzVsP3r8HivsYwO02e5WueboIH9v66PkHSGtadeUQQKUyxV32dzirM6YArWcI6+Iw5USQgVR9E+ryP3xg==", "requires": {} }, "@iobroker/adapter-dev": { @@ -9393,9 +9514,9 @@ } }, "@iobroker/types": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/@iobroker/types/-/types-5.0.13.tgz", - "integrity": "sha512-QfGN+P1ixBtbeevgDkTDa1/lC5C89oCrlCwu1/MoRpFn1ryHMfCYpTuQVIMcty2KJNtlh/H2ocAu7TFui4kB1Q==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/@iobroker/types/-/types-6.0.11.tgz", + "integrity": "sha512-RNDURjtL5Cm9wt6ocCqdRi86Qx1350zBIvvrJ9+Fjgasoi6cWCdoOghkwEeb95TH2j//q/uLqWwL8SZ0vxx6Kw==", "peer": true }, "@isaacs/cliui": { @@ -11891,9 +12012,9 @@ "peer": true }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true }, "for-each": { @@ -13679,6 +13800,12 @@ } } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "proxyquire": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", diff --git a/package.json b/package.json index d5ce9e4..6ceb572 100644 --- a/package.json +++ b/package.json @@ -17,16 +17,16 @@ "url": "https://github.com/foxriver76/ioBroker.notification-manager" }, "engines": { - "node": ">= 16" + "node": ">=18" }, "dependencies": { - "@iobroker/adapter-core": "^3.1.4" + "@iobroker/adapter-core": "^3.1.6" }, "devDependencies": { - "@alcalzone/release-script": "^3.5.9", - "@alcalzone/release-script-plugin-iobroker": "^3.5.9", - "@alcalzone/release-script-plugin-license": "^3.5.9", - "@alcalzone/release-script-plugin-manual-review": "^3.5.9", + "@alcalzone/release-script": "^3.8.0", + "@alcalzone/release-script-plugin-iobroker": "^3.7.2", + "@alcalzone/release-script-plugin-license": "^3.7.0", + "@alcalzone/release-script-plugin-manual-review": "^3.7.0", "@fortawesome/fontawesome-svg-core": "^6.4.0", "@fortawesome/free-regular-svg-icons": "^6.4.0", "@fortawesome/free-solid-svg-icons": "^6.4.0", diff --git a/src/main.ts b/src/main.ts index 92e94d4..fe0fb64 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,7 +5,7 @@ interface GetNotificationsResponse { result: NotificationsObject; } -type HostId = `system.host.${string}`; +type HostId = ioBroker.ObjectIDs.Host; type Severity = 'alert' | 'info' | 'notify'; @@ -167,7 +167,6 @@ class NotificationManager extends utils.Adapter { ); } - // @ts-expect-error js-controller types are restricted to "system" here, should be fixed soon await this.registerNotification(this.USER_SCOPE, category, message); this.sendTo(obj.from, obj.command, { success: true }, obj.callback); } @@ -255,9 +254,21 @@ class NotificationManager extends utils.Adapter { * Is called if a subscribed state changes */ private async onStateChange(id: string, _state: ioBroker.State | null | undefined): Promise { - const hostName = id.split('.')[2]; - this.log.debug(`Notification update on "${hostName}" detected`); - await this.handleNotifications([`system.host.${hostName}`]); + const hostId = this.extractHostFromId(id); + this.log.debug(`Notification update on "${hostId}" detected`); + await this.handleNotifications([hostId]); + } + + /** + * Extract the hostname from a `system.host.hostPart1.maybeHostPart2.maybeHostPartX.notifications.category` id + * + * @param id id with structure `system.host.hostPart1.maybeHostPart2.maybeHostPartX.notifications.category` + */ + private extractHostFromId(id: string): HostId { + const notificationsId = id.substring(0, id.lastIndexOf('.')) + const hostId = id.substring(0, notificationsId.lastIndexOf('.')) + + return hostId as HostId } /**