From 8042f816a24a6a5f10df7d941e33489fba11fb4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20M=C3=BCller?= Date: Mon, 23 Sep 2024 17:36:48 +0200 Subject: [PATCH] Updated dependencies, Fixes issues reported by repo checker Fixed some reported linter issues --- .buildconfig.json | 2 +- .eslintignore | 3 - .eslintrc.js | 102 -- .vscode/settings.json | 2 +- README.md | 9 +- admin/blockly.js | 73 +- build/commands.js | 416 ++--- build/commands.js.map | 4 +- build/lib/definitions.js.map | 4 +- build/lib/i18n.js | 18 +- build/lib/i18n.js.map | 4 +- build/lib/utils.js | 8 +- build/lib/utils.js.map | 4 +- build/main.js | 759 ++++---- build/main.js.map | 6 +- eslint.config.mjs | 62 + io-package.json | 5 +- package-lock.json | 3283 ++++++++++++++++++++-------------- package.json | 39 +- src/commands.ts | 370 ++-- src/lib/adapter-config.d.ts | 3 +- src/lib/definitions.ts | 10 +- src/lib/i18n.ts | 4 +- src/lib/utils.ts | 8 +- src/main.ts | 780 ++++---- tsconfig.json | 9 +- 26 files changed, 3261 insertions(+), 2726 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js create mode 100644 eslint.config.mjs diff --git a/.buildconfig.json b/.buildconfig.json index 302eb51..fcf512b 100644 --- a/.buildconfig.json +++ b/.buildconfig.json @@ -1,3 +1,3 @@ { - "typescriptCompileTarget": "node16" + "typescriptCompileTarget": "node18" } \ No newline at end of file diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 70b6a26..0000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -admin/build/ -build/ -**/.eslintrc.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 100e610..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,102 +0,0 @@ -module.exports = { - root: true, // Don't look outside this project for inherited configs - parser: '@typescript-eslint/parser', // Specifies the ESLint parser - parserOptions: { - ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features - sourceType: 'module', // Allows for the use of imports - project: './tsconfig.json', - ecmaFeatures: { - jsx: true, - }, - }, - extends: [ - 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], - settings: { - react: { - version: 'detect', - }, - }, - rules: { - 'indent': 'off', - '@typescript-eslint/indent': [ - 'error', - 2, - { - 'SwitchCase': 1 - } - ], - 'quotes': [ - 'error', - 'single', - { - 'avoidEscape': true, - 'allowTemplateLiterals': true - } - ], - '@typescript-eslint/no-parameter-properties': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-use-before-define': [ - 'error', - { - functions: false, - typedefs: false, - classes: false, - }, - ], - '@typescript-eslint/no-unused-vars': [ - 'error', - { - ignoreRestSiblings: true, - argsIgnorePattern: '^_', - }, - ], - '@typescript-eslint/explicit-function-return-type': [ - 'warn', - { - allowExpressions: true, - allowTypedFunctionExpressions: true, - }, - ], - '@typescript-eslint/no-object-literal-type-assertion': 'off', - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', // This is necessary for Map.has()/get()! - '@typescript-eslint/no-inferrable-types': 'off', - 'no-var': 'error', - 'prefer-const': 'error', - 'no-trailing-spaces': 'error', - - 'comma-dangle': [ - 'warn', - { - arrays: 'always-multiline', - objects: 'always-multiline', - imports: 'always-multiline', - exports: 'always-multiline', - functions: 'always-multiline', - } - ], - - 'semi': ['warn', 'always'], - - 'no-restricted-syntax': [ - 'warn', - { - selector: 'CallExpression[callee.name="setTimeout"]', - message: 'setTimeout should not be used. Use adapter.setTimeout instead.' - }, - { - selector: 'CallExpression[callee.name="setInterval"]', - message: 'setInterval should not be used. Use adapter.setInterval instead.' - } - ] - }, - overrides: [ - { - files: ['*.test.ts', '*.tsx'], - rules: { - '@typescript-eslint/explicit-function-return-type': 'off', - }, - }, - ], -}; \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index cd7730e..5d58aeb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,7 @@ "fileMatch": [ "io-package.json" ], - "url": "https://json.schemastore.org/io-package" + "url": "https://raw.githubusercontent.com/ioBroker/ioBroker.js-controller/master/schemas/io-package.json" }, { "fileMatch": [ diff --git a/README.md b/README.md index 6e98ee8..75cf03a 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ A detailed documentation is available in the `docs` directory of the repository: ## Requirements * Node.js >= 18 -* js-controller >= 4.0 -* admin >= 5.3 +* js-controller >= 5.0.19 +* admin >= 6.17 ## Features @@ -60,6 +60,11 @@ A detailed documentation is available in the `docs` directory of the repository: Placeholder for the next version (at the beginning of the line): ### **WORK IN PROGRESS** --> +### **WORK IN PROGRESS** + +* (crycode-de) Node.js >= 18, Admin >= 6.17, js-contoller >= 5.0.19 are required +* (crycode-de) Updated dependencies + ### 2.4.0 (2024-07-10) * (crycode-de) Added basic support for interactions unknown to the adapter (custom scripts required for handling) diff --git a/admin/blockly.js b/admin/blockly.js index 7a2f6bb..e097b5e 100644 --- a/admin/blockly.js +++ b/admin/blockly.js @@ -1,11 +1,12 @@ +// @ts-nocheck 'use strict'; if (typeof goog !== 'undefined') { goog.provide('Blockly.JavaScript.Discord'); - goog.require('Blockly.JavaScript'); } +/* eslint-disable @stylistic/quote-props */ Blockly.Words['Discord'] = { 'en': 'Discord', 'de': 'Discord', 'ru': 'Discord', 'pt': 'Discord', 'nl': 'Discord', 'fr': 'Discord', 'it': 'Discord', 'es': 'Discord', 'pl': 'Discord', 'uk': 'Discord', 'zh-cn': 'Discord' }; Blockly.Words['discord_send_message'] = { 'en': 'Send Discord message', 'de': 'Discord-Nachricht senden', 'ru': 'Отправить сообщение в дискорде', 'pt': 'Enviar mensagem do Discord', 'nl': 'Discord-bericht verzenden', 'fr': 'Envoyer un message Discord', 'it': 'Invia messaggio Discordia', 'es': 'Enviar mensaje de discordia', 'pl': 'Wyślij wiadomość na Discordzie', 'uk': 'Надіслати повідомлення Discord', 'zh-cn': '发送不和谐消息' }; Blockly.Words['discord_send_message_tooltip'] = { 'en': 'Send a message via Discord', 'de': 'Eine Nachricht über Discord senden', 'ru': 'Отправить сообщение через Discord', 'pt': 'Envie uma mensagem pelo Discord', 'nl': 'Stuur een bericht via Discord', 'fr': 'Envoyer un message via Discord', 'it': 'Invia un messaggio tramite Discord', 'es': 'Enviar un mensaje a través de Discord', 'pl': 'Wyślij wiadomość przez Discord', 'uk': 'Надішліть повідомлення через Discord', 'zh-cn': '通过 Discord 发送消息' }; @@ -62,6 +63,7 @@ Blockly.Words['discord_send_custom_command_reply'] = { 'en': 'Send reply to a cu Blockly.Words['discord_send_custom_command_reply_tooltip'] = { 'en': 'Send a reply to a custom Discord slash command.', 'de': 'Senden einer Antwort auf einen benutzerdefinierten Discord-Slash-Befehl.', 'ru': 'Отправьте ответ на пользовательскую косую черту Discord.', 'pt': 'Envie uma resposta a um comando de barra personalizado do Discord.', 'nl': 'Stuur een antwoord op een aangepast Discord-slash-commando.', 'fr': 'Envoyez une réponse à une commande slash Discord personnalisée.', 'it': 'Invia una risposta a un comando slash Discord personalizzato.', 'es': 'Envíe una respuesta a un comando de barra inclinada de Discord personalizado.', 'pl': 'Wyślij odpowiedź na niestandardowe polecenie ukośnika Discorda.', 'uk': 'Надішліть відповідь на спеціальну команду Discord зі слешем.', 'zh-cn': '发送对自定义 Discord 斜杠命令的回复。' }; Blockly.Words['discord_interaction_id'] = { 'en': 'Interaction ID', 'de': 'Interaktions-ID', 'ru': 'Идентификатор взаимодействия', 'pt': 'Código de interação', 'nl': 'Interactie-ID', 'fr': 'ID d\'interaction', 'it': 'ID interazione', 'es': 'ID de interacción', 'pl': 'Identyfikator interakcji', 'uk': 'ID взаємодії', 'zh-cn': '交互 ID' }; Blockly.Words['discord_help_url'] = { 'en': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'de': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/de/README.md#blockly', 'ru': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'pt': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'nl': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'fr': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'it': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'es': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'pl': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'uk': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly', 'zh-cn': 'https://github.com/crycode-de/ioBroker.discord/blob/main/docs/en/README.md#blockly' }; +/* eslint-enable @stylistic/quote-props */ Blockly.CustomBlocks = Blockly.CustomBlocks || []; Blockly.CustomBlocks.push('Discord'); @@ -81,17 +83,17 @@ const DiscordHelpers = { const m = instance.match(/^system.adapter.discord.(\d+)$/); if (m) { const k = parseInt(m[1], 10); - options.push(['discord.' + k, '.' + k]); + options.push([ 'discord.' + k, '.' + k ]); } } if (options.length === 0) { for (let u = 0; u <= 4; u++) { - options.push(['discord.' + u, '.' + u]); + options.push([ 'discord.' + u, '.' + u ]); } } } else { for (let n = 0; n <= 4; n++) { - options.push(['discord.' + n, '.' + n]); + options.push([ 'discord.' + n, '.' + n ]); } } @@ -256,14 +258,14 @@ const DiscordHelpers = { } return `await new Promise((resolve) => { - ${contentCode || ''} + ${contentCode ?? ''} const data = { ${opts.target ? `${opts.target},` : ''} ${opts.messageId ? `messageId: ${opts.messageId},` : ''} ${contentCode ? `content: content,` : ''} ${opts.emoji ? `emoji: ${opts.emoji},` : ''} }; - ${userCode || ''} + ${userCode ?? ''} sendTo('discord${opts.instance}', '${opts.action}', data, (result) => { if (result.error) { log(\`[discord${opts.instance}] sendTo error: \${result.error}\\n\${JSON.stringify(result)}\`, 'warn'); @@ -316,7 +318,7 @@ const DiscordHelpers = { if (opts.inputContent) { block.appendValueInput('content') - .setCheck(['String', 'DiscordMessageContent']) + .setCheck([ 'String', 'DiscordMessageContent' ]) .appendField(Blockly.Translate('discord_message')); } @@ -644,11 +646,11 @@ Blockly.Blocks['discord_create_content'] = { .appendField(Blockly.Translate('discord_content')); this.appendValueInput('embeds') - .setCheck(['String', 'Array', 'DiscordEmbed']) // may be a single sting, embed or array of both + .setCheck([ 'String', 'Array', 'DiscordEmbed' ]) // may be a single sting, embed or array of both .appendField(Blockly.Translate('discord_embeds')); this.appendValueInput('files') - .setCheck(['String', 'Array', 'DiscordFile']) // may be a single filename, attachment or array of both + .setCheck([ 'String', 'Array', 'DiscordFile' ]) // may be a single filename, attachment or array of both .appendField(Blockly.Translate('discord_attachments')); this.appendValueInput('replyToId') @@ -678,7 +680,7 @@ Blockly.JavaScript['discord_create_content'] = function (block) { const ret = `{ content: ${content},${propEmbeds}${propFiles}${propReply} }`; - return [ret, Blockly.JavaScript.ORDER_ATOMIC]; + return [ ret, Blockly.JavaScript.ORDER_ATOMIC ]; }; // --- Block create embed ------------------------------------------------------- @@ -782,7 +784,7 @@ Blockly.JavaScript['discord_create_embed'] = function (block) { } ret += '\n }'; - return [ret, Blockly.JavaScript.ORDER_ATOMIC]; + return [ ret, Blockly.JavaScript.ORDER_ATOMIC ]; }; // --- Block create file ------------------------------------------------------- @@ -849,7 +851,7 @@ Blockly.JavaScript['discord_create_file'] = function (block) { } ret += '\n }'; - return [ret, Blockly.JavaScript.ORDER_ATOMIC]; + return [ ret, Blockly.JavaScript.ORDER_ATOMIC ]; }; // --- Block on custom slash command ------------------------------------------- @@ -894,7 +896,7 @@ Blockly.Blocks['discord_on_custom_cmd_container'] = { this.appendStatementInput('STACK'); this.setTooltip(Blockly.Translate('discord_custom_cmd_option_tooltip')); this.contextMenu = false; - } + }, }; Blockly.Blocks['discord_on_custom_cmd_item'] = { @@ -912,7 +914,7 @@ Blockly.Blocks['discord_on_custom_cmd_item'] = { this.setNextStatement(true); this.setTooltip(Blockly.Translate('discord_custom_cmd_option_tooltip')); this.contextMenu = false; - } + }, }; Blockly.Blocks['discord_on_custom_cmd'] = { @@ -920,7 +922,6 @@ Blockly.Blocks['discord_on_custom_cmd'] = { this.appendDummyInput('_label') .appendField(Blockly.Translate('discord_on_custom_cmd')); - this.appendDummyInput('instance') .appendField(Blockly.Translate('discord_instance')) .appendField(new Blockly.FieldDropdown(DiscordHelpers.getInstancesOptions()), 'instance'); @@ -961,10 +962,10 @@ Blockly.Blocks['discord_on_custom_cmd'] = { this.setNextStatement(true, null); if (typeof Blockly.icons === 'object') { // Blockly >= 10 - this.setMutator(new Blockly.icons.MutatorIcon(['discord_on_custom_cmd_item'], this)); + this.setMutator(new Blockly.icons.MutatorIcon([ 'discord_on_custom_cmd_item' ], this)); } else { // Blockly 9.x - this.setMutator(new Blockly.Mutator(['discord_on_custom_cmd_item'])); + this.setMutator(new Blockly.Mutator([ 'discord_on_custom_cmd_item' ])); } this.setTooltip(Blockly.Translate('discord_on_custom_cmd_tooltip')); this.setHelpUrl(DiscordHelpers.helpUrl); @@ -1029,15 +1030,14 @@ Blockly.Blocks['discord_on_custom_cmd'] = { const names = []; while (itemBlock) { connections.push(itemBlock.valueConnection_); - itemBlock = itemBlock.nextConnection && - itemBlock.nextConnection.targetBlock(); + itemBlock = itemBlock.nextConnection?.targetBlock(); } // Disconnect any children that don't belong. for (let i = 0; i < this.itemCount_; i++) { const input = this.getInput('option' + i); const connection = input.connection.targetConnection; names[i] = input.fieldRow[0].getValue(); - if (connection && connections.indexOf(connection) === -1) { + if (connection && !connections.includes(connection)) { connection.disconnect(); } } @@ -1060,8 +1060,8 @@ Blockly.Blocks['discord_on_custom_cmd'] = { let i = 0; while (itemBlock) { const input = this.getInput('option' + i); - itemBlock.valueConnection_ = input && input.connection.targetConnection; - itemBlock = itemBlock.nextConnection && itemBlock.nextConnection.targetBlock(); + itemBlock.valueConnection_ = input?.connection.targetConnection; + itemBlock = itemBlock.nextConnection?.targetBlock(); i++; } }, @@ -1076,6 +1076,7 @@ Blockly.Blocks['discord_on_custom_cmd'] = { let _input; const wp = this.workspace; + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this.getInput('STATEMENT') && this.removeInput('STATEMENT'); // Add new inputs. @@ -1091,27 +1092,25 @@ Blockly.Blocks['discord_on_custom_cmd'] = { _input.appendField(new Blockly.FieldTextInput(names[i])); _input.setAlign(Blockly.ALIGN_RIGHT); _input.setCheck('Variable'); - setTimeout(function (_input) { - if (!_input.connection.isConnected()) { + setTimeout(function (_input2) { + if (!_input2.connection.isConnected()) { const _shadow = wp.newBlock('logic_null'); _shadow.setShadow(true); _shadow.initSvg(); _shadow.render(); - _shadow.outputConnection.connect(_input.connection); - //console.log('New ' + names[i]); + _shadow.outputConnection.connect(_input2.connection); } }, 100, _input); } else { _input.fieldRow[0].setValue(names[i]); - //console.log('Exist ' + names[i]); - setTimeout(function (_input, name) { - if (!_input.connection.isConnected()) { + setTimeout(function (_input2, name) { + if (!_input2.connection.isConnected()) { console.log('Create ' + name); const shadow = wp.newBlock('logic_null'); shadow.setShadow(true); shadow.initSvg(); shadow.render(); - shadow.outputConnection.connect(_input.connection); + shadow.outputConnection.connect(_input2.connection); } }, 100, _input, names[i]); } @@ -1119,9 +1118,10 @@ Blockly.Blocks['discord_on_custom_cmd'] = { // Remove deleted inputs. const blocks = []; + // eslint-disable-next-line no-cond-assign while (_input = this.getInput('option' + i)) { const b = _input.connection.targetBlock(); - if (b && b.isShadow()) { + if (b?.isShadow()) { blocks.push(b); } this.removeInput('option' + i); @@ -1131,14 +1131,15 @@ Blockly.Blocks['discord_on_custom_cmd'] = { if (blocks.length) { const ws = this.workspace; setTimeout(function () { - for (var b = 0; b < blocks.length; b++) { + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let b = 0; b < blocks.length; b++) { ws.removeTopBlock(blocks[b]); } }, 100); } this.appendStatementInput('STATEMENT'); - } + }, }; Blockly.JavaScript['discord_on_custom_cmd'] = function (block) { @@ -1146,7 +1147,7 @@ Blockly.JavaScript['discord_on_custom_cmd'] = function (block) { const varUserId = Blockly.JavaScript.valueToCode(block, 'varUserId', Blockly.JavaScript.ORDER_ATOMIC); const varUserTag = Blockly.JavaScript.valueToCode(block, 'varUserTag', Blockly.JavaScript.ORDER_ATOMIC); const log = block.getFieldValue('log'); - let commandName = block.getFieldValue('commandName').replace(/[^0-9a-z-_]/g, ''); + const commandName = block.getFieldValue('commandName').replace(/[^0-9a-z-_]/g, ''); const statement = Blockly.JavaScript.statementToCode(block, 'STATEMENT'); let varAssigns = ''; @@ -1160,7 +1161,7 @@ Blockly.JavaScript['discord_on_custom_cmd'] = function (block) { for (let n = 0; n < block.itemCount_; n++) { const input = this.getInput('option' + n); - let val = Blockly.JavaScript.valueToCode(block, 'option' + n, Blockly.JavaScript.ORDER_COMMA); + const val = Blockly.JavaScript.valueToCode(block, 'option' + n, Blockly.JavaScript.ORDER_COMMA); if (val && val !== 'null') { varAssigns += `\n ${val} = (data.options && data.options['${input.fieldRow[0].getValue()}']) ? data.options['${input.fieldRow[0].getValue()}'].value : null;`; } @@ -1170,7 +1171,7 @@ Blockly.JavaScript['discord_on_custom_cmd'] = function (block) { const id = 'discord${instance}.slashCommands.${commandName}.json'; on({ id: id, change: 'any', ack: true }, async (obj) => { if (typeof obj.state.val !== 'string' || obj.state.val.length === 0) return; - ${log === true || log === 'true' || log === 'TRUE' ? `log(\`[discord${instance}] Custom slash command ${commandName}: \${obj.state.val}\`);` : '' } + ${log === true || log === 'true' || log === 'TRUE' ? `log(\`[discord${instance}] Custom slash command ${commandName}: \${obj.state.val}\`);` : ''} let data; try { data = JSON.parse(obj.state.val); diff --git a/build/commands.js b/build/commands.js index a1ae202..fe1c903 100644 --- a/build/commands.js +++ b/build/commands.js @@ -39,71 +39,76 @@ var import_v10 = require("discord-api-types/v10"); var import_i18n = require("./lib/i18n"); var import_utils = require("./lib/utils"); class DiscordAdapterSlashCommands { + /** + * Reference to the adapter instance. + */ + adapter; + /** + * Discord REST api interface. + */ + rest = new import_rest.REST({ version: "10" }); + /** + * Command name for the get state command. + */ + cmdGetStateName = "iob-get"; + /** + * Command name for the set state command. + */ + cmdSetStateName = "iob-set"; + /** + * Possible choices for get state command state-option. + */ + cmdGetStateChoices = []; + /** + * Possible choices for set state command state-option. + */ + cmdSetStateChoices = []; + /** + * Collection of the known (registered) custom commands and their option choices. + */ + customCommands = new import_discord.Collection(); + /** + * If commands are fully registered including their permissions. + */ + registerCommandsDone = false; + /** + * The last registered commands. + * Used to check if something changed an we need to register the commands again. + */ + lastCommandsJson = null; + /** + * Collection of configurations for objects with commands enabled. + */ + commandObjectConfig = new import_discord.Collection(); + /** + * Collection of the last seen interactions of custom commands (not iob-get/-set) + * or other interactions which are not directly handled by the adapter. + * + * Need to cache this here since there seems to be no way to get an interaction + * by ID from discord.js. + */ + lastInteractions = new import_discord.Collection(); + /** + * Timeout to trigger the delayed registration of the slash commands. + */ + triggerDelayedRegisterSlashCommandsTimeout = null; + /** + * Set of well known values that will be interperted as true. + * This is extended by some localized strings at runtime. + * Used to determine true values from iob-set slash commands. + */ + wellKnownbooleanTrueValues = /* @__PURE__ */ new Set(["true", "on", "yes", "1"]); constructor(adapter) { - /** - * Discord REST api interface. - */ - this.rest = new import_rest.REST({ version: "10" }); - /** - * Command name for the get state command. - */ - this.cmdGetStateName = "iob-get"; - /** - * Command name for the set state command. - */ - this.cmdSetStateName = "iob-set"; - /** - * Possible choices for get state command state-option. - */ - this.cmdGetStateChoices = []; - /** - * Possible choices for set state command state-option. - */ - this.cmdSetStateChoices = []; - /** - * Collection of the known (registered) custom commands and their option choices. - */ - this.customCommands = new import_discord.Collection(); - /** - * If commands are fully registered including their permissions. - */ - this.registerCommandsDone = false; - /** - * The last registered commands. - * Used to check if something changed an we need to register the commands again. - */ - this.lastCommandsJson = null; - /** - * Collection of configurations for objects with commands enabled. - */ - this.commandObjectConfig = new import_discord.Collection(); - /** - * Collection of the last seen interactions of custom commands (not iob-get/-set) - * or other interactions which are not directly handled by the adapter. - * - * Need to cache this here since there seems to be no way to get an interaction - * by ID from discord.js. - */ - this.lastInteractions = new import_discord.Collection(); - /** - * Timeout to trigger the delayed registration of the slash commands. - */ - this.triggerDelayedRegisterSlashCommandsTimeout = null; - /** - * Set of well known values that will be interperted as true. - * This is extended by some localized strings at runtime. - * Used to determine true values from iob-set slash commands. - */ - this.wellKnownbooleanTrueValues = /* @__PURE__ */ new Set(["true", "on", "yes", "1"]); this.adapter = adapter; } /** * When the adapter is Ready. * Called by `adapter.onReady()` after some basic checks and setup. */ + // eslint-disable-next-line @typescript-eslint/require-await async onReady() { if (this.adapter.config.cmdGetStateName) { - if (this.adapter.config.cmdGetStateName.match(/^[a-z][0-9a-z-_]{1,32}$/)) { + if (/^[a-z][0-9a-z-_]{1,32}$/.exec(this.adapter.config.cmdGetStateName)) { this.cmdGetStateName = this.adapter.config.cmdGetStateName; } else { this.adapter.log.warn(`Invalid custom get state command name '${this.adapter.config.cmdGetStateName}' provied! Using default 'iob-get'.`); @@ -111,7 +116,7 @@ class DiscordAdapterSlashCommands { } if (this.adapter.config.cmdSetStateName) { this.cmdSetStateName = this.adapter.config.cmdSetStateName; - if (this.adapter.config.cmdSetStateName.match(/^[a-z][0-9a-z-_]{1,32}$/)) { + if (/^[a-z][0-9a-z-_]{1,32}$/.exec(this.adapter.config.cmdSetStateName)) { this.cmdSetStateName = this.adapter.config.cmdSetStateName; } else { this.adapter.log.warn(`Invalid custom set state command name '${this.adapter.config.cmdSetStateName}' provied! Using default 'iob-set'.`); @@ -131,9 +136,8 @@ class DiscordAdapterSlashCommands { * Register the commands on discord, if enabled. */ async registerSlashCommands() { - var _a, _b; this.registerCommandsDone = false; - if (!((_a = this.adapter.client) == null ? void 0 : _a.user)) { + if (!this.adapter.client?.user) { throw new Error("Discord client not available"); } if (this.adapter.unloaded) @@ -191,7 +195,7 @@ class DiscordAdapterSlashCommands { if (this.adapter.config.enableCustomCommands) { loopCustomCommands: for (const customCommandCfg of this.adapter.config.customCommands) { - if (!customCommandCfg.name.match(/^[a-z][0-9a-z-_]{1,32}$/) || customCommandCfg.description.length === 0 || customCommandCfg.description.length > 100) { + if (!/^[a-z][0-9a-z-_]{1,32}$/.exec(customCommandCfg.name) || customCommandCfg.description.length === 0 || customCommandCfg.description.length > 100) { this.adapter.log.warn(`Custom command "${customCommandCfg.name}" has an invalid name or description configured!`); continue; } @@ -220,7 +224,7 @@ class DiscordAdapterSlashCommands { } await this.setupCustomCommandIobObjects(customCommandCfg); for (const customCommandCfgOpt of customCommandCfg.options) { - if (!customCommandCfgOpt.name.match(/^[a-z][0-9a-z-_]{1,32}$/) || customCommandCfgOpt.description.length === 0 || customCommandCfgOpt.description.length > 100) { + if (!/^[a-z][0-9a-z-_]{1,32}$/.exec(customCommandCfgOpt.name) || customCommandCfgOpt.description.length === 0 || customCommandCfgOpt.description.length > 100) { this.adapter.log.warn(`Custom command "${customCommandCfg.name}" option "${customCommandCfgOpt.name}" has an invalid name or description configured!`); continue loopCustomCommands; } @@ -230,10 +234,10 @@ class DiscordAdapterSlashCommands { } cmdOpts.add(customCommandCfgOpt.name); switch (customCommandCfgOpt.type) { - case "string": + case "string": { let choices = []; try { - const val = ((_b = await this.adapter.getStateAsync(`slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices`)) == null ? void 0 : _b.val) ?? "[]"; + const val = (await this.adapter.getStateAsync(`slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices`))?.val ?? "[]"; if (typeof val !== "string") { this.adapter.log.warn(`Value of ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices is not a string!`); } else { @@ -260,6 +264,7 @@ class DiscordAdapterSlashCommands { return opt; }); break; + } case "number": cmdCustom.addNumberOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required)); break; @@ -348,16 +353,109 @@ class DiscordAdapterSlashCommands { } this.registerCommandsDone = true; } + /** + * Setup an ioBroker object for discord slash commands. + * @param objId ID of the ioBroker object to set up. + * @param cfg Command configuration for the ioBroker object or null to remove a possibly existing configuration. + */ + setupCommandObject(objId, cfg) { + if (cfg) { + const conflictingAlias = this.commandObjectConfig.find((coc) => coc.alias === cfg?.alias && coc.id !== cfg.id); + if (conflictingAlias) { + this.adapter.log.warn(`Command alias ${cfg.alias} of object ${cfg.id} already in use by object ${conflictingAlias.id}! ${cfg.id} will be ignored.`); + cfg = null; + } + } + if (!cfg) { + if (this.commandObjectConfig.has(objId)) { + this.commandObjectConfig.delete(objId); + this.triggerDelayedRegisterSlashCommands(); + } + return; + } + const currentCfg = this.commandObjectConfig.get(objId); + if (!(0, import_node_util.isDeepStrictEqual)(cfg, currentCfg)) { + this.adapter.log.debug(`Update command configuration for ${objId}: ${JSON.stringify(cfg)}`); + this.commandObjectConfig.set(objId, cfg); + this.triggerDelayedRegisterSlashCommands(); + } + } + /** + * Initialize a delayed registration of the slash commands. + * Calls `registerSlashCommands()` five seconds after the last call of this method. + * If called again within the five seconds the timeout starts again. + * + * This is used to handle object changes better and concat multiple changed + * object configurations into a single API call. + * + * If the initial custom objects setup of the adapter isn't done, this method + * does nothing since the command registration is called during this explicit. + */ + triggerDelayedRegisterSlashCommands() { + if (!this.adapter.initialCustomObjectSetupDone) + return; + if (this.triggerDelayedRegisterSlashCommandsTimeout) { + this.adapter.clearTimeout(this.triggerDelayedRegisterSlashCommandsTimeout); + } + this.adapter.setTimeout(() => { + this.triggerDelayedRegisterSlashCommandsTimeout = null; + this.adapter.log.debug("Starting delayed slash commands registration..."); + void this.registerSlashCommands(); + }, 5e3); + } + /** + * Send a reply to a custom slash command. + * @param interactionId The ID of the interaction to reply to. The interactions needs to be cached in this instance. + * @param msg The message to reply with. May be a simple string, a MessageOptions object or a stringified JSON MessageOptions object. + * @returns Promise which resolves withe the ID of the reply message if the reply is sent. + * @throws Error if the reply could not be sent for some reason (i.e. some check failed). + */ + async sendCmdCustomReply(interactionId, msg) { + const interaction = this.lastInteractions.get(interactionId); + if (!interaction) { + throw new Error(`No current interaction with ID ${interactionId} found for reply!`); + } + let cscTxt = ""; + if (interaction.isCommand()) { + const { commandName } = interaction; + const cmdCfg = this.adapter.config.customCommands.find((c) => c.name === commandName); + if (!cmdCfg) { + throw new Error(`No configuration for custom slash command ${commandName} of interaction ${interactionId} found for reply!`); + } + cscTxt = ` of custom slash command ${commandName}`; + } + if (!interaction.isRepliable()) { + throw new Error(`Interaction ${interactionId}${cscTxt} is not repliable!`); + } + if (typeof msg === "string") { + try { + msg = this.adapter.parseStringifiedMessageOptions(msg); + } catch (err) { + throw new Error(`Reply to interaction ${interactionId}${cscTxt} is invalid: ${err}`); + } + } + const replyMsg = await interaction.editReply(msg); + return replyMsg.id; + } + /** + * Write a summay of all currently for commands configured objects to the log. + */ + logConfiguredCommandObjects() { + this.adapter.log.info("Configured state objects for discord slash commands:"); + for (const [, cmdObjCfg] of this.commandObjectConfig) { + this.adapter.log.info(` |- ${cmdObjCfg.id} - alias:${cmdObjCfg.alias}, name:${cmdObjCfg.name}, get:${cmdObjCfg.get}, set:${cmdObjCfg.set}`); + } + this.adapter.log.info("---"); + } /** * Remove registered global commands if any. */ async removeGlobalCommands() { - var _a, _b; - if (!((_a = this.adapter.client) == null ? void 0 : _a.user)) { + if (!this.adapter.client?.user) { throw new Error("Discord client not available"); } try { - const globalCommands = await ((_b = this.adapter.client.application) == null ? void 0 : _b.commands.fetch()); + const globalCommands = await this.adapter.client.application?.commands.fetch(); if (this.adapter.unloaded) return; if (globalCommands && globalCommands.size > 0) { @@ -378,8 +476,7 @@ class DiscordAdapterSlashCommands { * @param guild The guild. */ async removeGuildCommands(guild) { - var _a; - if (!((_a = this.adapter.client) == null ? void 0 : _a.user)) { + if (!this.adapter.client?.user) { throw new Error("Discord client not available"); } try { @@ -403,9 +500,8 @@ class DiscordAdapterSlashCommands { * Setup the ioBroker object tree for the configured custom commands. */ async setupCustomCommandIobObjects(cmdCfg) { - var _a; const cmdName = cmdCfg.name; - await this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}`, { + await this.adapter.extendObjectCached(`slashCommands.${cmdName}`, { type: "channel", common: { name: cmdCfg.description @@ -413,7 +509,7 @@ class DiscordAdapterSlashCommands { native: {} }); await Promise.all([ - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.json`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.json`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("JSON data"), @@ -425,7 +521,7 @@ class DiscordAdapterSlashCommands { }, native: {} }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.timestamp`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.timestamp`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last use timestamp"), @@ -437,7 +533,7 @@ class DiscordAdapterSlashCommands { }, native: {} }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.sendReply`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.sendReply`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send reply"), @@ -449,7 +545,7 @@ class DiscordAdapterSlashCommands { }, native: {} }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.interactionId`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.interactionId`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Interaction ID"), @@ -461,7 +557,7 @@ class DiscordAdapterSlashCommands { }, native: {} }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userId`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.userId`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("User ID"), @@ -473,7 +569,7 @@ class DiscordAdapterSlashCommands { }, native: {} }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userTag`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.userTag`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("User tag"), @@ -485,7 +581,7 @@ class DiscordAdapterSlashCommands { }, native: {} }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userName`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.userName`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("User name"), @@ -497,7 +593,7 @@ class DiscordAdapterSlashCommands { }, native: {} }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.serverId`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.serverId`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Server ID"), @@ -509,7 +605,7 @@ class DiscordAdapterSlashCommands { }, native: {} }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.channelId`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.channelId`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Channel ID"), @@ -524,7 +620,7 @@ class DiscordAdapterSlashCommands { ]); const proms = []; for (const cmdCfgOpt of cmdCfg.options) { - await this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}`, { + await this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}`, { type: "channel", common: { name: import_i18n.i18n.getStringOrTranslated("Option %s", cmdCfgOpt.description) @@ -550,7 +646,7 @@ class DiscordAdapterSlashCommands { type = "string"; def = ""; } - proms.push(this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.value`, { + proms.push(this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.value`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Option %s value", cmdCfgOpt.description), @@ -563,7 +659,7 @@ class DiscordAdapterSlashCommands { native: {} })); if (cmdCfgOpt.type === "string") { - proms.push(this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.choices`, { + proms.push(this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.choices`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Option %s choices", cmdCfgOpt.description), @@ -590,67 +686,17 @@ class DiscordAdapterSlashCommands { const oldoptName = m[1]; if (!cmdCfg.options.find((o) => o.name === oldoptName)) { proms.push(this.adapter.delObjectAsyncCached(`slashCommands.${cmdName}.option-${oldoptName}`, { recursive: true })); - (_a = this.customCommands.get(cmdName)) == null ? void 0 : _a.delete(oldoptName); + this.customCommands.get(cmdName)?.delete(oldoptName); } } } await Promise.all(proms); } - /** - * Setup an ioBroker object for discord slash commands. - * @param objId ID of the ioBroker object to set up. - * @param cfg Command configuration for the ioBroker object or null to remove a possibly existing configuration. - */ - setupCommandObject(objId, cfg) { - if (cfg) { - const conflictingAlias = this.commandObjectConfig.find((coc) => coc.alias === (cfg == null ? void 0 : cfg.alias) && coc.id !== cfg.id); - if (conflictingAlias) { - this.adapter.log.warn(`Command alias ${cfg.alias} of object ${cfg.id} already in use by object ${conflictingAlias.id}! ${cfg.id} will be ignored.`); - cfg = null; - } - } - if (!cfg) { - if (this.commandObjectConfig.has(objId)) { - this.commandObjectConfig.delete(objId); - this.triggerDelayedRegisterSlashCommands(); - } - return; - } - const currentCfg = this.commandObjectConfig.get(objId); - if (!(0, import_node_util.isDeepStrictEqual)(cfg, currentCfg)) { - this.adapter.log.debug(`Update command configuration for ${objId}: ${JSON.stringify(cfg)}`); - this.commandObjectConfig.set(objId, cfg); - this.triggerDelayedRegisterSlashCommands(); - } - } - /** - * Initialize a delayed registration of the slash commands. - * Calls `registerSlashCommands()` five seconds after the last call of this method. - * If called again within the five seconds the timeout starts again. - * - * This is used to handle object changes better and concat multiple changed - * object configurations into a single API call. - * - * If the initial custom objects setup of the adapter isn't done, this method - * does nothing since the command registration is called during this explicit. - */ - triggerDelayedRegisterSlashCommands() { - if (!this.adapter.initialCustomObjectSetupDone) - return; - if (this.triggerDelayedRegisterSlashCommandsTimeout) { - this.adapter.clearTimeout(this.triggerDelayedRegisterSlashCommandsTimeout); - } - this.adapter.setTimeout(() => { - this.triggerDelayedRegisterSlashCommandsTimeout = null; - this.adapter.log.debug("Starting delayed slash commands registration..."); - this.registerSlashCommands(); - }, 5e3); - } async onInteractionCreate(interaction) { if (interaction.isCommand()) { - this.handleCommandInteraction(interaction); + void this.handleCommandInteraction(interaction); } else if (interaction.isAutocomplete()) { - this.handleAutocompleteInteraction(interaction); + void this.handleAutocompleteInteraction(interaction); } else { this.lastInteractions.set(interaction.id, interaction); if (interaction.isRepliable() && !interaction.deferred) { @@ -662,7 +708,7 @@ class DiscordAdapterSlashCommands { if (interaction.isCommand()) { interactionJson.options = interaction.options.data; } - this.adapter.setState("raw.interactionJson", JSON.stringify(interactionJson, (_key, value) => typeof value === "bigint" ? value.toString() : value), true); + void this.adapter.setState("raw.interactionJson", JSON.stringify(interactionJson, (_key, value) => typeof value === "bigint" ? value.toString() : value), true); } const outdatedTs = Date.now() - 15 * 6e4; const removedInteractions = this.lastInteractions.sweep((ia) => ia.createdTimestamp < outdatedTs); @@ -720,12 +766,11 @@ class DiscordAdapterSlashCommands { * Handle autocomplete for command interactions. */ async handleAutocompleteInteraction(interaction) { - var _a; const { commandName, user } = interaction; const focused = interaction.options.getFocused(true); let focusedValue; if (typeof focused.value !== "string") { - return interaction.respond([]); + return await interaction.respond([]); } else { focusedValue = focused.value.toLowerCase(); } @@ -733,27 +778,27 @@ class DiscordAdapterSlashCommands { let choices; if (commandName === this.cmdGetStateName) { if (!this.adapter.checkUserAuthorization(authCheckTarget, { getStates: true })) { - return interaction.respond([]); + return await interaction.respond([]); } choices = this.cmdGetStateChoices; } else if (commandName === this.cmdSetStateName) { if (!this.adapter.checkUserAuthorization(authCheckTarget, { setStates: true })) { - return interaction.respond([]); + return await interaction.respond([]); } choices = this.cmdSetStateChoices; } else if (this.customCommands.has(commandName)) { if (!this.adapter.checkUserAuthorization(authCheckTarget, { useCustomCommands: true })) { - return interaction.respond([]); + return await interaction.respond([]); } - choices = ((_a = this.customCommands.get(commandName)) == null ? void 0 : _a.get(focused.name)) ?? []; + choices = this.customCommands.get(commandName)?.get(focused.name) ?? []; } else { - return interaction.respond([]); + return await interaction.respond([]); } const matchedChoices = choices.filter((choice) => { return choice.name.normalize("NFKC").toLowerCase().includes(focusedValue) || choice.value.normalize("NFKC").toLowerCase().includes(focusedValue); }); matchedChoices.splice(25); - return interaction.respond(matchedChoices); + return await interaction.respond(matchedChoices); } /** * Try to get the ioBroker object and CommandObjectConfig for a given object alias. @@ -813,14 +858,13 @@ class DiscordAdapterSlashCommands { * @param interaction The interaction which triggered this. */ async handleCmdGetState(interaction) { - var _a; const objAlias = interaction.options.get("state", true).value; const [obj, cfg] = await this.getObjectAndCfgFromAlias(objAlias, interaction); if (!obj || !cfg) { return; } - const objCustom = (_a = obj.common.custom) == null ? void 0 : _a[this.adapter.namespace]; - if (!(objCustom == null ? void 0 : objCustom.commandsAllowGet)) { + const objCustom = obj.common.custom?.[this.adapter.namespace]; + if (!objCustom?.commandsAllowGet) { await interaction.reply({ content: import_i18n.i18n.getString("Get not allowed for state `%s`!", cfg.id), ephemeral: true @@ -839,7 +883,7 @@ class DiscordAdapterSlashCommands { await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral }); } let val = ""; - let msgOpts = void 0; + let msgOpts; const unit = obj.common.unit ? ` ${obj.common.unit}` : ""; const ack = objCustom.commandsShowAckFalse && !state.ack ? ` (_${import_i18n.i18n.getString("not acknowledged")}_)` : ""; if (obj.common.role === "date" && (obj.common.type === "string" && typeof state.val === "string" || obj.common.type === "number" && typeof state.val === "number")) { @@ -878,7 +922,7 @@ class DiscordAdapterSlashCommands { val = objCustom.commandsBooleanValueFalse ?? import_i18n.i18n.getString("false"); } break; - case "number": + case "number": { const decimals = objCustom.commandsNumberDecimals ?? 0; if (typeof state.val === "number") { val = state.val.toFixed(decimals); @@ -891,6 +935,7 @@ class DiscordAdapterSlashCommands { val = val.replace(".", ","); } break; + } default: if (typeof state.val === "string") { val = state.val; @@ -917,21 +962,20 @@ class DiscordAdapterSlashCommands { * @param interaction The interaction which triggered this. */ async handleCmdSetState(interaction) { - var _a, _b, _c; const objAlias = interaction.options.get("state", true).value; const [obj, cfg] = await this.getObjectAndCfgFromAlias(objAlias, interaction); if (!obj || !cfg) { return; } - const objCustom = (_a = obj.common.custom) == null ? void 0 : _a[this.adapter.namespace]; - if (!(objCustom == null ? void 0 : objCustom.commandsAllowSet)) { + const objCustom = obj.common.custom?.[this.adapter.namespace]; + if (!objCustom?.commandsAllowSet) { await interaction.reply({ content: import_i18n.i18n.getString("Set not allowed for state `%s`!", cfg.id), ephemeral: true }); return; } - let valueStr = (_b = interaction.options.get("value")) == null ? void 0 : _b.value; + let valueStr = interaction.options.get("value")?.value; if (typeof valueStr !== "string") { await interaction.reply({ content: import_i18n.i18n.getString("No value provided!"), @@ -949,7 +993,7 @@ class DiscordAdapterSlashCommands { switch (obj.common.type) { case "boolean": valueStr = valueStr.toLowerCase(); - if (valueStr === ((_c = objCustom.commandsBooleanValueTrue) == null ? void 0 : _c.toLowerCase()) || this.wellKnownbooleanTrueValues.has(valueStr)) { + if (valueStr === objCustom.commandsBooleanValueTrue?.toLowerCase() || this.wellKnownbooleanTrueValues.has(valueStr)) { value = true; valueReply = objCustom.commandsBooleanValueTrue ?? import_i18n.i18n.getString("true"); } else { @@ -1070,7 +1114,7 @@ class DiscordAdapterSlashCommands { id: opt.channel.id, name: opt.channel.name, type: import_discord.ChannelType[opt.channel.type], - lastMessageId: opt.channel.type === import_discord.ChannelType.GuildText || opt.channel.type == import_discord.ChannelType.GuildVoice ? opt.channel.lastMessageId : null + lastMessageId: opt.channel.type === import_discord.ChannelType.GuildText || opt.channel.type === import_discord.ChannelType.GuildVoice ? opt.channel.lastMessageId : null }; } } else { @@ -1079,64 +1123,20 @@ class DiscordAdapterSlashCommands { type: null }; } - proms.push(this.adapter.setStateAsync(`slashCommands.${commandName}.option-${optCfg.name}.value`, json.options[optCfg.name].value, true)); + proms.push(this.adapter.setState(`slashCommands.${commandName}.option-${optCfg.name}.value`, json.options[optCfg.name].value, true)); } await Promise.all([ - this.adapter.setStateAsync(`slashCommands.${commandName}.interactionId`, interaction.id, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.channelId`, channelId, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.serverId`, guildId ?? null, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.userId`, user.id, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.userTag`, user.tag, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.userName`, user.username, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.timestamp`, interaction.createdTimestamp, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.json`, JSON.stringify(json), true), + this.adapter.setState(`slashCommands.${commandName}.interactionId`, interaction.id, true), + this.adapter.setState(`slashCommands.${commandName}.channelId`, channelId, true), + this.adapter.setState(`slashCommands.${commandName}.serverId`, guildId ?? null, true), + this.adapter.setState(`slashCommands.${commandName}.userId`, user.id, true), + this.adapter.setState(`slashCommands.${commandName}.userTag`, user.tag, true), + this.adapter.setState(`slashCommands.${commandName}.userName`, user.username, true), + this.adapter.setState(`slashCommands.${commandName}.timestamp`, interaction.createdTimestamp, true), + this.adapter.setState(`slashCommands.${commandName}.json`, JSON.stringify(json), true), ...proms ]); } - /** - * Send a reply to a custom slash command. - * @param interactionId The ID of the interaction to reply to. The interactions needs to be cached in this instance. - * @param msg The message to reply with. May be a simple string, a MessageOptions object or a stringified JSON MessageOptions object. - * @returns Promise which resolves withe the ID of the reply message if the reply is sent. - * @throws Error if the reply could not be sent for some reason (i.e. some check failed). - */ - async sendCmdCustomReply(interactionId, msg) { - const interaction = this.lastInteractions.get(interactionId); - if (!interaction) { - throw new Error(`No current interaction with ID ${interactionId} found for reply!`); - } - let cscTxt = ""; - if (interaction.isCommand()) { - const { commandName } = interaction; - const cmdCfg = this.adapter.config.customCommands.find((c) => c.name === commandName); - if (!cmdCfg) { - throw new Error(`No configuration for custom slash command ${commandName} of interaction ${interactionId} found for reply!`); - } - cscTxt = ` of custom slash command ${commandName}`; - } - if (!interaction.isRepliable()) { - throw new Error(`Interaction ${interactionId}${cscTxt} is not repliable!`); - } - if (typeof msg === "string") { - try { - msg = this.adapter.parseStringifiedMessageOptions(msg); - } catch (err) { - throw new Error(`Reply to interaction ${interactionId}${cscTxt} is invalid: ${err}`); - } - } - const replyMsg = await interaction.editReply(msg); - return replyMsg.id; - } - /** - * Write a summay of all currently for commands configured objects to the log. - */ - logConfiguredCommandObjects() { - this.adapter.log.info("Configured state objects for discord slash commands:"); - for (const [, cmdObjCfg] of this.commandObjectConfig) { - this.adapter.log.info(` |- ${cmdObjCfg.id} - alias:${cmdObjCfg.alias}, name:${cmdObjCfg.name}, get:${cmdObjCfg.get}, set:${cmdObjCfg.set}`); - } - this.adapter.log.info("---"); - } } __decorateClass([ import_autobind_decorator.boundMethod diff --git a/build/commands.js.map b/build/commands.js.map index e5f53ca..e56fa87 100644 --- a/build/commands.js.map +++ b/build/commands.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/commands.ts"], - "sourcesContent": ["import { isDeepStrictEqual } from 'node:util';\n\nimport { boundMethod } from 'autobind-decorator';\n\nimport {\n ApplicationCommandOptionType,\n AutocompleteInteraction,\n CacheType,\n ChannelType,\n Collection,\n CommandInteraction,\n DiscordAPIError,\n Guild,\n GuildChannel,\n GuildMember,\n Interaction,\n MessageCreateOptions,\n Role,\n Snowflake,\n User,\n} from 'discord.js';\nimport { SlashCommandBuilder } from '@discordjs/builders';\nimport { REST } from '@discordjs/rest';\nimport { Routes } from 'discord-api-types/v10';\n\nimport type { DiscordAdapter } from './main';\nimport { i18n } from './lib/i18n';\nimport {\n getBasenameFromFilePathOrUrl,\n getBufferAndNameFromBase64String,\n userNameOrTag,\n} from './lib/utils';\nimport { ChannelTypeNames, JsonSlashCommandObj } from './lib/definitions';\n\nexport interface CommandObjectConfig {\n id: string;\n alias: string;\n name: string;\n get: boolean;\n set: boolean;\n}\n\ninterface CommandOptionChoiceData {\n name: string;\n value: string;\n}\n\n/**\n * Class for discord slash commands handling\n */\nexport class DiscordAdapterSlashCommands {\n\n /**\n * Reference to the adapter instance.\n */\n private adapter: DiscordAdapter;\n\n /**\n * Discord REST api interface.\n */\n private rest: REST = new REST({ version: '10' });\n\n /**\n * Command name for the get state command.\n */\n private cmdGetStateName: string = 'iob-get';\n\n /**\n * Command name for the set state command.\n */\n private cmdSetStateName: string = 'iob-set';\n\n /**\n * Possible choices for get state command state-option.\n */\n private cmdGetStateChoices: CommandOptionChoiceData[] = [];\n\n /**\n * Possible choices for set state command state-option.\n */\n private cmdSetStateChoices: CommandOptionChoiceData[] = [];\n\n /**\n * Collection of the known (registered) custom commands and their option choices.\n */\n private customCommands: Collection> = new Collection();\n\n /**\n * If commands are fully registered including their permissions.\n */\n private registerCommandsDone: boolean = false;\n\n /**\n * The last registered commands.\n * Used to check if something changed an we need to register the commands again.\n */\n private lastCommandsJson: any[] | null = null;\n\n /**\n * Collection of configurations for objects with commands enabled.\n */\n private commandObjectConfig: Collection = new Collection();\n\n /**\n * Collection of the last seen interactions of custom commands (not iob-get/-set)\n * or other interactions which are not directly handled by the adapter.\n *\n * Need to cache this here since there seems to be no way to get an interaction\n * by ID from discord.js.\n */\n private lastInteractions: Collection | Interaction> = new Collection();\n\n /**\n * Timeout to trigger the delayed registration of the slash commands.\n */\n private triggerDelayedRegisterSlashCommandsTimeout: ioBroker.Timeout | null = null;\n\n /**\n * Set of well known values that will be interperted as true.\n * This is extended by some localized strings at runtime.\n * Used to determine true values from iob-set slash commands.\n */\n private wellKnownbooleanTrueValues: Set = new Set(['true', 'on', 'yes', '1']);\n\n constructor (adapter: DiscordAdapter) {\n this.adapter = adapter;\n }\n\n /**\n * When the adapter is Ready.\n * Called by `adapter.onReady()` after some basic checks and setup.\n */\n public async onReady (): Promise {\n // apply custom command names if configured\n if (this.adapter.config.cmdGetStateName) {\n if (this.adapter.config.cmdGetStateName.match(/^[a-z][0-9a-z-_]{1,32}$/)) {\n this.cmdGetStateName = this.adapter.config.cmdGetStateName;\n } else {\n this.adapter.log.warn(`Invalid custom get state command name '${this.adapter.config.cmdGetStateName}' provied! Using default 'iob-get'.`);\n }\n }\n if (this.adapter.config.cmdSetStateName) {\n this.cmdSetStateName = this.adapter.config.cmdSetStateName;\n if (this.adapter.config.cmdSetStateName.match(/^[a-z][0-9a-z-_]{1,32}$/)) {\n this.cmdSetStateName = this.adapter.config.cmdSetStateName;\n } else {\n this.adapter.log.warn(`Invalid custom set state command name '${this.adapter.config.cmdSetStateName}' provied! Using default 'iob-set'.`);\n }\n }\n\n // setup REST interface\n this.rest.setToken(this.adapter.config.token);\n\n // check if commands are enabled\n if (!this.adapter.config.enableCommands) {\n return;\n }\n\n // add translated versions of true/on/yes to the set of well known boolean true values\n this.wellKnownbooleanTrueValues.add(i18n.getString('true'))\n .add(i18n.getString('on'))\n .add(i18n.getString('yes'));\n\n // setup interaction handler for commands\n if (!this.adapter.client) {\n throw new Error('Tried to setup interaction handler for commands, but client is not initialized!');\n }\n this.adapter.client.on('interactionCreate', this.onInteractionCreate);\n }\n\n /**\n * Register the commands on discord, if enabled.\n */\n public async registerSlashCommands (): Promise {\n this.registerCommandsDone = false;\n\n if (!this.adapter.client?.user) {\n throw new Error('Discord client not available');\n }\n\n if (this.adapter.unloaded) return;\n\n // check if commands are enabled and if not remove set commands\n if (!this.adapter.config.enableCommands) {\n this.adapter.log.debug('Commands not enabled');\n\n // check for commands and remove them all\n for (const [, guild] of this.adapter.client.guilds.cache) {\n await this.removeGuildCommands(guild);\n }\n\n await this.removeGlobalCommands();\n\n return;\n }\n\n // build commands array\n const commands: SlashCommandBuilder[] = [];\n\n const numGet = this.commandObjectConfig.filter((c) => c.get === true).size;\n const numSet = this.commandObjectConfig.filter((c) => c.set === true).size;\n\n // setup iob-get command if objects configured for get\n if (numGet > 0) {\n const cmdGet = new SlashCommandBuilder()\n .setName(this.cmdGetStateName)\n .setDescription(i18n.getString('Get an ioBroker state value'));\n\n // add options\n cmdGet.addStringOption((opt) => (\n opt.setName('state')\n .setDescription(i18n.getString('The ioBroker state to get'))\n .setRequired(true)\n .setAutocomplete(true)\n ));\n\n commands.push(cmdGet);\n }\n\n // setup iob-set command if objects configured for set\n if (numSet > 0) {\n const cmdSet = new SlashCommandBuilder()\n .setName(this.cmdSetStateName)\n .setDescription(i18n.getString('Set an ioBroker state value'));\n\n cmdSet.addStringOption((opt) => (\n opt.setName('state')\n .setDescription(i18n.getString('The ioBroker state to set'))\n .setRequired(true)\n .setAutocomplete(true)\n ));\n cmdSet.addStringOption((opt) => {\n return opt.setName('value')\n .setDescription(i18n.getString('The value to set'))\n .setRequired(true);\n });\n\n commands.push(cmdSet);\n }\n\n // setup choices for get and set commands\n this.cmdGetStateChoices = [];\n this.cmdSetStateChoices = [];\n for (const [, objCfg] of this.commandObjectConfig) {\n if (objCfg.get) {\n this.cmdGetStateChoices.push({\n name: objCfg.name,\n value: objCfg.alias,\n });\n }\n if (objCfg.set) {\n this.cmdSetStateChoices.push({\n name: objCfg.name,\n value: objCfg.alias,\n });\n }\n }\n\n // sort choices for get and set commands\n const sortFn = (a: CommandOptionChoiceData, b: CommandOptionChoiceData): -1 | 0 | 1 => {\n if (a.name > b.name) return 1;\n if (a.name < b.name) return -1;\n return 0;\n };\n this.cmdGetStateChoices.sort(sortFn);\n this.cmdSetStateChoices.sort(sortFn);\n\n // custom commands\n this.customCommands.clear();\n if (this.adapter.config.enableCustomCommands) {\n loopCustomCommands:\n for (const customCommandCfg of this.adapter.config.customCommands) {\n if (!customCommandCfg.name.match(/^[a-z][0-9a-z-_]{1,32}$/) || customCommandCfg.description.length === 0 || customCommandCfg.description.length > 100) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" has an invalid name or description configured!`);\n continue;\n }\n\n if (customCommandCfg.name === this.cmdGetStateName) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" is configured but conflicts with default get command! The command will be ignored.`);\n continue;\n }\n if (customCommandCfg.name === this.cmdSetStateName) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" is configured but conflicts with default set command! The command will be ignored.`);\n continue;\n }\n\n if (this.customCommands.has(customCommandCfg.name)) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" is configured multiple times! The command will be ignored.`);\n continue;\n }\n\n // create the command\n const cmdCustom = new SlashCommandBuilder()\n .setName(customCommandCfg.name)\n .setDescription(customCommandCfg.description);\n\n const optionsChoices = new Collection();\n\n // add configured options\n const cmdOpts: Set = new Set();\n if (Array.isArray(customCommandCfg.options)) {\n // max 25 options are allowed\n if (customCommandCfg.options.length > 25) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" has more than 25 options configured! Only the first 25 options will be used.`);\n customCommandCfg.options.splice(25);\n }\n } else {\n customCommandCfg.options = [];\n }\n\n // create/update the ioBroker objects\n await this.setupCustomCommandIobObjects(customCommandCfg);\n\n for (const customCommandCfgOpt of customCommandCfg.options) {\n if (!customCommandCfgOpt.name.match(/^[a-z][0-9a-z-_]{1,32}$/) || customCommandCfgOpt.description.length === 0 || customCommandCfgOpt.description.length > 100) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" option \"${customCommandCfgOpt.name}\" has an invalid name or description configured!`);\n continue loopCustomCommands;\n }\n\n if (cmdOpts.has(customCommandCfgOpt.name)) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" option \"${customCommandCfgOpt.name}\" is configured multiple times! The command will be ignored.`);\n continue loopCustomCommands;\n }\n cmdOpts.add(customCommandCfgOpt.name);\n\n switch (customCommandCfgOpt.type) {\n case 'string':\n // string options may have choices from the ioBroker object\n let choices: (string | CommandOptionChoiceData)[] = [];\n try {\n const val = (await this.adapter.getStateAsync(`slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices`))?.val ?? '[]';\n if (typeof val !== 'string') {\n this.adapter.log.warn(`Value of ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices is not a string!`);\n } else {\n choices = JSON.parse(val);\n }\n } catch (err) {\n this.adapter.log.warn(`Could not parse JSON from ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices! ${err}`);\n }\n\n optionsChoices.set(customCommandCfgOpt.name, choices.map((choice) => {\n if (typeof choice === 'string' && choice.length >= 1 && choice.length <= 100) {\n return { name: choice, value: choice };\n } else if (typeof choice === 'object' && typeof choice.value === 'string' && typeof choice.name === 'string' && choice.name.length >= 1 && choice.name.length <= 100 && choice.value.length <= 100) {\n return { name: choice.name, value: choice.value };\n } else {\n this.adapter.log.warn(`Choice ${JSON.stringify(choice)} is not valid for ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices and will be ignored!`);\n return null;\n }\n }).filter((choice) => choice !== null) as CommandOptionChoiceData[]);\n\n cmdCustom.addStringOption((opt) => {\n opt.setName(customCommandCfgOpt.name)\n .setDescription(customCommandCfgOpt.description)\n .setRequired(!!customCommandCfgOpt.required);\n\n if (choices.length > 0) {\n opt.setAutocomplete(true);\n }\n\n return opt;\n });\n break;\n\n case 'number':\n cmdCustom.addNumberOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'boolean':\n cmdCustom.addBooleanOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'user':\n cmdCustom.addUserOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'role':\n cmdCustom.addRoleOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'channel':\n cmdCustom.addChannelOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'mentionable':\n cmdCustom.addMentionableOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n default:\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" option \"${customCommandCfgOpt.name} has an invalid type set\"!`);\n continue loopCustomCommands;\n }\n }\n\n // add custom command to the commands\n commands.push(cmdCustom);\n this.customCommands.set(customCommandCfg.name, optionsChoices);\n }\n\n /*\n * find and delete old custom slash command objects\n */\n const objListSlashCommands = await this.adapter.getObjectListAsync({\n startkey: `${this.adapter.namespace}.slashCommands.`,\n endkey: `${this.adapter.namespace}.slashCommands.\\u9999`,\n });\n const re = new RegExp(`^${this.adapter.name}\\\\.${this.adapter.instance}\\\\.slashCommands\\\\.([^.]+)$`);\n for (const item of objListSlashCommands.rows) {\n const m = item.id.match(re);\n if (m) {\n const cmdName = m[1];\n if (!this.customCommands.has(cmdName)) {\n this.adapter.log.debug(`Custom slash command ${cmdName} is not configured - deleting objects`);\n await this.adapter.delObjectAsyncCached(`slashCommands.${cmdName}`, { recursive: true });\n }\n }\n }\n }\n\n // check if any command is set and log an warning if not\n if (commands.length === 0) {\n if (this.adapter.config.enableCustomCommands) {\n this.adapter.log.warn('Commands are enabled but not configured for any state object and no custom commands are configured! Use the custom configuration of a state object to activate commands on it or add custom commands in the adapter instance configuration.');\n } else {\n this.adapter.log.warn('Commands are enabled but not configured for any state object! Use the custom configuration of a state object to activate commands on it.');\n }\n }\n\n const commandsJson = commands.map((cmd) => cmd.toJSON());\n\n // only update the commands if something has changed\n if (!isDeepStrictEqual(commandsJson, this.lastCommandsJson)) {\n this.adapter.log.debug('Commands needs to be updated');\n\n // register commands for all servers of the bot (guild commands are applied instant and may have permissions per user set)\n for (const [, guild] of this.adapter.client.guilds.cache) {\n try {\n if (this.adapter.config.commandsGlobal) {\n // global commands enabled, remove per guild commands\n await this.removeGuildCommands(guild);\n\n } else {\n // commands per guild\n await this.rest.put(Routes.applicationGuildCommands(this.adapter.client.user.id, guild.id), { body: commandsJson });\n this.adapter.log.info(`Registered commands for server ${guild.name} (id:${guild.id}) (get: ${numGet}, set: ${numSet}, custom: ${this.customCommands.size})`);\n }\n\n } catch (err) {\n if (err instanceof DiscordAPIError && err.message === 'Missing Access'){\n this.adapter.log.warn(`Error registering commands for server ${guild.name} (id:${guild.id}). Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`);\n } else {\n this.adapter.log.warn(`Error registering commands for server ${guild.name} (id:${guild.id}): ${err}`);\n }\n }\n }\n\n // register global commands if enabled\n try {\n if (this.adapter.config.commandsGlobal) {\n // global commands enabled\n await this.rest.put(Routes.applicationCommands(this.adapter.client.user.id), { body: commandsJson });\n this.adapter.log.info(`Registered global commands (get: ${numGet}, set: ${numSet}, custom: ${this.customCommands.size})`);\n\n } else {\n // global command disabled\n await this.removeGlobalCommands();\n }\n\n } catch (err) {\n if (err instanceof DiscordAPIError && err.message === 'Missing Access') {\n this.adapter.log.warn(`Error registering global commands. Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`);\n } else {\n this.adapter.log.warn(`Error registering global commands: ${err}`);\n }\n }\n\n // cache the commandsJson for the next call of `registerSlashCommands()`\n this.lastCommandsJson = commandsJson;\n\n } else {\n this.adapter.log.debug('Commands seams to be up to date');\n }\n\n this.registerCommandsDone = true;\n }\n\n\n /**\n * Remove registered global commands if any.\n */\n private async removeGlobalCommands (): Promise {\n if (!this.adapter.client?.user) {\n throw new Error('Discord client not available');\n }\n\n try {\n const globalCommands = await this.adapter.client.application?.commands.fetch();\n if (this.adapter.unloaded) return;\n\n if (globalCommands && globalCommands.size > 0) {\n this.adapter.log.debug(`Currently ${globalCommands.size} global commands registered. Removing them...`);\n await this.rest.put(Routes.applicationCommands(this.adapter.client.user.id), { body: [] });\n this.adapter.log.info(`Removed global commands cause commands they are not used anymore.`);\n }\n } catch (err) {\n if (err instanceof DiscordAPIError && err.message === 'Missing Access') {\n this.adapter.log.warn(`Error while removing registered global commands. Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`);\n } else {\n this.adapter.log.warn(`Error while removing registered global commands: ${err}`);\n }\n }\n }\n\n /**\n * Remove registered guild commands if any.\n * @param guild The guild.\n */\n private async removeGuildCommands (guild: Guild): Promise {\n if (!this.adapter.client?.user) {\n throw new Error('Discord client not available');\n }\n\n try {\n const guildCommands = await guild.commands.fetch();\n if (this.adapter.unloaded) return;\n\n if (guildCommands.size > 0) {\n this.adapter.log.debug(`Currently ${guildCommands.size} commands registered for server ${guild.name}. Removing them...`);\n await this.rest.put(Routes.applicationGuildCommands(this.adapter.client.user.id, guild.id), { body: [] });\n this.adapter.log.info(`Removed commands for server ${guild.name} cause commands they are not used anymore.`);\n }\n } catch (err) {\n if (err instanceof DiscordAPIError && err.message === 'Missing Access') {\n this.adapter.log.warn(`Error while removing registered commands for server ${guild.name} (id:${guild.id}). Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`);\n } else {\n this.adapter.log.warn(`Error while removing registered commands for server ${guild.name} (id:${guild.id}): ${err}`);\n }\n }\n }\n\n /**\n * Setup the ioBroker object tree for the configured custom commands.\n */\n private async setupCustomCommandIobObjects (cmdCfg: ioBroker.AdapterConfigCustomCommand): Promise {\n const cmdName = cmdCfg.name;\n\n await this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}`, {\n type: 'channel',\n common: {\n name: cmdCfg.description,\n },\n native: {},\n });\n\n // generic custom command objects\n await Promise.all([\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.json`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.timestamp`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last use timestamp'),\n role: 'date',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.sendReply`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reply'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.interactionId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Interaction ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userTag`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User tag'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userName`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.serverId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Server ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.channelId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Channel ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n\n // custom command option objects\n const proms: Promise[] = [];\n for (const cmdCfgOpt of cmdCfg.options) {\n await this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}`, {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Option %s', cmdCfgOpt.description),\n },\n native: {},\n });\n\n let role: string;\n let type: ioBroker.CommonType;\n let def: any;\n switch (cmdCfgOpt.type) {\n case 'number':\n role = 'value';\n type = 'number';\n def = null;\n break;\n\n case 'boolean':\n role = 'indicator';\n type = 'boolean';\n def = null;\n break;\n\n default:\n role = 'text';\n type = 'string';\n def = '';\n }\n\n proms.push(this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.value`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Option %s value', cmdCfgOpt.description),\n role,\n type,\n read: true,\n write: false,\n def,\n },\n native: {},\n }));\n\n // for string options add a choices state\n if (cmdCfgOpt.type === 'string') {\n proms.push(this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.choices`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Option %s choices', cmdCfgOpt.description),\n role: 'json',\n type: 'string',\n read: true,\n write: true,\n def: '[]',\n },\n native: {},\n }));\n } else {\n // remove the state for non-string options\n proms.push(this.adapter.delObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.choices`));\n }\n }\n\n // check for unused (old) custom command option objects and remove them\n const objListOptions = await this.adapter.getObjectListAsync({\n startkey: `${this.adapter.namespace}.slashCommands.${cmdName}.option-`,\n endkey: `${this.adapter.namespace}.slashCommands.${cmdName}.option-\\u9999`,\n });\n const reOptionsName = new RegExp(`^${this.adapter.name}\\\\.${this.adapter.instance}\\\\.slashCommands\\\\.${cmdName}\\\\.option-([^.]+)$`);\n for (const item of objListOptions.rows) {\n const m = item.id.match(reOptionsName);\n if (m) {\n const oldoptName = m[1];\n if (!cmdCfg.options.find((o) => o.name === oldoptName)) {\n // option does not exist... delete the object and custom command option choices cache\n proms.push(this.adapter.delObjectAsyncCached(`slashCommands.${cmdName}.option-${oldoptName}`, { recursive: true }));\n this.customCommands.get(cmdName)?.delete(oldoptName);\n }\n }\n }\n\n // wait for object create/delete\n await Promise.all(proms);\n }\n\n /**\n * Setup an ioBroker object for discord slash commands.\n * @param objId ID of the ioBroker object to set up.\n * @param cfg Command configuration for the ioBroker object or null to remove a possibly existing configuration.\n */\n public setupCommandObject (objId: string, cfg: CommandObjectConfig | null): void {\n // check if alias is already in use\n if (cfg) {\n const conflictingAlias = this.commandObjectConfig.find((coc) => coc.alias === cfg?.alias && coc.id !== cfg.id);\n if (conflictingAlias) {\n this.adapter.log.warn(`Command alias ${cfg.alias} of object ${cfg.id} already in use by object ${conflictingAlias.id}! ${cfg.id} will be ignored.`);\n cfg = null;\n }\n }\n\n // remove if commands are not enabled or alias conflict\n if (!cfg) {\n if (this.commandObjectConfig.has(objId)) {\n this.commandObjectConfig.delete(objId);\n this.triggerDelayedRegisterSlashCommands();\n }\n return;\n }\n\n // update only if changed\n const currentCfg = this.commandObjectConfig.get(objId);\n if (!isDeepStrictEqual(cfg, currentCfg)) {\n this.adapter.log.debug(`Update command configuration for ${objId}: ${JSON.stringify(cfg)}`);\n this.commandObjectConfig.set(objId, cfg);\n this.triggerDelayedRegisterSlashCommands();\n }\n }\n\n /**\n * Initialize a delayed registration of the slash commands.\n * Calls `registerSlashCommands()` five seconds after the last call of this method.\n * If called again within the five seconds the timeout starts again.\n *\n * This is used to handle object changes better and concat multiple changed\n * object configurations into a single API call.\n *\n * If the initial custom objects setup of the adapter isn't done, this method\n * does nothing since the command registration is called during this explicit.\n */\n public triggerDelayedRegisterSlashCommands (): void {\n // do nothing on init\n if (!this.adapter.initialCustomObjectSetupDone) return;\n\n if (this.triggerDelayedRegisterSlashCommandsTimeout) {\n this.adapter.clearTimeout(this.triggerDelayedRegisterSlashCommandsTimeout);\n }\n\n this.adapter.setTimeout(() => {\n this.triggerDelayedRegisterSlashCommandsTimeout = null;\n this.adapter.log.debug('Starting delayed slash commands registration...');\n this.registerSlashCommands();\n }, 5000);\n }\n\n /**\n * Handle interactions.\n */\n @boundMethod\n private async onInteractionCreate (interaction: Interaction): Promise {\n if (interaction.isCommand()) {\n // handle command interaction for build in commands and custom commands\n this.handleCommandInteraction(interaction);\n\n } else if (interaction.isAutocomplete()) {\n // handle auto complete interaction\n this.handleAutocompleteInteraction(interaction);\n\n } else {\n // handle other interaction types to allow the usage of them in scripts\n\n // add this interaction to the collection of last interactions\n this.lastInteractions.set(interaction.id, interaction);\n\n // defer reply for all other interaction types to be hadled later\n if (interaction.isRepliable() && !interaction.deferred) {\n await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral });\n }\n }\n\n // raw states enabled?\n if (this.adapter.config.enableRawStates) {\n // set raw state... not async here since it should not block!\n const interactionJson = interaction.toJSON() as Record;\n if (interaction.isCommand()) {\n interactionJson.options = interaction.options.data;\n }\n this.adapter.setState('raw.interactionJson', JSON.stringify(interactionJson, (_key, value) => typeof value === 'bigint' ? value.toString() : value), true);\n }\n\n // remove outdated interactions\n const outdatedTs = Date.now() - 15 * 60000; // 15 min\n const removedInteractions = this.lastInteractions.sweep((ia) => ia.createdTimestamp < outdatedTs);\n if (removedInteractions > 0) {\n this.adapter.log.debug(`Removed ${removedInteractions} outdated interactions from cache`);\n }\n }\n\n /**\n * Handle command interactions.\n */\n private async handleCommandInteraction (interaction: CommandInteraction): Promise {\n const { commandName, user } = interaction;\n\n if (!this.registerCommandsDone) {\n this.adapter.log.warn(`Got command ${commandName} but command registration is not done yet.`);\n return;\n }\n\n this.adapter.log.debug(`Got command ${commandName} ${JSON.stringify(interaction.options.data)}`);\n\n const authCheckTarget = interaction.member instanceof GuildMember ? interaction.member : user;\n\n if (commandName === this.cmdGetStateName) {\n // check user authorization\n if (this.adapter.checkUserAuthorization(authCheckTarget, { getStates: true })) {\n // user authorized\n await this.handleCmdGetState(interaction);\n } else {\n // user not authorized\n this.adapter.log.warn(`User ${userNameOrTag(user)} (id:${user.id}) is not authorized to call /${commandName} commands!`);\n await interaction.reply({\n content: i18n.getString('You are not authorized to call this command!'),\n ephemeral: true,\n });\n }\n\n } else if (commandName === this.cmdSetStateName) {\n // check user authorization\n if (this.adapter.checkUserAuthorization(authCheckTarget, { setStates: true })) {\n // user authorized\n await this.handleCmdSetState(interaction);\n } else {\n // user not authorized\n this.adapter.log.warn(`User ${userNameOrTag(user)} (id:${user.id}) is not authorized to call /${commandName} commands!`);\n await interaction.reply({\n content: i18n.getString('You are not authorized to call this command!'),\n ephemeral: true,\n });\n }\n\n } else if (this.customCommands.has(commandName)) {\n // check user authorization\n if (this.adapter.checkUserAuthorization(authCheckTarget, { useCustomCommands: true })) {\n // user authorized\n await this.handleCmdCustom(interaction);\n } else {\n // user not authorized\n this.adapter.log.warn(`User ${userNameOrTag(user)} (id:${user.id}) is not authorized to call /${commandName} commands!`);\n await interaction.reply({\n content: i18n.getString('You are not authorized to call this command!'),\n ephemeral: true,\n });\n }\n\n } else {\n this.adapter.log.warn(`Got unknown command ${commandName}!`);\n await interaction.editReply(i18n.getString('Unknown command!'));\n }\n }\n\n /**\n * Handle autocomplete for command interactions.\n */\n private async handleAutocompleteInteraction (interaction: AutocompleteInteraction): Promise {\n const { commandName, user } = interaction;\n\n const focused = interaction.options.getFocused(true);\n let focusedValue: string;\n if (typeof focused.value !== 'string') {\n return interaction.respond([]);\n } else {\n focusedValue = focused.value.toLowerCase();\n }\n\n // check authorization\n const authCheckTarget = interaction.member instanceof GuildMember ? interaction.member : user;\n\n let choices: CommandOptionChoiceData[];\n\n if (commandName === this.cmdGetStateName) {\n // get state command\n if (!this.adapter.checkUserAuthorization(authCheckTarget, { getStates: true })) {\n return interaction.respond([]);\n }\n\n choices = this.cmdGetStateChoices;\n\n } else if (commandName === this.cmdSetStateName) {\n // set state command\n if (!this.adapter.checkUserAuthorization(authCheckTarget, { setStates: true })) {\n return interaction.respond([]);\n }\n\n choices = this.cmdSetStateChoices;\n\n } else if (this.customCommands.has(commandName)) {\n // custom command\n if (!this.adapter.checkUserAuthorization(authCheckTarget, { useCustomCommands: true })) {\n return interaction.respond([]);\n }\n\n choices = this.customCommands.get(commandName)?.get(focused.name) ?? [];\n\n } else {\n // unknown command\n return interaction.respond([]);\n }\n\n // filter for given input\n const matchedChoices = choices.filter((choice) => {\n return choice.name.normalize('NFKC').toLowerCase().includes(focusedValue)\n || choice.value.normalize('NFKC').toLowerCase().includes(focusedValue);\n });\n\n // max. 25 choices are allowed\n matchedChoices.splice(25);\n\n return interaction.respond(matchedChoices);\n }\n\n /**\n * Try to get the ioBroker object and CommandObjectConfig for a given object alias.\n * The object will be checked if it's a valid state object.\n *\n * In case of an error, a reply will be sent to the interaction.\n * @param objAlias The alias of the object.\n * @param interaction The interaction for replies on errors.\n * @returns Array containing the object and the config or null and null.\n */\n private async getObjectAndCfgFromAlias (objAlias: string | null, interaction: CommandInteraction): Promise<[ioBroker.StateObject | null, CommandObjectConfig | null]> {\n // find the config for the requested object\n const cfg = this.commandObjectConfig.find((coc) => coc.alias === objAlias);\n if (!cfg) {\n if (interaction.replied) {\n await interaction.editReply({\n content: i18n.getString('Object `%s` not found!', objAlias ?? ''),\n });\n } else {\n await interaction.reply({\n content: i18n.getString('Object `%s` not found!', objAlias ?? ''),\n ephemeral: true,\n });\n }\n return [null, null];\n }\n\n // get the object\n const obj = await this.adapter.getForeignObjectAsync(cfg.id);\n if (!obj) {\n if (interaction.replied) {\n await interaction.editReply({\n content: i18n.getString('Object `%s` not found!', cfg.id),\n });\n } else {\n await interaction.reply({\n content: i18n.getString('Object `%s` not found!', cfg.id),\n ephemeral: true,\n });\n }\n return [null, null];\n }\n if (obj.type !== 'state') {\n if (interaction.replied) {\n await interaction.editReply({\n content: i18n.getString('Object `%s` is not of type state!', cfg.id),\n });\n } else {\n await interaction.reply({\n content: i18n.getString('Object `%s` is not of type state!', cfg.id),\n ephemeral: true,\n });\n }\n return [null, null];\n }\n\n return [obj, cfg];\n }\n\n /**\n * Handler for \"get state\" slash commands.\n * @param interaction The interaction which triggered this.\n */\n private async handleCmdGetState (interaction: CommandInteraction): Promise {\n const objAlias = interaction.options.get('state', true).value as string;\n\n const [obj, cfg] = await this.getObjectAndCfgFromAlias(objAlias, interaction);\n if (!obj || !cfg) {\n return;\n }\n\n const objCustom: ioBroker.CustomConfig | undefined = obj.common.custom?.[this.adapter.namespace];\n\n // check if get allowed\n if (!objCustom?.commandsAllowGet) {\n await interaction.reply({\n content: i18n.getString('Get not allowed for state `%s`!', cfg.id),\n ephemeral: true,\n });\n return;\n }\n\n // get the state\n const state = await this.adapter.getForeignStateAsync(cfg.id);\n if (!state) {\n await interaction.reply({\n content: i18n.getString('State `%s` not found!', cfg.id),\n ephemeral: true,\n });\n return;\n }\n\n // defer the reply to have more time\n if (!interaction.deferred) {\n await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral });\n }\n\n // get the value depending on the state type\n let val: string = '';\n\n // an optional MessageOptions object for special cases (like sending files)\n let msgOpts: MessageCreateOptions | undefined = undefined;\n\n // add unit if defined in the object\n const unit = obj.common.unit ? ` ${obj.common.unit}` : '';\n\n // add info about missing ack flag if configured so\n const ack = objCustom.commandsShowAckFalse && !state.ack ? ` (_${i18n.getString('not acknowledged')}_)` : '';\n\n if (obj.common.role === 'date' && ((obj.common.type === 'string' && typeof state.val === 'string') || (obj.common.type === 'number' && typeof state.val === 'number'))) {\n // date values\n const d = new Date(state.val);\n val = d.toLocaleString(i18n.language, { dateStyle: 'full', timeStyle: 'long' });\n\n } else if (obj.common.type === 'string' && objCustom.commandsStringSendAsFile && typeof state.val === 'string') {\n // path or url to file or base64 encoded file\n const b64data = getBufferAndNameFromBase64String(state.val);\n if (b64data) {\n // base64 encoded content\n\n msgOpts = {\n content: `${cfg.name}${ack}:`,\n files: [{\n attachment: b64data.buffer,\n name: b64data.name,\n }],\n };\n val = 'file:base64';\n\n } else {\n // file path or url\n\n // remove file:// prefix\n if (state.val.startsWith('file://')) {\n state.val = state.val.slice(7);\n }\n\n msgOpts = {\n content: `${cfg.name}${ack}:`,\n files: [{\n attachment: state.val,\n name: getBasenameFromFilePathOrUrl(state.val),\n }],\n };\n val = `file:${state.val}`;\n }\n\n } else {\n // non special value\n switch (obj.common.type) {\n case 'boolean':\n if (state.val) {\n val = objCustom.commandsBooleanValueTrue ?? i18n.getString('true');\n } else {\n val = objCustom.commandsBooleanValueFalse ?? i18n.getString('false');\n }\n break;\n\n case 'number':\n // number values\n const decimals = objCustom.commandsNumberDecimals ?? 0;\n if (typeof state.val === 'number') {\n val = state.val.toFixed(decimals);\n } else if (state.val === null) {\n val = '_NULL_';\n } else {\n val = state.val.toString() || 'NaN';\n }\n if (i18n.isFloatComma) {\n val = val.replace('.', ',');\n }\n break;\n\n default:\n if (typeof state.val === 'string') {\n val = state.val;\n } else if (state.val === null) {\n val = '_NULL_';\n } else {\n val = state.val.toString();\n }\n }\n }\n\n this.adapter.log.debug(`Get command for ${cfg.id} - ${val}${unit}${ack}`);\n\n // send the value as reply to the user\n try {\n if (msgOpts) {\n // message\n await interaction.editReply(msgOpts);\n } else {\n // just text\n await interaction.editReply(`${cfg.name}: ${val}${unit}${ack}`);\n }\n } catch (err) {\n this.adapter.log.warn(`Error sending interaction reply for /${this.cmdGetStateName} command! ${err}`);\n }\n }\n\n /**\n * Handler for \"set state\" slash commands.\n * @param interaction The interaction which triggered this.\n */\n private async handleCmdSetState (interaction: CommandInteraction): Promise {\n const objAlias = interaction.options.get('state', true).value as string;\n\n const [obj, cfg] = await this.getObjectAndCfgFromAlias(objAlias, interaction);\n if (!obj || !cfg) {\n return;\n }\n\n const objCustom: ioBroker.CustomConfig | undefined = obj.common.custom?.[this.adapter.namespace];\n\n // check if set allowed\n if (!objCustom?.commandsAllowSet) {\n await interaction.reply({\n content: i18n.getString('Set not allowed for state `%s`!', cfg.id),\n ephemeral: true,\n });\n return;\n }\n\n let valueStr = interaction.options.get('value')?.value;\n if (typeof valueStr !== 'string') {\n await interaction.reply({\n content: i18n.getString('No value provided!'),\n ephemeral: true,\n });\n return;\n }\n\n // defer the reply to have more time\n if (!interaction.deferred) {\n await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral });\n }\n\n valueStr = valueStr.trim();\n\n // add unit if defined in the object\n const unit = obj.common.unit ? ` ${obj.common.unit}` : '';\n\n let value: string | number | boolean;\n let valueReply: string;\n\n switch (obj.common.type) {\n case 'boolean':\n // parse as boolean value\n valueStr = valueStr.toLowerCase();\n if (valueStr === objCustom.commandsBooleanValueTrue?.toLowerCase() || this.wellKnownbooleanTrueValues.has(valueStr)) {\n // true value form configures custom value or from well known boolean true values\n value = true;\n valueReply = objCustom.commandsBooleanValueTrue ?? i18n.getString('true');\n } else {\n // false value\n value = false;\n valueReply = objCustom.commandsBooleanValueFalse ?? i18n.getString('false');\n }\n break;\n\n case 'number':\n // parse as number (float) value\n if (i18n.isFloatComma) {\n valueStr = valueStr.replace(',', '.');\n }\n value = parseFloat(valueStr);\n\n if (isNaN(value)) {\n await interaction.editReply(i18n.getString('The given value is not a number!'));\n return;\n }\n\n valueReply = value.toString();\n if (i18n.isFloatComma) {\n valueReply = valueReply.replace('.', ',');\n }\n\n // check min and max if configured\n if (typeof obj.common.min === 'number' && value < obj.common.min) {\n let min = obj.common.min.toString();\n if (i18n.isFloatComma) {\n min = min.replace('.', ',');\n }\n await interaction.editReply(i18n.getString('Value %s is below the allowed minimum of %s!', `${valueReply}${unit}`, `${min}${unit}`));\n return;\n }\n if (typeof obj.common.max === 'number' && value > obj.common.max) {\n let max = obj.common.max.toString();\n if (i18n.isFloatComma) {\n max = max.replace('.', ',');\n }\n await interaction.editReply(i18n.getString('Value %s is above the allowed maximum of %s!', `${valueReply}${unit}`, `${max}${unit}`));\n return;\n }\n\n break;\n\n default:\n // string values\n value = valueStr;\n valueReply = valueStr;\n }\n\n this.adapter.log.debug(`Set command for ${cfg.id} - ${value}${unit}`);\n\n // set the state\n try {\n await this.adapter.setForeignStateAsync(cfg.id, value, !!objCustom.commandsSetWithAck);\n } catch (err) {\n this.adapter.log.warn(`Error while setting state ${cfg.id} to ${value}! ${err}`);\n await interaction.editReply(i18n.getString('Error while setting the state value!'));\n return;\n }\n\n // send reply\n await interaction.editReply(`${cfg.name}: ${valueReply}${unit}`);\n }\n\n /**\n * Handler for custom slash commands.\n * @param interaction The interaction which triggered this.\n */\n private async handleCmdCustom (interaction: CommandInteraction): Promise {\n const {\n commandName,\n channelId,\n guildId,\n user,\n options,\n } = interaction;\n\n // get the related custom command config\n const cmdCfg = this.adapter.config.customCommands.find((c) => c.name === commandName);\n if (!cmdCfg) return; // should never happen, but to be sure\n\n // defer the reply to have more time\n if (!interaction.deferred) {\n await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral });\n }\n\n // add this interaction to the collection of last interactions\n this.lastInteractions.set(interaction.id, interaction);\n\n // promises for all set state actions\n const proms: Promise[] = [];\n\n // prepare json data\n const json: JsonSlashCommandObj = {\n interactionId: interaction.id,\n commandName,\n channelId,\n serverId: guildId ?? null,\n user: {\n id: user.id,\n tag: user.tag,\n name: user.username,\n displayName: interaction.member instanceof GuildMember ? interaction.member.displayName : user.username,\n },\n timestamp: interaction.createdTimestamp,\n options: {},\n };\n\n // loop over configured options and prepare data ... options.data* may not be set for optional options\n for (const optCfg of cmdCfg.options) {\n const opt = options.data.find((o) => o.name === optCfg.name);\n if (opt) {\n json.options[optCfg.name] = {\n value: opt.value ?? null,\n type: ApplicationCommandOptionType[opt.type],\n };\n\n if (opt.user instanceof User) {\n json.options[optCfg.name].user = {\n id: opt.user.id,\n tag: opt.user.tag,\n name: opt.user.username,\n bot: opt.user.bot,\n };\n }\n if (opt.member instanceof GuildMember) {\n json.options[optCfg.name].member = {\n id: opt.member.id,\n tag: opt.member.user.tag,\n name: opt.member.user.username,\n displayName: opt.member.displayName,\n roles: opt.member.roles.cache.map((r) => ({ id: r.id, name: r.name })),\n };\n }\n if (opt.role instanceof Role) {\n json.options[optCfg.name].role = {\n id: opt.role.id,\n name: opt.role.name,\n };\n }\n if (opt.channel instanceof GuildChannel) {\n json.options[optCfg.name].channel = {\n id: opt.channel.id,\n name: opt.channel.name,\n type: ChannelType[opt.channel.type] as ChannelTypeNames,\n lastMessageId: (opt.channel.type === ChannelType.GuildText || opt.channel.type == ChannelType.GuildVoice) ? opt.channel.lastMessageId : null,\n };\n }\n } else {\n json.options[optCfg.name] = {\n value: null,\n type: null,\n };\n }\n proms.push(this.adapter.setStateAsync(`slashCommands.${commandName}.option-${optCfg.name}.value`, json.options[optCfg.name].value, true));\n }\n\n // set the states\n await Promise.all([\n this.adapter.setStateAsync(`slashCommands.${commandName}.interactionId`, interaction.id, true),\n this.adapter.setStateAsync(`slashCommands.${commandName}.channelId`, channelId, true),\n this.adapter.setStateAsync(`slashCommands.${commandName}.serverId`, guildId ?? null, true),\n this.adapter.setStateAsync(`slashCommands.${commandName}.userId`, user.id, true),\n this.adapter.setStateAsync(`slashCommands.${commandName}.userTag`, user.tag, true),\n this.adapter.setStateAsync(`slashCommands.${commandName}.userName`, user.username, true),\n this.adapter.setStateAsync(`slashCommands.${commandName}.timestamp`, interaction.createdTimestamp, true),\n this.adapter.setStateAsync(`slashCommands.${commandName}.json`, JSON.stringify(json), true),\n ...proms,\n ]);\n\n /*****\n * Hint: Interaction reply is deferred, but no reply will be send here.\n * The reply must be triggered by the user using the .sendReply state or a `sendTo(...)` action.\n *****/\n }\n\n /**\n * Send a reply to a custom slash command.\n * @param interactionId The ID of the interaction to reply to. The interactions needs to be cached in this instance.\n * @param msg The message to reply with. May be a simple string, a MessageOptions object or a stringified JSON MessageOptions object.\n * @returns Promise which resolves withe the ID of the reply message if the reply is sent.\n * @throws Error if the reply could not be sent for some reason (i.e. some check failed).\n */\n public async sendCmdCustomReply (interactionId: Snowflake, msg: string | MessageCreateOptions): Promise {\n // get the interaction\n const interaction = this.lastInteractions.get(interactionId);\n\n if (!interaction) {\n throw new Error(`No current interaction with ID ${interactionId} found for reply!`);\n }\n\n let cscTxt: string = '';\n\n if (interaction.isCommand()) {\n // command interaction\n const { commandName } = interaction;\n\n const cmdCfg = this.adapter.config.customCommands.find((c) => c.name === commandName);\n if (!cmdCfg) {\n throw new Error(`No configuration for custom slash command ${commandName} of interaction ${interactionId} found for reply!`);\n }\n\n cscTxt = ` of custom slash command ${commandName}`;\n }\n\n if (!interaction.isRepliable()) {\n throw new Error(`Interaction ${interactionId}${cscTxt} is not repliable!`);\n }\n\n // if a string is given try to parse it and prepare it as MessageOptions object\n if (typeof msg === 'string') {\n try {\n msg = this.adapter.parseStringifiedMessageOptions(msg);\n } catch (err) {\n throw new Error(`Reply to interaction ${interactionId}${cscTxt} is invalid: ${err}`);\n }\n }\n\n // send the reply\n const replyMsg = await interaction.editReply(msg);\n return replyMsg.id;\n }\n\n /**\n * Write a summay of all currently for commands configured objects to the log.\n */\n public logConfiguredCommandObjects (): void {\n this.adapter.log.info('Configured state objects for discord slash commands:');\n for (const [, cmdObjCfg] of this.commandObjectConfig) {\n this.adapter.log.info(` |- ${cmdObjCfg.id} - alias:${cmdObjCfg.alias}, name:${cmdObjCfg.name}, get:${cmdObjCfg.get}, set:${cmdObjCfg.set}`);\n }\n this.adapter.log.info('---');\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["import { isDeepStrictEqual } from 'node:util';\n\nimport { boundMethod } from 'autobind-decorator';\n\nimport {\n ApplicationCommandOptionType,\n AutocompleteInteraction,\n CacheType,\n ChannelType,\n Collection,\n CommandInteraction,\n DiscordAPIError,\n Guild,\n GuildChannel,\n GuildMember,\n Interaction,\n MessageCreateOptions,\n Role,\n Snowflake,\n User,\n} from 'discord.js';\nimport { SlashCommandBuilder } from '@discordjs/builders';\nimport { REST } from '@discordjs/rest';\nimport { Routes } from 'discord-api-types/v10';\n\nimport type { DiscordAdapter } from './main';\nimport { i18n } from './lib/i18n';\nimport {\n getBasenameFromFilePathOrUrl,\n getBufferAndNameFromBase64String,\n userNameOrTag,\n} from './lib/utils';\nimport { ChannelTypeNames, JsonSlashCommandObj } from './lib/definitions';\n\nexport interface CommandObjectConfig {\n id: string;\n alias: string;\n name: string;\n get: boolean;\n set: boolean;\n}\n\ninterface CommandOptionChoiceData {\n name: string;\n value: string;\n}\n\n/**\n * Class for discord slash commands handling\n */\nexport class DiscordAdapterSlashCommands {\n\n /**\n * Reference to the adapter instance.\n */\n private adapter: DiscordAdapter;\n\n /**\n * Discord REST api interface.\n */\n private rest: REST = new REST({ version: '10' });\n\n /**\n * Command name for the get state command.\n */\n private cmdGetStateName: string = 'iob-get';\n\n /**\n * Command name for the set state command.\n */\n private cmdSetStateName: string = 'iob-set';\n\n /**\n * Possible choices for get state command state-option.\n */\n private cmdGetStateChoices: CommandOptionChoiceData[] = [];\n\n /**\n * Possible choices for set state command state-option.\n */\n private cmdSetStateChoices: CommandOptionChoiceData[] = [];\n\n /**\n * Collection of the known (registered) custom commands and their option choices.\n */\n private customCommands: Collection> = new Collection>();\n\n /**\n * If commands are fully registered including their permissions.\n */\n private registerCommandsDone: boolean = false;\n\n /**\n * The last registered commands.\n * Used to check if something changed an we need to register the commands again.\n */\n private lastCommandsJson: unknown[] | null = null;\n\n /**\n * Collection of configurations for objects with commands enabled.\n */\n private commandObjectConfig: Collection = new Collection();\n\n /**\n * Collection of the last seen interactions of custom commands (not iob-get/-set)\n * or other interactions which are not directly handled by the adapter.\n *\n * Need to cache this here since there seems to be no way to get an interaction\n * by ID from discord.js.\n */\n private lastInteractions: Collection | Interaction> = new Collection | Interaction>();\n\n /**\n * Timeout to trigger the delayed registration of the slash commands.\n */\n private triggerDelayedRegisterSlashCommandsTimeout: ioBroker.Timeout | null = null;\n\n /**\n * Set of well known values that will be interperted as true.\n * This is extended by some localized strings at runtime.\n * Used to determine true values from iob-set slash commands.\n */\n private wellKnownbooleanTrueValues: Set = new Set([ 'true', 'on', 'yes', '1' ]);\n\n constructor (adapter: DiscordAdapter) {\n this.adapter = adapter;\n }\n\n /**\n * When the adapter is Ready.\n * Called by `adapter.onReady()` after some basic checks and setup.\n */\n // eslint-disable-next-line @typescript-eslint/require-await\n public async onReady (): Promise {\n // apply custom command names if configured\n if (this.adapter.config.cmdGetStateName) {\n if (/^[a-z][0-9a-z-_]{1,32}$/.exec(this.adapter.config.cmdGetStateName)) {\n this.cmdGetStateName = this.adapter.config.cmdGetStateName;\n } else {\n this.adapter.log.warn(`Invalid custom get state command name '${this.adapter.config.cmdGetStateName}' provied! Using default 'iob-get'.`);\n }\n }\n if (this.adapter.config.cmdSetStateName) {\n this.cmdSetStateName = this.adapter.config.cmdSetStateName;\n if (/^[a-z][0-9a-z-_]{1,32}$/.exec(this.adapter.config.cmdSetStateName)) {\n this.cmdSetStateName = this.adapter.config.cmdSetStateName;\n } else {\n this.adapter.log.warn(`Invalid custom set state command name '${this.adapter.config.cmdSetStateName}' provied! Using default 'iob-set'.`);\n }\n }\n\n // setup REST interface\n this.rest.setToken(this.adapter.config.token);\n\n // check if commands are enabled\n if (!this.adapter.config.enableCommands) {\n return;\n }\n\n // add translated versions of true/on/yes to the set of well known boolean true values\n this.wellKnownbooleanTrueValues.add(i18n.getString('true'))\n .add(i18n.getString('on'))\n .add(i18n.getString('yes'));\n\n // setup interaction handler for commands\n if (!this.adapter.client) {\n throw new Error('Tried to setup interaction handler for commands, but client is not initialized!');\n }\n this.adapter.client.on('interactionCreate', this.onInteractionCreate);\n }\n\n /**\n * Register the commands on discord, if enabled.\n */\n public async registerSlashCommands (): Promise {\n this.registerCommandsDone = false;\n\n if (!this.adapter.client?.user) {\n throw new Error('Discord client not available');\n }\n\n if (this.adapter.unloaded) return;\n\n // check if commands are enabled and if not remove set commands\n if (!this.adapter.config.enableCommands) {\n this.adapter.log.debug('Commands not enabled');\n\n // check for commands and remove them all\n for (const [ , guild ] of this.adapter.client.guilds.cache) {\n await this.removeGuildCommands(guild);\n }\n\n await this.removeGlobalCommands();\n\n return;\n }\n\n // build commands array\n const commands: SlashCommandBuilder[] = [];\n\n const numGet = this.commandObjectConfig.filter((c) => c.get === true).size;\n const numSet = this.commandObjectConfig.filter((c) => c.set === true).size;\n\n // setup iob-get command if objects configured for get\n if (numGet > 0) {\n const cmdGet = new SlashCommandBuilder()\n .setName(this.cmdGetStateName)\n .setDescription(i18n.getString('Get an ioBroker state value'));\n\n // add options\n cmdGet.addStringOption((opt) => (\n opt.setName('state')\n .setDescription(i18n.getString('The ioBroker state to get'))\n .setRequired(true)\n .setAutocomplete(true)\n ));\n\n commands.push(cmdGet);\n }\n\n // setup iob-set command if objects configured for set\n if (numSet > 0) {\n const cmdSet = new SlashCommandBuilder()\n .setName(this.cmdSetStateName)\n .setDescription(i18n.getString('Set an ioBroker state value'));\n\n cmdSet.addStringOption((opt) => (\n opt.setName('state')\n .setDescription(i18n.getString('The ioBroker state to set'))\n .setRequired(true)\n .setAutocomplete(true)\n ));\n cmdSet.addStringOption((opt) => {\n return opt.setName('value')\n .setDescription(i18n.getString('The value to set'))\n .setRequired(true);\n });\n\n commands.push(cmdSet);\n }\n\n // setup choices for get and set commands\n this.cmdGetStateChoices = [];\n this.cmdSetStateChoices = [];\n for (const [ , objCfg ] of this.commandObjectConfig) {\n if (objCfg.get) {\n this.cmdGetStateChoices.push({\n name: objCfg.name,\n value: objCfg.alias,\n });\n }\n if (objCfg.set) {\n this.cmdSetStateChoices.push({\n name: objCfg.name,\n value: objCfg.alias,\n });\n }\n }\n\n // sort choices for get and set commands\n const sortFn = (a: CommandOptionChoiceData, b: CommandOptionChoiceData): -1 | 0 | 1 => {\n if (a.name > b.name) return 1;\n if (a.name < b.name) return -1;\n return 0;\n };\n this.cmdGetStateChoices.sort(sortFn);\n this.cmdSetStateChoices.sort(sortFn);\n\n // custom commands\n this.customCommands.clear();\n if (this.adapter.config.enableCustomCommands) {\n loopCustomCommands:\n for (const customCommandCfg of this.adapter.config.customCommands) {\n if (!(/^[a-z][0-9a-z-_]{1,32}$/.exec(customCommandCfg.name)) || customCommandCfg.description.length === 0 || customCommandCfg.description.length > 100) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" has an invalid name or description configured!`);\n continue;\n }\n\n if (customCommandCfg.name === this.cmdGetStateName) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" is configured but conflicts with default get command! The command will be ignored.`);\n continue;\n }\n if (customCommandCfg.name === this.cmdSetStateName) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" is configured but conflicts with default set command! The command will be ignored.`);\n continue;\n }\n\n if (this.customCommands.has(customCommandCfg.name)) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" is configured multiple times! The command will be ignored.`);\n continue;\n }\n\n // create the command\n const cmdCustom = new SlashCommandBuilder()\n .setName(customCommandCfg.name)\n .setDescription(customCommandCfg.description);\n\n const optionsChoices = new Collection();\n\n // add configured options\n const cmdOpts: Set = new Set();\n if (Array.isArray(customCommandCfg.options)) {\n // max 25 options are allowed\n if (customCommandCfg.options.length > 25) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" has more than 25 options configured! Only the first 25 options will be used.`);\n customCommandCfg.options.splice(25);\n }\n } else {\n customCommandCfg.options = [];\n }\n\n // create/update the ioBroker objects\n await this.setupCustomCommandIobObjects(customCommandCfg);\n\n for (const customCommandCfgOpt of customCommandCfg.options) {\n if (!(/^[a-z][0-9a-z-_]{1,32}$/.exec(customCommandCfgOpt.name)) || customCommandCfgOpt.description.length === 0 || customCommandCfgOpt.description.length > 100) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" option \"${customCommandCfgOpt.name}\" has an invalid name or description configured!`);\n continue loopCustomCommands;\n }\n\n if (cmdOpts.has(customCommandCfgOpt.name)) {\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" option \"${customCommandCfgOpt.name}\" is configured multiple times! The command will be ignored.`);\n continue loopCustomCommands;\n }\n cmdOpts.add(customCommandCfgOpt.name);\n\n switch (customCommandCfgOpt.type) {\n case 'string': {\n // string options may have choices from the ioBroker object\n let choices: (string | CommandOptionChoiceData)[] = [];\n try {\n const val = (await this.adapter.getStateAsync(`slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices`))?.val ?? '[]';\n if (typeof val !== 'string') {\n this.adapter.log.warn(`Value of ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices is not a string!`);\n } else {\n choices = JSON.parse(val) as (string | CommandOptionChoiceData)[];\n }\n } catch (err) {\n this.adapter.log.warn(`Could not parse JSON from ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices! ${err}`);\n }\n\n optionsChoices.set(customCommandCfgOpt.name, choices.map((choice) => {\n if (typeof choice === 'string' && choice.length >= 1 && choice.length <= 100) {\n return { name: choice, value: choice };\n } else if (typeof choice === 'object' && typeof choice.value === 'string' && typeof choice.name === 'string' && choice.name.length >= 1 && choice.name.length <= 100 && choice.value.length <= 100) {\n return { name: choice.name, value: choice.value };\n } else {\n this.adapter.log.warn(`Choice ${JSON.stringify(choice)} is not valid for ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices and will be ignored!`);\n return null;\n }\n }).filter((choice) => choice !== null) as CommandOptionChoiceData[]);\n\n cmdCustom.addStringOption((opt) => {\n opt.setName(customCommandCfgOpt.name)\n .setDescription(customCommandCfgOpt.description)\n .setRequired(!!customCommandCfgOpt.required);\n\n if (choices.length > 0) {\n opt.setAutocomplete(true);\n }\n\n return opt;\n });\n break;\n }\n\n case 'number':\n cmdCustom.addNumberOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'boolean':\n cmdCustom.addBooleanOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'user':\n cmdCustom.addUserOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'role':\n cmdCustom.addRoleOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'channel':\n cmdCustom.addChannelOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n case 'mentionable':\n cmdCustom.addMentionableOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required));\n break;\n\n default:\n this.adapter.log.warn(`Custom command \"${customCommandCfg.name}\" option \"${customCommandCfgOpt.name} has an invalid type set\"!`);\n continue loopCustomCommands;\n }\n }\n\n // add custom command to the commands\n commands.push(cmdCustom);\n this.customCommands.set(customCommandCfg.name, optionsChoices);\n }\n\n /*\n * find and delete old custom slash command objects\n */\n const objListSlashCommands = await this.adapter.getObjectListAsync({\n startkey: `${this.adapter.namespace}.slashCommands.`,\n endkey: `${this.adapter.namespace}.slashCommands.\\u9999`,\n });\n const re = new RegExp(`^${this.adapter.name}\\\\.${this.adapter.instance}\\\\.slashCommands\\\\.([^.]+)$`);\n for (const item of objListSlashCommands.rows) {\n const m = item.id.match(re);\n if (m) {\n const cmdName = m[1];\n if (!this.customCommands.has(cmdName)) {\n this.adapter.log.debug(`Custom slash command ${cmdName} is not configured - deleting objects`);\n await this.adapter.delObjectAsyncCached(`slashCommands.${cmdName}`, { recursive: true });\n }\n }\n }\n }\n\n // check if any command is set and log an warning if not\n if (commands.length === 0) {\n if (this.adapter.config.enableCustomCommands) {\n this.adapter.log.warn('Commands are enabled but not configured for any state object and no custom commands are configured! Use the custom configuration of a state object to activate commands on it or add custom commands in the adapter instance configuration.');\n } else {\n this.adapter.log.warn('Commands are enabled but not configured for any state object! Use the custom configuration of a state object to activate commands on it.');\n }\n }\n\n const commandsJson = commands.map((cmd) => cmd.toJSON());\n\n // only update the commands if something has changed\n if (!isDeepStrictEqual(commandsJson, this.lastCommandsJson)) {\n this.adapter.log.debug('Commands needs to be updated');\n\n // register commands for all servers of the bot (guild commands are applied instant and may have permissions per user set)\n for (const [ , guild ] of this.adapter.client.guilds.cache) {\n try {\n if (this.adapter.config.commandsGlobal) {\n // global commands enabled, remove per guild commands\n await this.removeGuildCommands(guild);\n\n } else {\n // commands per guild\n await this.rest.put(Routes.applicationGuildCommands(this.adapter.client.user.id, guild.id), { body: commandsJson });\n this.adapter.log.info(`Registered commands for server ${guild.name} (id:${guild.id}) (get: ${numGet}, set: ${numSet}, custom: ${this.customCommands.size})`);\n }\n\n } catch (err) {\n if (err instanceof DiscordAPIError && err.message === 'Missing Access') {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n this.adapter.log.warn(`Error registering commands for server ${guild.name} (id:${guild.id}). Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`);\n } else {\n this.adapter.log.warn(`Error registering commands for server ${guild.name} (id:${guild.id}): ${err}`);\n }\n }\n }\n\n // register global commands if enabled\n try {\n if (this.adapter.config.commandsGlobal) {\n // global commands enabled\n await this.rest.put(Routes.applicationCommands(this.adapter.client.user.id), { body: commandsJson });\n this.adapter.log.info(`Registered global commands (get: ${numGet}, set: ${numSet}, custom: ${this.customCommands.size})`);\n\n } else {\n // global command disabled\n await this.removeGlobalCommands();\n }\n\n } catch (err) {\n if (err instanceof DiscordAPIError && err.message === 'Missing Access') {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n this.adapter.log.warn(`Error registering global commands. Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`);\n } else {\n this.adapter.log.warn(`Error registering global commands: ${err}`);\n }\n }\n\n // cache the commandsJson for the next call of `registerSlashCommands()`\n this.lastCommandsJson = commandsJson;\n\n } else {\n this.adapter.log.debug('Commands seams to be up to date');\n }\n\n this.registerCommandsDone = true;\n }\n\n /**\n * Setup an ioBroker object for discord slash commands.\n * @param objId ID of the ioBroker object to set up.\n * @param cfg Command configuration for the ioBroker object or null to remove a possibly existing configuration.\n */\n public setupCommandObject (objId: string, cfg: CommandObjectConfig | null): void {\n // check if alias is already in use\n if (cfg) {\n const conflictingAlias = this.commandObjectConfig.find((coc) => coc.alias === cfg?.alias && coc.id !== cfg.id);\n if (conflictingAlias) {\n this.adapter.log.warn(`Command alias ${cfg.alias} of object ${cfg.id} already in use by object ${conflictingAlias.id}! ${cfg.id} will be ignored.`);\n cfg = null;\n }\n }\n\n // remove if commands are not enabled or alias conflict\n if (!cfg) {\n if (this.commandObjectConfig.has(objId)) {\n this.commandObjectConfig.delete(objId);\n this.triggerDelayedRegisterSlashCommands();\n }\n return;\n }\n\n // update only if changed\n const currentCfg = this.commandObjectConfig.get(objId);\n if (!isDeepStrictEqual(cfg, currentCfg)) {\n this.adapter.log.debug(`Update command configuration for ${objId}: ${JSON.stringify(cfg)}`);\n this.commandObjectConfig.set(objId, cfg);\n this.triggerDelayedRegisterSlashCommands();\n }\n }\n\n /**\n * Initialize a delayed registration of the slash commands.\n * Calls `registerSlashCommands()` five seconds after the last call of this method.\n * If called again within the five seconds the timeout starts again.\n *\n * This is used to handle object changes better and concat multiple changed\n * object configurations into a single API call.\n *\n * If the initial custom objects setup of the adapter isn't done, this method\n * does nothing since the command registration is called during this explicit.\n */\n public triggerDelayedRegisterSlashCommands (): void {\n // do nothing on init\n if (!this.adapter.initialCustomObjectSetupDone) return;\n\n if (this.triggerDelayedRegisterSlashCommandsTimeout) {\n this.adapter.clearTimeout(this.triggerDelayedRegisterSlashCommandsTimeout);\n }\n\n this.adapter.setTimeout(() => {\n this.triggerDelayedRegisterSlashCommandsTimeout = null;\n this.adapter.log.debug('Starting delayed slash commands registration...');\n void this.registerSlashCommands();\n }, 5000);\n }\n\n /**\n * Send a reply to a custom slash command.\n * @param interactionId The ID of the interaction to reply to. The interactions needs to be cached in this instance.\n * @param msg The message to reply with. May be a simple string, a MessageOptions object or a stringified JSON MessageOptions object.\n * @returns Promise which resolves withe the ID of the reply message if the reply is sent.\n * @throws Error if the reply could not be sent for some reason (i.e. some check failed).\n */\n public async sendCmdCustomReply (interactionId: Snowflake, msg: string | MessageCreateOptions): Promise {\n // get the interaction\n const interaction = this.lastInteractions.get(interactionId);\n\n if (!interaction) {\n throw new Error(`No current interaction with ID ${interactionId} found for reply!`);\n }\n\n let cscTxt: string = '';\n\n if (interaction.isCommand()) {\n // command interaction\n const { commandName } = interaction;\n\n const cmdCfg = this.adapter.config.customCommands.find((c) => c.name === commandName);\n if (!cmdCfg) {\n throw new Error(`No configuration for custom slash command ${commandName} of interaction ${interactionId} found for reply!`);\n }\n\n cscTxt = ` of custom slash command ${commandName}`;\n }\n\n if (!interaction.isRepliable()) {\n throw new Error(`Interaction ${interactionId}${cscTxt} is not repliable!`);\n }\n\n // if a string is given try to parse it and prepare it as MessageOptions object\n if (typeof msg === 'string') {\n try {\n msg = this.adapter.parseStringifiedMessageOptions(msg);\n } catch (err) {\n throw new Error(`Reply to interaction ${interactionId}${cscTxt} is invalid: ${err}`);\n }\n }\n\n // send the reply\n const replyMsg = await interaction.editReply(msg);\n return replyMsg.id;\n }\n\n /**\n * Write a summay of all currently for commands configured objects to the log.\n */\n public logConfiguredCommandObjects (): void {\n this.adapter.log.info('Configured state objects for discord slash commands:');\n for (const [ , cmdObjCfg ] of this.commandObjectConfig) {\n this.adapter.log.info(` |- ${cmdObjCfg.id} - alias:${cmdObjCfg.alias}, name:${cmdObjCfg.name}, get:${cmdObjCfg.get}, set:${cmdObjCfg.set}`);\n }\n this.adapter.log.info('---');\n }\n\n /**\n * Remove registered global commands if any.\n */\n private async removeGlobalCommands (): Promise {\n if (!this.adapter.client?.user) {\n throw new Error('Discord client not available');\n }\n\n try {\n const globalCommands = await this.adapter.client.application?.commands.fetch();\n if (this.adapter.unloaded) return;\n\n if (globalCommands && globalCommands.size > 0) {\n this.adapter.log.debug(`Currently ${globalCommands.size} global commands registered. Removing them...`);\n await this.rest.put(Routes.applicationCommands(this.adapter.client.user.id), { body: [] });\n this.adapter.log.info(`Removed global commands cause commands they are not used anymore.`);\n }\n } catch (err) {\n if (err instanceof DiscordAPIError && err.message === 'Missing Access') {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n this.adapter.log.warn(`Error while removing registered global commands. Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`);\n } else {\n this.adapter.log.warn(`Error while removing registered global commands: ${err}`);\n }\n }\n }\n\n /**\n * Remove registered guild commands if any.\n * @param guild The guild.\n */\n private async removeGuildCommands (guild: Guild): Promise {\n if (!this.adapter.client?.user) {\n throw new Error('Discord client not available');\n }\n\n try {\n const guildCommands = await guild.commands.fetch();\n if (this.adapter.unloaded) return;\n\n if (guildCommands.size > 0) {\n this.adapter.log.debug(`Currently ${guildCommands.size} commands registered for server ${guild.name}. Removing them...`);\n await this.rest.put(Routes.applicationGuildCommands(this.adapter.client.user.id, guild.id), { body: [] });\n this.adapter.log.info(`Removed commands for server ${guild.name} cause commands they are not used anymore.`);\n }\n } catch (err) {\n if (err instanceof DiscordAPIError && err.message === 'Missing Access') {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n this.adapter.log.warn(`Error while removing registered commands for server ${guild.name} (id:${guild.id}). Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`);\n } else {\n this.adapter.log.warn(`Error while removing registered commands for server ${guild.name} (id:${guild.id}): ${err}`);\n }\n }\n }\n\n /**\n * Setup the ioBroker object tree for the configured custom commands.\n */\n private async setupCustomCommandIobObjects (cmdCfg: ioBroker.AdapterConfigCustomCommand): Promise {\n const cmdName = cmdCfg.name;\n\n await this.adapter.extendObjectCached(`slashCommands.${cmdName}`, {\n type: 'channel',\n common: {\n name: cmdCfg.description,\n },\n native: {},\n });\n\n // generic custom command objects\n await Promise.all([\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.json`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.timestamp`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last use timestamp'),\n role: 'date',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.sendReply`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reply'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.interactionId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Interaction ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.userId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.userTag`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User tag'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.userName`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.serverId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Server ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.adapter.extendObjectCached(`slashCommands.${cmdName}.channelId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Channel ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n\n // custom command option objects\n const proms: Promise[] = [];\n for (const cmdCfgOpt of cmdCfg.options) {\n await this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}`, {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Option %s', cmdCfgOpt.description),\n },\n native: {},\n });\n\n let role: string;\n let type: ioBroker.CommonType;\n let def: unknown;\n switch (cmdCfgOpt.type) {\n case 'number':\n role = 'value';\n type = 'number';\n def = null;\n break;\n\n case 'boolean':\n role = 'indicator';\n type = 'boolean';\n def = null;\n break;\n\n default:\n role = 'text';\n type = 'string';\n def = '';\n }\n\n proms.push(this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.value`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Option %s value', cmdCfgOpt.description),\n role,\n type,\n read: true,\n write: false,\n def,\n },\n native: {},\n }));\n\n // for string options add a choices state\n if (cmdCfgOpt.type === 'string') {\n proms.push(this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.choices`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Option %s choices', cmdCfgOpt.description),\n role: 'json',\n type: 'string',\n read: true,\n write: true,\n def: '[]',\n },\n native: {},\n }));\n } else {\n // remove the state for non-string options\n proms.push(this.adapter.delObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.choices`));\n }\n }\n\n // check for unused (old) custom command option objects and remove them\n const objListOptions = await this.adapter.getObjectListAsync({\n startkey: `${this.adapter.namespace}.slashCommands.${cmdName}.option-`,\n endkey: `${this.adapter.namespace}.slashCommands.${cmdName}.option-\\u9999`,\n });\n const reOptionsName = new RegExp(`^${this.adapter.name}\\\\.${this.adapter.instance}\\\\.slashCommands\\\\.${cmdName}\\\\.option-([^.]+)$`);\n for (const item of objListOptions.rows) {\n const m = item.id.match(reOptionsName);\n if (m) {\n const oldoptName = m[1];\n if (!cmdCfg.options.find((o) => o.name === oldoptName)) {\n // option does not exist... delete the object and custom command option choices cache\n proms.push(this.adapter.delObjectAsyncCached(`slashCommands.${cmdName}.option-${oldoptName}`, { recursive: true }));\n this.customCommands.get(cmdName)?.delete(oldoptName);\n }\n }\n }\n\n // wait for object create/delete\n await Promise.all(proms);\n }\n\n /**\n * Handle interactions.\n */\n @boundMethod\n private async onInteractionCreate (interaction: Interaction): Promise {\n if (interaction.isCommand()) {\n // handle command interaction for build in commands and custom commands\n void this.handleCommandInteraction(interaction);\n\n } else if (interaction.isAutocomplete()) {\n // handle auto complete interaction\n void this.handleAutocompleteInteraction(interaction);\n\n } else {\n // handle other interaction types to allow the usage of them in scripts\n\n // add this interaction to the collection of last interactions\n this.lastInteractions.set(interaction.id, interaction);\n\n // defer reply for all other interaction types to be hadled later\n if (interaction.isRepliable() && !interaction.deferred) {\n await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral });\n }\n }\n\n // raw states enabled?\n if (this.adapter.config.enableRawStates) {\n // set raw state... not async here since it should not block!\n const interactionJson = interaction.toJSON() as Record;\n if (interaction.isCommand()) {\n interactionJson.options = interaction.options.data;\n }\n void this.adapter.setState('raw.interactionJson', JSON.stringify(interactionJson, (_key, value: unknown) => typeof value === 'bigint' ? value.toString() : value), true);\n }\n\n // remove outdated interactions\n const outdatedTs = Date.now() - 15 * 60000; // 15 min\n const removedInteractions = this.lastInteractions.sweep((ia) => ia.createdTimestamp < outdatedTs);\n if (removedInteractions > 0) {\n this.adapter.log.debug(`Removed ${removedInteractions} outdated interactions from cache`);\n }\n }\n\n /**\n * Handle command interactions.\n */\n private async handleCommandInteraction (interaction: CommandInteraction): Promise {\n const { commandName, user } = interaction;\n\n if (!this.registerCommandsDone) {\n this.adapter.log.warn(`Got command ${commandName} but command registration is not done yet.`);\n return;\n }\n\n this.adapter.log.debug(`Got command ${commandName} ${JSON.stringify(interaction.options.data)}`);\n\n const authCheckTarget = interaction.member instanceof GuildMember ? interaction.member : user;\n\n if (commandName === this.cmdGetStateName) {\n // check user authorization\n if (this.adapter.checkUserAuthorization(authCheckTarget, { getStates: true })) {\n // user authorized\n await this.handleCmdGetState(interaction);\n } else {\n // user not authorized\n this.adapter.log.warn(`User ${userNameOrTag(user)} (id:${user.id}) is not authorized to call /${commandName} commands!`);\n await interaction.reply({\n content: i18n.getString('You are not authorized to call this command!'),\n ephemeral: true,\n });\n }\n\n } else if (commandName === this.cmdSetStateName) {\n // check user authorization\n if (this.adapter.checkUserAuthorization(authCheckTarget, { setStates: true })) {\n // user authorized\n await this.handleCmdSetState(interaction);\n } else {\n // user not authorized\n this.adapter.log.warn(`User ${userNameOrTag(user)} (id:${user.id}) is not authorized to call /${commandName} commands!`);\n await interaction.reply({\n content: i18n.getString('You are not authorized to call this command!'),\n ephemeral: true,\n });\n }\n\n } else if (this.customCommands.has(commandName)) {\n // check user authorization\n if (this.adapter.checkUserAuthorization(authCheckTarget, { useCustomCommands: true })) {\n // user authorized\n await this.handleCmdCustom(interaction);\n } else {\n // user not authorized\n this.adapter.log.warn(`User ${userNameOrTag(user)} (id:${user.id}) is not authorized to call /${commandName} commands!`);\n await interaction.reply({\n content: i18n.getString('You are not authorized to call this command!'),\n ephemeral: true,\n });\n }\n\n } else {\n this.adapter.log.warn(`Got unknown command ${commandName}!`);\n await interaction.editReply(i18n.getString('Unknown command!'));\n }\n }\n\n /**\n * Handle autocomplete for command interactions.\n */\n private async handleAutocompleteInteraction (interaction: AutocompleteInteraction): Promise {\n const { commandName, user } = interaction;\n\n const focused = interaction.options.getFocused(true);\n let focusedValue: string;\n if (typeof focused.value !== 'string') {\n return await interaction.respond([]);\n } else {\n focusedValue = focused.value.toLowerCase();\n }\n\n // check authorization\n const authCheckTarget = interaction.member instanceof GuildMember ? interaction.member : user;\n\n let choices: CommandOptionChoiceData[];\n\n if (commandName === this.cmdGetStateName) {\n // get state command\n if (!this.adapter.checkUserAuthorization(authCheckTarget, { getStates: true })) {\n return await interaction.respond([]);\n }\n\n choices = this.cmdGetStateChoices;\n\n } else if (commandName === this.cmdSetStateName) {\n // set state command\n if (!this.adapter.checkUserAuthorization(authCheckTarget, { setStates: true })) {\n return await interaction.respond([]);\n }\n\n choices = this.cmdSetStateChoices;\n\n } else if (this.customCommands.has(commandName)) {\n // custom command\n if (!this.adapter.checkUserAuthorization(authCheckTarget, { useCustomCommands: true })) {\n return await interaction.respond([]);\n }\n\n choices = this.customCommands.get(commandName)?.get(focused.name) ?? [];\n\n } else {\n // unknown command\n return await interaction.respond([]);\n }\n\n // filter for given input\n const matchedChoices = choices.filter((choice) => {\n return choice.name.normalize('NFKC').toLowerCase().includes(focusedValue)\n || choice.value.normalize('NFKC').toLowerCase().includes(focusedValue);\n });\n\n // max. 25 choices are allowed\n matchedChoices.splice(25);\n\n return await interaction.respond(matchedChoices);\n }\n\n /**\n * Try to get the ioBroker object and CommandObjectConfig for a given object alias.\n * The object will be checked if it's a valid state object.\n *\n * In case of an error, a reply will be sent to the interaction.\n * @param objAlias The alias of the object.\n * @param interaction The interaction for replies on errors.\n * @returns Array containing the object and the config or null and null.\n */\n private async getObjectAndCfgFromAlias (objAlias: string | null, interaction: CommandInteraction): Promise<[ioBroker.StateObject | null, CommandObjectConfig | null]> {\n // find the config for the requested object\n const cfg = this.commandObjectConfig.find((coc) => coc.alias === objAlias);\n if (!cfg) {\n if (interaction.replied) {\n await interaction.editReply({\n content: i18n.getString('Object `%s` not found!', objAlias ?? ''),\n });\n } else {\n await interaction.reply({\n content: i18n.getString('Object `%s` not found!', objAlias ?? ''),\n ephemeral: true,\n });\n }\n return [ null, null ];\n }\n\n // get the object\n const obj = await this.adapter.getForeignObjectAsync(cfg.id);\n if (!obj) {\n if (interaction.replied) {\n await interaction.editReply({\n content: i18n.getString('Object `%s` not found!', cfg.id),\n });\n } else {\n await interaction.reply({\n content: i18n.getString('Object `%s` not found!', cfg.id),\n ephemeral: true,\n });\n }\n return [ null, null ];\n }\n if (obj.type !== 'state') {\n if (interaction.replied) {\n await interaction.editReply({\n content: i18n.getString('Object `%s` is not of type state!', cfg.id),\n });\n } else {\n await interaction.reply({\n content: i18n.getString('Object `%s` is not of type state!', cfg.id),\n ephemeral: true,\n });\n }\n return [ null, null ];\n }\n\n return [ obj, cfg ];\n }\n\n /**\n * Handler for \"get state\" slash commands.\n * @param interaction The interaction which triggered this.\n */\n private async handleCmdGetState (interaction: CommandInteraction): Promise {\n const objAlias = interaction.options.get('state', true).value as string;\n\n const [ obj, cfg ] = await this.getObjectAndCfgFromAlias(objAlias, interaction);\n if (!obj || !cfg) {\n return;\n }\n\n const objCustom: ioBroker.CustomConfig | undefined = obj.common.custom?.[this.adapter.namespace] as ioBroker.CustomConfig | undefined;\n\n // check if get allowed\n if (!objCustom?.commandsAllowGet) {\n await interaction.reply({\n content: i18n.getString('Get not allowed for state `%s`!', cfg.id),\n ephemeral: true,\n });\n return;\n }\n\n // get the state\n const state = await this.adapter.getForeignStateAsync(cfg.id);\n if (!state) {\n await interaction.reply({\n content: i18n.getString('State `%s` not found!', cfg.id),\n ephemeral: true,\n });\n return;\n }\n\n // defer the reply to have more time\n if (!interaction.deferred) {\n await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral });\n }\n\n // get the value depending on the state type\n let val: string = '';\n\n // an optional MessageOptions object for special cases (like sending files)\n let msgOpts: MessageCreateOptions | undefined;\n\n // add unit if defined in the object\n const unit = obj.common.unit ? ` ${obj.common.unit}` : '';\n\n // add info about missing ack flag if configured so\n const ack = objCustom.commandsShowAckFalse && !state.ack ? ` (_${i18n.getString('not acknowledged')}_)` : '';\n\n if (obj.common.role === 'date' && ((obj.common.type === 'string' && typeof state.val === 'string') || (obj.common.type === 'number' && typeof state.val === 'number'))) {\n // date values\n const d = new Date(state.val);\n val = d.toLocaleString(i18n.language, { dateStyle: 'full', timeStyle: 'long' });\n\n } else if (obj.common.type === 'string' && objCustom.commandsStringSendAsFile && typeof state.val === 'string') {\n // path or url to file or base64 encoded file\n const b64data = getBufferAndNameFromBase64String(state.val);\n if (b64data) {\n // base64 encoded content\n\n msgOpts = {\n content: `${cfg.name}${ack}:`,\n files: [ {\n attachment: b64data.buffer,\n name: b64data.name,\n } ],\n };\n val = 'file:base64';\n\n } else {\n // file path or url\n\n // remove file:// prefix\n if (state.val.startsWith('file://')) {\n state.val = state.val.slice(7);\n }\n\n msgOpts = {\n content: `${cfg.name}${ack}:`,\n files: [ {\n attachment: state.val,\n name: getBasenameFromFilePathOrUrl(state.val),\n } ],\n };\n val = `file:${state.val}`;\n }\n\n } else {\n // non special value\n switch (obj.common.type) {\n case 'boolean':\n if (state.val) {\n val = objCustom.commandsBooleanValueTrue ?? i18n.getString('true');\n } else {\n val = objCustom.commandsBooleanValueFalse ?? i18n.getString('false');\n }\n break;\n\n case 'number': {\n // number values\n const decimals = objCustom.commandsNumberDecimals ?? 0;\n if (typeof state.val === 'number') {\n val = state.val.toFixed(decimals);\n } else if (state.val === null) {\n val = '_NULL_';\n } else {\n val = state.val.toString() || 'NaN';\n }\n if (i18n.isFloatComma) {\n val = val.replace('.', ',');\n }\n break;\n }\n\n default:\n if (typeof state.val === 'string') {\n val = state.val;\n } else if (state.val === null) {\n val = '_NULL_';\n } else {\n val = state.val.toString();\n }\n }\n }\n\n this.adapter.log.debug(`Get command for ${cfg.id} - ${val}${unit}${ack}`);\n\n // send the value as reply to the user\n try {\n if (msgOpts) {\n // message\n await interaction.editReply(msgOpts);\n } else {\n // just text\n await interaction.editReply(`${cfg.name}: ${val}${unit}${ack}`);\n }\n } catch (err) {\n this.adapter.log.warn(`Error sending interaction reply for /${this.cmdGetStateName} command! ${err}`);\n }\n }\n\n /**\n * Handler for \"set state\" slash commands.\n * @param interaction The interaction which triggered this.\n */\n private async handleCmdSetState (interaction: CommandInteraction): Promise {\n const objAlias = interaction.options.get('state', true).value as string;\n\n const [ obj, cfg ] = await this.getObjectAndCfgFromAlias(objAlias, interaction);\n if (!obj || !cfg) {\n return;\n }\n\n const objCustom: ioBroker.CustomConfig | undefined = obj.common.custom?.[this.adapter.namespace] as ioBroker.CustomConfig | undefined;\n\n // check if set allowed\n if (!objCustom?.commandsAllowSet) {\n await interaction.reply({\n content: i18n.getString('Set not allowed for state `%s`!', cfg.id),\n ephemeral: true,\n });\n return;\n }\n\n let valueStr = interaction.options.get('value')?.value;\n if (typeof valueStr !== 'string') {\n await interaction.reply({\n content: i18n.getString('No value provided!'),\n ephemeral: true,\n });\n return;\n }\n\n // defer the reply to have more time\n if (!interaction.deferred) {\n await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral });\n }\n\n valueStr = valueStr.trim();\n\n // add unit if defined in the object\n const unit = obj.common.unit ? ` ${obj.common.unit}` : '';\n\n let value: string | number | boolean;\n let valueReply: string;\n\n switch (obj.common.type) {\n case 'boolean':\n // parse as boolean value\n valueStr = valueStr.toLowerCase();\n if (valueStr === objCustom.commandsBooleanValueTrue?.toLowerCase() || this.wellKnownbooleanTrueValues.has(valueStr)) {\n // true value form configures custom value or from well known boolean true values\n value = true;\n valueReply = objCustom.commandsBooleanValueTrue ?? i18n.getString('true');\n } else {\n // false value\n value = false;\n valueReply = objCustom.commandsBooleanValueFalse ?? i18n.getString('false');\n }\n break;\n\n case 'number':\n // parse as number (float) value\n if (i18n.isFloatComma) {\n valueStr = valueStr.replace(',', '.');\n }\n value = parseFloat(valueStr);\n\n if (isNaN(value)) {\n await interaction.editReply(i18n.getString('The given value is not a number!'));\n return;\n }\n\n valueReply = value.toString();\n if (i18n.isFloatComma) {\n valueReply = valueReply.replace('.', ',');\n }\n\n // check min and max if configured\n if (typeof obj.common.min === 'number' && value < obj.common.min) {\n let min = obj.common.min.toString();\n if (i18n.isFloatComma) {\n min = min.replace('.', ',');\n }\n await interaction.editReply(i18n.getString('Value %s is below the allowed minimum of %s!', `${valueReply}${unit}`, `${min}${unit}`));\n return;\n }\n if (typeof obj.common.max === 'number' && value > obj.common.max) {\n let max = obj.common.max.toString();\n if (i18n.isFloatComma) {\n max = max.replace('.', ',');\n }\n await interaction.editReply(i18n.getString('Value %s is above the allowed maximum of %s!', `${valueReply}${unit}`, `${max}${unit}`));\n return;\n }\n\n break;\n\n default:\n // string values\n value = valueStr;\n valueReply = valueStr;\n }\n\n this.adapter.log.debug(`Set command for ${cfg.id} - ${value}${unit}`);\n\n // set the state\n try {\n await this.adapter.setForeignStateAsync(cfg.id, value, !!objCustom.commandsSetWithAck);\n } catch (err) {\n this.adapter.log.warn(`Error while setting state ${cfg.id} to ${value}! ${err}`);\n await interaction.editReply(i18n.getString('Error while setting the state value!'));\n return;\n }\n\n // send reply\n await interaction.editReply(`${cfg.name}: ${valueReply}${unit}`);\n }\n\n /**\n * Handler for custom slash commands.\n * @param interaction The interaction which triggered this.\n */\n private async handleCmdCustom (interaction: CommandInteraction): Promise {\n const {\n commandName,\n channelId,\n guildId,\n user,\n options,\n } = interaction;\n\n // get the related custom command config\n const cmdCfg = this.adapter.config.customCommands.find((c) => c.name === commandName);\n if (!cmdCfg) return; // should never happen, but to be sure\n\n // defer the reply to have more time\n if (!interaction.deferred) {\n await interaction.deferReply({ ephemeral: this.adapter.config.commandRepliesEphemeral });\n }\n\n // add this interaction to the collection of last interactions\n this.lastInteractions.set(interaction.id, interaction);\n\n // promises for all set state actions\n const proms: Promise[] = [];\n\n // prepare json data\n const json: JsonSlashCommandObj = {\n interactionId: interaction.id,\n commandName,\n channelId,\n serverId: guildId ?? null,\n user: {\n id: user.id,\n tag: user.tag,\n name: user.username,\n displayName: interaction.member instanceof GuildMember ? interaction.member.displayName : user.username,\n },\n timestamp: interaction.createdTimestamp,\n options: {},\n };\n\n // loop over configured options and prepare data ... options.data* may not be set for optional options\n for (const optCfg of cmdCfg.options) {\n const opt = options.data.find((o) => o.name === optCfg.name);\n if (opt) {\n json.options[optCfg.name] = {\n value: opt.value ?? null,\n type: ApplicationCommandOptionType[opt.type],\n };\n\n if (opt.user instanceof User) {\n json.options[optCfg.name].user = {\n id: opt.user.id,\n tag: opt.user.tag,\n name: opt.user.username,\n bot: opt.user.bot,\n };\n }\n if (opt.member instanceof GuildMember) {\n json.options[optCfg.name].member = {\n id: opt.member.id,\n tag: opt.member.user.tag,\n name: opt.member.user.username,\n displayName: opt.member.displayName,\n roles: opt.member.roles.cache.map((r) => ({ id: r.id, name: r.name })),\n };\n }\n if (opt.role instanceof Role) {\n json.options[optCfg.name].role = {\n id: opt.role.id,\n name: opt.role.name,\n };\n }\n if (opt.channel instanceof GuildChannel) {\n json.options[optCfg.name].channel = {\n id: opt.channel.id,\n name: opt.channel.name,\n type: ChannelType[opt.channel.type] as ChannelTypeNames,\n lastMessageId: (opt.channel.type === ChannelType.GuildText || opt.channel.type === ChannelType.GuildVoice) ? opt.channel.lastMessageId : null,\n };\n }\n } else {\n json.options[optCfg.name] = {\n value: null,\n type: null,\n };\n }\n proms.push(this.adapter.setState(`slashCommands.${commandName}.option-${optCfg.name}.value`, json.options[optCfg.name].value, true));\n }\n\n // set the states\n await Promise.all([\n this.adapter.setState(`slashCommands.${commandName}.interactionId`, interaction.id, true),\n this.adapter.setState(`slashCommands.${commandName}.channelId`, channelId, true),\n this.adapter.setState(`slashCommands.${commandName}.serverId`, guildId ?? null, true),\n this.adapter.setState(`slashCommands.${commandName}.userId`, user.id, true),\n this.adapter.setState(`slashCommands.${commandName}.userTag`, user.tag, true),\n this.adapter.setState(`slashCommands.${commandName}.userName`, user.username, true),\n this.adapter.setState(`slashCommands.${commandName}.timestamp`, interaction.createdTimestamp, true),\n this.adapter.setState(`slashCommands.${commandName}.json`, JSON.stringify(json), true),\n ...proms,\n ]);\n\n /*****\n * Hint: Interaction reply is deferred, but no reply will be send here.\n * The reply must be triggered by the user using the .sendReply state or a `sendTo(...)` action.\n *****/\n }\n}\n"], + "mappings": "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", "names": [] } diff --git a/build/lib/definitions.js.map b/build/lib/definitions.js.map index 5c0af85..8d29842 100644 --- a/build/lib/definitions.js.map +++ b/build/lib/definitions.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../src/lib/definitions.ts"], - "sourcesContent": ["export const VALID_PRESENCE_STATUS_DATA = ['online', 'idle', 'dnd', 'invisible'];\n\nexport const ACTIVITY_TYPES = ['', 'Playing', 'Streaming', 'Listening', 'Watching', 'Custom', 'Competing'];\nexport type ActivityTypeNames = typeof ACTIVITY_TYPES[number];\n\n//export const VALID_ACTIVITY_TYPES = ['', 'Playing', 'Streaming', 'Listening', 'Watching', 'Competing'];\n//export type ValidActivityTypeNames = typeof VALID_ACTIVITY_TYPES[number];\n\n/**\n * Valid channel types.\n * @see discord-api-types/payloads/v10/channel.d.ts#304\n */\nexport type ChannelTypeNames = 'GuildText' | 'DM' | 'GuildVoice' | 'GroupDM' | 'GuildCategory' | 'GuildAnnouncement' | 'AnnouncementThread' | 'PublicThread' | 'PrivateThread' | 'GuildStageVoice' | 'GuildDirectory' | 'GuildForum' | 'GuildNews' | 'GuildNewsThread' | 'GuildPublicThread' | 'GuildPrivateThread';\n\nimport {\n MessageEditOptions,\n MessageCreateOptions,\n PresenceStatus,\n PresenceStatusData,\n Snowflake,\n} from 'discord.js';\n\nexport interface Text2commandMessagePayload {\n text: string;\n response?: string;\n}\n\nexport interface SetBotPresenceOptions {\n status?: PresenceStatusData;\n activityType?: ActivityTypeNames;\n activityName?: string;\n}\n\nexport interface JsonServersMembersObj {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n roles: string[];\n joined: number | null;\n voiceChannel: string;\n voiceChannelId: Snowflake;\n voiceSelfDeaf: boolean;\n voiceServerDeaf: boolean;\n voiceSelfMute: boolean;\n voiceServerMute: boolean;\n}\n\nexport interface JsonServersChannelsObj {\n id: Snowflake;\n name: string;\n memberCount: number;\n members: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n }[];\n type: ChannelTypeNames;\n}\n\nexport interface JsonUsersObj {\n id: Snowflake;\n tag: string;\n name: string;\n activityName: string;\n activityType: ActivityTypeNames;\n avatarUrl: string;\n bot: boolean;\n status: PresenceStatus | '';\n}\n\nexport interface JsonMessageObj {\n id: Snowflake;\n content: string;\n attachments: {\n attachment: string;\n name: string | null;\n size: number;\n id: Snowflake;\n }[];\n mentions: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n }[];\n mentioned: boolean;\n timestamp: number;\n authorized: boolean;\n\n author?: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n };\n}\n\nexport interface JsonSlashCommandObj {\n interactionId: Snowflake;\n commandName: string;\n user: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n };\n channelId: Snowflake;\n serverId: Snowflake | null;\n timestamp: number;\n options: Record;\n}\n\nexport interface JsonSlashCommandObjOption {\n value: string | number | boolean | null;\n type: string | null;\n user?: {\n id: Snowflake;\n tag: string;\n name: string;\n bot: boolean;\n };\n member?: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n roles: { id: Snowflake, name: string }[];\n };\n role?: {\n id: Snowflake;\n name: string;\n };\n channel?: {\n id: Snowflake;\n name: string;\n type: ChannelTypeNames;\n lastMessageId: Snowflake | null;\n };\n}\n\nexport interface UpdateUserPresenceResult {\n status: PresenceStatus | '';\n activityType: ActivityTypeNames;\n activityName: string;\n}\n\nexport type CheckAuthorizationOpts = Partial;\n\n/**\n * Parameters needed to identify a message target.\n * One of the following is needed:\n * - `userId`\n * - `userTag`\n * - `userName`\n * - `serverId` and `channelId`\n */\nexport interface MessageTargetIdentifier {\n serverId?: Snowflake;\n channelId?: Snowflake;\n\n userId?: Snowflake;\n userTag?: Snowflake;\n userName?: Snowflake;\n}\n\n/**\n * Parameters needed to identify a message.\n */\nexport interface MessageIdentifier extends MessageTargetIdentifier {\n messageId: Snowflake;\n}\n\n/**\n * Payload for a `sentTo(...)` `sendMessage` action.\n */\nexport interface SendToActionSendPayload extends MessageTargetIdentifier {\n content: string | MessageCreateOptions;\n}\n\n/**\n * Payload for a `sentTo(...)` `editMessage` action.\n */\nexport interface SendToActionEditMessagePayload extends MessageIdentifier {\n content: string | MessageEditOptions;\n}\n\n/**\n * Payload for a `sentTo(...)` `awaitMessageReaction` action.\n */\nexport interface SendToActionAwaitMessageReactionPayload extends MessageIdentifier {\n timeout: number;\n max?: number;\n}\n\n/**\n * Payload for a `sentTo(...)` `addReaction` action.\n */\nexport interface SendToActionAddReactionPayload extends MessageIdentifier {\n emoji: string;\n}\n\n/**\n * Payload for `sentTo(...)` actions requiring a server.\n */\nexport interface SendToActionServerIdentifier {\n serverId: Snowflake;\n}\n\n/**\n * Payload for `sentTo(...)` actions requiring a server channel.\n */\nexport interface SendToActionChannelIdentifier extends SendToActionServerIdentifier {\n channelId: Snowflake;\n}\n\n/**\n * Payload for `sentTo(...)` actions requiring a user.\n */\nexport interface SendToActionUserIdentifier {\n userId?: Snowflake;\n userTag?: string;\n userName?: string;\n}\n\n/**\n * Payload for `sentTo(...)` actions requiring a server member.\n */\nexport interface SendToActionServerMemberIdentifier extends SendToActionServerIdentifier, SendToActionUserIdentifier {\n // just extends\n}\n\n/**\n * Payload for a `sentTo(...)` `sendCustomCommandReply` action.\n */\nexport interface SendToActionSendCustomCommandReplyPayload {\n interactionId: Snowflake;\n content: string | MessageCreateOptions;\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,6BAAoC,CAAC,UAAU,QAAQ,OAAO,WAAW;AAE/E,MAAM,iBAAwB,CAAC,IAAI,WAAW,aAAa,aAAa,YAAY,UAAU,WAAW;", + "sourcesContent": ["export const VALID_PRESENCE_STATUS_DATA = [ 'online', 'idle', 'dnd', 'invisible' ] as const;\n\nexport const ACTIVITY_TYPES = [ '', 'Playing', 'Streaming', 'Listening', 'Watching', 'Custom', 'Competing' ] as const;\nexport type ActivityTypeNames = typeof ACTIVITY_TYPES[number];\n\n// export const VALID_ACTIVITY_TYPES = ['', 'Playing', 'Streaming', 'Listening', 'Watching', 'Competing'];\n// export type ValidActivityTypeNames = typeof VALID_ACTIVITY_TYPES[number];\n\n/**\n * Valid channel types.\n * @see discord-api-types/payloads/v10/channel.d.ts#304\n */\nexport type ChannelTypeNames = 'GuildText' | 'DM' | 'GuildVoice' | 'GroupDM' | 'GuildCategory' | 'GuildAnnouncement' | 'AnnouncementThread' | 'PublicThread' | 'PrivateThread' | 'GuildStageVoice' | 'GuildDirectory' | 'GuildForum' | 'GuildNews' | 'GuildNewsThread' | 'GuildPublicThread' | 'GuildPrivateThread';\n\nimport {\n MessageCreateOptions,\n MessageEditOptions,\n PresenceStatus,\n PresenceStatusData,\n Snowflake,\n} from 'discord.js';\n\nexport interface Text2commandMessagePayload {\n text: string;\n response?: string;\n}\n\nexport interface SetBotPresenceOptions {\n status?: PresenceStatusData;\n activityType?: ActivityTypeNames;\n activityName?: string;\n}\n\nexport interface JsonServersMembersObj {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n roles: string[];\n joined: number | null;\n voiceChannel: string;\n voiceChannelId: Snowflake;\n voiceSelfDeaf: boolean;\n voiceServerDeaf: boolean;\n voiceSelfMute: boolean;\n voiceServerMute: boolean;\n}\n\nexport interface JsonServersChannelsObj {\n id: Snowflake;\n name: string;\n memberCount: number;\n members: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n }[];\n type: ChannelTypeNames;\n}\n\nexport interface JsonUsersObj {\n id: Snowflake;\n tag: string;\n name: string;\n activityName: string;\n activityType: ActivityTypeNames;\n avatarUrl: string;\n bot: boolean;\n status: PresenceStatus | '';\n}\n\nexport interface JsonMessageObj {\n id: Snowflake;\n content: string;\n attachments: {\n attachment: string;\n name: string | null;\n size: number;\n id: Snowflake;\n }[];\n mentions: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n }[];\n mentioned: boolean;\n timestamp: number;\n authorized: boolean;\n\n author?: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n };\n}\n\nexport interface JsonSlashCommandObj {\n interactionId: Snowflake;\n commandName: string;\n user: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n };\n channelId: Snowflake;\n serverId: Snowflake | null;\n timestamp: number;\n options: Record;\n}\n\nexport interface JsonSlashCommandObjOption {\n value: string | number | boolean | null;\n type: string | null;\n user?: {\n id: Snowflake;\n tag: string;\n name: string;\n bot: boolean;\n };\n member?: {\n id: Snowflake;\n tag: string;\n name: string;\n displayName: string;\n roles: { id: Snowflake, name: string }[];\n };\n role?: {\n id: Snowflake;\n name: string;\n };\n channel?: {\n id: Snowflake;\n name: string;\n type: ChannelTypeNames;\n lastMessageId: Snowflake | null;\n };\n}\n\nexport interface UpdateUserPresenceResult {\n status: PresenceStatus | '';\n activityType: ActivityTypeNames;\n activityName: string;\n}\n\nexport type CheckAuthorizationOpts = Partial;\n\n/**\n * Parameters needed to identify a message target.\n * One of the following is needed:\n * - `userId`\n * - `userTag`\n * - `userName`\n * - `serverId` and `channelId`\n */\nexport interface MessageTargetIdentifier {\n serverId?: Snowflake;\n channelId?: Snowflake;\n\n userId?: Snowflake;\n userTag?: Snowflake;\n userName?: Snowflake;\n}\n\n/**\n * Parameters needed to identify a message.\n */\nexport interface MessageIdentifier extends MessageTargetIdentifier {\n messageId: Snowflake;\n}\n\n/**\n * Payload for a `sentTo(...)` `sendMessage` action.\n */\nexport interface SendToActionSendPayload extends MessageTargetIdentifier {\n content: string | MessageCreateOptions;\n}\n\n/**\n * Payload for a `sentTo(...)` `editMessage` action.\n */\nexport interface SendToActionEditMessagePayload extends MessageIdentifier {\n content: string | MessageEditOptions;\n}\n\n/**\n * Payload for a `sentTo(...)` `awaitMessageReaction` action.\n */\nexport interface SendToActionAwaitMessageReactionPayload extends MessageIdentifier {\n timeout: number;\n max?: number;\n}\n\n/**\n * Payload for a `sentTo(...)` `addReaction` action.\n */\nexport interface SendToActionAddReactionPayload extends MessageIdentifier {\n emoji: string;\n}\n\n/**\n * Payload for `sentTo(...)` actions requiring a server.\n */\nexport interface SendToActionServerIdentifier {\n serverId: Snowflake;\n}\n\n/**\n * Payload for `sentTo(...)` actions requiring a server channel.\n */\nexport interface SendToActionChannelIdentifier extends SendToActionServerIdentifier {\n channelId: Snowflake;\n}\n\n/**\n * Payload for `sentTo(...)` actions requiring a user.\n */\nexport interface SendToActionUserIdentifier {\n userId?: Snowflake;\n userTag?: string;\n userName?: string;\n}\n\n/**\n * Payload for `sentTo(...)` actions requiring a server member.\n */\nexport interface SendToActionServerMemberIdentifier extends SendToActionServerIdentifier, SendToActionUserIdentifier {\n // just extends\n}\n\n/**\n * Payload for a `sentTo(...)` `sendCustomCommandReply` action.\n */\nexport interface SendToActionSendCustomCommandReplyPayload {\n interactionId: Snowflake;\n content: string | MessageCreateOptions;\n}\n"], + "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,6BAA6B,CAAE,UAAU,QAAQ,OAAO,WAAY;AAE1E,MAAM,iBAAiB,CAAE,IAAI,WAAW,aAAa,aAAa,YAAY,UAAU,WAAY;", "names": [] } diff --git a/build/lib/i18n.js b/build/lib/i18n.js index d59cc64..838fc55 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -42,16 +42,14 @@ var import_pt = __toESM(require("../../admin/i18n/pt.json")); var import_ru = __toESM(require("../../admin/i18n/ru.json")); var import_zh_cn = __toESM(require("../../admin/i18n/zh-cn.json")); class I18n { - constructor() { - /** - * Language configured in `system.config` object. - */ - this.language = "en"; - /** - * If float numbers should be displayed using a comma instead of a dot. - */ - this.isFloatComma = false; - } + /** + * Language configured in `system.config` object. + */ + language = "en"; + /** + * If float numbers should be displayed using a comma instead of a dot. + */ + isFloatComma = false; /** * Get a translation object or a single string for a given translation key. * Uses the i18n files in `admin/i18n`. diff --git a/build/lib/i18n.js.map b/build/lib/i18n.js.map index 16d9136..0b13d12 100644 --- a/build/lib/i18n.js.map +++ b/build/lib/i18n.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../src/lib/i18n.ts"], - "sourcesContent": ["import de from '../../admin/i18n/de.json';\nimport en from '../../admin/i18n/en.json';\nimport es from '../../admin/i18n/es.json';\nimport fr from '../../admin/i18n/fr.json';\nimport it from '../../admin/i18n/it.json';\nimport nl from '../../admin/i18n/nl.json';\nimport pl from '../../admin/i18n/pl.json';\nimport pt from '../../admin/i18n/pt.json';\nimport ru from '../../admin/i18n/ru.json';\nimport zhCn from '../../admin/i18n/zh-cn.json';\n\ntype I18nObj = Partial;\ntype I18nKey = keyof I18nObj;\n\n/**\n * Internationalization class to handle translations.\n */\nclass I18n {\n\n /**\n * Language configured in `system.config` object.\n */\n public language: ioBroker.Languages = 'en';\n\n /**\n * If float numbers should be displayed using a comma instead of a dot.\n */\n public isFloatComma: boolean = false;\n\n /**\n * Get a translation object or a single string for a given translation key.\n * Uses the i18n files in `admin/i18n`.\n * @param key The key from `en.json`.\n * @param args Array of strings to be inserted at `%s` in the translated strings.\n */\n public getStringOrTranslated (key: I18nKey, ...args: string[]): ioBroker.StringOrTranslated {\n if (en[key]) {\n return {\n de: this.replacePlaceholders((de as I18nObj)[key] ?? key, ...args),\n en: this.replacePlaceholders((en as I18nObj)[key] ?? key, ...args),\n es: this.replacePlaceholders((es as I18nObj)[key] ?? key, ...args),\n fr: this.replacePlaceholders((fr as I18nObj)[key] ?? key, ...args),\n it: this.replacePlaceholders((it as I18nObj)[key] ?? key, ...args),\n nl: this.replacePlaceholders((nl as I18nObj)[key] ?? key, ...args),\n pl: this.replacePlaceholders((pl as I18nObj)[key] ?? key, ...args),\n pt: this.replacePlaceholders((pt as I18nObj)[key] ?? key, ...args),\n ru: this.replacePlaceholders((ru as I18nObj)[key] ?? key, ...args),\n 'zh-cn': this.replacePlaceholders((zhCn as I18nObj)[key] ?? key, ...args),\n };\n } else {\n return key;\n }\n }\n\n /**\n * Get a translated string string for a given translation key and language.\n * Uses the i18n files in `admin/i18n`.\n * @param key The key from `en.json`.\n * @param args Array of strings to be inserted at `%s` in the translated string.\n */\n public getString (key: I18nKey, ...args: string[]): string {\n let str: string;\n switch (this.language) {\n case 'de': str = (de as I18nObj)[key] ?? key; break;\n case 'en': str = (en as I18nObj)[key] ?? key; break;\n case 'es': str = (es as I18nObj)[key] ?? key; break;\n case 'fr': str = (fr as I18nObj)[key] ?? key; break;\n case 'it': str = (it as I18nObj)[key] ?? key; break;\n case 'nl': str = (nl as I18nObj)[key] ?? key; break;\n case 'pl': str = (pl as I18nObj)[key] ?? key; break;\n case 'pt': str = (pt as I18nObj)[key] ?? key; break;\n case 'ru': str = (ru as I18nObj)[key] ?? key; break;\n case 'zh-cn': str = (zhCn as I18nObj)[key] ?? key; break;\n default: str = key;\n }\n\n return this.replacePlaceholders(str, ...args);\n }\n\n /**\n * Replace `%s` placeholders in the given text.\n * @param text The text.\n * @param args Array of strings to be inserted at `%s` in the text.\n */\n private replacePlaceholders (text: string, ...args: string[]) : string {\n for (const s of args) {\n text = text.replace('%s', s);\n }\n\n return text;\n }\n}\n\n/**\n * Singleton instance of the I18n class.\n */\nexport const i18n = new I18n();\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,mBAAiB;AAQjB,MAAM,KAAK;AAAA,EAAX;AAKE;AAAA;AAAA;AAAA,SAAO,WAA+B;AAKtC;AAAA;AAAA;AAAA,SAAO,eAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQxB,sBAAuB,QAAiB,MAA6C;AAC1F,QAAI,UAAAA,QAAG,GAAG,GAAG;AACX,aAAO;AAAA,QACL,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAD,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAE,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,SAAS,KAAK,oBAAqB,aAAAC,QAAiB,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,MAC1E;AAAA,IACF,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,UAAW,QAAiB,MAAwB;AACzD,QAAI;AACJ,YAAQ,KAAK,UAAU;AAAA,MACrB,KAAK;AAAM,cAAO,UAAAR,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAD,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAE,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAS,cAAO,aAAAC,QAAiB,GAAG,KAAK;AAAK;AAAA,MACnD;AAAS,cAAM;AAAA,IACjB;AAEA,WAAO,KAAK,oBAAoB,KAAK,GAAG,IAAI;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,oBAAqB,SAAiB,MAAyB;AACrE,eAAW,KAAK,MAAM;AACpB,aAAO,KAAK,QAAQ,MAAM,CAAC;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AACF;AAKO,MAAM,OAAO,IAAI,KAAK;", + "sourcesContent": ["import de from '../../admin/i18n/de.json';\nimport en from '../../admin/i18n/en.json';\nimport es from '../../admin/i18n/es.json';\nimport fr from '../../admin/i18n/fr.json';\nimport it from '../../admin/i18n/it.json';\nimport nl from '../../admin/i18n/nl.json';\nimport pl from '../../admin/i18n/pl.json';\nimport pt from '../../admin/i18n/pt.json';\nimport ru from '../../admin/i18n/ru.json';\nimport zhCn from '../../admin/i18n/zh-cn.json';\n\ntype I18nObj = Partial;\ntype I18nKey = keyof I18nObj;\n\n/**\n * Internationalization class to handle translations.\n */\nclass I18n {\n\n /**\n * Language configured in `system.config` object.\n */\n public language: ioBroker.Languages = 'en';\n\n /**\n * If float numbers should be displayed using a comma instead of a dot.\n */\n public isFloatComma: boolean = false;\n\n /**\n * Get a translation object or a single string for a given translation key.\n * Uses the i18n files in `admin/i18n`.\n * @param key The key from `en.json`.\n * @param args Array of strings to be inserted at `%s` in the translated strings.\n */\n public getStringOrTranslated (key: I18nKey, ...args: string[]): ioBroker.StringOrTranslated {\n if (en[key]) {\n return {\n de: this.replacePlaceholders((de as I18nObj)[key] ?? key, ...args),\n en: this.replacePlaceholders((en as I18nObj)[key] ?? key, ...args),\n es: this.replacePlaceholders((es as I18nObj)[key] ?? key, ...args),\n fr: this.replacePlaceholders((fr as I18nObj)[key] ?? key, ...args),\n it: this.replacePlaceholders((it as I18nObj)[key] ?? key, ...args),\n nl: this.replacePlaceholders((nl as I18nObj)[key] ?? key, ...args),\n pl: this.replacePlaceholders((pl as I18nObj)[key] ?? key, ...args),\n pt: this.replacePlaceholders((pt as I18nObj)[key] ?? key, ...args),\n ru: this.replacePlaceholders((ru as I18nObj)[key] ?? key, ...args),\n 'zh-cn': this.replacePlaceholders((zhCn as I18nObj)[key] ?? key, ...args),\n };\n } else {\n return key;\n }\n }\n\n /**\n * Get a translated string string for a given translation key and language.\n * Uses the i18n files in `admin/i18n`.\n * @param key The key from `en.json`.\n * @param args Array of strings to be inserted at `%s` in the translated string.\n */\n public getString (key: I18nKey, ...args: string[]): string {\n let str: string;\n switch (this.language) {\n /* eslint-disable @stylistic/max-statements-per-line */\n case 'de': str = (de as I18nObj)[key] ?? key; break;\n case 'en': str = (en as I18nObj)[key] ?? key; break;\n case 'es': str = (es as I18nObj)[key] ?? key; break;\n case 'fr': str = (fr as I18nObj)[key] ?? key; break;\n case 'it': str = (it as I18nObj)[key] ?? key; break;\n case 'nl': str = (nl as I18nObj)[key] ?? key; break;\n case 'pl': str = (pl as I18nObj)[key] ?? key; break;\n case 'pt': str = (pt as I18nObj)[key] ?? key; break;\n case 'ru': str = (ru as I18nObj)[key] ?? key; break;\n case 'zh-cn': str = (zhCn as I18nObj)[key] ?? key; break;\n /* eslint-enable @stylistic/max-statements-per-line */\n default: str = key;\n }\n\n return this.replacePlaceholders(str, ...args);\n }\n\n /**\n * Replace `%s` placeholders in the given text.\n * @param text The text.\n * @param args Array of strings to be inserted at `%s` in the text.\n */\n private replacePlaceholders (text: string, ...args: string[]): string {\n for (const s of args) {\n text = text.replace('%s', s);\n }\n\n return text;\n }\n}\n\n/**\n * Singleton instance of the I18n class.\n */\nexport const i18n = new I18n();\n"], + "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,gBAAe;AACf,mBAAiB;AAQjB,MAAM,KAAK;AAAA;AAAA;AAAA;AAAA,EAKF,WAA+B;AAAA;AAAA;AAAA;AAAA,EAK/B,eAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQxB,sBAAuB,QAAiB,MAA6C;AAC1F,QAAI,UAAAA,QAAG,GAAG,GAAG;AACX,aAAO;AAAA,QACL,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAD,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAE,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,IAAI,KAAK,oBAAqB,UAAAC,QAAe,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,QACjE,SAAS,KAAK,oBAAqB,aAAAC,QAAiB,GAAG,KAAK,KAAK,GAAG,IAAI;AAAA,MAC1E;AAAA,IACF,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,UAAW,QAAiB,MAAwB;AACzD,QAAI;AACJ,YAAQ,KAAK,UAAU;AAAA,MAErB,KAAK;AAAM,cAAO,UAAAR,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAD,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAE,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAM,cAAO,UAAAC,QAAe,GAAG,KAAK;AAAK;AAAA,MAC9C,KAAK;AAAS,cAAO,aAAAC,QAAiB,GAAG,KAAK;AAAK;AAAA,MAEnD;AAAS,cAAM;AAAA,IACjB;AAEA,WAAO,KAAK,oBAAoB,KAAK,GAAG,IAAI;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,oBAAqB,SAAiB,MAAwB;AACpE,eAAW,KAAK,MAAM;AACpB,aAAO,KAAK,QAAQ,MAAM,CAAC;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AACF;AAKO,MAAM,OAAO,IAAI,KAAK;", "names": ["en", "de", "es", "fr", "it", "nl", "pl", "pt", "ru", "zhCn"] } diff --git a/build/lib/utils.js b/build/lib/utils.js index 8204f5c..6babcd2 100644 --- a/build/lib/utils.js +++ b/build/lib/utils.js @@ -27,7 +27,7 @@ module.exports = __toCommonJS(utils_exports); var import_node_path = require("node:path"); var import_node_url = require("node:url"); function getBufferAndNameFromBase64String(base64String, name) { - const b64match = base64String.match(/^data:([^/]+)\/([^;]+);base64,([a-zA-Z0-9+/]+=*)$/); + const b64match = /^data:([^/]+)\/([^;]+);base64,([a-zA-Z0-9+/]+=*)$/.exec(base64String); if (!b64match) { return null; } @@ -41,11 +41,11 @@ function getBufferAndNameFromBase64String(base64String, name) { }; } function getBasenameFromFilePathOrUrl(file) { - if (file.match(/^\w+:\/\//)) { + if (/^\w+:\/\//.exec(file)) { try { const url = new import_node_url.URL(file); return (0, import_node_path.basename)(url.pathname); - } catch (err) { + } catch (_err) { return (0, import_node_path.basename)(file); } } else { @@ -56,7 +56,7 @@ function getObjName(common) { if (typeof common.name === "string") { return common.name; } - return common.name["en"]; + return common.name.en; } function userNameOrTag(user) { return user.discriminator === "0" ? user.username : user.tag; diff --git a/build/lib/utils.js.map b/build/lib/utils.js.map index 6e48fb5..e79222b 100644 --- a/build/lib/utils.js.map +++ b/build/lib/utils.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../src/lib/utils.ts"], - "sourcesContent": ["import { User } from 'discord.js';\nimport { basename } from 'node:path';\nimport { URL } from 'node:url';\n\ninterface BufferAndName {\n buffer: Buffer;\n name: string;\n}\n\n/**\n * Get a buffer and a file name from a possibly base64 encoded string.\n * @param base64String The possibly bas64 encoded data string.\n * @param name An optional file name.\n * @returns Object of `buffer` and `name` from the base64 string or null if no base64 string.\n */\nexport function getBufferAndNameFromBase64String (base64String: string, name?: string): BufferAndName | null {\n // check for base64 encoded data\n const b64match = base64String.match(/^data:([^/]+)\\/([^;]+);base64,([a-zA-Z0-9+/]+=*)$/);\n if (!b64match) {\n return null;\n }\n\n // base64 encoded content\n const buffer = Buffer.from(b64match[3], 'base64');\n\n // guess a generic name from the mime type if no name provided\n if (!name) {\n name = `${b64match[1].replace(/\\W/g, '_')}.${b64match[2].replace(/\\W/g, '_')}`;\n }\n\n return {\n buffer,\n name,\n };\n}\n\n/**\n * Get the basename of a path or URL to a file.\n * @param file Path or URL to a file.\n * @returns The basename of the file.\n */\nexport function getBasenameFromFilePathOrUrl (file: string): string {\n if (file.match(/^\\w+:\\/\\//)) {\n try {\n const url = new URL(file);\n return basename(url.pathname);\n } catch (err) {\n return basename(file);\n }\n } else {\n return basename(file);\n }\n}\n\n/**\n * Get the name of an ioBroker object.\n * The name in the common object may be a single string or an object containing\n * the translations. If it's an object, the 'en' translation will be used.\n * @param common The common object of an ioBroker object.\n * @returns The object name.\n */\nexport function getObjName (common: ioBroker.ObjectCommon): string {\n if (typeof common.name === 'string') {\n return common.name;\n }\n\n return common.name['en'];\n}\n\n/**\n * Get the unique username of a discord user or the tag if no unique name is set.\n * @param user The discord user.\n * @returns The username or tag.\n */\nexport function userNameOrTag (user: User): string {\n return user.discriminator === '0' ? user.username : user.tag;\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,uBAAyB;AACzB,sBAAoB;AAab,SAAS,iCAAkC,cAAsB,MAAqC;AAE3G,QAAM,WAAW,aAAa,MAAM,mDAAmD;AACvF,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,OAAO,KAAK,SAAS,CAAC,GAAG,QAAQ;AAGhD,MAAI,CAAC,MAAM;AACT,WAAO,GAAG,SAAS,CAAC,EAAE,QAAQ,OAAO,GAAG,CAAC,IAAI,SAAS,CAAC,EAAE,QAAQ,OAAO,GAAG,CAAC;AAAA,EAC9E;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAOO,SAAS,6BAA8B,MAAsB;AAClE,MAAI,KAAK,MAAM,WAAW,GAAG;AAC3B,QAAI;AACF,YAAM,MAAM,IAAI,oBAAI,IAAI;AACxB,iBAAO,2BAAS,IAAI,QAAQ;AAAA,IAC9B,SAAS,KAAK;AACZ,iBAAO,2BAAS,IAAI;AAAA,IACtB;AAAA,EACF,OAAO;AACL,eAAO,2BAAS,IAAI;AAAA,EACtB;AACF;AASO,SAAS,WAAY,QAAuC;AACjE,MAAI,OAAO,OAAO,SAAS,UAAU;AACnC,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO,OAAO,KAAK,IAAI;AACzB;AAOO,SAAS,cAAe,MAAoB;AACjD,SAAO,KAAK,kBAAkB,MAAM,KAAK,WAAW,KAAK;AAC3D;", + "sourcesContent": ["import { User } from 'discord.js';\nimport { basename } from 'node:path';\nimport { URL } from 'node:url';\n\ninterface BufferAndName {\n buffer: Buffer;\n name: string;\n}\n\n/**\n * Get a buffer and a file name from a possibly base64 encoded string.\n * @param base64String The possibly bas64 encoded data string.\n * @param name An optional file name.\n * @returns Object of `buffer` and `name` from the base64 string or null if no base64 string.\n */\nexport function getBufferAndNameFromBase64String (base64String: string, name?: string): BufferAndName | null {\n // check for base64 encoded data\n const b64match = /^data:([^/]+)\\/([^;]+);base64,([a-zA-Z0-9+/]+=*)$/.exec(base64String);\n if (!b64match) {\n return null;\n }\n\n // base64 encoded content\n const buffer = Buffer.from(b64match[3], 'base64');\n\n // guess a generic name from the mime type if no name provided\n if (!name) {\n name = `${b64match[1].replace(/\\W/g, '_')}.${b64match[2].replace(/\\W/g, '_')}`;\n }\n\n return {\n buffer,\n name,\n };\n}\n\n/**\n * Get the basename of a path or URL to a file.\n * @param file Path or URL to a file.\n * @returns The basename of the file.\n */\nexport function getBasenameFromFilePathOrUrl (file: string): string {\n if (/^\\w+:\\/\\//.exec(file)) {\n try {\n const url = new URL(file);\n return basename(url.pathname);\n } catch (_err) {\n return basename(file);\n }\n } else {\n return basename(file);\n }\n}\n\n/**\n * Get the name of an ioBroker object.\n * The name in the common object may be a single string or an object containing\n * the translations. If it's an object, the 'en' translation will be used.\n * @param common The common object of an ioBroker object.\n * @returns The object name.\n */\nexport function getObjName (common: ioBroker.ObjectCommon): string {\n if (typeof common.name === 'string') {\n return common.name;\n }\n\n return common.name.en;\n}\n\n/**\n * Get the unique username of a discord user or the tag if no unique name is set.\n * @param user The discord user.\n * @returns The username or tag.\n */\nexport function userNameOrTag (user: User): string {\n return user.discriminator === '0' ? user.username : user.tag;\n}\n"], + "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,uBAAyB;AACzB,sBAAoB;AAab,SAAS,iCAAkC,cAAsB,MAAqC;AAE3G,QAAM,WAAW,oDAAoD,KAAK,YAAY;AACtF,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,OAAO,KAAK,SAAS,CAAC,GAAG,QAAQ;AAGhD,MAAI,CAAC,MAAM;AACT,WAAO,GAAG,SAAS,CAAC,EAAE,QAAQ,OAAO,GAAG,CAAC,IAAI,SAAS,CAAC,EAAE,QAAQ,OAAO,GAAG,CAAC;AAAA,EAC9E;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAOO,SAAS,6BAA8B,MAAsB;AAClE,MAAI,YAAY,KAAK,IAAI,GAAG;AAC1B,QAAI;AACF,YAAM,MAAM,IAAI,oBAAI,IAAI;AACxB,iBAAO,2BAAS,IAAI,QAAQ;AAAA,IAC9B,SAAS,MAAM;AACb,iBAAO,2BAAS,IAAI;AAAA,IACtB;AAAA,EACF,OAAO;AACL,eAAO,2BAAS,IAAI;AAAA,EACtB;AACF;AASO,SAAS,WAAY,QAAuC;AACjE,MAAI,OAAO,OAAO,SAAS,UAAU;AACnC,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO,OAAO,KAAK;AACrB;AAOO,SAAS,cAAe,MAAoB;AACjD,SAAO,KAAK,kBAAkB,MAAM,KAAK,WAAW,KAAK;AAC3D;", "names": [] } diff --git a/build/main.js b/build/main.js index d6995c9..8d2cf61 100644 --- a/build/main.js +++ b/build/main.js @@ -58,58 +58,62 @@ const LOGIN_WAIT_TIMES = [ // 10 min ]; class DiscordAdapter extends import_adapter_core.Adapter { + /** + * Instance of the discord client. + */ + client = null; + /** + * Flag if the adapter is unloaded or is unloading. + * Used to check this in some async operations. + */ + unloaded = false; + /** + * Flag if the initial setup of the custom object configurations is done or not. + * While not done, custom object configuration changes will not trigger a + * slash commands registration automatically. + */ + initialCustomObjectSetupDone = false; + /** + * Local cache for `info.connection` state. + */ + infoConnected = false; + /** + * Set of state IDs where received discord messages will be stored to. + * Used to identify target states for received discord messages. + */ + messageReceiveStates = /* @__PURE__ */ new Set(); + /** + * Set user IDs known to set up. + * Used to check if the user objects are created on some events. + */ + knownUsers = /* @__PURE__ */ new Set(); + /** + * Set of objects from this instance with text2command enabled. + */ + text2commandObjects = /* @__PURE__ */ new Set(); + /** + * Cache for `extendObjectCache(...)` calls to extend objects only when changed. + */ + extendObjectCache = new import_discord.Collection(); + /** + * Cache for `.json` states. + */ + jsonStateCache = new import_discord.Collection(); + /** + * Instance of the slash commands handler class. + */ + discordSlashCommands; + /** + * Flag if we are currently in shard error state from discord.js. + * `false` currently not on error state, A `string` containing the error name in + * case of en error. + */ + isShardError = false; constructor(options = {}) { super({ ...options, name: "discord" }); - /** - * Local cache for `info.connection` state. - */ - this.infoConnected = false; - /** - * Instance of the discord client. - */ - this.client = null; - /** - * Set of state IDs where received discord messages will be stored to. - * Used to identify target states for received discord messages. - */ - this.messageReceiveStates = /* @__PURE__ */ new Set(); - /** - * Set user IDs known to set up. - * Used to check if the user objects are created on some events. - */ - this.knownUsers = /* @__PURE__ */ new Set(); - /** - * Set of objects from this instance with text2command enabled. - */ - this.text2commandObjects = /* @__PURE__ */ new Set(); - /** - * Cache for `extendObjectCache(...)` calls to extend objects only when changed. - */ - this.extendObjectCache = new import_discord.Collection(); - /** - * Cache for `.json` states. - */ - this.jsonStateCache = new import_discord.Collection(); - /** - * Flag if the initial setup of the custom object configurations is done or not. - * While not done, custom object configuration changes will not trigger a - * slash commands registration automatically. - */ - this.initialCustomObjectSetupDone = false; - /** - * Flag if we are currently in shard error state from discord.js. - * `false` currently not on error state, A `string` containing the error name in - * case of en error. - */ - this.isShardError = false; - /** - * Flag if the adapter is unloaded or is unloading. - * Used to check this in some async operations. - */ - this.unloaded = false; this.discordSlashCommands = new import_commands.DiscordAdapterSlashCommands(this); this.on("ready", this.onReady); this.on("stateChange", this.onStateChange); @@ -117,14 +121,128 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.on("message", this.onMessage); this.on("unload", this.onUnload); } + /** + * Try to detect and parse stringified JSON MessageOptions. + * + * If the `content` starts/ends with curly braces if will be treated as + * stringified JSON. Then the JSON will be parsed and some basic checks will + * be run against the parsed object. + * + * Otherwise the content will be treated as a simple string and wrapped into + * a `MessageOptions` object. + * @param content The stringified content to be parsed. + * @returns A `MessageOptions` object. + * @throws An error if parsing JSON or a check failed. + */ + parseStringifiedMessageOptions(content) { + let mo; + if (content.startsWith("{") && content.endsWith("}")) { + this.log.debug(`Content seems to be json`); + try { + mo = JSON.parse(content); + } catch (_err) { + throw new Error(`Content seems to be json but cannot be parsed!`); + } + if (!mo?.files && !mo.content || mo.files && !Array.isArray(mo.files) || mo.embeds && !Array.isArray(mo.embeds)) { + throw new Error(`Content is json but seems to be invalid!`); + } + } else { + mo = { + content + }; + } + return mo; + } + /** + * Check if a user or guild member is authorized to do something. + * For guild members their roles will also be checked. + * @param user The User or GuildMember to check. + * @param required Object containing the required flags. If not provided the check returns if the user in the list of authorized users. + * @returns `true` if the user is authorized or authorization is not enabled, `false` otherwise + */ + checkUserAuthorization(user, required) { + if (!this.config.enableAuthorization) { + return true; + } + let given = this.config.authorizedUsers.find((au) => au.userId === user.id); + if (this.config.authorizedServerRoles.length > 0 && user instanceof import_discord.GuildMember) { + for (const [, role] of user.roles.cache) { + const roleGiven = this.config.authorizedServerRoles.find((ar) => ar.serverAndRoleId === `${user.guild.id}|${role.id}`); + if (roleGiven) { + if (!given) { + given = roleGiven; + } else { + given = { + getStates: given.getStates || roleGiven.getStates, + setStates: given.setStates || roleGiven.setStates, + useCustomCommands: given.useCustomCommands || roleGiven.useCustomCommands, + useText2command: given.useText2command || roleGiven.useText2command + }; + } + } + } + } + if (!given) { + return false; + } + if (!required) { + return true; + } + if (required.getStates && !given.getStates || required.setStates && !given.setStates || required.useCustomCommands && !given.useCustomCommands || required.useText2command && !given.useText2command) { + return false; + } + return true; + } + /** + * Awaitable function to just wait some time. + * + * Uses `Adapter.setTimeout(...)` internally to make sure the timeout is cleared on adapter unload. + * @param time Time to wait in ms. + */ + async wait(time) { + return await new Promise((resolve) => this.setTimeout(resolve, time)); + } + /** + * Internal replacemend for `extendObject(...)` which compares the given + * object for each `id` against a cached version and only calls na original + * `extendObject(...)` if the object changed. + * Using this, the object gets only updated if + * a) it's the first call for this `id` or + * b) the object needs to be changed. + */ + async extendObjectCached(id, objPart, options) { + const cachedObj = this.extendObjectCache.get(id); + if ((0, import_node_util.isDeepStrictEqual)(cachedObj, objPart)) { + return { id }; + } + let ret; + if (options) { + ret = await this.extendObject(id, objPart, options); + } else { + ret = await this.extendObject(id, objPart); + } + this.extendObjectCache.set(id, objPart); + return ret; + } + /** + * Internal replacement for `delObjectAsync(...)` which also removes the local + * cache entry for the given `id`. + */ + async delObjectAsyncCached(id, options) { + if (options?.recursive) { + this.extendObjectCache.filter((_obj, id2) => id2.startsWith(id)).each((_obj, id2) => this.extendObjectCache.delete(id2)); + } else { + this.extendObjectCache.delete(id); + } + return await this.delObjectAsync(id, options); + } async onReady() { - var _a, _b, _c, _d; await this.setInfoConnectionState(false, true); this.log.debug(`Version of discord.js: ${import_discord.version}`); const systemConfig = await this.getForeignObjectAsync("system.config"); - import_i18n.i18n.language = (systemConfig == null ? void 0 : systemConfig.common.language) || "en"; - import_i18n.i18n.isFloatComma = (systemConfig == null ? void 0 : systemConfig.common.isFloatComma) || false; - if (typeof this.config.token !== "string" || !this.config.token.match(/^[0-9a-zA-Z-_]{24,}\.[0-9a-zA-Z-_]{6}\.[0-9a-zA-Z-_]{27,}$/)) { + import_i18n.i18n.language = systemConfig?.common.language ?? "en"; + import_i18n.i18n.isFloatComma = systemConfig?.common.isFloatComma ?? false; + if (typeof this.config.token !== "string" || !/^[0-9a-zA-Z-_]{24,}\.[0-9a-zA-Z-_]{6}\.[0-9a-zA-Z-_]{27,}$/.exec(this.config.token)) { this.log.error(`No or invalid token!`); return; } @@ -143,9 +261,9 @@ class DiscordAdapter extends import_adapter_core.Adapter { if (this.config.enableCustomCommands && !Array.isArray(this.config.customCommands)) { this.config.customCommands = []; } - this.config.reactOnMentionsEmoji = ((_a = this.config.reactOnMentionsEmoji) == null ? void 0 : _a.trim()) || "\u{1F44D}"; + this.config.reactOnMentionsEmoji = this.config.reactOnMentionsEmoji?.trim() || "\u{1F44D}"; const botActivityTypeObj = await this.getObjectAsync("bot.activityType"); - if ((_c = (_b = botActivityTypeObj == null ? void 0 : botActivityTypeObj.common) == null ? void 0 : _b.states) == null ? void 0 : _c.hasOwnProperty("PLAYING")) { + if (botActivityTypeObj?.common?.states?.PLAYING) { delete botActivityTypeObj.common.states.PLAYING; delete botActivityTypeObj.common.states.STREAMING; delete botActivityTypeObj.common.states.LISTENING; @@ -154,7 +272,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { await this.setObjectAsync("bot.activityType", botActivityTypeObj); } if (this.config.enableRawStates) { - await this.extendObjectAsync("raw", { + await this.extendObject("raw", { type: "channel", common: { name: import_i18n.i18n.getStringOrTranslated("Raw data") @@ -162,7 +280,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { native: {} }); await Promise.all([ - this.extendObjectAsync("raw.interactionJson", { + this.extendObject("raw.interactionJson", { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last interaction JSON data"), @@ -174,7 +292,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsync("raw.messageJson", { + this.extendObject("raw.messageJson", { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message JSON data"), @@ -191,7 +309,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { await this.delObjectAsync("raw", { recursive: true }); } if (this.config.enableCustomCommands) { - await this.extendObjectAsync("slashCommands", { + await this.extendObject("slashCommands", { type: "channel", common: { name: import_i18n.i18n.getStringOrTranslated("Custom Discord slash commands") @@ -229,7 +347,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.client.on("invalidRequestWarning", (invalidRequestWarningData) => this.log.warn(`Discord client invalid request warning: ${JSON.stringify(invalidRequestWarningData)}`)); this.client.on("invalidated", () => { this.log.warn("Discord client session invalidated"); - this.setInfoConnectionState(false); + void this.setInfoConnectionState(false); }); this.client.on("shardError", (err, shardId) => { let errorMsg; @@ -238,10 +356,10 @@ class DiscordAdapter extends import_adapter_core.Adapter { } else { errorMsg = err.toString(); } - if (this.isShardError != errorMsg) { + if (this.isShardError !== errorMsg) { this.isShardError = errorMsg; this.log.warn(`Discord client websocket error (shardId:${shardId}): ${errorMsg}`); - this.setInfoConnectionState(false); + void this.setInfoConnectionState(false); } else { this.log.debug(`Discord client websocket error (shardId:${shardId}): ${errorMsg}`); } @@ -249,8 +367,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.client.on("shardReady", (shardId) => { this.isShardError = false; this.log.info(`Discord client websocket connected (shardId:${shardId})`); - this.setInfoConnectionState(true); - this.setBotPresence(); + void this.setInfoConnectionState(true); + void this.setBotPresence(); }); this.client.on("shardResume", (shardId, replayedEvents) => this.log.debug(`Discord client websocket resume (shardId:${shardId} replayedEvents:${replayedEvents})`)); this.client.on("shardDisconnect", (event, shardId) => this.log.debug(`Discord client websocket disconnect (shardId:${shardId} code:${event.code})`)); @@ -271,14 +389,12 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.client.on("userUpdate", () => this.updateGuilds()); } if (this.config.observeUserPresence) { - this.client.on("presenceUpdate", (_oldPresence, newPresence) => { - this.updateUserPresence(newPresence.userId, newPresence); - }); + this.client.on("presenceUpdate", (_oldPresence, newPresence) => this.updateUserPresence(newPresence.userId, newPresence)); } if (this.config.observeUserVoiceState) { this.client.on("voiceStateUpdate", this.onClientVoiceStateUpdate); } - this.discordSlashCommands.onReady(); + await this.discordSlashCommands.onReady(); this.subscribeStates("servers.*.channels.*.send"); this.subscribeStates("servers.*.channels.*.sendFile"); this.subscribeStates("servers.*.channels.*.sendReply"); @@ -296,9 +412,9 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.subscribeForeignObjects("*"); this.log.debug("Get all objects with custom config ..."); const view = await this.getObjectViewAsync("system", "custom", {}); - if (view == null ? void 0 : view.rows) { + if (view?.rows) { for (const item of view.rows) { - await this.setupObjCustom(item.id, (_d = item.value) == null ? void 0 : _d[this.namespace]); + await this.setupObjCustom(item.id, item.value?.[this.namespace]); } } this.log.debug("Getting all objects with custom config done"); @@ -351,7 +467,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { } this.log.info(`Wait ${LOGIN_WAIT_TIMES[tryNr] / 1e3} seconds before next login try (#${tryNr + 1}) ...`); await this.wait(LOGIN_WAIT_TIMES[tryNr]); - return this.loginClient(tryNr); + return await this.loginClient(tryNr); } return err.name; } else { @@ -361,8 +477,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { } } async onClientReady() { - var _a; - if (!((_a = this.client) == null ? void 0 : _a.user)) { + if (!this.client?.user) { this.log.error("Discord client has no user!"); return; } @@ -400,8 +515,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { * This will create/update all dynamic objects for all servers and users if needed. */ async updateGuilds() { - var _a, _b, _c, _d; - if (!((_a = this.client) == null ? void 0 : _a.user)) { + if (!this.client?.user) { throw new Error("Client not loaded"); } const allServersUsers = new import_discord.Collection(); @@ -425,7 +539,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { if (this.unloaded) return; knownServersAndChannelsIds.add(`${this.namespace}.servers.${guild.id}`); - await this.extendObjectAsyncCached(`servers.${guild.id}`, { + await this.extendObjectCached(`servers.${guild.id}`, { type: "channel", common: { name: guild.name @@ -433,14 +547,14 @@ class DiscordAdapter extends import_adapter_core.Adapter { native: {} }); await Promise.all([ - this.extendObjectAsyncCached(`servers.${guild.id}.members`, { + this.extendObjectCached(`servers.${guild.id}.members`, { type: "channel", common: { name: import_i18n.i18n.getStringOrTranslated("Members") }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.channels`, { + this.extendObjectCached(`servers.${guild.id}.channels`, { type: "channel", common: { name: import_i18n.i18n.getStringOrTranslated("Channels") @@ -455,7 +569,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { if (member.user.id !== this.client.user.id) { allServersUsers.set(member.user.id, { user: member.user, presence: member.presence }); } - await this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}`, { + await this.extendObjectCached(`servers.${guild.id}.members.${member.id}`, { type: "channel", common: { name: `${member.displayName} (${(0, import_utils.userNameOrTag)(member.user)})` @@ -463,7 +577,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { native: {} }); await Promise.all([ - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.tag`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.tag`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("User tag"), @@ -475,7 +589,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.name`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.name`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("User name"), @@ -487,7 +601,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.displayName`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.displayName`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Display name"), @@ -499,7 +613,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.roles`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.roles`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Roles"), @@ -511,7 +625,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.joinedAt`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.joinedAt`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Joined at"), @@ -523,7 +637,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceChannel`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceChannel`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Voice channel"), @@ -535,7 +649,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceDisconnect`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceDisconnect`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Voice disconnect"), @@ -547,7 +661,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Voice self deafen"), @@ -559,7 +673,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Voice server deafen"), @@ -571,7 +685,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Voice self mute"), @@ -583,7 +697,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceServerMute`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceServerMute`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Voice server mute"), @@ -595,7 +709,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.json`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.json`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("JSON data"), @@ -610,16 +724,16 @@ class DiscordAdapter extends import_adapter_core.Adapter { ]); const memberRoles = member.roles.cache.map((role) => role.name); await Promise.all([ - this.setStateAsync(`servers.${guild.id}.members.${member.id}.tag`, member.user.tag, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.name`, member.user.username, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.displayName`, member.displayName, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.roles`, memberRoles.join(", "), true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.joinedAt`, member.joinedTimestamp, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceChannel`, ((_b = member.voice.channel) == null ? void 0 : _b.name) ?? "", true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, !!member.voice.selfDeaf, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, !!member.voice.serverDeaf, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, !!member.voice.selfMute, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceServerMute`, !!member.voice.serverMute, true) + this.setState(`servers.${guild.id}.members.${member.id}.tag`, member.user.tag, true), + this.setState(`servers.${guild.id}.members.${member.id}.name`, member.user.username, true), + this.setState(`servers.${guild.id}.members.${member.id}.displayName`, member.displayName, true), + this.setState(`servers.${guild.id}.members.${member.id}.roles`, memberRoles.join(", "), true), + this.setState(`servers.${guild.id}.members.${member.id}.joinedAt`, member.joinedTimestamp, true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceChannel`, member.voice.channel?.name ?? "", true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, !!member.voice.selfDeaf, true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, !!member.voice.serverDeaf, true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, !!member.voice.selfMute, true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceServerMute`, !!member.voice.serverMute, true) ]); const json = { tag: member.user.tag, @@ -628,15 +742,15 @@ class DiscordAdapter extends import_adapter_core.Adapter { displayName: member.displayName, roles: memberRoles, joined: member.joinedTimestamp, - voiceChannel: ((_c = member.voice.channel) == null ? void 0 : _c.name) ?? "", - voiceChannelId: ((_d = member.voice.channel) == null ? void 0 : _d.id) ?? "", + voiceChannel: member.voice.channel?.name ?? "", + voiceChannelId: member.voice.channel?.id ?? "", voiceSelfDeaf: !!member.voice.selfDeaf, voiceServerDeaf: !!member.voice.serverDeaf, voiceSelfMute: !!member.voice.selfMute, voiceServerMute: !!member.voice.serverMute }; if (!(0, import_node_util.isDeepStrictEqual)(json, this.jsonStateCache.get(`${this.namespace}.servers.${guild.id}.members.${member.id}.json`))) { - await this.setStateAsync(`servers.${guild.id}.members.${member.id}.json`, JSON.stringify(json), true); + await this.setState(`servers.${guild.id}.members.${member.id}.json`, JSON.stringify(json), true); this.jsonStateCache.set(`${this.namespace}.servers.${guild.id}.members.${member.id}.json`, json); } } @@ -652,14 +766,14 @@ class DiscordAdapter extends import_adapter_core.Adapter { } const channelIdPrefix = parents ? `servers.${guild.id}.channels.${channel.id}` : `servers.${guild.id}.channels.${channel.parentId}.channels.${channel.id}`; knownServersAndChannelsIds.add(`${this.namespace}.${channelIdPrefix}`); - let icon = void 0; + let icon; if (channel.type === import_discord.ChannelType.GuildText) { icon = "channel-text.svg"; } if (channel.type === import_discord.ChannelType.GuildVoice) { icon = "channel-voice.svg"; } - await this.extendObjectAsyncCached(channelIdPrefix, { + await this.extendObjectCached(channelIdPrefix, { type: "channel", common: { name: channel.parent ? `${channel.parent.name} / ${channel.name}` : channel.name, @@ -670,7 +784,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { } }); if (channel.type === import_discord.ChannelType.GuildCategory) { - await this.extendObjectAsyncCached(`${channelIdPrefix}.channels`, { + await this.extendObjectCached(`${channelIdPrefix}.channels`, { type: "channel", common: { name: import_i18n.i18n.getStringOrTranslated("Channels") @@ -679,7 +793,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }); } await Promise.all([ - this.extendObjectAsyncCached(`${channelIdPrefix}.json`, { + this.extendObjectCached(`${channelIdPrefix}.json`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("JSON data"), @@ -691,7 +805,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.memberCount`, { + this.extendObjectCached(`${channelIdPrefix}.memberCount`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Member count"), @@ -703,7 +817,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.members`, { + this.extendObjectCached(`${channelIdPrefix}.members`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Members"), @@ -718,7 +832,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { ]); if (channel.type === import_discord.ChannelType.GuildText || channel.type === import_discord.ChannelType.GuildVoice) { await Promise.all([ - this.extendObjectAsyncCached(`${channelIdPrefix}.message`, { + this.extendObjectCached(`${channelIdPrefix}.message`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message"), @@ -730,7 +844,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.messageId`, { + this.extendObjectCached(`${channelIdPrefix}.messageId`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message ID"), @@ -742,7 +856,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.messageAuthor`, { + this.extendObjectCached(`${channelIdPrefix}.messageAuthor`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message author"), @@ -754,7 +868,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.messageTimestamp`, { + this.extendObjectCached(`${channelIdPrefix}.messageTimestamp`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message timestamp"), @@ -766,7 +880,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.messageJson`, { + this.extendObjectCached(`${channelIdPrefix}.messageJson`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message JSON data"), @@ -778,7 +892,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.send`, { + this.extendObjectCached(`${channelIdPrefix}.send`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send message"), @@ -790,7 +904,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.sendFile`, { + this.extendObjectCached(`${channelIdPrefix}.sendFile`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send file"), @@ -802,7 +916,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.sendReply`, { + this.extendObjectCached(`${channelIdPrefix}.sendReply`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send reply"), @@ -814,7 +928,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`${channelIdPrefix}.sendReaction`, { + this.extendObjectCached(`${channelIdPrefix}.sendReaction`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send reaction"), @@ -851,7 +965,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { } for (const [, { user, presence }] of allServersUsers) { this.log.debug(`Known user: ${user.tag} id:${user.id}`); - await this.extendObjectAsyncCached(`users.${user.id}`, { + await this.extendObjectCached(`users.${user.id}`, { type: "channel", common: { name: (0, import_utils.userNameOrTag)(user) @@ -861,7 +975,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { } }); await Promise.all([ - this.extendObjectAsyncCached(`users.${user.id}.json`, { + this.extendObjectCached(`users.${user.id}.json`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("JSON data"), @@ -873,7 +987,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.tag`, { + this.extendObjectCached(`users.${user.id}.tag`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("User tag"), @@ -885,7 +999,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.name`, { + this.extendObjectCached(`users.${user.id}.name`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("User name"), @@ -897,7 +1011,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.message`, { + this.extendObjectCached(`users.${user.id}.message`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message"), @@ -909,7 +1023,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.messageId`, { + this.extendObjectCached(`users.${user.id}.messageId`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message ID"), @@ -921,7 +1035,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.messageTimestamp`, { + this.extendObjectCached(`users.${user.id}.messageTimestamp`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message timestamp"), @@ -933,7 +1047,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.messageJson`, { + this.extendObjectCached(`users.${user.id}.messageJson`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Last message JSON data"), @@ -945,7 +1059,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.send`, { + this.extendObjectCached(`users.${user.id}.send`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send message"), @@ -957,7 +1071,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.sendFile`, { + this.extendObjectCached(`users.${user.id}.sendFile`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send file"), @@ -969,7 +1083,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.sendReply`, { + this.extendObjectCached(`users.${user.id}.sendReply`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send reply"), @@ -981,7 +1095,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.sendReaction`, { + this.extendObjectCached(`users.${user.id}.sendReaction`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Send reaction"), @@ -993,7 +1107,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.avatarUrl`, { + this.extendObjectCached(`users.${user.id}.avatarUrl`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Avatar"), @@ -1005,7 +1119,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.bot`, { + this.extendObjectCached(`users.${user.id}.bot`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Bot"), @@ -1017,7 +1131,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.status`, { + this.extendObjectCached(`users.${user.id}.status`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Status"), @@ -1029,7 +1143,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.activityType`, { + this.extendObjectCached(`users.${user.id}.activityType`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Activity type"), @@ -1041,7 +1155,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { }, native: {} }), - this.extendObjectAsyncCached(`users.${user.id}.activityName`, { + this.extendObjectCached(`users.${user.id}.activityName`, { type: "state", common: { name: import_i18n.i18n.getStringOrTranslated("Activity name"), @@ -1069,14 +1183,14 @@ class DiscordAdapter extends import_adapter_core.Adapter { status: ps.status }; if (!(0, import_node_util.isDeepStrictEqual)(json, this.jsonStateCache.get(`${this.namespace}.users.${user.id}.json`))) { - proms.push(this.setStateAsync(`users.${user.id}.json`, JSON.stringify(json), true)); + proms.push(this.setState(`users.${user.id}.json`, JSON.stringify(json), true)); this.jsonStateCache.set(`${this.namespace}.users.${user.id}.json`, json); } await Promise.all([ - this.setStateAsync(`users.${user.id}.tag`, user.tag, true), - this.setStateAsync(`users.${user.id}.name`, user.username, true), - this.setStateAsync(`users.${user.id}.avatarUrl`, json.avatarUrl, true), - this.setStateAsync(`users.${user.id}.bot`, user.bot, true), + this.setState(`users.${user.id}.tag`, user.tag, true), + this.setState(`users.${user.id}.name`, user.username, true), + this.setState(`users.${user.id}.avatarUrl`, json.avatarUrl, true), + this.setState(`users.${user.id}.bot`, user.bot, true), ...proms, this.updateUserPresence(user.id, presence) ]); @@ -1140,12 +1254,12 @@ class DiscordAdapter extends import_adapter_core.Adapter { }; const proms = []; if (!(0, import_node_util.isDeepStrictEqual)(json, this.jsonStateCache.get(`${this.namespace}.${channelIdPrefix}.json`))) { - proms.push(this.setStateAsync(`${channelIdPrefix}.json`, JSON.stringify(json), true)); + proms.push(this.setState(`${channelIdPrefix}.json`, JSON.stringify(json), true)); this.jsonStateCache.set(`${this.namespace}.${channelIdPrefix}.json`, json); } await Promise.all([ - this.setStateAsync(`${channelIdPrefix}.memberCount`, members.length, true), - this.setStateAsync(`${channelIdPrefix}.members`, members.map((m) => m.displayName).join(", "), true), + this.setState(`${channelIdPrefix}.memberCount`, members.length, true), + this.setState(`${channelIdPrefix}.members`, members.map((m) => m.displayName).join(", "), true), ...proms ]); } @@ -1156,7 +1270,6 @@ class DiscordAdapter extends import_adapter_core.Adapter { * @param skipJsonStateUpdate If the json state of the user should not be updated. */ async updateUserPresence(userId, presence, skipJsonStateUpdate = false) { - var _a, _b, _c, _d; if (!this.config.observeUserPresence) { return { activityName: "", activityType: "", status: "" }; } @@ -1166,9 +1279,9 @@ class DiscordAdapter extends import_adapter_core.Adapter { } try { const p = { - status: (presence == null ? void 0 : presence.status) ?? "", - activityName: (((_a = presence == null ? void 0 : presence.activities[0]) == null ? void 0 : _a.type) === import_discord.ActivityType.Custom ? (_b = presence == null ? void 0 : presence.activities[0]) == null ? void 0 : _b.state : (_c = presence == null ? void 0 : presence.activities[0]) == null ? void 0 : _c.name) ?? "", - activityType: (((_d = presence == null ? void 0 : presence.activities[0]) == null ? void 0 : _d.type) !== void 0 ? import_discord.ActivityType[presence.activities[0].type] : "") ?? "" + status: presence?.status ?? "", + activityName: (presence?.activities[0]?.type === import_discord.ActivityType.Custom ? presence?.activities[0]?.state : presence?.activities[0]?.name) ?? "", + activityType: (presence?.activities[0]?.type !== void 0 ? import_discord.ActivityType[presence.activities[0].type] : "") ?? "" }; const proms = []; if (!skipJsonStateUpdate) { @@ -1178,13 +1291,13 @@ class DiscordAdapter extends import_adapter_core.Adapter { json.activityName = p.activityName; json.activityType = p.activityType; this.jsonStateCache.set(`${this.namespace}.users.${userId}.json`, json); - proms.push(this.setStateAsync(`users.${userId}.json`, JSON.stringify(json), true)); + proms.push(this.setState(`users.${userId}.json`, JSON.stringify(json), true)); } } await Promise.all([ - this.setStateAsync(`users.${userId}.status`, p.status, true), - this.setStateAsync(`users.${userId}.activityName`, p.activityName, true), - this.setStateAsync(`users.${userId}.activityType`, p.activityType, true), + this.setState(`users.${userId}.status`, p.status, true), + this.setState(`users.${userId}.activityName`, p.activityName, true), + this.setState(`users.${userId}.activityType`, p.activityType, true), ...proms ]); return p; @@ -1197,14 +1310,13 @@ class DiscordAdapter extends import_adapter_core.Adapter { * Set the presence status of the discord bot. */ async setBotPresence(opts) { - var _a, _b, _c, _d; - if (!((_a = this.client) == null ? void 0 : _a.user)) + if (!this.client?.user) return; if (!opts) { opts = {}; } if (!opts.status) { - opts.status = ((_b = await this.getStateAsync("bot.status")) == null ? void 0 : _b.val) ?? "online"; + opts.status = (await this.getStateAsync("bot.status"))?.val ?? "online"; } if (!import_definitions.VALID_PRESENCE_STATUS_DATA.includes(opts.status)) { opts.status = "online"; @@ -1214,14 +1326,14 @@ class DiscordAdapter extends import_adapter_core.Adapter { activities: [] }; if (opts.activityType === void 0) { - opts.activityType = ((_c = await this.getStateAsync("bot.activityType")) == null ? void 0 : _c.val) ?? ""; + opts.activityType = (await this.getStateAsync("bot.activityType"))?.val ?? ""; } if (!import_definitions.ACTIVITY_TYPES.includes(opts.activityType)) { this.log.warn(`Invalid activityType! ${opts.activityType}`); opts.activityType = ""; } if (opts.activityName === void 0) { - opts.activityName = ((_d = await this.getStateAsync("bot.activityName")) == null ? void 0 : _d.val) ?? ""; + opts.activityName = (await this.getStateAsync("bot.activityName"))?.val ?? ""; } if (opts.activityType && opts.activityName) { presenceData.activities = [{ @@ -1233,14 +1345,13 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.client.user.setPresence(presenceData); } async onClientMessageCreate(message) { - var _a, _b, _c, _d, _e; this.log.debug(`Discord message: mId:${message.id} cId:${message.channelId} uId: ${message.author.id} - ${message.content}`); if (this.config.enableRawStates) { - this.setState("raw.messageJson", JSON.stringify(message.toJSON(), (_key, value) => typeof value === "bigint" ? value.toString() : value), true); + void this.setState("raw.messageJson", JSON.stringify(message.toJSON(), (_key, value) => typeof value === "bigint" ? value.toString() : value), true); } - if (!((_b = (_a = this.client) == null ? void 0 : _a.user) == null ? void 0 : _b.id)) + if (!this.client?.user?.id) return; - if (message.interaction) { + if (message.interactionMetadata) { return; } const { author, channel, content } = message; @@ -1285,7 +1396,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { content, attachments: message.attachments.map((att) => ({ attachment: att.url, name: att.name, description: att.description ?? "", size: att.size, contentType: att.contentType ?? "", id: att.id })), id: message.id, - mentions: ((_c = message.mentions.members) == null ? void 0 : _c.map((m) => ({ id: m.id, tag: m.user.tag, name: m.user.username, displayName: m.displayName }))) ?? [], + mentions: message.mentions.members?.map((m) => ({ id: m.id, tag: m.user.tag, name: m.user.username, displayName: m.displayName })) ?? [], mentioned, timestamp: message.createdTimestamp, authorized: isAuthorAuthorized @@ -1296,18 +1407,18 @@ class DiscordAdapter extends import_adapter_core.Adapter { id: author.id, tag: author.tag, name: author.username, - displayName: ((_e = (_d = this.client.guilds.cache.get(message.guildId)) == null ? void 0 : _d.members.cache.get(author.id)) == null ? void 0 : _e.displayName) ?? author.username + displayName: this.client.guilds.cache.get(message.guildId)?.members.cache.get(author.id)?.displayName ?? author.username }; - proms.push(this.setStateAsync(`${msgStateIdPrefix}.messageAuthor`, (0, import_utils.userNameOrTag)(author), true)); + proms.push(this.setState(`${msgStateIdPrefix}.messageAuthor`, (0, import_utils.userNameOrTag)(author), true)); } if (!(0, import_node_util.isDeepStrictEqual)(json, this.jsonStateCache.get(`${this.namespace}.${msgStateIdPrefix}.messageJson`))) { - proms.push(this.setStateAsync(`${msgStateIdPrefix}.messageJson`, JSON.stringify(json), true)); + proms.push(this.setState(`${msgStateIdPrefix}.messageJson`, JSON.stringify(json), true)); this.jsonStateCache.set(`${this.namespace}.${msgStateIdPrefix}.messageJson`, json); } await Promise.all([ - this.setStateAsync(`${msgStateIdPrefix}.message`, content, true), - this.setStateAsync(`${msgStateIdPrefix}.messageId`, message.id, true), - this.setStateAsync(`${msgStateIdPrefix}.messageTimestamp`, message.createdTimestamp, true), + this.setState(`${msgStateIdPrefix}.message`, content, true), + this.setState(`${msgStateIdPrefix}.messageId`, message.id, true), + this.setState(`${msgStateIdPrefix}.messageTimestamp`, message.createdTimestamp, true), ...proms ]); if (content && this.config.text2commandInstance && this.text2commandObjects.has(`${msgStateIdPrefix}.message`)) { @@ -1317,7 +1428,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { text: content }; this.sendTo(this.config.text2commandInstance, "send", payload, async (responseObj) => { - const response = responseObj == null ? void 0 : responseObj.response; + const response = responseObj?.response; try { if (!response) { this.log.debug(`Empty response from ${this.config.text2commandInstance}`); @@ -1329,7 +1440,9 @@ class DiscordAdapter extends import_adapter_core.Adapter { await message.reply(response); break; case "message": - await message.channel.send(response); + if (message.channel.isTextBased()) { + await message.channel.send(response); + } break; default: } @@ -1343,8 +1456,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { } } async onClientVoiceStateUpdate(oldState, newState) { - var _a, _b, _c, _d; - if (!((_a = newState.member) == null ? void 0 : _a.id)) { + if (!newState.member?.id) { return; } const proms = []; @@ -1362,33 +1474,33 @@ class DiscordAdapter extends import_adapter_core.Adapter { }; let update = false; if (oldState.channelId !== newState.channelId) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceChannel`, ((_b = newState.channel) == null ? void 0 : _b.name) ?? "", true)); - json.voiceChannel = ((_c = newState.channel) == null ? void 0 : _c.name) ?? ""; - json.voiceChannelId = ((_d = newState.channel) == null ? void 0 : _d.id) ?? ""; + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceChannel`, newState.channel?.name ?? "", true)); + json.voiceChannel = newState.channel?.name ?? ""; + json.voiceChannelId = newState.channel?.id ?? ""; update = true; } if (oldState.serverDeaf !== newState.serverDeaf) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerDeaf`, !!newState.serverDeaf, true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerDeaf`, !!newState.serverDeaf, true)); json.voiceSelfDeaf = !!newState.selfDeaf; update = true; } if (oldState.selfDeaf !== newState.selfDeaf) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfDeaf`, !!newState.selfDeaf, true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfDeaf`, !!newState.selfDeaf, true)); json.voiceServerDeaf = !!newState.serverDeaf; update = true; } if (oldState.serverMute !== newState.serverMute) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerMute`, !!newState.serverMute, true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerMute`, !!newState.serverMute, true)); json.voiceSelfMute = !!newState.selfMute; update = true; } if (oldState.selfMute !== newState.selfMute) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfMute`, !!newState.selfMute, true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfMute`, !!newState.selfMute, true)); json.voiceServerMute = !!newState.serverMute; update = true; } if (update) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.json`, JSON.stringify(json), true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.json`, JSON.stringify(json), true)); this.jsonStateCache.set(`${this.namespace}.servers.${newState.guild.id}.members.${newState.member.id}.json`, json); } } else { @@ -1404,7 +1516,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { */ async setupObjCustom(objId, customCfg, objCommon) { if (objId.startsWith(`${this.namespace}.`) && objId.endsWith(".message")) { - if ((customCfg == null ? void 0 : customCfg.enabled) && customCfg.enableText2command) { + if (customCfg?.enabled && customCfg.enableText2command) { this.log.debug(`Custom option text2command enabled for ${objId}`); this.text2commandObjects.add(objId); } else if (this.text2commandObjects.has(objId)) { @@ -1412,10 +1524,10 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.text2commandObjects.delete(objId); } } - if (customCfg == null ? void 0 : customCfg.enableCommands) { + if (customCfg?.enableCommands) { if (!objCommon) { const obj = await this.getForeignObjectAsync(objId); - if ((obj == null ? void 0 : obj.type) === "state") { + if (obj?.type === "state") { objCommon = obj.common; } else { this.log.warn(`Object ${objId} has commands enabled but this seems to be an error because it is not a state object!`); @@ -1441,7 +1553,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.log.warn(`Command name for ${objId} exceeds the limit of 100 chars! This object will be ignored.`); cfgOk = false; } - if (!cfg.alias.match(/^[0-9a-zA-Z._-]{0,100}$/)) { + if (!/^[0-9a-zA-Z._-]{0,100}$/.exec(cfg.alias)) { this.log.warn(`Command alias for ${objId} includes invalid chars or exceeds the limit of 100 chars! This object will be ignored.`); cfgOk = false; } @@ -1451,19 +1563,18 @@ class DiscordAdapter extends import_adapter_core.Adapter { } } onObjectChange(objId, obj) { - var _a, _b; if (obj) { if (obj.type === "state") { this.log.silly(`Object ${objId} changed: ${JSON.stringify(obj)}`); - this.setupObjCustom(objId, (_b = (_a = obj.common) == null ? void 0 : _a.custom) == null ? void 0 : _b[this.namespace], obj.common); + void this.setupObjCustom(objId, obj.common?.custom?.[this.namespace], obj.common); } } else { this.log.silly(`Object ${objId} deleted`); - this.setupObjCustom(objId, null); + void this.setupObjCustom(objId, null); } } async onStateChange(stateId, state) { - this.log.silly(`State changed: ${stateId} ${state == null ? void 0 : state.val} (ack=${state == null ? void 0 : state.ack})`); + this.log.silly(`State changed: ${stateId} ${state?.val} (ack=${state?.ack})`); if (!state || state.ack) return; let setAck = false; @@ -1482,9 +1593,9 @@ class DiscordAdapter extends import_adapter_core.Adapter { setAck = true; break; default: - if (stateId.match(/^discord\.\d+\.slashCommands\..*\.sendReply/)) { + if (/^discord\.\d+\.slashCommands\..*\.sendReply/.exec(stateId)) { setAck = await this.onCustomCommandSendReplyStateChange(stateId, state); - } else if (stateId.match(/^discord\.\d+\.slashCommands\..*\.option-[^.]+\.choices/)) { + } else if (/^discord\.\d+\.slashCommands\..*\.option-[^.]+\.choices/.exec(stateId)) { this.discordSlashCommands.triggerDelayedRegisterSlashCommands(); setAck = true; } else if (stateId.endsWith(".send") || stateId.endsWith(".sendFile") || stateId.endsWith(".sendReply") || stateId.endsWith(".sendReaction")) { @@ -1495,7 +1606,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { } } if (setAck) { - await this.setStateAsync(stateId, { + await this.setState(stateId, { ...state, ack: true }); @@ -1507,8 +1618,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { * @returns `true` if the message is send. */ async onSendStateChange(stateId, state) { - var _a, _b, _c; - if (!((_a = this.client) == null ? void 0 : _a.isReady())) { + if (!this.client?.isReady()) { this.log.warn(`State ${stateId} changed but client is not ready!`); return false; } @@ -1524,13 +1634,13 @@ class DiscordAdapter extends import_adapter_core.Adapter { let target; let targetName = ""; let targetStateIdBase; - let m = stateId.match(/^(discord\.\d+\.servers\.(\d+)\.channels\.(\d+)(\.channels\.(\d+))?)\.(send|sendFile|sendReaction|sendReply)$/); + let m = /^(discord\.\d+\.servers\.(\d+)\.channels\.(\d+)(\.channels\.(\d+))?)\.(send|sendFile|sendReaction|sendReply)$/.exec(stateId); if (m) { const guildId = m[2]; const channelId = m[5] || m[3]; targetStateIdBase = m[1]; action = m[6]; - const channel = (_b = this.client.guilds.cache.get(guildId)) == null ? void 0 : _b.channels.cache.get(channelId); + const channel = this.client.guilds.cache.get(guildId)?.channels.cache.get(channelId); if (!channel || channel.type !== import_discord.ChannelType.GuildText && channel.type !== import_discord.ChannelType.GuildVoice || channel.isThread()) { this.log.warn(`State ${stateId} changed but target is not a valid text channel!`); return false; @@ -1538,7 +1648,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { target = channel; targetName = channel.parent ? `${channel.guild.name}/${channel.parent.name}/${channel.name}` : `${channel.guild.name}/${channel.name}`; } else { - m = stateId.match(/^(discord\.\d+\.users\.(\d+))\.(send|sendFile|sendReaction|sendReply)$/); + m = /^(discord\.\d+\.users\.(\d+))\.(send|sendFile|sendReaction|sendReply)$/.exec(stateId); if (!m) { this.log.warn(`State ${stateId} changed but could not determine target to send message to!`); return false; @@ -1558,7 +1668,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { if (action === "sendFile") { const idx = state.val.indexOf("|"); let file; - let content = void 0; + let content; if (idx > 0) { file = state.val.slice(0, idx); content = state.val.slice(idx + 1); @@ -1596,7 +1706,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { content = state.val.slice(idx + 1); } else { this.log.debug(`Get reply message reference from last received message for ${targetStateIdBase}`); - messageReference = (_c = await this.getForeignStateAsync(`${targetStateIdBase}.messageId`)) == null ? void 0 : _c.val; + messageReference = (await this.getForeignStateAsync(`${targetStateIdBase}.messageId`))?.val; content = state.val; } if (action === "sendReply") { @@ -1664,8 +1774,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { * @returns `true` if the reply is send. */ async onCustomCommandSendReplyStateChange(stateId, state) { - var _a, _b; - if (!((_a = this.client) == null ? void 0 : _a.isReady())) { + if (!this.client?.isReady()) { this.log.warn(`State ${stateId} changed but client is not ready!`); return false; } @@ -1686,7 +1795,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { content = state.val.slice(idx + 1); } else { this.log.debug(`Get reply interaction reference from last received interaction for ${targetStateIdBase}`); - interactionId = (_b = await this.getForeignStateAsync(`${targetStateIdBase}.interactionId`)) == null ? void 0 : _b.val; + interactionId = (await this.getForeignStateAsync(`${targetStateIdBase}.interactionId`))?.val; content = state.val; } if (!interactionId || !content) { @@ -1706,15 +1815,14 @@ class DiscordAdapter extends import_adapter_core.Adapter { * @returns `true` if successfull. */ async onVoiceStateChange(stateId, state) { - var _a; - const m = stateId.match(/^discord\.\d+\.servers\.(\d+)\.members\.(\d+)\.voice(Disconnect|ServerMute|ServerDeaf)$/); + const m = /^discord\.\d+\.servers\.(\d+)\.members\.(\d+)\.voice(Disconnect|ServerMute|ServerDeaf)$/.exec(stateId); if (!m) { this.log.debug(`Voice state ${stateId} changed but could not get serverID and memberID!`); return false; } const [, guildId, memberId, action] = m; - const guild = (_a = this.client) == null ? void 0 : _a.guilds.cache.get(guildId); - const member = guild == null ? void 0 : guild.members.cache.get(memberId); + const guild = this.client?.guilds.cache.get(guildId); + const member = guild?.members.cache.get(memberId); if (!guild || !member) { this.log.warn(`Voice state ${stateId} changed but could not get the server member!`); return false; @@ -1746,7 +1854,6 @@ class DiscordAdapter extends import_adapter_core.Adapter { } } async onMessage(obj) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B; if (typeof obj !== "object") return; this.log.debug(`Got message: ${JSON.stringify(obj)}`); @@ -1754,7 +1861,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { let msg; let user; switch (obj.command) { - case "getText2commandInstances": + case "getText2commandInstances": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -1773,16 +1880,17 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.log.debug(`Found text2command instances: ${text2commandInstances.map((i) => i.value)}`); this.sendTo(obj.from, obj.command, [{ value: "", label: "---" }, ...text2commandInstances], obj.callback); break; - case "getNotificationTargets": + } + case "getNotificationTargets": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; } const targets = [{ value: "", label: "---" }]; - (_a = this.client) == null ? void 0 : _a.users.cache.forEach((u) => { + this.client?.users.cache.forEach((u) => { targets.push({ label: (0, import_utils.userNameOrTag)(u), value: u.id }); }); - (_b = this.client) == null ? void 0 : _b.guilds.cache.forEach((g) => { + this.client?.guilds.cache.forEach((g) => { g.channels.cache.forEach((c) => { if (c.type === import_discord.ChannelType.GuildText) { if (c.parent) { @@ -1796,25 +1904,28 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.log.debug(`Notification targets: ${targets.map((i) => i.value)}`); this.sendTo(obj.from, obj.command, targets, obj.callback); break; - case "getUsers": + } + case "getUsers": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; } - const users = ((_c = this.client) == null ? void 0 : _c.users.cache.map((u) => ({ label: (0, import_utils.userNameOrTag)(u), value: u.id }))) ?? []; + const users = this.client?.users.cache.map((u) => ({ label: (0, import_utils.userNameOrTag)(u), value: u.id })) ?? []; this.log.debug(`Users: ${users.map((i) => i.value)}`); this.sendTo(obj.from, obj.command, users, obj.callback); break; - case "getServers": + } + case "getServers": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; } - const servers = ((_d = this.client) == null ? void 0 : _d.guilds.cache.map((g) => ({ label: g.name, value: g.id }))) ?? []; + const servers = this.client?.guilds.cache.map((g) => ({ label: g.name, value: g.id })) ?? []; this.log.debug(`Servers: ${servers.map((i) => i.value)}`); this.sendTo(obj.from, obj.command, servers, obj.callback); break; - case "getServerRoles": + } + case "getServerRoles": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -1835,12 +1946,13 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.log.debug(`Server roles: ${guildRolesWithLabel.map((i) => i.value)}`); this.sendTo(obj.from, obj.command, guildRolesWithLabel, obj.callback); break; - case "getAddToServerLink": + } + case "getAddToServerLink": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; } - if ((_f = (_e = this.client) == null ? void 0 : _e.user) == null ? void 0 : _f.id) { + if (this.client?.user?.id) { const perms = new import_discord.PermissionsBitField([ import_discord.PermissionsBitField.Flags.ChangeNickname, import_discord.PermissionsBitField.Flags.ViewChannel, @@ -1860,12 +1972,14 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendTo(obj.from, obj.command, `- ${import_i18n.i18n.getString("Error: The Bot is not connected to Discord!")} -`, obj.callback); } break; - case "logConfiguredCommandObjects": + } + case "logConfiguredCommandObjects": { this.discordSlashCommands.logConfiguredCommandObjects(); this.sendToIfCb(obj.from, obj.command, { result: "ok" }, obj.callback); break; + } case "send": - case "sendMessage": + case "sendMessage": { if (typeof obj.message !== "object") { this.sendToIfCb(obj.from, obj.command, { error: "sendTo message needs to be an object" }, obj.callback); return; @@ -1877,19 +1991,19 @@ class DiscordAdapter extends import_adapter_core.Adapter { } if (sendPayload.userId || sendPayload.userTag || sendPayload.userName) { if (sendPayload.userId) { - user = (_g = this.client) == null ? void 0 : _g.users.cache.get(sendPayload.userId); + user = this.client?.users.cache.get(sendPayload.userId); if (!user) { this.sendToIfCb(obj.from, obj.command, { error: `No user with userId ${sendPayload.userId} found`, ...sendPayload }, obj.callback); return; } } else if (sendPayload.userTag) { - user = (_h = this.client) == null ? void 0 : _h.users.cache.find((u) => u.tag === sendPayload.userTag); + user = this.client?.users.cache.find((u) => u.tag === sendPayload.userTag); if (!user) { this.sendToIfCb(obj.from, obj.command, { error: `No user with userTag ${sendPayload.userTag} found`, ...sendPayload }, obj.callback); return; } } else { - user = (_i = this.client) == null ? void 0 : _i.users.cache.find((u) => u.discriminator === "0" && u.username === sendPayload.userName); + user = this.client?.users.cache.find((u) => u.discriminator === "0" && u.username === sendPayload.userName); if (!user) { this.sendToIfCb(obj.from, obj.command, { error: `No user with unique userName ${sendPayload.userName} found`, ...sendPayload }, obj.callback); return; @@ -1902,8 +2016,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error sending message to user ${(0, import_utils.userNameOrTag)(user)}: ${err}`, ...sendPayload }, obj.callback); } } else if (sendPayload.serverId && sendPayload.channelId) { - channel = (_k = (_j = this.client) == null ? void 0 : _j.guilds.cache.get(sendPayload.serverId)) == null ? void 0 : _k.channels.cache.get(sendPayload.channelId); - if ((channel == null ? void 0 : channel.type) !== import_discord.ChannelType.GuildText && (channel == null ? void 0 : channel.type) !== import_discord.ChannelType.GuildVoice) { + channel = this.client?.guilds.cache.get(sendPayload.serverId)?.channels.cache.get(sendPayload.channelId); + if (channel?.type !== import_discord.ChannelType.GuildText && channel?.type !== import_discord.ChannelType.GuildVoice) { this.sendToIfCb(obj.from, obj.command, { error: `No text channel with channelId ${sendPayload.channelId} on server ${sendPayload.serverId} found`, ...sendPayload }, obj.callback); return; } @@ -1917,7 +2031,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendToIfCb(obj.from, obj.command, { error: "userId, userTag, userName or serverId and channelId needs to be set", ...sendPayload }, obj.callback); } break; - case "editMessage": + } + case "editMessage": { if (typeof obj.message !== "object") { this.sendToIfCb(obj.from, obj.command, { error: "sendTo message needs to be an object" }, obj.callback); return; @@ -1948,7 +2063,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error editing message: ${err}`, ...editMessagePayload }, obj.callback); } break; - case "deleteMessage": + } + case "deleteMessage": { if (typeof obj.message !== "object") { this.sendToIfCb(obj.from, obj.command, { error: "sendTo message needs to be an object" }, obj.callback); return; @@ -1975,7 +2091,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error deleting message: ${err}`, ...deleteMessagePayload }, obj.callback); } break; - case "addReaction": + } + case "addReaction": { if (typeof obj.message !== "object") { this.sendToIfCb(obj.from, obj.command, { error: "sendTo message needs to be an object" }, obj.callback); return; @@ -2002,7 +2119,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error adding reaction to message: ${err}`, ...addReactionPayload }, obj.callback); } break; - case "awaitMessageReaction": + } + case "awaitMessageReaction": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2030,10 +2148,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { return; } const reactionCollector = msg.createReactionCollector({ - filter: (_r2, u) => { - var _a2, _b2; - return u.id !== ((_b2 = (_a2 = this.client) == null ? void 0 : _a2.user) == null ? void 0 : _b2.id); - }, + filter: (_r, u) => u.id !== this.client?.user?.id, max: awaitMessageReactionPayload.max, time: awaitMessageReactionPayload.timeout }); @@ -2042,7 +2157,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendTo(obj.from, obj.command, { reactions, ...awaitMessageReactionPayload }, obj.callback); }); break; - case "sendCustomCommandReply": + } + case "sendCustomCommandReply": { if (typeof obj.message !== "object") { this.sendToIfCb(obj.from, obj.command, { error: "sendTo message needs to be an object" }, obj.callback); return; @@ -2063,7 +2179,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error sending reply: ${err}`, ...sendCustomCommandReplyPayload }, obj.callback); } break; - case "leaveServer": + } + case "leaveServer": { if (typeof obj.message !== "object") { this.sendToIfCb(obj.from, obj.command, { error: "sendTo message needs to be an object" }, obj.callback); return; @@ -2073,7 +2190,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendToIfCb(obj.from, obj.command, { error: "serverId needs to be set", ...leaveServerPayload }, obj.callback); return; } - const guildToLeave = (_l = this.client) == null ? void 0 : _l.guilds.cache.get(leaveServerPayload.serverId); + const guildToLeave = this.client?.guilds.cache.get(leaveServerPayload.serverId); if (!guildToLeave) { this.sendToIfCb(obj.from, obj.command, { error: `No server with ID ${leaveServerPayload.serverId} found` }, obj.callback); return; @@ -2086,7 +2203,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error leaving server ${leaveServerPayload.serverId}: ${err}`, ...leaveServerPayload }, obj.callback); } break; - case "getServerInfo": + } + case "getServerInfo": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2100,7 +2218,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendTo(obj.from, obj.command, { error: "serverId needs to be set", ...getServerInfoPayload }, obj.callback); return; } - const server = (_m = this.client) == null ? void 0 : _m.guilds.cache.get(getServerInfoPayload.serverId); + const server = this.client?.guilds.cache.get(getServerInfoPayload.serverId); if (!server) { this.sendTo(obj.from, obj.command, { error: `No server with ID ${getServerInfoPayload.serverId} found`, ...getServerInfoPayload }, obj.callback); return; @@ -2128,7 +2246,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { })) }, obj.callback); break; - case "getChannelInfo": + } + case "getChannelInfo": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2142,7 +2261,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { this.sendTo(obj.from, obj.command, { error: "serverId and channelId need to be set", ...getChannelInfoPayload }, obj.callback); return; } - channel = (_o = (_n = this.client) == null ? void 0 : _n.guilds.cache.get(getChannelInfoPayload.serverId)) == null ? void 0 : _o.channels.cache.get(getChannelInfoPayload.channelId); + channel = this.client?.guilds.cache.get(getChannelInfoPayload.serverId)?.channels.cache.get(getChannelInfoPayload.channelId); if (!channel) { this.sendTo(obj.from, obj.command, { error: `No channel with ID ${getChannelInfoPayload.channelId} for server with ID ${getChannelInfoPayload.serverId} found`, ...getChannelInfoPayload }, obj.callback); return; @@ -2160,7 +2279,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { })) }, obj.callback); break; - case "getServerMemberInfo": + } + case "getServerMemberInfo": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2176,19 +2296,19 @@ class DiscordAdapter extends import_adapter_core.Adapter { } let member; if (getServerMemberInfoPayload.userId) { - member = (_q = (_p = this.client) == null ? void 0 : _p.guilds.cache.get(getServerMemberInfoPayload.serverId)) == null ? void 0 : _q.members.cache.get(getServerMemberInfoPayload.userId); + member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.get(getServerMemberInfoPayload.userId); if (!member) { this.sendTo(obj.from, obj.command, { error: `No member with ID ${getServerMemberInfoPayload.userId} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback); return; } } else if (getServerMemberInfoPayload.userTag) { - member = (_s = (_r = this.client) == null ? void 0 : _r.guilds.cache.get(getServerMemberInfoPayload.serverId)) == null ? void 0 : _s.members.cache.find((m) => m.user.tag === getServerMemberInfoPayload.userTag); + member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.find((m) => m.user.tag === getServerMemberInfoPayload.userTag); if (!member) { this.sendTo(obj.from, obj.command, { error: `No member with tag ${getServerMemberInfoPayload.userTag} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback); return; } } else { - member = (_u = (_t = this.client) == null ? void 0 : _t.guilds.cache.get(getServerMemberInfoPayload.serverId)) == null ? void 0 : _u.members.cache.find((m) => m.user.discriminator === "0" && m.user.username === getServerMemberInfoPayload.userName); + member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.find((m) => m.user.discriminator === "0" && m.user.username === getServerMemberInfoPayload.userName); if (!member) { this.sendTo(obj.from, obj.command, { error: `No member with unique name ${getServerMemberInfoPayload.userName} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback); return; @@ -2212,7 +2332,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { voiceDeaf: member.voice.deaf }, obj.callback); break; - case "getUserInfo": + } + case "getUserInfo": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2227,19 +2348,19 @@ class DiscordAdapter extends import_adapter_core.Adapter { return; } if (getUserInfoPayload.userId) { - user = (_v = this.client) == null ? void 0 : _v.users.cache.get(getUserInfoPayload.userId); + user = this.client?.users.cache.get(getUserInfoPayload.userId); if (!user) { this.sendTo(obj.from, obj.command, { error: `No user with ID ${getUserInfoPayload.userId} found`, ...getUserInfoPayload }, obj.callback); return; } } else if (getUserInfoPayload.userTag) { - user = (_w = this.client) == null ? void 0 : _w.users.cache.find((u) => u.tag === getUserInfoPayload.userTag); + user = this.client?.users.cache.find((u) => u.tag === getUserInfoPayload.userTag); if (!user) { this.sendTo(obj.from, obj.command, { error: `No user with tag ${getUserInfoPayload.userTag} found`, ...getUserInfoPayload }, obj.callback); return; } } else { - user = (_x = this.client) == null ? void 0 : _x.users.cache.find((u) => u.discriminator === "0" && u.username === getUserInfoPayload.userName); + user = this.client?.users.cache.find((u) => u.discriminator === "0" && u.username === getUserInfoPayload.userName); if (!user) { this.sendTo(obj.from, obj.command, { error: `No user with unique name ${getUserInfoPayload.userName} found`, ...getUserInfoPayload }, obj.callback); return; @@ -2254,7 +2375,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { accentColor: user.hexAccentColor }, obj.callback); break; - case "getMessageInfo": + } + case "getMessageInfo": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2290,7 +2412,8 @@ class DiscordAdapter extends import_adapter_core.Adapter { reference: msg.reference }, obj.callback); break; - case "sendNotification": + } + case "sendNotification": { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2301,15 +2424,15 @@ class DiscordAdapter extends import_adapter_core.Adapter { return; } this.log.info(`New notification received from ${obj.from.replace(/^system\.adapter\./, "")}`); - let target = void 0; + let target; if (this.config.sendNotificationsTo.indexOf("/") > 0) { const [serverId, channelId] = this.config.sendNotificationsTo.split("/"); - const channel2 = (_z = (_y = this.client) == null ? void 0 : _y.guilds.cache.get(serverId)) == null ? void 0 : _z.channels.cache.get(channelId); - if ((channel2 == null ? void 0 : channel2.type) === import_discord.ChannelType.GuildText) { + const channel2 = this.client?.guilds.cache.get(serverId)?.channels.cache.get(channelId); + if (channel2?.type === import_discord.ChannelType.GuildText) { target = channel2; } } else { - target = (_A = this.client) == null ? void 0 : _A.users.cache.get(this.config.sendNotificationsTo); + target = this.client?.users.cache.get(this.config.sendNotificationsTo); } if (!target) { this.log.error(`Cannot send notification because the configured target is invalid!`); @@ -2317,7 +2440,7 @@ class DiscordAdapter extends import_adapter_core.Adapter { return; } const message = obj.message; - if (!((_B = message == null ? void 0 : message.category) == null ? void 0 : _B.instances) || !message.category.name) { + if (!message?.category?.instances || !message.category.name) { this.log.warn(`Cannot send notification because the received message object is invalid`); this.sendTo(obj.from, obj.command, { sent: false }, obj.callback); return; @@ -2351,6 +2474,7 @@ ${readableInstances.join("\n")}`; this.sendTo(obj.from, obj.command, { sent: false }, obj.callback); } break; + } default: this.log.warn(`Got message with unknown command: ${obj.command}`); if (obj.callback) { @@ -2372,38 +2496,6 @@ ${readableInstances.join("\n")}`; this.log.warn(message.error); } } - /** - * Try to detect and parse stringified JSON MessageOptions. - * - * If the `content` starts/ends with curly braces if will be treated as - * stringified JSON. Then the JSON will be parsed and some basic checks will - * be run against the parsed object. - * - * Otherwise the content will be treated as a simple string and wrapped into - * a `MessageOptions` object. - * @param content The stringified content to be parsed. - * @returns A `MessageOptions` object. - * @throws An error if parsing JSON or a check failed. - */ - parseStringifiedMessageOptions(content) { - let mo; - if (content.startsWith("{") && content.endsWith("}")) { - this.log.debug(`Content seems to be json`); - try { - mo = JSON.parse(content); - } catch (err) { - throw new Error(`Content seems to be json but cannot be parsed!`); - } - if (!(mo == null ? void 0 : mo.files) && !mo.content || mo.files && !Array.isArray(mo.files) || mo.embeds && !Array.isArray(mo.embeds)) { - throw new Error(`Content is json but seems to be invalid!`); - } - } else { - mo = { - content - }; - } - return mo; - } /** * Prepare a message for sending. * @@ -2419,7 +2511,7 @@ ${readableInstances.join("\n")}`; for (const embed of msg.embeds) { if (typeof embed.color === "string") { const colorStr = embed.color; - if (colorStr.match(/^\d+$/)) { + if (/^\d+$/.exec(colorStr)) { embed.color = parseInt(colorStr, 10); } else { try { @@ -2440,24 +2532,23 @@ ${readableInstances.join("\n")}`; * @throws An error if some parameters are missing or the message could not be found. */ async getPreviousMessage(identifier) { - var _a, _b, _c, _d, _e, _f, _g; if (!identifier.messageId) { throw new Error("messageId needs to be set"); } if (identifier.userId || identifier.userTag || identifier.userName) { let user; if (identifier.userId) { - user = (_a = this.client) == null ? void 0 : _a.users.cache.get(identifier.userId); + user = this.client?.users.cache.get(identifier.userId); if (!user) { throw new Error(`No user with userId ${identifier.userId} found`); } } else if (identifier.userTag) { - user = (_b = this.client) == null ? void 0 : _b.users.cache.find((u) => u.tag === identifier.userTag); + user = this.client?.users.cache.find((u) => u.tag === identifier.userTag); if (!user) { throw new Error(`No user with userTag ${identifier.userTag} found`); } } else { - user = (_c = this.client) == null ? void 0 : _c.users.cache.find((u) => u.discriminator === "0" && u.username === identifier.userName); + user = this.client?.users.cache.find((u) => u.discriminator === "0" && u.username === identifier.userName); if (!user) { throw new Error(`No user with unique userName ${identifier.userName} found`); } @@ -2466,7 +2557,7 @@ ${readableInstances.join("\n")}`; if (!user.dmChannel) { await user.createDM(); } - const msg = ((_d = user.dmChannel) == null ? void 0 : _d.messages.cache.get(identifier.messageId)) ?? await ((_e = user.dmChannel) == null ? void 0 : _e.messages.fetch(identifier.messageId)); + const msg = user.dmChannel?.messages.cache.get(identifier.messageId) ?? await user.dmChannel?.messages.fetch(identifier.messageId); if (!msg) { throw new Error(`No message with messageId ${identifier.messageId} for user ${(0, import_utils.userNameOrTag)(user)} found`); } @@ -2475,8 +2566,8 @@ ${readableInstances.join("\n")}`; throw new Error(`Error finding message for user ${(0, import_utils.userNameOrTag)(user)}: ${err}`); } } else if (identifier.serverId && identifier.channelId) { - const channel = (_g = (_f = this.client) == null ? void 0 : _f.guilds.cache.get(identifier.serverId)) == null ? void 0 : _g.channels.cache.get(identifier.channelId); - if ((channel == null ? void 0 : channel.type) !== import_discord.ChannelType.GuildText && (channel == null ? void 0 : channel.type) !== import_discord.ChannelType.GuildVoice) { + const channel = this.client?.guilds.cache.get(identifier.serverId)?.channels.cache.get(identifier.channelId); + if (channel?.type !== import_discord.ChannelType.GuildText && channel?.type !== import_discord.ChannelType.GuildVoice) { throw new Error(`No text channel with channelId ${identifier.channelId} on server ${identifier.serverId} found`); } try { @@ -2492,55 +2583,6 @@ ${readableInstances.join("\n")}`; throw new Error("userId, userTag, userName or serverId and channelId needs to be set"); } } - /** - * Check if a user or guild member is authorized to do something. - * For guild members their roles will also be checked. - * @param user The User or GuildMember to check. - * @param required Object containing the required flags. If not provided the check returns if the user in the list of authorized users. - * @returns `true` if the user is authorized or authorization is not enabled, `false` otherwise - */ - checkUserAuthorization(user, required) { - if (!this.config.enableAuthorization) { - return true; - } - let given = this.config.authorizedUsers.find((au) => au.userId === user.id); - if (this.config.authorizedServerRoles.length > 0 && user instanceof import_discord.GuildMember) { - for (const [, role] of user.roles.cache) { - const roleGiven = this.config.authorizedServerRoles.find((ar) => ar.serverAndRoleId === `${user.guild.id}|${role.id}`); - if (roleGiven) { - if (!given) { - given = roleGiven; - } else { - given = { - getStates: given.getStates || roleGiven.getStates, - setStates: given.setStates || roleGiven.setStates, - useCustomCommands: given.useCustomCommands || roleGiven.useCustomCommands, - useText2command: given.useText2command || roleGiven.useText2command - }; - } - } - } - } - if (!given) { - return false; - } - if (!required) { - return true; - } - if (required.getStates && !given.getStates || required.setStates && !given.setStates || required.useCustomCommands && !given.useCustomCommands || required.useText2command && !given.useText2command) { - return false; - } - return true; - } - /** - * Awaitable function to just wait some time. - * - * Uses `Adapter.setTimeout(...)` internally to make sure the timeout is cleared on adapter unload. - * @param time Time to wait in ms. - */ - wait(time) { - return new Promise((resolve) => this.setTimeout(resolve, time)); - } /** * Set the `info.connection` state if changed. * @param connected If connected. @@ -2548,48 +2590,19 @@ ${readableInstances.join("\n")}`; */ async setInfoConnectionState(connected, force = false) { if (force || connected !== this.infoConnected) { - await this.setStateAsync("info.connection", connected, true); + await this.setState("info.connection", connected, true); this.infoConnected = connected; } } - /** - * Internal replacemend for `extendObjectAsync(...)` which compares the given - * object for each `id` against a cached version and only calls na original - * `extendObjectAsync(...)` if the object changed. - * Using this, the object gets only updated if - * a) it's the first call for this `id` or - * b) the object needs to be changed. - */ - async extendObjectAsyncCached(id, objPart, options) { - const cachedObj = this.extendObjectCache.get(id); - if ((0, import_node_util.isDeepStrictEqual)(cachedObj, objPart)) { - return { id }; - } - const ret = await this.extendObjectAsync(id, objPart, options); - this.extendObjectCache.set(id, objPart); - return ret; - } - /** - * Internal replacement for `delObjectAsync(...)` which also removes the local - * cache entry for the given `id`. - */ - async delObjectAsyncCached(id, options) { - if (options == null ? void 0 : options.recursive) { - this.extendObjectCache.filter((_obj, id2) => id2.startsWith(id)).each((_obj, id2) => this.extendObjectCache.delete(id2)); - } else { - this.extendObjectCache.delete(id); - } - return this.delObjectAsync(id, options); - } async onUnload(callback) { try { this.unloaded = true; await this.setInfoConnectionState(false, true); if (this.client) { - this.client.destroy(); + await this.client.destroy(); } callback(); - } catch (e) { + } catch (_e) { callback(); } } diff --git a/build/main.js.map b/build/main.js.map index cdc1137..7eccfb5 100644 --- a/build/main.js.map +++ b/build/main.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/main.ts"], - "sourcesContent": ["import 'source-map-support/register';\n\nimport { isDeepStrictEqual } from 'node:util';\n\nimport { boundMethod } from 'autobind-decorator';\n\nimport {\n Adapter,\n AdapterOptions,\n EXIT_CODES,\n} from '@iobroker/adapter-core';\n\nimport {\n ChannelType,\n Client,\n CloseEvent as DjsCloseEvent,\n Collection,\n GatewayIntentBits,\n Guild,\n GuildBasedChannel,\n GuildMember,\n Message,\n MessageCreateOptions,\n NonThreadGuildBasedChannel,\n Partials,\n PermissionsBitField,\n Presence,\n PresenceData,\n PresenceStatusData,\n Snowflake,\n User,\n version as djsVersion,\n VoiceState,\n ActivityType,\n TextChannel,\n APIEmbed,\n resolveColor,\n HexColorString,\n} from 'discord.js';\n\nimport {\n CommandObjectConfig,\n DiscordAdapterSlashCommands,\n} from './commands';\nimport {\n SetBotPresenceOptions,\n Text2commandMessagePayload,\n VALID_PRESENCE_STATUS_DATA,\n JsonServersMembersObj,\n JsonServersChannelsObj,\n JsonUsersObj,\n UpdateUserPresenceResult,\n JsonMessageObj,\n CheckAuthorizationOpts,\n SendToActionSendPayload,\n SendToActionEditMessagePayload,\n MessageIdentifier,\n SendToActionAwaitMessageReactionPayload,\n SendToActionAddReactionPayload,\n SendToActionServerIdentifier,\n SendToActionSendCustomCommandReplyPayload,\n SendToActionChannelIdentifier,\n SendToActionServerMemberIdentifier,\n SendToActionUserIdentifier,\n ACTIVITY_TYPES,\n ActivityTypeNames,\n ChannelTypeNames,\n} from './lib/definitions';\nimport { i18n } from './lib/i18n';\nimport {\n getBasenameFromFilePathOrUrl,\n getBufferAndNameFromBase64String,\n getObjName,\n userNameOrTag,\n} from './lib/utils';\nimport { LocalizedNotification, getNewestDate } from './lib/notification-manager';\n\nconst LOGIN_WAIT_TIMES = [\n 0, // none - first try!\n 5000, // 5 sek\n 10000, // 10 sek\n 30000, // 30 sek\n 60000, // 1 min\n 120000, // 2 min\n 120000, // 2 min\n 300000, // 5 min\n 300000, // 5 min\n 300000, // 5 min\n 600000, // 10 min\n];\n\n/**\n * ioBroker.discord adapter\n */\nclass DiscordAdapter extends Adapter {\n\n /**\n * Local cache for `info.connection` state.\n */\n private infoConnected: boolean = false;\n\n /**\n * Instance of the discord client.\n */\n public client: Client | null = null;\n\n /**\n * Set of state IDs where received discord messages will be stored to.\n * Used to identify target states for received discord messages.\n */\n private messageReceiveStates: Set = new Set();\n\n /**\n * Set user IDs known to set up.\n * Used to check if the user objects are created on some events.\n */\n private knownUsers: Set = new Set();\n\n /**\n * Set of objects from this instance with text2command enabled.\n */\n private text2commandObjects: Set = new Set();\n\n /**\n * Cache for `extendObjectCache(...)` calls to extend objects only when changed.\n */\n private extendObjectCache: Collection = new Collection();\n\n /**\n * Cache for `.json` states.\n */\n private jsonStateCache: Collection = new Collection();\n\n /**\n * Instance of the slash commands handler class.\n */\n private discordSlashCommands: DiscordAdapterSlashCommands;\n\n /**\n * Flag if the initial setup of the custom object configurations is done or not.\n * While not done, custom object configuration changes will not trigger a\n * slash commands registration automatically.\n */\n public initialCustomObjectSetupDone: boolean = false;\n\n /**\n * Flag if we are currently in shard error state from discord.js.\n * `false` currently not on error state, A `string` containing the error name in\n * case of en error.\n */\n private isShardError: false | string = false;\n\n /**\n * Flag if the adapter is unloaded or is unloading.\n * Used to check this in some async operations.\n */\n public unloaded: boolean = false;\n\n public constructor(options: Partial = {}) {\n super({\n ...options,\n name: 'discord',\n });\n\n this.discordSlashCommands = new DiscordAdapterSlashCommands(this);\n\n this.on('ready', this.onReady);\n this.on('stateChange', this.onStateChange);\n this.on('objectChange', this.onObjectChange);\n this.on('message', this.onMessage);\n this.on('unload', this.onUnload);\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n @boundMethod\n private async onReady(): Promise {\n\n // Reset the connection indicator during startup\n await this.setInfoConnectionState(false, true);\n\n // log version of discord.js\n this.log.debug(`Version of discord.js: ${djsVersion}`);\n\n // try to get the system language\n const systemConfig = await this.getForeignObjectAsync('system.config');\n i18n.language = systemConfig?.common.language || 'en';\n i18n.isFloatComma = systemConfig?.common.isFloatComma || false;\n\n // validate config\n if (typeof this.config.token !== 'string' || !this.config.token.match(/^[0-9a-zA-Z-_]{24,}\\.[0-9a-zA-Z-_]{6}\\.[0-9a-zA-Z-_]{27,}$/)) {\n this.log.error(`No or invalid token!`);\n return;\n }\n if (!Array.isArray(this.config.authorizedUsers)) {\n this.config.authorizedUsers = [];\n }\n if (!Array.isArray(this.config.authorizedServerRoles)) {\n this.config.authorizedServerRoles = [];\n }\n if (!this.config.enableAuthorization) {\n this.log.info('Authorization is disabled, so any user is able to interact with the bot. You should only disable authorization if you trust all users on any server where the bot is on.');\n }\n if (this.config.enableAuthorization && this.config.authorizedUsers.length === 0 && this.config.authorizedServerRoles.length === 0) {\n this.log.info('Authorization is enabled but no authorized users are defined!');\n }\n if (this.config.enableCustomCommands && !Array.isArray(this.config.customCommands)) {\n this.config.customCommands = [];\n }\n this.config.reactOnMentionsEmoji = this.config.reactOnMentionsEmoji?.trim() || '\uD83D\uDC4D';\n\n // setup/fix native objects from older adapter versions\n const botActivityTypeObj = await this.getObjectAsync('bot.activityType');\n if (botActivityTypeObj?.common?.states?.hasOwnProperty('PLAYING')) {\n // TODO: use extendObjectAsync with null values when issue https://github.com/ioBroker/ioBroker.js-controller/issues/1735 is resolved\n delete botActivityTypeObj.common.states.PLAYING;\n delete botActivityTypeObj.common.states.STREAMING;\n delete botActivityTypeObj.common.states.LISTENING;\n delete botActivityTypeObj.common.states.WATCHING;\n delete botActivityTypeObj.common.states.COMPETING;\n await this.setObjectAsync('bot.activityType', botActivityTypeObj);\n }\n\n // setup generic dynamic objects (most objects will be set up in `updateGuilds` method)\n if (this.config.enableRawStates) {\n await this.extendObjectAsync('raw', {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Raw data'),\n },\n native: {},\n });\n await Promise.all([\n this.extendObjectAsync('raw.interactionJson', {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last interaction JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsync('raw.messageJson', {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n } else {\n await this.delObjectAsync('raw', { recursive: true });\n }\n\n if (this.config.enableCustomCommands) {\n await this.extendObjectAsync('slashCommands', {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Custom Discord slash commands'),\n },\n native: {},\n });\n } else {\n await this.delObjectAsync('slashCommands', { recursive: true });\n }\n\n // setup the discord client\n this.client = new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMembers,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.GuildMessageReactions,\n GatewayIntentBits.GuildMessageTyping,\n GatewayIntentBits.GuildPresences,\n GatewayIntentBits.GuildVoiceStates,\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.DirectMessageReactions,\n GatewayIntentBits.DirectMessageTyping,\n ],\n partials: [\n Partials.Channel, // needed for DMs\n ],\n });\n\n this.client.on('ready', this.onClientReady);\n\n if (this.log.level === 'silly') {\n this.client.on('debug', (message) => this.log.silly(`discordjs: ${message}`));\n }\n this.client.on('warn', (message) => this.log.warn(`Discord client warning: ${message}`));\n this.client.on('error', (err) => this.log.error(`Discord client error: ${err.toString()}`));\n this.client.on('rateLimit', (rateLimitData) => this.log.debug(`Discord client rate limit hit: ${JSON.stringify(rateLimitData)}`)); // rate limit event is just a information - discord.js handels rate limits\n this.client.on('invalidRequestWarning', (invalidRequestWarningData) => this.log.warn(`Discord client invalid request warning: ${JSON.stringify(invalidRequestWarningData)}`));\n\n this.client.on('invalidated', () => {\n this.log.warn('Discord client session invalidated');\n this.setInfoConnectionState(false);\n });\n\n this.client.on('shardError', (err: Error, shardId: number) => {\n // discord.js internally handles websocket errors and reconnects\n // this is just for some logging and setting the connection state\n\n // just handle the error if it's not the already handled error\n let errorMsg: string;\n if (err instanceof AggregateError) {\n // create a list of unique error code entries\n errorMsg = Array.from(new Set(err.errors.map((e: NodeJS.ErrnoException) => e.code))).join(', ');\n } else {\n errorMsg = err.toString();\n }\n\n if (this.isShardError != errorMsg) {\n this.isShardError = errorMsg;\n this.log.warn(`Discord client websocket error (shardId:${shardId}): ${errorMsg}`);\n this.setInfoConnectionState(false);\n } else {\n this.log.debug(`Discord client websocket error (shardId:${shardId}): ${errorMsg}`);\n }\n });\n\n this.client.on('shardReady', (shardId: number) => {\n // discord.js websocket is ready (connected)\n this.isShardError = false;\n this.log.info(`Discord client websocket connected (shardId:${shardId})`);\n this.setInfoConnectionState(true);\n this.setBotPresence();\n });\n\n this.client.on('shardResume', (shardId: number, replayedEvents: number) => this.log.debug(`Discord client websocket resume (shardId:${shardId} replayedEvents:${replayedEvents})`));\n this.client.on('shardDisconnect', (event: DjsCloseEvent, shardId: number) => this.log.debug(`Discord client websocket disconnect (shardId:${shardId} code:${event.code})`));\n this.client.on('shardReconnecting', (shardId: number) => this.log.debug(`Discord client websocket reconnecting (shardId:${shardId})`));\n\n this.client.on('messageCreate', this.onClientMessageCreate);\n\n if (this.config.dynamicServerUpdates) {\n this.client.on('channelCreate', () => this.updateGuilds());\n this.client.on('channelDelete', () => this.updateGuilds());\n this.client.on('channelUpdate', () => this.updateGuilds());\n this.client.on('guildCreate', () => this.updateGuilds());\n this.client.on('guildDelete', () => this.updateGuilds());\n this.client.on('guildUpdate', () => this.updateGuilds());\n this.client.on('guildMemberAdd', () => this.updateGuilds());\n this.client.on('guildMemberRemove', () => this.updateGuilds());\n this.client.on('roleCreate', () => this.updateGuilds());\n this.client.on('roleDelete', () => this.updateGuilds());\n this.client.on('roleUpdate', () => this.updateGuilds());\n this.client.on('userUpdate', () => this.updateGuilds());\n }\n\n if (this.config.observeUserPresence) {\n this.client.on('presenceUpdate', (_oldPresence, newPresence) => { this.updateUserPresence(newPresence.userId, newPresence); });\n }\n\n if (this.config.observeUserVoiceState) {\n this.client.on('voiceStateUpdate', this.onClientVoiceStateUpdate);\n }\n\n // init commands instance - need to be done after discord client setup\n this.discordSlashCommands.onReady();\n\n // subscribe needed states and objects\n this.subscribeStates('servers.*.channels.*.send');\n this.subscribeStates('servers.*.channels.*.sendFile');\n this.subscribeStates('servers.*.channels.*.sendReply');\n this.subscribeStates('servers.*.channels.*.sendReaction');\n this.subscribeStates('users.*.send');\n this.subscribeStates('users.*.sendFile');\n this.subscribeStates('users.*.sendReply');\n this.subscribeStates('users.*.sendReaction');\n this.subscribeStates('servers.*.members.*.voiceDisconnect');\n this.subscribeStates('servers.*.members.*.voiceServerMute');\n this.subscribeStates('servers.*.members.*.voiceServerDeaf');\n this.subscribeStates('slashCommands.*.sendReply');\n this.subscribeStates('slashCommands.*.option-*.choices');\n this.subscribeStates('bot.*');\n this.subscribeForeignObjects('*'); // needed to handle custom object configs\n\n // initially get all objects with custom config\n this.log.debug('Get all objects with custom config ...');\n const view = await this.getObjectViewAsync('system', 'custom', {});\n if (view?.rows) {\n for (const item of view.rows) {\n await this.setupObjCustom(item.id, item.value?.[this.namespace]);\n }\n }\n this.log.debug('Getting all objects with custom config done');\n\n // remember that the initial setup of the custom objects is done\n this.initialCustomObjectSetupDone = true;\n\n // try to log in the client, terminate if this was not successfull\n const loginResult = await this.loginClient();\n if (loginResult !== true) {\n if (loginResult.includes('TOKEN_INVALID')) {\n this.terminate('Invalid token, please check your configuration!', EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);\n } else {\n this.terminate('No connection to Discord', EXIT_CODES.START_IMMEDIATELY_AFTER_STOP);\n }\n return; // needed!\n }\n\n // register discord commands if login was successfull\n await this.discordSlashCommands.registerSlashCommands();\n }\n\n /**\n * Try to log in the discord client.\n *\n * This will also handle network related errors.\n * In case of networt related errors this will retry the login after some time.\n * The wait time before each retry will be increased for each try, as defined\n * in `LOGIN_WAIT_TIMES`.\n * @param tryNr Number of the login try. Should be `0` when login process is started and is increased internally in each try.\n * @returns Promise which resolves to `true` if logged in, or an error name/message otherwise.\n */\n private async loginClient (tryNr: number = 0): Promise {\n if (!this.client || this.unloaded) {\n return 'No Client';\n }\n\n try {\n await this.client.login(this.config.token);\n return true;\n } catch (err) {\n if (err instanceof Error) {\n let errorMsg: string;\n if (err instanceof AggregateError) {\n // create a list of unique error code entries\n errorMsg = Array.from(new Set(err.errors.map((e: NodeJS.ErrnoException) => e.code))).join(', ');\n } else {\n errorMsg = err.toString();\n }\n // log first 4 errors as info, then as warning\n if (tryNr < 4) {\n this.log.info(`Discord login error: ${errorMsg}`);\n } else {\n this.log.warn(`Discord login error: ${errorMsg}`);\n }\n if (err.name === 'AbortError' || err.name === 'ConnectTimeoutError' || (err as NodeJS.ErrnoException).code === 'EAI_AGAIN'\n || (err instanceof AggregateError && err.errors.map((e: NodeJS.ErrnoException) => e.code).includes('ENETUNREACH')) ) {\n // AbortError and ConnectTimeoutError are results of network errors\n // EAI_AGAIN is a result of DNS errors\n // AggregateError containing ENETUNREACH occurs in case routing problems\n // ... retry\n tryNr++;\n if (tryNr >= LOGIN_WAIT_TIMES.length) {\n tryNr = LOGIN_WAIT_TIMES.length - 1;\n }\n\n this.log.info(`Wait ${LOGIN_WAIT_TIMES[tryNr] / 1000} seconds before next login try (#${tryNr+1}) ...`);\n await this.wait(LOGIN_WAIT_TIMES[tryNr]);\n\n return this.loginClient(tryNr);\n }\n return err.name;\n } else {\n this.log.error('Unknown Discord login error');\n return 'Unknown Discord login error';\n }\n }\n }\n\n /**\n * When the discord client is ready.\n */\n @boundMethod\n private async onClientReady (): Promise {\n if (!this.client?.user) {\n this.log.error('Discord client has no user!');\n return;\n }\n\n this.log.info(`Logged in as ${this.client.user.tag}!`);\n this.log.debug(`User ID: ${this.client.user.id}`);\n\n // change the bot username/nickname if needed\n if (this.config.botName) {\n if (this.client.user.username !== this.config.botName) {\n // update needed\n this.log.debug(`Update of bot name needed - current name: ${this.client.user.username} - configured name: ${this.config.botName}`);\n try {\n const proms: Promise[] = [];\n proms.push(this.client.user.setUsername(this.config.botName));\n\n for (const [, guild] of this.client.guilds.cache) {\n const me = guild.members.cache.get(this.client.user.id);\n if (me) {\n proms.push(me.setNickname(this.config.botName));\n }\n }\n\n await Promise.all(proms);\n this.log.debug(`Bot name updated`);\n } catch (err) {\n this.log.warn(`Error setting the bot name to \"${this.config.botName}\": ${err}`);\n }\n } else {\n // up to date\n this.log.debug('Bot name is up to date');\n }\n }\n\n try {\n await this.updateGuilds();\n } catch (err) {\n this.log.error(`Error while updating server information: ${err}`);\n }\n }\n\n /**\n * Update the guilds (servers), channels and users seen by the discord bot.\n * This will create/update all dynamic objects for all servers and users if needed.\n */\n private async updateGuilds (): Promise {\n if (!this.client?.user) {\n throw new Error('Client not loaded');\n }\n\n /**\n * Collection of known users on all known servers.\n * Used to create/delete user objects.\n */\n const allServersUsers: Collection = new Collection();\n\n /**\n * Set of object IDs for all known servers and channels.\n * Used to detect server/channel objects which have be deleted.\n */\n const knownServersAndChannelsIds: Set = new Set();\n\n if (this.unloaded) return;\n const guilds = await this.client.guilds.fetch();\n if (this.unloaded) return;\n\n for (const [, guildBase] of guilds) {\n\n if (this.unloaded) return;\n let guild: Guild;\n try {\n guild = await guildBase.fetch();\n } catch (err) {\n this.log.warn(`Could not fetch guild information for guild \"${guildBase.name}\" id:${guildBase.id}`);\n this.log.debug(`Error: ${err}`);\n continue;\n }\n if (this.unloaded) return;\n\n knownServersAndChannelsIds.add(`${this.namespace}.servers.${guild.id}`);\n\n // create channel for this guild\n await this.extendObjectAsyncCached(`servers.${guild.id}`, {\n type: 'channel',\n common: {\n name: guild.name,\n },\n native: {},\n });\n\n await Promise.all([\n this.extendObjectAsyncCached(`servers.${guild.id}.members`, {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Members'),\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.channels`, {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Channels'),\n },\n native: {},\n }),\n ]);\n\n // add guild member objects\n const guildMembers = await guild.members.fetch();\n if (this.unloaded) return;\n\n for (const [, member] of guildMembers) {\n // remember user if not the bot itself\n if (member.user.id !== this.client.user.id) {\n allServersUsers.set(member.user.id, { user: member.user, presence: member.presence });\n }\n\n await this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}`, {\n type: 'channel',\n common: {\n name: `${member.displayName} (${userNameOrTag(member.user)})`,\n },\n native: {},\n });\n\n await Promise.all([\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.tag`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User tag'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.name`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.displayName`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Display name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.roles`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Roles'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.joinedAt`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Joined at'),\n role: 'date',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceChannel`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice channel'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceDisconnect`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice disconnect'),\n role: 'button',\n type: 'boolean',\n read: false,\n write: true,\n def: false,\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice self deafen'),\n role: 'indicator',\n type: 'boolean',\n read: true,\n write: false,\n def: false,\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice server deafen'),\n role: 'switch',\n type: 'boolean',\n read: true,\n write: true,\n def: false,\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice self mute'),\n role: 'indicator',\n type: 'boolean',\n read: true,\n write: false,\n def: false,\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceServerMute`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice server mute'),\n role: 'switch',\n type: 'boolean',\n read: true,\n write: true,\n def: false,\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.json`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n\n\n const memberRoles = member.roles.cache.map((role) => role.name);\n await Promise.all([\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.tag`, member.user.tag, true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.name`, member.user.username, true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.displayName`, member.displayName, true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.roles`, memberRoles.join(', '), true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.joinedAt`, member.joinedTimestamp, true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceChannel`, member.voice.channel?.name ?? '', true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, !!member.voice.selfDeaf, true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, !!member.voice.serverDeaf, true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, !!member.voice.selfMute, true),\n this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceServerMute`, !!member.voice.serverMute, true),\n ]);\n\n const json: JsonServersMembersObj = {\n tag: member.user.tag,\n name: member.user.username,\n id: member.id,\n displayName: member.displayName,\n roles: memberRoles,\n joined: member.joinedTimestamp,\n voiceChannel: member.voice.channel?.name ?? '',\n voiceChannelId: member.voice.channel?.id ?? '',\n voiceSelfDeaf: !!member.voice.selfDeaf,\n voiceServerDeaf: !!member.voice.serverDeaf,\n voiceSelfMute: !!member.voice.selfMute,\n voiceServerMute: !!member.voice.serverMute,\n };\n if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.servers.${guild.id}.members.${member.id}.json`))) {\n await this.setStateAsync(`servers.${guild.id}.members.${member.id}.json`, JSON.stringify(json), true);\n this.jsonStateCache.set(`${this.namespace}.servers.${guild.id}.members.${member.id}.json`, json);\n }\n\n }\n\n // guild channels\n if (this.unloaded) return;\n const channels = await guild.channels.fetch();\n if (this.unloaded) return;\n\n // loop over all channels twice to setup the parent channel objects first and afterwards the child channel objects\n for (const parents of [true, false]) {\n for (const [, channel] of channels) {\n if (!channel || (parents && channel.parentId) || (!parents && !channel.parentId)) {\n continue;\n }\n const channelIdPrefix = parents ? `servers.${guild.id}.channels.${channel.id}` : `servers.${guild.id}.channels.${channel.parentId}.channels.${channel.id}`;\n\n knownServersAndChannelsIds.add(`${this.namespace}.${channelIdPrefix}`);\n\n let icon: string | undefined = undefined;\n if (channel.type === ChannelType.GuildText) {\n icon = 'channel-text.svg';\n }\n if (channel.type === ChannelType.GuildVoice) {\n icon = 'channel-voice.svg';\n }\n await this.extendObjectAsyncCached(channelIdPrefix, {\n type: 'channel',\n common: {\n name: channel.parent ? `${channel.parent.name} / ${channel.name}` : channel.name,\n icon,\n },\n native: {\n channelId: channel.id,\n },\n });\n if (channel.type === ChannelType.GuildCategory) {\n await this.extendObjectAsyncCached(`${channelIdPrefix}.channels`, {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Channels'),\n },\n native: {},\n });\n }\n\n await Promise.all([\n this.extendObjectAsyncCached(`${channelIdPrefix}.json`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.memberCount`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Member count'),\n role: 'value',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.members`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Members'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n\n if (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildVoice) {\n await Promise.all([\n this.extendObjectAsyncCached(`${channelIdPrefix}.message`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.messageId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.messageAuthor`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message author'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.messageTimestamp`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message timestamp'),\n role: 'date',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.messageJson`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`${channelIdPrefix}.send`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send message'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.sendFile`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send file'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.sendReply`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reply'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`${channelIdPrefix}.sendReaction`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reaction'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n ]);\n\n this.messageReceiveStates.add(`${this.namespace}.${channelIdPrefix}.message`);\n }\n\n await this.updateChannelInfoStates(channel);\n }\n }\n\n /*\n * Delete objects for unknown server members\n */\n const objListMembers = await this.getObjectListAsync({\n startkey: `${this.namespace}.servers.${guild.id}.members.`,\n endkey: `${this.namespace}.servers.${guild.id}.members.\\u9999`,\n });\n const reServersMembers = new RegExp(`^${this.name}\\\\.${this.instance}\\\\.servers\\\\.${guild.id}.members\\\\.(\\\\d+)$`);\n for (const item of objListMembers.rows) {\n const m = item.id.match(reServersMembers);\n if (m) {\n const memberId = m[1];\n if (!guild.members.cache.has(memberId)) {\n this.log.debug(`Server member ${memberId} of server ${guild.id} is no longer available - deleting objects`);\n this.jsonStateCache.delete(`${this.namespace}.servers.${guild.id}.members.${memberId}.json`);\n await this.delObjectAsyncCached(`servers.${guild.id}.members.${memberId}`, { recursive: true });\n }\n }\n }\n }\n\n /*\n * Create objects/states for all known users.\n */\n for (const [, {user, presence}] of allServersUsers) {\n this.log.debug(`Known user: ${user.tag} id:${user.id}`);\n\n await this.extendObjectAsyncCached(`users.${user.id}`, {\n type: 'channel',\n common: {\n name: userNameOrTag(user),\n },\n native: {\n userId: user.id,\n },\n });\n\n await Promise.all([\n this.extendObjectAsyncCached(`users.${user.id}.json`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`users.${user.id}.tag`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User tag'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`users.${user.id}.name`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`users.${user.id}.message`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`users.${user.id}.messageId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`users.${user.id}.messageTimestamp`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message timestamp'),\n role: 'date',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`users.${user.id}.messageJson`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`users.${user.id}.send`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send message'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`users.${user.id}.sendFile`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send file'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`users.${user.id}.sendReply`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reply'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`users.${user.id}.sendReaction`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reaction'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`users.${user.id}.avatarUrl`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Avatar'),\n role: 'media.link',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`users.${user.id}.bot`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Bot'),\n role: 'indicator',\n type: 'boolean',\n read: true,\n write: false,\n def: false,\n },\n native: {},\n }),\n\n this.extendObjectAsyncCached(`users.${user.id}.status`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Status'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`users.${user.id}.activityType`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Activity type'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectAsyncCached(`users.${user.id}.activityName`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Activity name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n\n this.messageReceiveStates.add(`${this.namespace}.users.${user.id}.message`);\n\n this.knownUsers.add(user.id);\n\n const ps = await this.updateUserPresence(user.id, presence, true);\n\n const proms: Promise[] = [];\n const json: JsonUsersObj = {\n id: user.id,\n tag: user.tag,\n name: user.username,\n activityName: ps.activityName,\n activityType: ps.activityType,\n avatarUrl: user.displayAvatarURL(),\n bot: user.bot,\n status: ps.status,\n };\n if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.users.${user.id}.json`))) {\n proms.push(this.setStateAsync(`users.${user.id}.json`, JSON.stringify(json), true));\n this.jsonStateCache.set(`${this.namespace}.users.${user.id}.json`, json);\n }\n await Promise.all([\n this.setStateAsync(`users.${user.id}.tag`, user.tag, true),\n this.setStateAsync(`users.${user.id}.name`, user.username, true),\n this.setStateAsync(`users.${user.id}.avatarUrl`, json.avatarUrl, true),\n this.setStateAsync(`users.${user.id}.bot`, user.bot, true),\n ...proms,\n this.updateUserPresence(user.id, presence),\n ]);\n\n }\n\n /*\n * Delete objects for unknown Channels/Servers\n */\n const objListServers = await this.getObjectListAsync({\n startkey: `${this.namespace}.servers.`,\n endkey: `${this.namespace}.servers.\\u9999`,\n });\n const reServersChannels = new RegExp(`^${this.name}\\\\.${this.instance}\\\\.servers\\\\.((\\\\d+)(\\\\.channels\\\\.(\\\\d+)){0,2})$`);\n for (const item of objListServers.rows) {\n const m = item.id.match(reServersChannels);\n if (m) {\n const idPath = m[1];\n if (!knownServersAndChannelsIds.has(item.id)) {\n this.log.debug(`Server/Channel ${idPath} \"${getObjName(item.value.common)}\" is no longer available - deleting objects`);\n this.messageReceiveStates.delete(`${this.namespace}.servers.${idPath}.message`);\n this.jsonStateCache.delete(`${this.namespace}.servers.${idPath}.json`);\n await this.delObjectAsyncCached(`servers.${idPath}`, { recursive: true });\n }\n }\n }\n\n /*\n * Delete objects for unknown users\n */\n const objListUsers = await this.getObjectListAsync({\n startkey: `${this.namespace}.users.`,\n endkey: `${this.namespace}.users.\\u9999`,\n });\n const reUsers = new RegExp(`^${this.name}\\\\.${this.instance}\\\\.users\\\\.(\\\\d+)$`);\n for (const item of objListUsers.rows) {\n const m = item.id.match(reUsers);\n if (m) {\n const userId = m[1];\n if (!allServersUsers.has(userId)) {\n this.log.debug(`User ${userId} \"${getObjName(item.value.common)}\" is no longer available - deleting objects`);\n this.knownUsers.delete(userId);\n this.messageReceiveStates.delete(`${this.namespace}.users.${userId}.message`);\n this.jsonStateCache.delete(`${this.namespace}.users.${userId}.json`);\n await this.delObjectAsyncCached(`users.${userId}`, { recursive: true });\n }\n }\n }\n }\n\n /**\n * Update the states containing basic information about a channel.\n *\n * This includes the following channel states: `.json`, `.memberCount`, `.members`\n * @param channel The channel to update the states for.\n */\n private async updateChannelInfoStates (channel: NonThreadGuildBasedChannel): Promise {\n const channelIdPrefix = channel.parentId ? `servers.${channel.guildId}.channels.${channel.parentId}.channels.${channel.id}` : `servers.${channel.guild.id}.channels.${channel.id}`;\n\n const members = [...channel.members.values()];\n const json: JsonServersChannelsObj = {\n id: channel.id,\n name: channel.name,\n type: ChannelType[channel.type] as ChannelTypeNames,\n memberCount: members.length,\n members: members.map((m) => ({\n id: m.user.id,\n tag: m.user.tag,\n name: m.user.username,\n displayName: m.displayName,\n })),\n };\n const proms: Promise[] = [];\n if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.${channelIdPrefix}.json`))) {\n proms.push(this.setStateAsync(`${channelIdPrefix}.json`, JSON.stringify(json), true));\n this.jsonStateCache.set(`${this.namespace}.${channelIdPrefix}.json`, json);\n }\n await Promise.all([\n this.setStateAsync(`${channelIdPrefix}.memberCount`, members.length, true),\n this.setStateAsync(`${channelIdPrefix}.members`, members.map((m) => m.displayName).join(', '), true),\n ...proms,\n ]);\n }\n\n /**\n * Update the presence states of a user.\n * @param userId ID of the user.\n * @param presence The user presence.\n * @param skipJsonStateUpdate If the json state of the user should not be updated.\n */\n private async updateUserPresence (userId: Snowflake, presence: Presence | null, skipJsonStateUpdate: boolean = false): Promise {\n if (!this.config.observeUserPresence) {\n return { activityName: '', activityType: '', status: '' };\n }\n\n if (!this.knownUsers.has(userId)) {\n this.log.debug(`Can't update user presence for unknown user ${userId}`);\n return { activityName: '', activityType: '', status: '' };\n }\n\n try {\n const p: UpdateUserPresenceResult = {\n status: presence?.status ?? '',\n activityName: (presence?.activities[0]?.type === ActivityType.Custom ? presence?.activities[0]?.state : presence?.activities[0]?.name) ?? '',\n activityType: (presence?.activities[0]?.type !== undefined ? ActivityType[presence.activities[0].type] as ActivityTypeNames : '') ?? '',\n };\n\n const proms: Promise[] = [];\n if (!skipJsonStateUpdate) {\n const json = this.jsonStateCache.get(`${this.namespace}.users.${userId}.json`) as JsonUsersObj | undefined;\n if (json) {\n json.status = p.status;\n json.activityName = p.activityName;\n json.activityType = p.activityType;\n this.jsonStateCache.set(`${this.namespace}.users.${userId}.json`, json);\n proms.push(this.setStateAsync(`users.${userId}.json`, JSON.stringify(json), true));\n }\n }\n await Promise.all([\n this.setStateAsync(`users.${userId}.status`, p.status , true),\n this.setStateAsync(`users.${userId}.activityName`, p.activityName, true),\n this.setStateAsync(`users.${userId}.activityType`, p.activityType, true),\n ...proms,\n ]);\n return p;\n } catch (err) {\n this.log.warn(`Error while updating user presence of user ${userId}: ${err}`);\n return { activityName: '', activityType: '', status: '' };\n }\n }\n\n /**\n * Set the presence status of the discord bot.\n */\n private async setBotPresence (opts?: SetBotPresenceOptions): Promise {\n if (!this.client?.user) return;\n\n if (!opts) {\n opts = {};\n }\n\n if (!opts.status) {\n opts.status = ((await this.getStateAsync('bot.status'))?.val as PresenceStatusData | undefined) ?? 'online';\n }\n if (!VALID_PRESENCE_STATUS_DATA.includes(opts.status)) {\n opts.status = 'online';\n }\n\n const presenceData: PresenceData = {\n status: opts.status,\n activities: [],\n };\n\n if (opts.activityType === undefined) {\n opts.activityType = ((await this.getStateAsync('bot.activityType'))?.val as ActivityTypeNames | undefined) ?? '';\n }\n if (!ACTIVITY_TYPES.includes(opts.activityType)) {\n this.log.warn(`Invalid activityType! ${opts.activityType}`);\n opts.activityType = '';\n }\n if (opts.activityName === undefined) {\n opts.activityName = ((await this.getStateAsync('bot.activityName'))?.val as string | undefined) ?? '';\n }\n if (opts.activityType && opts.activityName) {\n presenceData.activities = [{\n type: ActivityType[opts.activityType],\n name: opts.activityName,\n }];\n }\n\n this.log.debug(`Set bot presence: ${JSON.stringify(presenceData)}`);\n this.client.user.setPresence(presenceData);\n }\n\n /**\n * Handler for received discord messages.\n * @param message The discord message.\n */\n @boundMethod\n private async onClientMessageCreate (message: Message): Promise {\n this.log.debug(`Discord message: mId:${message.id} cId:${message.channelId} uId: ${message.author.id} - ${message.content}`);\n\n // raw states enabled?\n if (this.config.enableRawStates) {\n // set raw state... not async here since it should not block!\n this.setState('raw.messageJson', JSON.stringify(message.toJSON(), (_key, value) => typeof value === 'bigint' ? value.toString() : value), true);\n }\n\n if (!this.client?.user?.id) return;\n\n // don't process interactions here\n if (message.interaction) {\n return;\n }\n\n const { author, channel, content } = message;\n\n // don't process own messages\n if (author.id === this.client.user.id) {\n return;\n }\n\n const authCheckTarget = message.member ?? author;\n\n const isAuthorAuthorized = this.checkUserAuthorization(authCheckTarget);\n\n if (!this.config.processMessagesFromUnauthorizedUsers && !isAuthorAuthorized) {\n this.log.debug(`Ignore message from unauthorized user ${userNameOrTag(author)} (id:${author.id})`);\n return;\n }\n\n const mentioned = message.mentions.users.has(this.client.user.id);\n\n if (mentioned && this.config.reactOnMentions && isAuthorAuthorized) {\n try {\n await message.react(this.config.reactOnMentionsEmoji);\n } catch (err) {\n this.log.warn(`Error while adding reaction to message ${message.id}! ${err}`);\n }\n }\n\n if (!mentioned && (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildVoice) && !this.config.processAllMessagesInServerChannel) {\n this.log.debug('Server channel message without mention ignored');\n return;\n }\n\n let msgStateIdPrefix: string;\n if (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildVoice) {\n msgStateIdPrefix = channel.parentId ? `${this.namespace}.servers.${message.guildId}.channels.${channel.parentId}.channels.${channel.id}` : `${this.namespace}.servers.${message.guildId}.channels.${channel.id}`;\n } else if (channel.type === ChannelType.DM) {\n msgStateIdPrefix = `${this.namespace}.users.${author.id}`;\n } else if (channel.isThread()) {\n this.log.debug('Thread message ignored');\n return;\n } else {\n this.log.warn(`Received message from unsupported channel type ${ChannelType[channel.type]}!`);\n return;\n }\n\n // check if a valid object/state for this received message is known by the adapter\n if (!this.messageReceiveStates.has(`${msgStateIdPrefix}.message`)) {\n this.log.debug(`State for received message ${msgStateIdPrefix} is not known for receiving messages`);\n return;\n }\n\n // prepare json state object\n const json: JsonMessageObj = {\n content,\n attachments: message.attachments.map((att) => ({ attachment: att.url, name: att.name, description: att.description ?? '', size: att.size, contentType: att.contentType ?? '', id: att.id })),\n id: message.id,\n mentions: message.mentions.members?.map((m) => ({ id: m.id, tag: m.user.tag, name: m.user.username, displayName: m.displayName })) ?? [],\n mentioned,\n timestamp: message.createdTimestamp,\n authorized: isAuthorAuthorized,\n };\n const proms: Promise[] = [];\n if (message.guildId) {\n json.author = {\n id: author.id,\n tag: author.tag,\n name: author.username,\n displayName: this.client.guilds.cache.get(message.guildId)?.members.cache.get(author.id)?.displayName ?? author.username,\n };\n proms.push(this.setStateAsync(`${msgStateIdPrefix}.messageAuthor`, userNameOrTag(author), true));\n }\n if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.${msgStateIdPrefix}.messageJson`))) {\n proms.push(this.setStateAsync(`${msgStateIdPrefix}.messageJson`, JSON.stringify(json), true));\n this.jsonStateCache.set(`${this.namespace}.${msgStateIdPrefix}.messageJson`, json);\n }\n await Promise.all([\n this.setStateAsync(`${msgStateIdPrefix}.message`, content, true),\n this.setStateAsync(`${msgStateIdPrefix}.messageId`, message.id, true),\n this.setStateAsync(`${msgStateIdPrefix}.messageTimestamp`, message.createdTimestamp, true),\n ...proms,\n ]);\n\n // handle text2command if enabled for this receiving state\n if (content && this.config.text2commandInstance && this.text2commandObjects.has(`${msgStateIdPrefix}.message`)) {\n // check user authorization to use text2command\n if (this.checkUserAuthorization(authCheckTarget, { useText2command: true })) {\n // authorization disabled or user is allowed to use text2command\n this.log.debug(`Sending \"${content}\" to ${this.config.text2commandInstance}`);\n // prepare message payload\n const payload: Text2commandMessagePayload = {\n text: content,\n };\n // use callback style sendTo here to not block message processing here if text2command instance is not running\n this.sendTo(this.config.text2commandInstance, 'send', payload, async (responseObj) => {\n // Response object from text2command is the message payload from the sendTo call with a `response` property set\n const response: string | undefined = (responseObj as unknown as Text2commandMessagePayload | undefined)?.response;\n try {\n if (!response) {\n this.log.debug(`Empty response from ${this.config.text2commandInstance}`);\n return;\n }\n this.log.debug(`Response from ${this.config.text2commandInstance}: ${response}`);\n switch (this.config.text2commandRespondWith) {\n case 'reply':\n await message.reply(response);\n break;\n case 'message':\n await message.channel.send(response);\n break;\n default:\n // no response needed\n }\n } catch (err) {\n this.log.warn(`Error while processing response \"${response}\" from ${this.config.text2commandInstance}! ${err}`);\n }\n });\n } else {\n // user NOT allowed to text2command\n this.log.debug(`User ${userNameOrTag(author)} (id:${author.id}) NOT allowed to use text2command`);\n }\n }\n\n }\n\n /**\n * Handler for user voice state changes.\n */\n @boundMethod\n private async onClientVoiceStateUpdate (oldState: VoiceState, newState: VoiceState): Promise {\n if (!newState.member?.id) {\n return;\n }\n\n const proms: Promise[] = [];\n\n // update channel states\n if (oldState.channelId !== newState.channelId) {\n if (oldState.channel) {\n proms.push(this.updateChannelInfoStates(oldState.channel));\n }\n if (newState.channel) {\n proms.push(this.updateChannelInfoStates(newState.channel));\n }\n }\n\n // update user states\n if (this.knownUsers.has(newState.member.id)) {\n const json: JsonServersMembersObj = {\n ...this.jsonStateCache.get(`${this.namespace}.servers.${newState.guild.id}.members.${newState.member.id}.json`) as JsonServersMembersObj,\n };\n\n let update: boolean = false;\n\n if (oldState.channelId !== newState.channelId) {\n proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceChannel`, newState.channel?.name ?? '', true));\n json.voiceChannel = newState.channel?.name ?? '';\n json.voiceChannelId = newState.channel?.id ?? '';\n update = true;\n }\n if (oldState.serverDeaf !== newState.serverDeaf) {\n proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerDeaf`, !!newState.serverDeaf, true));\n json.voiceSelfDeaf = !!newState.selfDeaf;\n update = true;\n }\n if (oldState.selfDeaf !== newState.selfDeaf) {\n proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfDeaf`, !!newState.selfDeaf, true));\n json.voiceServerDeaf = !!newState.serverDeaf;\n update = true;\n }\n if (oldState.serverMute !== newState.serverMute) {\n proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerMute`, !!newState.serverMute, true));\n json.voiceSelfMute = !!newState.selfMute;\n update = true;\n }\n if (oldState.selfMute !== newState.selfMute) {\n proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfMute`, !!newState.selfMute, true));\n json.voiceServerMute = !!newState.serverMute;\n update = true;\n }\n\n // json state update\n if (update) {\n proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.json`, JSON.stringify(json), true));\n this.jsonStateCache.set(`${this.namespace}.servers.${newState.guild.id}.members.${newState.member.id}.json`, json);\n }\n\n } else {\n this.log.debug(`Can't update user voice state for unknown user ${newState.member.id}`);\n }\n\n await Promise.all(proms);\n }\n\n /**\n * Setup for objects custom config related to the adapter instance.\n * E.g. text2command enabled or state availability for commands.\n * @param objId The object ID.\n * @param customCfg The custom config part of the object for this adapter instance.\n */\n private async setupObjCustom (objId: string, customCfg: ioBroker.CustomConfig | null | undefined, objCommon?: ioBroker.StateCommon): Promise {\n // own .message objects - enableText2command\n if (objId.startsWith(`${this.namespace}.`) && objId.endsWith('.message')) {\n if (customCfg?.enabled && customCfg.enableText2command) {\n this.log.debug(`Custom option text2command enabled for ${objId}`);\n this.text2commandObjects.add(objId);\n } else if (this.text2commandObjects.has(objId)) {\n this.log.debug(`Custom option text2command disabled for ${objId}`);\n this.text2commandObjects.delete(objId);\n }\n }\n\n if (customCfg?.enableCommands) {\n // commands enabled\n\n // load objCommon if not provided\n if (!objCommon) {\n const obj = await this.getForeignObjectAsync(objId);\n if (obj?.type === 'state') {\n objCommon = obj.common;\n } else {\n this.log.warn(`Object ${objId} has commands enabled but this seems to be an error because it is not a state object!`);\n }\n }\n\n // try to get the name\n let name = customCfg.commandsName;\n if (!name && objCommon) {\n if (typeof objCommon.name === 'object') {\n name = objCommon.name[i18n.language] ?? objCommon.name.en;\n } else {\n name = objCommon.name;\n }\n }\n\n const cfg: CommandObjectConfig = {\n id: objId,\n alias: customCfg.commandsAlias ?? objId,\n name: name ?? objId,\n get: !!customCfg.commandsAllowGet,\n set: !!customCfg.commandsAllowSet,\n };\n\n // do some checks\n let cfgOk: boolean = true;\n if (cfg.name.length > 100) {\n this.log.warn(`Command name for ${objId} exceeds the limit of 100 chars! This object will be ignored.`);\n cfgOk = false;\n }\n if (!cfg.alias.match(/^[0-9a-zA-Z._-]{0,100}$/)) {\n this.log.warn(`Command alias for ${objId} includes invalid chars or exceeds the limit of 100 chars! This object will be ignored.`);\n cfgOk = false;\n }\n\n // setup command\n this.discordSlashCommands.setupCommandObject(objId, cfgOk ? cfg : null);\n\n } else {\n // commands not enabled\n this.discordSlashCommands.setupCommandObject(objId, null);\n }\n }\n\n /**\n * Is called if a subscribed object changes.\n */\n @boundMethod\n private onObjectChange (objId: string, obj: ioBroker.Object | null | undefined): void {\n if (obj) {\n // The object was changed\n if (obj.type === 'state') {\n this.log.silly(`Object ${objId} changed: ${JSON.stringify(obj)}`);\n this.setupObjCustom(objId, obj.common?.custom?.[this.namespace], obj.common);\n }\n } else {\n // The object was deleted\n this.log.silly(`Object ${objId} deleted`);\n this.setupObjCustom(objId, null);\n }\n }\n\n /**\n * Is called if a subscribed state changes\n */\n @boundMethod\n private async onStateChange(stateId: string, state: ioBroker.State | null | undefined): Promise {\n this.log.silly(`State changed: ${stateId} ${state?.val} (ack=${state?.ack})`);\n\n if (!state || state.ack) return;\n\n let setAck = false;\n\n /*\n * Own states\n */\n if (stateId.startsWith(`${this.namespace}.`)) {\n\n switch (stateId) {\n case `${this.namespace}.bot.status`:\n await this.setBotPresence({ status: state.val as PresenceStatusData });\n setAck = true;\n break;\n case `${this.namespace}.bot.activityType`:\n await this.setBotPresence({ activityType: state.val as ActivityTypeNames });\n setAck = true;\n break;\n case `${this.namespace}.bot.activityName`:\n await this.setBotPresence({ activityName: state.val as string });\n setAck = true;\n break;\n\n default: // other own states\n // custom slash command reply\n if (stateId.match(/^discord\\.\\d+\\.slashCommands\\..*\\.sendReply/)) {\n setAck = await this.onCustomCommandSendReplyStateChange(stateId, state);\n\n // custom slash command option choices\n } else if (stateId.match(/^discord\\.\\d+\\.slashCommands\\..*\\.option-[^.]+\\.choices/)) {\n // trigger delayed register slash commands to handle multiple changes of choices states together\n this.discordSlashCommands.triggerDelayedRegisterSlashCommands();\n setAck = true;\n\n // .send / .sendFile / .sendReply\n } else if (stateId.endsWith('.send') || stateId.endsWith('.sendFile') || stateId.endsWith('.sendReply') || stateId.endsWith('.sendReaction')) {\n setAck = await this.onSendStateChange(stateId, state);\n\n // voice disconnect, mute/unmute, deafen/undeafen\n } else if (stateId.endsWith('.voiceDisconnect') || stateId.endsWith('.voiceServerMute') || stateId.endsWith('.voiceServerDeaf')) {\n setAck = await this.onVoiceStateChange(stateId, state);\n\n }\n }\n\n }\n\n if (setAck) {\n await this.setStateAsync(stateId, {\n ...state,\n ack: true,\n });\n }\n\n }\n\n /**\n * Handler for changes on own .send or .sendFile states.\n * Sends the given text, json or file to the corresponding discord channel.\n * @returns `true` if the message is send.\n */\n private async onSendStateChange (stateId: string, state: ioBroker.State): Promise {\n\n if (!this.client?.isReady()) {\n this.log.warn(`State ${stateId} changed but client is not ready!`);\n return false;\n }\n\n if (typeof state.val !== 'string') {\n this.log.warn(`State ${stateId} changed but value if not a string!`);\n return false;\n }\n\n if (state.val.length === 0) {\n this.log.debug(`State ${stateId} changed but value is empty`);\n return false;\n }\n\n let action: string;\n let target: NonThreadGuildBasedChannel | User;\n let targetName: string = '';\n let targetStateIdBase: string;\n\n // channel or user?\n let m = stateId.match(/^(discord\\.\\d+\\.servers\\.(\\d+)\\.channels\\.(\\d+)(\\.channels\\.(\\d+))?)\\.(send|sendFile|sendReaction|sendReply)$/);\n if (m) {\n const guildId = m[2];\n const channelId = m[5] || m[3];\n targetStateIdBase = m[1];\n action = m[6];\n\n const channel = this.client.guilds.cache.get(guildId)?.channels.cache.get(channelId);\n if (!channel || (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildVoice) || channel.isThread()) {\n this.log.warn(`State ${stateId} changed but target is not a valid text channel!`);\n return false;\n }\n\n target = channel;\n targetName = channel.parent ? `${channel.guild.name}/${channel.parent.name}/${channel.name}` : `${channel.guild.name}/${channel.name}`;\n\n } else {\n m = stateId.match(/^(discord\\.\\d+\\.users\\.(\\d+))\\.(send|sendFile|sendReaction|sendReply)$/);\n if (!m) {\n this.log.warn(`State ${stateId} changed but could not determine target to send message to!`);\n return false;\n }\n const userId = m[2];\n targetStateIdBase = m[1];\n action = m[3];\n\n const user = this.client.users.cache.get(userId);\n if (!user) {\n this.log.warn(`State ${stateId} changed but target is not a valid user!`);\n return false;\n }\n\n target = user;\n targetName = userNameOrTag(user);\n }\n\n let mo: MessageCreateOptions;\n\n /*\n * Special case .sendFile state\n */\n if (action === 'sendFile') {\n const idx = state.val.indexOf('|');\n let file: string;\n let content: string | undefined = undefined;\n if (idx > 0) {\n file = state.val.slice(0, idx);\n content = state.val.slice(idx + 1);\n } else {\n file = state.val;\n }\n\n // check for base64 encoded data\n const b64data = getBufferAndNameFromBase64String(file);\n if (b64data) {\n // base64 encoded content\n mo = {\n content,\n files: [{\n attachment: b64data.buffer,\n name: b64data.name,\n }],\n };\n\n } else {\n // not base64 encoded content\n const name = getBasenameFromFilePathOrUrl(file);\n\n // remove file:// prefix\n if (file.startsWith('file://')) {\n file = file.slice(7);\n }\n\n mo = {\n content,\n files: [{\n attachment: file,\n name,\n }],\n };\n }\n\n\n /*\n * Special case .sendReply state\n */\n } else if (action === 'sendReply' || action === 'sendReaction') {\n const idx = state.val.indexOf('|');\n let messageReference: string;\n let content: string;\n if (idx > 0) {\n messageReference = state.val.slice(0, idx);\n content = state.val.slice(idx + 1);\n } else {\n // use id from last received message\n this.log.debug(`Get reply message reference from last received message for ${targetStateIdBase}`);\n messageReference = (await this.getForeignStateAsync(`${targetStateIdBase}.messageId`))?.val as string;\n content = state.val;\n }\n\n if (action === 'sendReply') {\n // reply\n if (!messageReference || !content) {\n this.log.warn(`No message reference or no content for reply for ${stateId}!`);\n return false;\n }\n\n try {\n mo = this.parseStringifiedMessageOptions(state.val);\n } catch (err) {\n this.log.debug(`State ${stateId} value is invalid: ${err}`);\n return false;\n }\n\n // add the message reference if it is not already set\n if (!mo.reply) {\n mo.reply = {\n messageReference,\n };\n } else if (!mo.reply.messageReference) {\n mo.reply.messageReference = messageReference;\n }\n\n } else {\n // reaction\n if (!messageReference || !content) {\n this.log.warn(`No message reference or no/invalid content for reaction for ${stateId}!`);\n return false;\n }\n\n const channel = target instanceof User ? target.dmChannel ?? await target.createDM() : target;\n if (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildVoice && channel.type !== ChannelType.DM) {\n this.log.warn(`Could not determine target channel for reaction ${stateId}!`);\n return false;\n }\n\n // get the message from cache or try to fetch the message\n const message: Message | undefined = channel.messages.cache.get(messageReference) ?? await channel.messages.fetch(messageReference);\n if (!message) {\n this.log.warn(`Could not determine target message for reaction ${stateId}!`);\n return false;\n }\n\n try {\n await message.react(content);\n return true;\n } catch (err) {\n this.log.warn(`Message reaction ${stateId} failed: ${err}`);\n return false;\n }\n }\n\n\n /*\n * `state.val` may be JSON for .send states\n * Try to parse the JSON as MessageOptions object to allow sending of files, embeds, ...\n */\n } else {\n try {\n mo = this.parseStringifiedMessageOptions(state.val);\n } catch (err) {\n this.log.debug(`State ${stateId} value is invalid: ${err}`);\n return false;\n }\n }\n\n this.log.debug(`Send to ${targetName}: ${JSON.stringify(mo)}`);\n try {\n const msg = await target.send(this.prepareMessageForSend(mo));\n this.log.debug(`Sent with message ID ${msg.id}`);\n return true;\n } catch (err) {\n this.log.warn(`Error sending value of ${stateId} to ${targetName}: ${err}`);\n return false;\n }\n }\n\n /**\n * Handler for changes on own custom commands .sendReply states.\n * Sends the given text, json or file to the corresponding discord channel.\n * @returns `true` if the reply is send.\n */\n private async onCustomCommandSendReplyStateChange (stateId: string, state: ioBroker.State): Promise {\n\n if (!this.client?.isReady()) {\n this.log.warn(`State ${stateId} changed but client is not ready!`);\n return false;\n }\n\n if (typeof state.val !== 'string') {\n this.log.warn(`State ${stateId} changed but value if not a string!`);\n return false;\n }\n\n if (state.val.length === 0) {\n this.log.debug(`State ${stateId} changed but value is empty`);\n return false;\n }\n\n const targetStateIdBase = stateId.replace(/\\.\\w+$/, '');\n\n const idx = state.val.indexOf('|');\n let interactionId: Snowflake;\n let content: string;\n if (idx > 0) {\n interactionId = state.val.slice(0, idx);\n content = state.val.slice(idx + 1);\n } else {\n // use id from last received command\n this.log.debug(`Get reply interaction reference from last received interaction for ${targetStateIdBase}`);\n interactionId = (await this.getForeignStateAsync(`${targetStateIdBase}.interactionId`))?.val as string;\n content = state.val;\n }\n\n if (!interactionId || !content) {\n this.log.warn(`No interaction reference or no content for reply for ${stateId}!`);\n return false;\n }\n\n try {\n await this.discordSlashCommands.sendCmdCustomReply(interactionId, content);\n return true;\n } catch (err) {\n this.log.warn(`Error while replying to interaction ${interactionId} of custom slash command! ${err}`);\n return false;\n }\n }\n\n /**\n * Handler for changes of own .voiceDisconnect, .voiceServerMute or .voiceServerDeaf states.\n * @returns `true` if successfull.\n */\n private async onVoiceStateChange (stateId: string, state: ioBroker.State): Promise {\n const m = stateId.match(/^discord\\.\\d+\\.servers\\.(\\d+)\\.members\\.(\\d+)\\.voice(Disconnect|ServerMute|ServerDeaf)$/);\n if (!m) {\n this.log.debug(`Voice state ${stateId} changed but could not get serverID and memberID!`);\n return false;\n }\n const [, guildId, memberId, action] = m;\n\n const guild = this.client?.guilds.cache.get(guildId);\n const member = guild?.members.cache.get(memberId);\n if (!guild || !member) {\n this.log.warn(`Voice state ${stateId} changed but could not get the server member!`);\n return false;\n }\n\n try {\n switch (action) {\n case 'Disconnect':\n if (!state.val) {\n return false;\n }\n await member.voice.disconnect();\n this.log.debug(`Voice member ${userNameOrTag(member.user)} of server ${guild.name} disconnected.`);\n break;\n\n case 'ServerDeaf':\n await member.voice.setDeaf(!!state.val);\n this.log.debug(`Voice server deafen of member ${userNameOrTag(member.user)} of server ${guild.name} set to ${!!state.val}.`);\n break;\n\n case 'ServerMute':\n await member.voice.setMute(!!state.val);\n this.log.debug(`Voice server mute of member ${userNameOrTag(member.user)} of server ${guild.name} set to ${!!state.val}.`);\n break;\n\n default:\n // should never happen...\n return false;\n }\n return true;\n } catch (err) {\n this.log.warn(`Voice server action of member ${userNameOrTag(member.user)} of server ${guild.name} can't be done! ${err}`);\n return false;\n }\n }\n\n /**\n * Handle messages send to the adapter.\n */\n @boundMethod\n private async onMessage (obj: ioBroker.Message): Promise {\n if (typeof obj !== 'object') return;\n this.log.debug(`Got message: ${JSON.stringify(obj)}`);\n\n // channel and msg are needed in some switch cases...\n let channel: GuildBasedChannel | undefined;\n let msg: Message;\n let user: User | undefined;\n\n switch (obj.command) {\n case 'getText2commandInstances':\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n const view = await this.getObjectViewAsync('system', 'instance', {\n startkey: 'system.adapter.text2command.',\n endkey: 'system.adapter.text2command.\\u9999',\n });\n const text2commandInstances = view.rows.map((r) => {\n const id = r.id.slice(15);\n return {\n label: id,\n value: id,\n };\n });\n this.log.debug(`Found text2command instances: ${text2commandInstances.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, [{value: '', label: '---'}, ...text2commandInstances], obj.callback);\n break;\n\n case 'getNotificationTargets':\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n const targets: { label: string, value: string }[] = [{ value: '', label: '---' }];\n\n // users\n this.client?.users.cache.forEach((u) => {\n targets.push({ label: userNameOrTag(u), value: u.id });\n });\n\n // server channels\n this.client?.guilds.cache.forEach((g) => {\n g.channels.cache.forEach((c) => {\n if (c.type === ChannelType.GuildText) {\n if (c.parent) {\n // channel has a parent\n targets.push({ label: `${g.name} \u00BB ${c.parent.name} \u00BB ${c.name}`, value: `${g.id}/${c.id}` });\n } else {\n // channel has no parent\n targets.push({ label: `${g.name} \u00BB ${c.name}`, value: `${g.id}/${c.id}` });\n }\n }\n });\n });\n\n this.log.debug(`Notification targets: ${targets.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, targets, obj.callback);\n break;\n\n case 'getUsers':\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n const users = this.client?.users.cache.map((u) => ({ label: userNameOrTag(u), value: u.id })) ?? [];\n this.log.debug(`Users: ${users.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, users, obj.callback);\n break;\n\n case 'getServers':\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n const servers = this.client?.guilds.cache.map((g) => ({ label: g.name, value: g.id })) ?? [];\n this.log.debug(`Servers: ${servers.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, servers, obj.callback);\n break;\n\n case 'getServerRoles':\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (!this.client) {\n this.sendTo(obj.from, obj.command, [], obj.callback);\n return;\n }\n\n const guildRolesWithLabel = [];\n for (const [, guild] of this.client.guilds.cache) {\n for (const [, role] of guild.roles.cache) {\n guildRolesWithLabel.push({\n label: `${guild.name} - ${role.name}`,\n value: `${guild.id}|${role.id}`,\n });\n }\n }\n\n this.log.debug(`Server roles: ${guildRolesWithLabel.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, guildRolesWithLabel, obj.callback);\n\n break;\n\n case 'getAddToServerLink':\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n if (this.client?.user?.id) {\n const perms = new PermissionsBitField([\n PermissionsBitField.Flags.ChangeNickname,\n PermissionsBitField.Flags.ViewChannel,\n PermissionsBitField.Flags.ModerateMembers,\n PermissionsBitField.Flags.SendMessages,\n PermissionsBitField.Flags.EmbedLinks,\n PermissionsBitField.Flags.AttachFiles,\n PermissionsBitField.Flags.ReadMessageHistory,\n PermissionsBitField.Flags.MentionEveryone,\n PermissionsBitField.Flags.AddReactions,\n PermissionsBitField.Flags.MuteMembers,\n PermissionsBitField.Flags.DeafenMembers,\n PermissionsBitField.Flags.MoveMembers,\n ]);\n this.sendTo(obj.from, obj.command, `https://discord.com/api/oauth2/authorize?client_id=${this.client.user.id}&permissions=${perms.bitfield}&scope=bot%20applications.commands`, obj.callback);\n } else {\n this.sendTo(obj.from, obj.command, `- ${i18n.getString('Error: The Bot is not connected to Discord!')} -`, obj.callback);\n }\n break;\n\n case 'logConfiguredCommandObjects':\n this.discordSlashCommands.logConfiguredCommandObjects();\n this.sendToIfCb(obj.from, obj.command, { result: 'ok' }, obj.callback);\n break;\n\n case 'send':\n case 'sendMessage':\n /*\n * send a message\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const sendPayload = obj.message as SendToActionSendPayload;\n\n // check payload\n if (!sendPayload.content || (typeof sendPayload.content !== 'string' && typeof sendPayload.content !== 'object')) {\n this.sendToIfCb(obj.from, obj.command, { error: 'content needs to be a string or a MessageOptions object', ...sendPayload }, obj.callback);\n return;\n }\n\n if (sendPayload.userId || sendPayload.userTag || sendPayload.userName) {\n // send to a user\n if (sendPayload.userId) {\n // by userId\n user = this.client?.users.cache.get(sendPayload.userId);\n if (!user) {\n this.sendToIfCb(obj.from, obj.command, { error: `No user with userId ${sendPayload.userId} found`, ...sendPayload }, obj.callback);\n return;\n }\n } else if (sendPayload.userTag) {\n // by userTag\n user = this.client?.users.cache.find((u) => u.tag === sendPayload.userTag);\n if (!user) {\n this.sendToIfCb(obj.from, obj.command, { error: `No user with userTag ${sendPayload.userTag} found`, ...sendPayload }, obj.callback);\n return;\n }\n } else {\n // by unique userName\n user = this.client?.users.cache.find((u) => u.discriminator === '0' && u.username === sendPayload.userName);\n if (!user) {\n this.sendToIfCb(obj.from, obj.command, { error: `No user with unique userName ${sendPayload.userName} found`, ...sendPayload }, obj.callback);\n return;\n }\n }\n try {\n msg = await user.send(this.prepareMessageForSend(sendPayload.content));\n this.sendToIfCb(obj.from, obj.command, { result: `Message sent to user ${userNameOrTag(user)}`, ...sendPayload, messageId: msg.id }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error sending message to user ${userNameOrTag(user)}: ${err}`, ...sendPayload }, obj.callback);\n }\n\n } else if (sendPayload.serverId && sendPayload.channelId) {\n // send to a channel\n channel = this.client?.guilds.cache.get(sendPayload.serverId)?.channels.cache.get(sendPayload.channelId);\n if (channel?.type !== ChannelType.GuildText && channel?.type !== ChannelType.GuildVoice) {\n this.sendToIfCb(obj.from, obj.command, { error: `No text channel with channelId ${sendPayload.channelId} on server ${sendPayload.serverId} found`, ...sendPayload }, obj.callback);\n return;\n }\n try {\n msg = await channel.send(this.prepareMessageForSend(sendPayload.content));\n this.sendToIfCb(obj.from, obj.command, { result: `Message sent to channel ${channel.name}`, ...sendPayload, messageId: msg.id }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error sending message to channel ${channel.name}: ${err}`, ...sendPayload }, obj.callback);\n }\n\n } else {\n // missing arguments\n this.sendToIfCb(obj.from, obj.command, { error: 'userId, userTag, userName or serverId and channelId needs to be set', ...sendPayload }, obj.callback);\n }\n\n break; // send / sendMessage\n\n case 'editMessage':\n /*\n * edit a message\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const editMessagePayload = obj.message as SendToActionEditMessagePayload;\n\n // check payload\n if (!editMessagePayload.content || (typeof editMessagePayload.content !== 'string' && typeof editMessagePayload.content !== 'object')) {\n this.sendToIfCb(obj.from, obj.command, { error: 'content needs to be a string or a MessageOptions object', ...editMessagePayload }, obj.callback);\n return;\n }\n\n // try to get the message\n try {\n msg = await this.getPreviousMessage(editMessagePayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendToIfCb(obj.from, obj.command, { error: err.message, ...editMessagePayload }, obj.callback);\n } else {\n this.sendToIfCb(obj.from, obj.command, { error: err, ...editMessagePayload }, obj.callback);\n }\n return;\n }\n\n // try to edit the message\n try {\n if (!msg.editable) {\n this.sendToIfCb(obj.from, obj.command, { error: `Message with messageId ${editMessagePayload.messageId} is not editable`, ...editMessagePayload }, obj.callback);\n return;\n }\n await msg.edit(editMessagePayload.content);\n this.sendToIfCb(obj.from, obj.command, { result: `Message edited`, ...editMessagePayload }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error editing message: ${err}`, ...editMessagePayload }, obj.callback);\n }\n\n break; // editMessage\n\n case 'deleteMessage':\n /*\n * delete a message\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const deleteMessagePayload = obj.message as MessageIdentifier;\n\n // try to get the message\n try {\n msg = await this.getPreviousMessage(deleteMessagePayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendToIfCb(obj.from, obj.command, { error: err.message, ...deleteMessagePayload }, obj.callback);\n } else {\n this.sendToIfCb(obj.from, obj.command, { error: err, ...deleteMessagePayload }, obj.callback);\n }\n return;\n }\n\n // try to delete the message\n try {\n if (!msg.deletable) {\n this.sendToIfCb(obj.from, obj.command, { error: `Message with messageId ${deleteMessagePayload.messageId} is not deletable`, ...deleteMessagePayload }, obj.callback);\n return;\n }\n await msg.delete();\n this.sendToIfCb(obj.from, obj.command, { result: `Message deleted`, ...deleteMessagePayload }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error deleting message: ${err}`, ...deleteMessagePayload }, obj.callback);\n }\n\n break; // deleteMessage\n\n case 'addReaction':\n /*\n * add a reaction emoji to a message\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const addReactionPayload = obj.message as SendToActionAddReactionPayload;\n\n // check payload\n if (typeof addReactionPayload.emoji !== 'string') {\n this.sendToIfCb(obj.from, obj.command, { error: 'emoji needs to be a string', ...addReactionPayload }, obj.callback);\n return;\n }\n\n // try to get the message\n try {\n msg = await this.getPreviousMessage(addReactionPayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendToIfCb(obj.from, obj.command, { error: err.message, ...addReactionPayload }, obj.callback);\n } else {\n this.sendToIfCb(obj.from, obj.command, { error: err, ...addReactionPayload }, obj.callback);\n }\n return;\n }\n\n // try to add the reaction to the message\n try {\n await msg.react(addReactionPayload.emoji);\n this.sendToIfCb(obj.from, obj.command, { result: `Reaction added to message`, ...addReactionPayload }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error adding reaction to message: ${err}`, ...addReactionPayload }, obj.callback);\n }\n\n break; // addReaction\n\n case 'awaitMessageReaction':\n /*\n * wait for a message reaction\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const awaitMessageReactionPayload = obj.message as SendToActionAwaitMessageReactionPayload;\n\n // check payload\n if (typeof awaitMessageReactionPayload.timeout !== 'number' || awaitMessageReactionPayload.timeout < 100 || awaitMessageReactionPayload.timeout > 60000) {\n this.sendTo(obj.from, obj.command, { error: 'timeout needs to be a number between 100 and 60000', ...awaitMessageReactionPayload }, obj.callback);\n return;\n }\n if (typeof awaitMessageReactionPayload.max !== 'number' || awaitMessageReactionPayload.max < 1) {\n awaitMessageReactionPayload.max = 1;\n }\n\n // try to get the message\n try {\n msg = await this.getPreviousMessage(awaitMessageReactionPayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendTo(obj.from, obj.command, { error: err.message, ...awaitMessageReactionPayload }, obj.callback);\n } else {\n this.sendTo(obj.from, obj.command, { error: err, ...awaitMessageReactionPayload }, obj.callback);\n }\n return;\n }\n\n // collect reactions\n const reactionCollector = msg.createReactionCollector({\n filter: (_r, u) => u.id !== this.client?.user?.id,\n max: awaitMessageReactionPayload.max,\n time: awaitMessageReactionPayload.timeout,\n });\n reactionCollector.on('end', (collected) => {\n const reactions = collected.map((r) => ({ emoji: r.emoji.name, emojiId: r.emoji.id, users: r.users.cache.map((u) => ({ id: u.id, name: u.username, tag: u.tag })) }));\n this.sendTo(obj.from, obj.command, { reactions, ...awaitMessageReactionPayload }, obj.callback);\n });\n\n break; // awaitMessageReaction\n\n case 'sendCustomCommandReply':\n /*\n * send a reply to a custom slash command\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const sendCustomCommandReplyPayload = obj.message as SendToActionSendCustomCommandReplyPayload;\n\n // check payload\n if (typeof sendCustomCommandReplyPayload.interactionId !== 'string') {\n this.sendToIfCb(obj.from, obj.command, { error: 'interactionId needs to be a string', ...sendCustomCommandReplyPayload }, obj.callback);\n return;\n }\n if (!sendCustomCommandReplyPayload.content || (typeof sendCustomCommandReplyPayload.content !== 'string' && typeof sendCustomCommandReplyPayload.content !== 'object')) {\n this.sendToIfCb(obj.from, obj.command, { error: 'content needs to be a string or a MessageOptions object', ...sendCustomCommandReplyPayload }, obj.callback);\n return;\n }\n\n // send the reply\n try {\n const messageId = await this.discordSlashCommands.sendCmdCustomReply(sendCustomCommandReplyPayload.interactionId, this.prepareMessageForSend(sendCustomCommandReplyPayload.content));\n this.sendToIfCb(obj.from, obj.command, { result: `Reply sent`, ...sendCustomCommandReplyPayload, messageId }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error sending reply: ${err}`, ...sendCustomCommandReplyPayload }, obj.callback);\n }\n\n break; // sendCustomCommandReply\n\n case 'leaveServer':\n /*\n * let the bot leave a server\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const leaveServerPayload = obj.message as SendToActionServerIdentifier;\n\n // check payload\n if (!leaveServerPayload.serverId) {\n this.sendToIfCb(obj.from, obj.command, { error: 'serverId needs to be set', ...leaveServerPayload }, obj.callback);\n return;\n }\n\n const guildToLeave = this.client?.guilds.cache.get(leaveServerPayload.serverId);\n if (!guildToLeave) {\n this.sendToIfCb(obj.from, obj.command, { error: `No server with ID ${leaveServerPayload.serverId} found` }, obj.callback);\n return;\n }\n\n try {\n await guildToLeave.leave();\n this.log.info(`Left server ${guildToLeave.name} (${guildToLeave.id})`);\n\n this.sendToIfCb(obj.from, obj.command, { result: 'ok' }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error leaving server ${leaveServerPayload.serverId}: ${err}`, ...leaveServerPayload }, obj.callback);\n }\n\n break;\n\n case 'getServerInfo':\n /*\n * get information about a server\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getServerInfoPayload = obj.message as SendToActionServerIdentifier;\n\n // check payload\n if (!getServerInfoPayload.serverId) {\n this.sendTo(obj.from, obj.command, { error: 'serverId needs to be set', ...getServerInfoPayload }, obj.callback);\n return;\n }\n\n const server = this.client?.guilds.cache.get(getServerInfoPayload.serverId);\n if (!server) {\n this.sendTo(obj.from, obj.command, { error: `No server with ID ${getServerInfoPayload.serverId} found`, ...getServerInfoPayload }, obj.callback);\n return;\n }\n\n this.sendTo(obj.from, obj.command, {\n id: server.id,\n name: server.name,\n description: server.description,\n members: server.members.cache.map((m) => ({\n id: m.id,\n tag: m.user.tag,\n name: m.user.username,\n displayName: m.displayName,\n })),\n roles: server.roles.cache.map((r) => ({\n id: r.id,\n name: r.name,\n color: r.hexColor,\n })),\n channels: server.channels.cache.map((c) => ({\n id: c.id,\n parentId: c.parentId,\n name: c.name,\n type: c.type,\n })),\n }, obj.callback);\n\n break; // getServerInfo\n\n case 'getChannelInfo':\n /*\n * get information about a channel\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getChannelInfoPayload = obj.message as SendToActionChannelIdentifier;\n\n // check payload\n if (!getChannelInfoPayload.serverId || !getChannelInfoPayload.channelId) {\n this.sendTo(obj.from, obj.command, { error: 'serverId and channelId need to be set', ...getChannelInfoPayload }, obj.callback);\n return;\n }\n\n channel = this.client?.guilds.cache.get(getChannelInfoPayload.serverId)?.channels.cache.get(getChannelInfoPayload.channelId);\n if (!channel) {\n this.sendTo(obj.from, obj.command, { error: `No channel with ID ${getChannelInfoPayload.channelId} for server with ID ${getChannelInfoPayload.serverId} found`, ...getChannelInfoPayload }, obj.callback);\n return;\n }\n\n this.sendTo(obj.from, obj.command, {\n id: channel.id,\n parentId: channel.parentId,\n name: channel.name,\n type: channel.type,\n members: !channel.isThread() && channel.members.map((m) => ({\n id: m.id,\n tag: m.user.tag,\n name: m.user.username,\n displayName: m.displayName,\n })),\n }, obj.callback);\n\n break; // getChannelInfo\n\n case 'getServerMemberInfo':\n /*\n * get information about a server member\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getServerMemberInfoPayload = obj.message as SendToActionServerMemberIdentifier;\n\n // check payload\n if (!getServerMemberInfoPayload.serverId || (!getServerMemberInfoPayload.userId && !getServerMemberInfoPayload.userTag && !getServerMemberInfoPayload.userName)) {\n this.sendTo(obj.from, obj.command, { error: 'serverId and userlId, userTag or userName need to be set', ...getServerMemberInfoPayload }, obj.callback);\n return;\n }\n\n let member: GuildMember | undefined;\n if (getServerMemberInfoPayload.userId) {\n member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.get(getServerMemberInfoPayload.userId);\n if (!member) {\n this.sendTo(obj.from, obj.command, { error: `No member with ID ${getServerMemberInfoPayload.userId} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback);\n return;\n }\n } else if (getServerMemberInfoPayload.userTag) {\n member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.find((m) => m.user.tag === getServerMemberInfoPayload.userTag);\n if (!member) {\n this.sendTo(obj.from, obj.command, { error: `No member with tag ${getServerMemberInfoPayload.userTag} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback);\n return;\n }\n } else {\n member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.find((m) => m.user.discriminator === '0' && m.user.username === getServerMemberInfoPayload.userName);\n if (!member) {\n this.sendTo(obj.from, obj.command, { error: `No member with unique name ${getServerMemberInfoPayload.userName} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback);\n return;\n }\n }\n\n this.sendTo(obj.from, obj.command, {\n id: member.id,\n tag: member.user.tag,\n name: member.user.username,\n displayName: member.displayName,\n displayColor: member.displayHexColor,\n displayAvatarUrl: member.displayAvatarURL(),\n roles: member.roles.cache.map((r) => ({\n id: r.id,\n name: r.name,\n color: r.hexColor,\n })),\n joinedAt: member.joinedTimestamp,\n voiceChannelId: member.voice.channelId,\n voiceMuted: member.voice.mute,\n voiceDeaf: member.voice.deaf,\n }, obj.callback);\n\n break; // getServerMemberInfo\n\n case 'getUserInfo':\n /*\n * get information about a user\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getUserInfoPayload = obj.message as SendToActionUserIdentifier;\n\n // check payload\n if (!getUserInfoPayload.userId && !getUserInfoPayload.userTag && !getUserInfoPayload.userName) {\n this.sendTo(obj.from, obj.command, { error: 'userId, userTag or userName need to be set', ...getUserInfoPayload }, obj.callback);\n return;\n }\n\n if (getUserInfoPayload.userId) {\n user = this.client?.users.cache.get(getUserInfoPayload.userId);\n if (!user) {\n this.sendTo(obj.from, obj.command, { error: `No user with ID ${getUserInfoPayload.userId} found`, ...getUserInfoPayload }, obj.callback);\n return;\n }\n } else if (getUserInfoPayload.userTag) {\n user = this.client?.users.cache.find((u) => u.tag === getUserInfoPayload.userTag);\n if (!user) {\n this.sendTo(obj.from, obj.command, { error: `No user with tag ${getUserInfoPayload.userTag} found`, ...getUserInfoPayload }, obj.callback);\n return;\n }\n } else {\n user = this.client?.users.cache.find((u) => u.discriminator === '0' && u.username === getUserInfoPayload.userName);\n if (!user) {\n this.sendTo(obj.from, obj.command, { error: `No user with unique name ${getUserInfoPayload.userName} found`, ...getUserInfoPayload }, obj.callback);\n return;\n }\n }\n\n this.sendTo(obj.from, obj.command, {\n id: user.id,\n tag: user.tag,\n name: user.username,\n avatarUrl: user.avatarURL(),\n bot: user.bot,\n accentColor: user.hexAccentColor,\n }, obj.callback);\n\n break; // getUserInfo\n\n case 'getMessageInfo':\n /*\n * get information about a message\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getMessageInfoPayload = obj.message as MessageIdentifier;\n\n try {\n msg = await this.getPreviousMessage(getMessageInfoPayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendTo(obj.from, obj.command, { error: err.message, ...getMessageInfoPayload }, obj.callback);\n } else {\n this.sendTo(obj.from, obj.command, { error: err, ...getMessageInfoPayload }, obj.callback);\n }\n return;\n }\n\n this.sendTo(obj.from, obj.command, {\n id: msg.id,\n author: {\n id: msg.author.id,\n tag: msg.author.tag,\n name: msg.author.username,\n },\n content: msg.content,\n embeds: msg.embeds.map((e) => e.toJSON()),\n attachments: msg.attachments.map((a) => a.toJSON()),\n reactions: msg.reactions.cache.map((r) => r.toJSON()),\n createdTimestamp: msg.createdTimestamp,\n editedTimestamp: msg.editedTimestamp,\n reference: msg.reference,\n }, obj.callback);\n\n break; // getMessageInfo\n\n case 'sendNotification':\n /*\n * notification from ioBrokers notification system\n * see https://github.com/foxriver76/ioBroker.notification-manager\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (!this.config.sendNotificationsTo) {\n this.log.debug(`New notification received from ${obj.from}, but sending notifications is not enabled in adapter config`);\n this.sendTo(obj.from, obj.command, { sent: false }, obj.callback);\n return;\n }\n\n this.log.info(`New notification received from ${obj.from.replace(/^system\\.adapter\\./, '')}`);\n\n let target: User | TextChannel | undefined = undefined;\n\n if (this.config.sendNotificationsTo.indexOf('/') > 0) {\n // server channel\n const [serverId, channelId] = this.config.sendNotificationsTo.split('/');\n const channel = this.client?.guilds.cache.get(serverId)?.channels.cache.get(channelId);\n if (channel?.type === ChannelType.GuildText) {\n target = channel;\n }\n } else {\n // user\n target = this.client?.users.cache.get(this.config.sendNotificationsTo);\n }\n\n if (!target) {\n this.log.error(`Cannot send notification because the configured target is invalid!`);\n this.sendTo(obj.from, obj.command, { sent: false }, obj.callback);\n return;\n }\n\n const message = obj.message as LocalizedNotification;\n\n // check the message object\n if (!message?.category?.instances || !message.category.name) {\n this.log.warn(`Cannot send notification because the received message object is invalid`);\n this.sendTo(obj.from, obj.command, { sent: false }, obj.callback);\n return;\n }\n\n const { instances, severity } = message.category;\n\n let icon: string = '';\n switch (severity) {\n case 'alert':\n icon = ':warning: ';\n break;\n case 'info':\n icon = ':information_source: ';\n break;\n case 'notify':\n icon = ':bell: ';\n break;\n }\n\n const readableInstances = Object.entries(instances).map(([instance, entry]) => `${instance.substring('system.adapter.'.length)}: ${getNewestDate(entry.messages, i18n.language)}`);\n\n const text = `${icon}**${message.category.name}**\n\n${message.category.description ?? ''}\n\n${message.host}:\n${readableInstances.join('\\n')}`;\n\n try {\n const msg = await target.send(text);\n this.log.debug(`Sent message from notification-manager adapter with message ID ${msg.id}`);\n this.sendTo(obj.from, obj.command, { sent: true }, obj.callback);\n } catch (err) {\n this.log.warn(`Error sending message from notification-manager adapter: ${err}`);\n this.sendTo(obj.from, obj.command, { sent: false }, obj.callback);\n }\n\n break;\n\n default:\n /*\n * unknown command\n */\n this.log.warn(`Got message with unknown command: ${obj.command}`);\n if (obj.callback) {\n this.sendTo(obj.from, obj.command, { error: `Unknown command: ${obj.command}` }, obj.callback);\n }\n\n }\n }\n\n /**\n * Like `sendTo(...)` but only sends if a callback is given.\n *\n * If no callback given, but `message.error` is defined, the error will be\n * logged as a warning.\n * @see sendTo\n */\n private sendToIfCb (instanceName: string, command: string, message: ioBroker.MessagePayload, callback: ioBroker.MessageCallback | ioBroker.MessageCallbackInfo | undefined): void {\n if (callback) {\n this.sendTo(instanceName, command, message, callback);\n } else if (typeof message === 'object' && message.error) {\n this.log.warn(message.error);\n }\n }\n\n /**\n * Try to detect and parse stringified JSON MessageOptions.\n *\n * If the `content` starts/ends with curly braces if will be treated as\n * stringified JSON. Then the JSON will be parsed and some basic checks will\n * be run against the parsed object.\n *\n * Otherwise the content will be treated as a simple string and wrapped into\n * a `MessageOptions` object.\n * @param content The stringified content to be parsed.\n * @returns A `MessageOptions` object.\n * @throws An error if parsing JSON or a check failed.\n */\n public parseStringifiedMessageOptions (content: string): MessageCreateOptions {\n let mo: MessageCreateOptions;\n\n if (content.startsWith('{') && content.endsWith('}')) {\n // seems to be json\n this.log.debug(`Content seems to be json`);\n\n try {\n mo = JSON.parse(content) as MessageCreateOptions;\n } catch (err) {\n throw new Error(`Content seems to be json but cannot be parsed!`);\n }\n\n // do some basic checks against the parsed object\n if ((!mo?.files && !mo.content) || (mo.files && !Array.isArray(mo.files)) || (mo.embeds && !Array.isArray(mo.embeds))) {\n throw new Error(`Content is json but seems to be invalid!`);\n }\n\n } else {\n // just a string... create MessageOptions object\n mo = {\n content,\n };\n }\n\n return mo;\n }\n\n /**\n * Prepare a message for sending.\n *\n * This some message parts to be valid discord message data.\n * @param msg The message as `string` or `MessageCreateOptions`.\n * @returns The prepared message.\n */\n private prepareMessageForSend (msg: string | MessageCreateOptions): string | MessageCreateOptions {\n if (typeof msg === 'string') {\n return msg;\n }\n\n // replace hexo color codes in embeds\n if (msg.embeds) {\n for (const embed of msg.embeds) {\n // color codes may be given as string in user defined embeds\n if (typeof (embed as APIEmbed).color === 'string') {\n const colorStr: string = (embed as APIEmbed).color as unknown as string;\n if (colorStr.match(/^\\d+$/)) {\n // it's a number color given as string\n (embed as APIEmbed).color = parseInt(colorStr, 10);\n } else {\n // it's something else (maybe a color name or hexo color)\n // try to resolve the color\n try {\n (embed as APIEmbed).color = resolveColor(colorStr as HexColorString);\n } catch (err) {\n // color could not be resolved, use a default color\n (embed as APIEmbed).color = resolveColor('Greyple');\n this.log.warn(`Error embed color '${colorStr}': ${err}`);\n }\n }\n }\n }\n }\n\n return msg;\n }\n\n /**\n * Find a previous message from/to a user or in a server text channel.\n * @param identifier Parameters to find the message.\n * @throws An error if some parameters are missing or the message could not be found.\n */\n private async getPreviousMessage (identifier: MessageIdentifier): Promise> {\n if (!identifier.messageId) {\n throw new Error('messageId needs to be set');\n }\n\n if (identifier.userId || identifier.userTag || identifier.userName) {\n // a user\n let user: User | undefined;\n if (identifier.userId) {\n // by userId\n user = this.client?.users.cache.get(identifier.userId);\n if (!user) {\n throw new Error(`No user with userId ${identifier.userId} found`);\n }\n } else if (identifier.userTag) {\n // by userTag\n user = this.client?.users.cache.find((u) => u.tag === identifier.userTag);\n if (!user) {\n throw new Error(`No user with userTag ${identifier.userTag} found`);\n }\n } else {\n // by unique userName\n user = this.client?.users.cache.find((u) => u.discriminator === '0' && u.username === identifier.userName);\n if (!user) {\n throw new Error(`No user with unique userName ${identifier.userName} found`);\n }\n }\n try {\n if (!user.dmChannel) {\n await user.createDM();\n }\n const msg = user.dmChannel?.messages.cache.get(identifier.messageId) ?? await user.dmChannel?.messages.fetch(identifier.messageId);\n if (!msg) {\n throw new Error(`No message with messageId ${identifier.messageId} for user ${userNameOrTag(user)} found`);\n }\n return msg;\n } catch (err) {\n throw new Error(`Error finding message for user ${userNameOrTag(user)}: ${err}`);\n }\n\n } else if (identifier.serverId && identifier.channelId) {\n // a channel\n const channel = this.client?.guilds.cache.get(identifier.serverId)?.channels.cache.get(identifier.channelId);\n if (channel?.type !== ChannelType.GuildText && channel?.type !== ChannelType.GuildVoice) {\n throw new Error(`No text channel with channelId ${identifier.channelId} on server ${identifier.serverId} found`);\n }\n try {\n const msg = channel.messages.cache.get(identifier.messageId) ?? await channel.messages.fetch(identifier.messageId);\n if (!msg) {\n throw new Error(`No message with messageId ${identifier.messageId} for channel ${channel.name} found`);\n }\n return msg;\n } catch (err) {\n throw new Error(`Error finding message in channel ${channel.name}: ${err}`);\n }\n\n } else {\n // missing arguments\n throw new Error('userId, userTag, userName or serverId and channelId needs to be set');\n }\n }\n\n /**\n * Check if a user or guild member is authorized to do something.\n * For guild members their roles will also be checked.\n * @param user The User or GuildMember to check.\n * @param required Object containing the required flags. If not provided the check returns if the user in the list of authorized users.\n * @returns `true` if the user is authorized or authorization is not enabled, `false` otherwise\n */\n public checkUserAuthorization (user: User | GuildMember, required?: CheckAuthorizationOpts): boolean {\n if (!this.config.enableAuthorization) {\n return true;\n }\n\n // get direct user flags\n let given: ioBroker.AdapterConfigAuthorizedFlags | undefined = this.config.authorizedUsers.find((au) => au.userId === user.id);\n\n // for guild members find role flags and merge them all together\n if (this.config.authorizedServerRoles.length > 0 && user instanceof GuildMember) {\n for (const [, role] of user.roles.cache) {\n const roleGiven = this.config.authorizedServerRoles.find((ar) => ar.serverAndRoleId === `${user.guild.id}|${role.id}`);\n if (roleGiven) {\n if (!given) {\n given = roleGiven;\n } else {\n given = {\n getStates: given.getStates || roleGiven.getStates,\n setStates: given.setStates || roleGiven.setStates,\n useCustomCommands: given.useCustomCommands || roleGiven.useCustomCommands,\n useText2command: given.useText2command || roleGiven.useText2command,\n };\n }\n }\n }\n }\n\n // nothing found?\n if (!given) {\n return false;\n }\n\n // if no required flags given just return true if something found\n if (!required) {\n return true;\n }\n\n if ((required.getStates && !given.getStates)\n || (required.setStates && !given.setStates)\n || (required.useCustomCommands && !given.useCustomCommands)\n || (required.useText2command && !given.useText2command)) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Awaitable function to just wait some time.\n *\n * Uses `Adapter.setTimeout(...)` internally to make sure the timeout is cleared on adapter unload.\n * @param time Time to wait in ms.\n */\n public wait (time: number): Promise {\n return new Promise((resolve: () => void) => this.setTimeout(resolve, time));\n }\n\n /**\n * Set the `info.connection` state if changed.\n * @param connected If connected.\n * @param force `true` to skip local cache check and always set the state.\n */\n private async setInfoConnectionState (connected: boolean, force: boolean = false): Promise {\n if (force || connected !== this.infoConnected) {\n await this.setStateAsync('info.connection', connected, true);\n this.infoConnected = connected;\n }\n }\n\n /**\n * Internal replacemend for `extendObjectAsync(...)` which compares the given\n * object for each `id` against a cached version and only calls na original\n * `extendObjectAsync(...)` if the object changed.\n * Using this, the object gets only updated if\n * a) it's the first call for this `id` or\n * b) the object needs to be changed.\n */\n public async extendObjectAsyncCached (id: string, objPart: ioBroker.PartialObject, options?: ioBroker.ExtendObjectOptions): ioBroker.SetObjectPromise {\n const cachedObj: ioBroker.PartialObject | undefined = this.extendObjectCache.get(id);\n\n if (isDeepStrictEqual(cachedObj, objPart)) {\n return { id };\n }\n\n const ret = await this.extendObjectAsync(id, objPart, options);\n this.extendObjectCache.set(id, objPart);\n return ret;\n }\n\n /**\n * Internal replacement for `delObjectAsync(...)` which also removes the local\n * cache entry for the given `id`.\n */\n public async delObjectAsyncCached (id: string, options?: ioBroker.DelObjectOptions): Promise {\n if (options?.recursive) {\n this.extendObjectCache.filter((_obj, id2) => id2.startsWith(id)).each((_obj, id2) => this.extendObjectCache.delete(id2));\n } else {\n this.extendObjectCache.delete(id);\n }\n\n return this.delObjectAsync(id, options);\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n @boundMethod\n private async onUnload (callback: () => void): Promise {\n try {\n this.unloaded = true;\n\n await this.setInfoConnectionState(false, true);\n\n if (this.client) {\n this.client.destroy();\n }\n\n callback();\n } catch (e) {\n callback();\n }\n }\n\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial | undefined) => new DiscordAdapter(options);\n} else {\n // otherwise start the instance directly\n (() => new DiscordAdapter())();\n}\n\n// export the type of the adapter class to use it in other files\nexport type { DiscordAdapter };\n"], - "mappings": "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", - "names": ["djsVersion", "_r", "_a", "_b", "channel", "msg"] + "sourcesContent": ["import 'source-map-support/register';\n\nimport { isDeepStrictEqual } from 'node:util';\n\nimport { boundMethod } from 'autobind-decorator';\n\nimport {\n Adapter,\n AdapterOptions,\n EXIT_CODES,\n} from '@iobroker/adapter-core';\n\nimport {\n ActivityType,\n APIEmbed,\n ChannelType,\n Client,\n Collection,\n CloseEvent as DjsCloseEvent,\n version as djsVersion,\n DMChannel,\n GatewayIntentBits,\n Guild,\n GuildBasedChannel,\n GuildMember,\n HexColorString,\n Message,\n MessageCreateOptions,\n NonThreadGuildBasedChannel,\n Partials,\n PermissionsBitField,\n Presence,\n PresenceData,\n PresenceStatusData,\n resolveColor,\n Snowflake,\n TextChannel,\n User,\n VoiceState,\n} from 'discord.js';\n\nimport {\n CommandObjectConfig,\n DiscordAdapterSlashCommands,\n} from './commands';\nimport {\n ACTIVITY_TYPES,\n ActivityTypeNames,\n ChannelTypeNames,\n CheckAuthorizationOpts,\n JsonMessageObj,\n JsonServersChannelsObj,\n JsonServersMembersObj,\n JsonUsersObj,\n MessageIdentifier,\n SendToActionAddReactionPayload,\n SendToActionAwaitMessageReactionPayload,\n SendToActionChannelIdentifier,\n SendToActionEditMessagePayload,\n SendToActionSendCustomCommandReplyPayload,\n SendToActionSendPayload,\n SendToActionServerIdentifier,\n SendToActionServerMemberIdentifier,\n SendToActionUserIdentifier,\n SetBotPresenceOptions,\n Text2commandMessagePayload,\n UpdateUserPresenceResult,\n VALID_PRESENCE_STATUS_DATA,\n} from './lib/definitions';\nimport { i18n } from './lib/i18n';\nimport {\n getBasenameFromFilePathOrUrl,\n getBufferAndNameFromBase64String,\n getObjName,\n userNameOrTag,\n} from './lib/utils';\nimport { getNewestDate, LocalizedNotification } from './lib/notification-manager';\n\nconst LOGIN_WAIT_TIMES = [\n 0, // none - first try!\n 5000, // 5 sek\n 10000, // 10 sek\n 30000, // 30 sek\n 60000, // 1 min\n 120000, // 2 min\n 120000, // 2 min\n 300000, // 5 min\n 300000, // 5 min\n 300000, // 5 min\n 600000, // 10 min\n] as const;\n\n/**\n * ioBroker.discord adapter\n */\nclass DiscordAdapter extends Adapter {\n\n /**\n * Instance of the discord client.\n */\n public client: Client | null = null;\n\n /**\n * Flag if the adapter is unloaded or is unloading.\n * Used to check this in some async operations.\n */\n public unloaded: boolean = false;\n\n /**\n * Flag if the initial setup of the custom object configurations is done or not.\n * While not done, custom object configuration changes will not trigger a\n * slash commands registration automatically.\n */\n public initialCustomObjectSetupDone: boolean = false;\n\n /**\n * Local cache for `info.connection` state.\n */\n private infoConnected: boolean = false;\n\n /**\n * Set of state IDs where received discord messages will be stored to.\n * Used to identify target states for received discord messages.\n */\n private messageReceiveStates: Set = new Set();\n\n /**\n * Set user IDs known to set up.\n * Used to check if the user objects are created on some events.\n */\n private knownUsers: Set = new Set();\n\n /**\n * Set of objects from this instance with text2command enabled.\n */\n private text2commandObjects: Set = new Set();\n\n /**\n * Cache for `extendObjectCache(...)` calls to extend objects only when changed.\n */\n private extendObjectCache: Collection = new Collection();\n\n /**\n * Cache for `.json` states.\n */\n private jsonStateCache: Collection = new Collection();\n\n /**\n * Instance of the slash commands handler class.\n */\n private discordSlashCommands: DiscordAdapterSlashCommands;\n\n /**\n * Flag if we are currently in shard error state from discord.js.\n * `false` currently not on error state, A `string` containing the error name in\n * case of en error.\n */\n private isShardError: false | string = false;\n\n public constructor (options: Partial = {}) {\n super({\n ...options,\n name: 'discord',\n });\n\n this.discordSlashCommands = new DiscordAdapterSlashCommands(this);\n\n this.on('ready', this.onReady);\n this.on('stateChange', this.onStateChange);\n this.on('objectChange', this.onObjectChange);\n this.on('message', this.onMessage);\n this.on('unload', this.onUnload);\n }\n\n /**\n * Try to detect and parse stringified JSON MessageOptions.\n *\n * If the `content` starts/ends with curly braces if will be treated as\n * stringified JSON. Then the JSON will be parsed and some basic checks will\n * be run against the parsed object.\n *\n * Otherwise the content will be treated as a simple string and wrapped into\n * a `MessageOptions` object.\n * @param content The stringified content to be parsed.\n * @returns A `MessageOptions` object.\n * @throws An error if parsing JSON or a check failed.\n */\n public parseStringifiedMessageOptions (content: string): MessageCreateOptions {\n let mo: MessageCreateOptions;\n\n if (content.startsWith('{') && content.endsWith('}')) {\n // seems to be json\n this.log.debug(`Content seems to be json`);\n\n try {\n mo = JSON.parse(content) as MessageCreateOptions;\n } catch (_err) {\n throw new Error(`Content seems to be json but cannot be parsed!`);\n }\n\n // do some basic checks against the parsed object\n if ((!mo?.files && !mo.content) || (mo.files && !Array.isArray(mo.files)) || (mo.embeds && !Array.isArray(mo.embeds))) {\n throw new Error(`Content is json but seems to be invalid!`);\n }\n\n } else {\n // just a string... create MessageOptions object\n mo = {\n content,\n };\n }\n\n return mo;\n }\n\n /**\n * Check if a user or guild member is authorized to do something.\n * For guild members their roles will also be checked.\n * @param user The User or GuildMember to check.\n * @param required Object containing the required flags. If not provided the check returns if the user in the list of authorized users.\n * @returns `true` if the user is authorized or authorization is not enabled, `false` otherwise\n */\n public checkUserAuthorization (user: User | GuildMember, required?: CheckAuthorizationOpts): boolean {\n if (!this.config.enableAuthorization) {\n return true;\n }\n\n // get direct user flags\n let given: ioBroker.AdapterConfigAuthorizedFlags | undefined = this.config.authorizedUsers.find((au) => au.userId === user.id);\n\n // for guild members find role flags and merge them all together\n if (this.config.authorizedServerRoles.length > 0 && user instanceof GuildMember) {\n for (const [ , role ] of user.roles.cache) {\n const roleGiven = this.config.authorizedServerRoles.find((ar) => ar.serverAndRoleId === `${user.guild.id}|${role.id}`);\n if (roleGiven) {\n if (!given) {\n given = roleGiven;\n } else {\n given = {\n getStates: given.getStates || roleGiven.getStates,\n setStates: given.setStates || roleGiven.setStates,\n useCustomCommands: given.useCustomCommands || roleGiven.useCustomCommands,\n useText2command: given.useText2command || roleGiven.useText2command,\n };\n }\n }\n }\n }\n\n // nothing found?\n if (!given) {\n return false;\n }\n\n // if no required flags given just return true if something found\n if (!required) {\n return true;\n }\n\n if ((required.getStates && !given.getStates)\n || (required.setStates && !given.setStates)\n || (required.useCustomCommands && !given.useCustomCommands)\n || (required.useText2command && !given.useText2command)) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Awaitable function to just wait some time.\n *\n * Uses `Adapter.setTimeout(...)` internally to make sure the timeout is cleared on adapter unload.\n * @param time Time to wait in ms.\n */\n public async wait (time: number): Promise {\n return await new Promise((resolve: () => void) => this.setTimeout(resolve, time));\n }\n\n /**\n * Internal replacemend for `extendObject(...)` which compares the given\n * object for each `id` against a cached version and only calls na original\n * `extendObject(...)` if the object changed.\n * Using this, the object gets only updated if\n * a) it's the first call for this `id` or\n * b) the object needs to be changed.\n */\n public async extendObjectCached (id: string, objPart: ioBroker.PartialObject, options?: ioBroker.ExtendObjectOptions): ioBroker.SetObjectPromise {\n const cachedObj: ioBroker.PartialObject | undefined = this.extendObjectCache.get(id);\n\n if (isDeepStrictEqual(cachedObj, objPart)) {\n return { id };\n }\n let ret: ioBroker.NonNullCallbackReturnTypeOf;\n if (options) {\n ret = await this.extendObject(id, objPart, options);\n } else {\n ret = await this.extendObject(id, objPart);\n }\n this.extendObjectCache.set(id, objPart);\n return ret;\n }\n\n /**\n * Internal replacement for `delObjectAsync(...)` which also removes the local\n * cache entry for the given `id`.\n */\n public async delObjectAsyncCached (id: string, options?: ioBroker.DelObjectOptions): Promise {\n if (options?.recursive) {\n this.extendObjectCache.filter((_obj, id2) => id2.startsWith(id)).each((_obj, id2) => this.extendObjectCache.delete(id2));\n } else {\n this.extendObjectCache.delete(id);\n }\n\n return await this.delObjectAsync(id, options);\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n @boundMethod\n private async onReady (): Promise {\n\n // Reset the connection indicator during startup\n await this.setInfoConnectionState(false, true);\n\n // log version of discord.js\n this.log.debug(`Version of discord.js: ${djsVersion}`);\n\n // try to get the system language\n const systemConfig = await this.getForeignObjectAsync('system.config');\n i18n.language = systemConfig?.common.language ?? 'en';\n i18n.isFloatComma = systemConfig?.common.isFloatComma ?? false;\n\n // validate config\n if (typeof this.config.token !== 'string' || !(/^[0-9a-zA-Z-_]{24,}\\.[0-9a-zA-Z-_]{6}\\.[0-9a-zA-Z-_]{27,}$/.exec(this.config.token))) {\n this.log.error(`No or invalid token!`);\n return;\n }\n if (!Array.isArray(this.config.authorizedUsers)) {\n this.config.authorizedUsers = [];\n }\n if (!Array.isArray(this.config.authorizedServerRoles)) {\n this.config.authorizedServerRoles = [];\n }\n if (!this.config.enableAuthorization) {\n this.log.info('Authorization is disabled, so any user is able to interact with the bot. You should only disable authorization if you trust all users on any server where the bot is on.');\n }\n if (this.config.enableAuthorization && this.config.authorizedUsers.length === 0 && this.config.authorizedServerRoles.length === 0) {\n this.log.info('Authorization is enabled but no authorized users are defined!');\n }\n if (this.config.enableCustomCommands && !Array.isArray(this.config.customCommands)) {\n this.config.customCommands = [];\n }\n this.config.reactOnMentionsEmoji = this.config.reactOnMentionsEmoji?.trim() || '\uD83D\uDC4D';\n\n // setup/fix native objects from older adapter versions\n const botActivityTypeObj = await this.getObjectAsync('bot.activityType');\n /* eslint-disable @typescript-eslint/no-unsafe-member-access */\n if (botActivityTypeObj?.common?.states?.PLAYING) {\n // TODO: use extendObject with null values when issue https://github.com/ioBroker/ioBroker.js-controller/issues/1735 is resolved\n delete botActivityTypeObj.common.states.PLAYING;\n delete botActivityTypeObj.common.states.STREAMING;\n delete botActivityTypeObj.common.states.LISTENING;\n delete botActivityTypeObj.common.states.WATCHING;\n delete botActivityTypeObj.common.states.COMPETING;\n await this.setObjectAsync('bot.activityType', botActivityTypeObj);\n }\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n\n // setup generic dynamic objects (most objects will be set up in `updateGuilds` method)\n if (this.config.enableRawStates) {\n await this.extendObject('raw', {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Raw data'),\n },\n native: {},\n });\n await Promise.all([\n this.extendObject('raw.interactionJson', {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last interaction JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObject('raw.messageJson', {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n } else {\n await this.delObjectAsync('raw', { recursive: true });\n }\n\n if (this.config.enableCustomCommands) {\n await this.extendObject('slashCommands', {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Custom Discord slash commands'),\n },\n native: {},\n });\n } else {\n await this.delObjectAsync('slashCommands', { recursive: true });\n }\n\n // setup the discord client\n this.client = new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMembers,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.GuildMessageReactions,\n GatewayIntentBits.GuildMessageTyping,\n GatewayIntentBits.GuildPresences,\n GatewayIntentBits.GuildVoiceStates,\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.DirectMessageReactions,\n GatewayIntentBits.DirectMessageTyping,\n ],\n partials: [\n Partials.Channel, // needed for DMs\n ],\n });\n\n this.client.on('ready', this.onClientReady);\n\n if (this.log.level === 'silly') {\n this.client.on('debug', (message) => this.log.silly(`discordjs: ${message}`));\n }\n this.client.on('warn', (message) => this.log.warn(`Discord client warning: ${message}`));\n this.client.on('error', (err) => this.log.error(`Discord client error: ${err.toString()}`));\n this.client.on('rateLimit', (rateLimitData) => this.log.debug(`Discord client rate limit hit: ${JSON.stringify(rateLimitData)}`)); // rate limit event is just a information - discord.js handels rate limits\n this.client.on('invalidRequestWarning', (invalidRequestWarningData) => this.log.warn(`Discord client invalid request warning: ${JSON.stringify(invalidRequestWarningData)}`));\n\n this.client.on('invalidated', () => {\n this.log.warn('Discord client session invalidated');\n void this.setInfoConnectionState(false);\n });\n\n this.client.on('shardError', (err: Error, shardId: number) => {\n // discord.js internally handles websocket errors and reconnects\n // this is just for some logging and setting the connection state\n\n // just handle the error if it's not the already handled error\n let errorMsg: string;\n if (err instanceof AggregateError) {\n // create a list of unique error code entries\n errorMsg = Array.from(new Set(err.errors.map((e: NodeJS.ErrnoException) => e.code))).join(', ');\n } else {\n errorMsg = err.toString();\n }\n\n if (this.isShardError !== errorMsg) {\n this.isShardError = errorMsg;\n this.log.warn(`Discord client websocket error (shardId:${shardId}): ${errorMsg}`);\n void this.setInfoConnectionState(false);\n } else {\n this.log.debug(`Discord client websocket error (shardId:${shardId}): ${errorMsg}`);\n }\n });\n\n this.client.on('shardReady', (shardId: number) => {\n // discord.js websocket is ready (connected)\n this.isShardError = false;\n this.log.info(`Discord client websocket connected (shardId:${shardId})`);\n void this.setInfoConnectionState(true);\n void this.setBotPresence();\n });\n\n this.client.on('shardResume', (shardId: number, replayedEvents: number) => this.log.debug(`Discord client websocket resume (shardId:${shardId} replayedEvents:${replayedEvents})`));\n this.client.on('shardDisconnect', (event: DjsCloseEvent, shardId: number) => this.log.debug(`Discord client websocket disconnect (shardId:${shardId} code:${event.code})`));\n this.client.on('shardReconnecting', (shardId: number) => this.log.debug(`Discord client websocket reconnecting (shardId:${shardId})`));\n\n this.client.on('messageCreate', this.onClientMessageCreate);\n\n if (this.config.dynamicServerUpdates) {\n this.client.on('channelCreate', () => this.updateGuilds());\n this.client.on('channelDelete', () => this.updateGuilds());\n this.client.on('channelUpdate', () => this.updateGuilds());\n this.client.on('guildCreate', () => this.updateGuilds());\n this.client.on('guildDelete', () => this.updateGuilds());\n this.client.on('guildUpdate', () => this.updateGuilds());\n this.client.on('guildMemberAdd', () => this.updateGuilds());\n this.client.on('guildMemberRemove', () => this.updateGuilds());\n this.client.on('roleCreate', () => this.updateGuilds());\n this.client.on('roleDelete', () => this.updateGuilds());\n this.client.on('roleUpdate', () => this.updateGuilds());\n this.client.on('userUpdate', () => this.updateGuilds());\n }\n\n if (this.config.observeUserPresence) {\n this.client.on('presenceUpdate', (_oldPresence, newPresence) => this.updateUserPresence(newPresence.userId, newPresence));\n }\n\n if (this.config.observeUserVoiceState) {\n this.client.on('voiceStateUpdate', this.onClientVoiceStateUpdate);\n }\n\n // init commands instance - need to be done after discord client setup\n await this.discordSlashCommands.onReady();\n\n // subscribe needed states and objects\n this.subscribeStates('servers.*.channels.*.send');\n this.subscribeStates('servers.*.channels.*.sendFile');\n this.subscribeStates('servers.*.channels.*.sendReply');\n this.subscribeStates('servers.*.channels.*.sendReaction');\n this.subscribeStates('users.*.send');\n this.subscribeStates('users.*.sendFile');\n this.subscribeStates('users.*.sendReply');\n this.subscribeStates('users.*.sendReaction');\n this.subscribeStates('servers.*.members.*.voiceDisconnect');\n this.subscribeStates('servers.*.members.*.voiceServerMute');\n this.subscribeStates('servers.*.members.*.voiceServerDeaf');\n this.subscribeStates('slashCommands.*.sendReply');\n this.subscribeStates('slashCommands.*.option-*.choices');\n this.subscribeStates('bot.*');\n this.subscribeForeignObjects('*'); // needed to handle custom object configs\n\n // initially get all objects with custom config\n this.log.debug('Get all objects with custom config ...');\n const view = await this.getObjectViewAsync('system', 'custom', {});\n if (view?.rows) {\n for (const item of view.rows) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n await this.setupObjCustom(item.id, item.value?.[this.namespace]);\n }\n }\n this.log.debug('Getting all objects with custom config done');\n\n // remember that the initial setup of the custom objects is done\n this.initialCustomObjectSetupDone = true;\n\n // try to log in the client, terminate if this was not successfull\n const loginResult = await this.loginClient();\n if (loginResult !== true) {\n if (loginResult.includes('TOKEN_INVALID')) {\n this.terminate('Invalid token, please check your configuration!', EXIT_CODES.ADAPTER_REQUESTED_TERMINATION);\n } else {\n this.terminate('No connection to Discord', EXIT_CODES.START_IMMEDIATELY_AFTER_STOP);\n }\n return; // needed!\n }\n\n // register discord commands if login was successfull\n await this.discordSlashCommands.registerSlashCommands();\n }\n\n /**\n * Try to log in the discord client.\n *\n * This will also handle network related errors.\n * In case of networt related errors this will retry the login after some time.\n * The wait time before each retry will be increased for each try, as defined\n * in `LOGIN_WAIT_TIMES`.\n * @param tryNr Number of the login try. Should be `0` when login process is started and is increased internally in each try.\n * @returns Promise which resolves to `true` if logged in, or an error name/message otherwise.\n */\n private async loginClient (tryNr: number = 0): Promise {\n if (!this.client || this.unloaded) {\n return 'No Client';\n }\n\n try {\n await this.client.login(this.config.token);\n return true;\n } catch (err) {\n if (err instanceof Error) {\n let errorMsg: string;\n if (err instanceof AggregateError) {\n // create a list of unique error code entries\n errorMsg = Array.from(new Set(err.errors.map((e: NodeJS.ErrnoException) => e.code))).join(', ');\n } else {\n errorMsg = err.toString();\n }\n // log first 4 errors as info, then as warning\n if (tryNr < 4) {\n this.log.info(`Discord login error: ${errorMsg}`);\n } else {\n this.log.warn(`Discord login error: ${errorMsg}`);\n }\n if (err.name === 'AbortError' || err.name === 'ConnectTimeoutError' || (err as NodeJS.ErrnoException).code === 'EAI_AGAIN'\n || (err instanceof AggregateError && err.errors.map((e: NodeJS.ErrnoException) => e.code).includes('ENETUNREACH'))) {\n // AbortError and ConnectTimeoutError are results of network errors\n // EAI_AGAIN is a result of DNS errors\n // AggregateError containing ENETUNREACH occurs in case routing problems\n // ... retry\n tryNr++;\n if (tryNr >= LOGIN_WAIT_TIMES.length) {\n tryNr = LOGIN_WAIT_TIMES.length - 1;\n }\n\n this.log.info(`Wait ${LOGIN_WAIT_TIMES[tryNr] / 1000} seconds before next login try (#${tryNr + 1}) ...`);\n await this.wait(LOGIN_WAIT_TIMES[tryNr]);\n\n return await this.loginClient(tryNr);\n }\n return err.name;\n } else {\n this.log.error('Unknown Discord login error');\n return 'Unknown Discord login error';\n }\n }\n }\n\n /**\n * When the discord client is ready.\n */\n @boundMethod\n private async onClientReady (): Promise {\n if (!this.client?.user) {\n this.log.error('Discord client has no user!');\n return;\n }\n\n this.log.info(`Logged in as ${this.client.user.tag}!`);\n this.log.debug(`User ID: ${this.client.user.id}`);\n\n // change the bot username/nickname if needed\n if (this.config.botName) {\n if (this.client.user.username !== this.config.botName) {\n // update needed\n this.log.debug(`Update of bot name needed - current name: ${this.client.user.username} - configured name: ${this.config.botName}`);\n try {\n const proms: Promise[] = [];\n proms.push(this.client.user.setUsername(this.config.botName));\n\n for (const [ , guild ] of this.client.guilds.cache) {\n const me = guild.members.cache.get(this.client.user.id);\n if (me) {\n proms.push(me.setNickname(this.config.botName));\n }\n }\n\n await Promise.all(proms);\n this.log.debug(`Bot name updated`);\n } catch (err) {\n this.log.warn(`Error setting the bot name to \"${this.config.botName}\": ${err}`);\n }\n } else {\n // up to date\n this.log.debug('Bot name is up to date');\n }\n }\n\n try {\n await this.updateGuilds();\n } catch (err) {\n this.log.error(`Error while updating server information: ${err}`);\n }\n }\n\n /**\n * Update the guilds (servers), channels and users seen by the discord bot.\n * This will create/update all dynamic objects for all servers and users if needed.\n */\n private async updateGuilds (): Promise {\n if (!this.client?.user) {\n throw new Error('Client not loaded');\n }\n\n /**\n * Collection of known users on all known servers.\n * Used to create/delete user objects.\n */\n const allServersUsers: Collection = new Collection();\n\n /**\n * Set of object IDs for all known servers and channels.\n * Used to detect server/channel objects which have be deleted.\n */\n const knownServersAndChannelsIds: Set = new Set();\n\n if (this.unloaded) return;\n const guilds = await this.client.guilds.fetch();\n if (this.unloaded) return;\n\n for (const [ , guildBase ] of guilds) {\n\n if (this.unloaded) return;\n let guild: Guild;\n try {\n guild = await guildBase.fetch();\n } catch (err) {\n this.log.warn(`Could not fetch guild information for guild \"${guildBase.name}\" id:${guildBase.id}`);\n this.log.debug(`Error: ${err}`);\n continue;\n }\n if (this.unloaded) return;\n\n knownServersAndChannelsIds.add(`${this.namespace}.servers.${guild.id}`);\n\n // create channel for this guild\n await this.extendObjectCached(`servers.${guild.id}`, {\n type: 'channel',\n common: {\n name: guild.name,\n },\n native: {},\n });\n\n await Promise.all([\n this.extendObjectCached(`servers.${guild.id}.members`, {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Members'),\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.channels`, {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Channels'),\n },\n native: {},\n }),\n ]);\n\n // add guild member objects\n const guildMembers = await guild.members.fetch();\n if (this.unloaded) return;\n\n for (const [ , member ] of guildMembers) {\n // remember user if not the bot itself\n if (member.user.id !== this.client.user.id) {\n allServersUsers.set(member.user.id, { user: member.user, presence: member.presence });\n }\n\n await this.extendObjectCached(`servers.${guild.id}.members.${member.id}`, {\n type: 'channel',\n common: {\n name: `${member.displayName} (${userNameOrTag(member.user)})`,\n },\n native: {},\n });\n\n await Promise.all([\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.tag`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User tag'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.name`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.displayName`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Display name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.roles`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Roles'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.joinedAt`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Joined at'),\n role: 'date',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceChannel`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice channel'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceDisconnect`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice disconnect'),\n role: 'button',\n type: 'boolean',\n read: false,\n write: true,\n def: false,\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice self deafen'),\n role: 'indicator',\n type: 'boolean',\n read: true,\n write: false,\n def: false,\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice server deafen'),\n role: 'switch',\n type: 'boolean',\n read: true,\n write: true,\n def: false,\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice self mute'),\n role: 'indicator',\n type: 'boolean',\n read: true,\n write: false,\n def: false,\n },\n native: {},\n }),\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceServerMute`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Voice server mute'),\n role: 'switch',\n type: 'boolean',\n read: true,\n write: true,\n def: false,\n },\n native: {},\n }),\n\n this.extendObjectCached(`servers.${guild.id}.members.${member.id}.json`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n\n const memberRoles = member.roles.cache.map((role) => role.name);\n await Promise.all([\n this.setState(`servers.${guild.id}.members.${member.id}.tag`, member.user.tag, true),\n this.setState(`servers.${guild.id}.members.${member.id}.name`, member.user.username, true),\n this.setState(`servers.${guild.id}.members.${member.id}.displayName`, member.displayName, true),\n this.setState(`servers.${guild.id}.members.${member.id}.roles`, memberRoles.join(', '), true),\n this.setState(`servers.${guild.id}.members.${member.id}.joinedAt`, member.joinedTimestamp, true),\n this.setState(`servers.${guild.id}.members.${member.id}.voiceChannel`, member.voice.channel?.name ?? '', true),\n this.setState(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, !!member.voice.selfDeaf, true),\n this.setState(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, !!member.voice.serverDeaf, true),\n this.setState(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, !!member.voice.selfMute, true),\n this.setState(`servers.${guild.id}.members.${member.id}.voiceServerMute`, !!member.voice.serverMute, true),\n ]);\n\n const json: JsonServersMembersObj = {\n tag: member.user.tag,\n name: member.user.username,\n id: member.id,\n displayName: member.displayName,\n roles: memberRoles,\n joined: member.joinedTimestamp,\n voiceChannel: member.voice.channel?.name ?? '',\n voiceChannelId: member.voice.channel?.id ?? '',\n voiceSelfDeaf: !!member.voice.selfDeaf,\n voiceServerDeaf: !!member.voice.serverDeaf,\n voiceSelfMute: !!member.voice.selfMute,\n voiceServerMute: !!member.voice.serverMute,\n };\n if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.servers.${guild.id}.members.${member.id}.json`))) {\n await this.setState(`servers.${guild.id}.members.${member.id}.json`, JSON.stringify(json), true);\n this.jsonStateCache.set(`${this.namespace}.servers.${guild.id}.members.${member.id}.json`, json);\n }\n\n }\n\n // guild channels\n if (this.unloaded) return;\n const channels = await guild.channels.fetch();\n if (this.unloaded) return;\n\n // loop over all channels twice to setup the parent channel objects first and afterwards the child channel objects\n for (const parents of [ true, false ]) {\n for (const [ , channel ] of channels) {\n if (!channel || (parents && channel.parentId) || (!parents && !channel.parentId)) {\n continue;\n }\n const channelIdPrefix = parents ? `servers.${guild.id}.channels.${channel.id}` : `servers.${guild.id}.channels.${channel.parentId}.channels.${channel.id}`;\n\n knownServersAndChannelsIds.add(`${this.namespace}.${channelIdPrefix}`);\n\n let icon: string | undefined;\n if (channel.type === ChannelType.GuildText) {\n icon = 'channel-text.svg';\n }\n if (channel.type === ChannelType.GuildVoice) {\n icon = 'channel-voice.svg';\n }\n await this.extendObjectCached(channelIdPrefix, {\n type: 'channel',\n common: {\n name: channel.parent ? `${channel.parent.name} / ${channel.name}` : channel.name,\n icon,\n },\n native: {\n channelId: channel.id,\n },\n });\n if (channel.type === ChannelType.GuildCategory) {\n await this.extendObjectCached(`${channelIdPrefix}.channels`, {\n type: 'channel',\n common: {\n name: i18n.getStringOrTranslated('Channels'),\n },\n native: {},\n });\n }\n\n await Promise.all([\n this.extendObjectCached(`${channelIdPrefix}.json`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.memberCount`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Member count'),\n role: 'value',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.members`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Members'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n\n if (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildVoice) {\n await Promise.all([\n this.extendObjectCached(`${channelIdPrefix}.message`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.messageId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.messageAuthor`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message author'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.messageTimestamp`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message timestamp'),\n role: 'date',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.messageJson`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectCached(`${channelIdPrefix}.send`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send message'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.sendFile`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send file'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.sendReply`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reply'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`${channelIdPrefix}.sendReaction`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reaction'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n ]);\n\n this.messageReceiveStates.add(`${this.namespace}.${channelIdPrefix}.message`);\n }\n\n await this.updateChannelInfoStates(channel);\n }\n }\n\n /*\n * Delete objects for unknown server members\n */\n const objListMembers = await this.getObjectListAsync({\n startkey: `${this.namespace}.servers.${guild.id}.members.`,\n endkey: `${this.namespace}.servers.${guild.id}.members.\\u9999`,\n });\n const reServersMembers = new RegExp(`^${this.name}\\\\.${this.instance}\\\\.servers\\\\.${guild.id}.members\\\\.(\\\\d+)$`);\n for (const item of objListMembers.rows) {\n const m = item.id.match(reServersMembers);\n if (m) {\n const memberId = m[1];\n if (!guild.members.cache.has(memberId)) {\n this.log.debug(`Server member ${memberId} of server ${guild.id} is no longer available - deleting objects`);\n this.jsonStateCache.delete(`${this.namespace}.servers.${guild.id}.members.${memberId}.json`);\n await this.delObjectAsyncCached(`servers.${guild.id}.members.${memberId}`, { recursive: true });\n }\n }\n }\n }\n\n /*\n * Create objects/states for all known users.\n */\n for (const [ , { user, presence } ] of allServersUsers) {\n this.log.debug(`Known user: ${user.tag} id:${user.id}`);\n\n await this.extendObjectCached(`users.${user.id}`, {\n type: 'channel',\n common: {\n name: userNameOrTag(user),\n },\n native: {\n userId: user.id,\n },\n });\n\n await Promise.all([\n this.extendObjectCached(`users.${user.id}.json`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectCached(`users.${user.id}.tag`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User tag'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectCached(`users.${user.id}.name`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('User name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectCached(`users.${user.id}.message`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`users.${user.id}.messageId`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message ID'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`users.${user.id}.messageTimestamp`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message timestamp'),\n role: 'date',\n type: 'number',\n read: true,\n write: false,\n def: 0,\n },\n native: {},\n }),\n this.extendObjectCached(`users.${user.id}.messageJson`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Last message JSON data'),\n role: 'json',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectCached(`users.${user.id}.send`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send message'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`users.${user.id}.sendFile`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send file'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`users.${user.id}.sendReply`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reply'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`users.${user.id}.sendReaction`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Send reaction'),\n role: 'text',\n type: 'string',\n read: false,\n write: true,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectCached(`users.${user.id}.avatarUrl`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Avatar'),\n role: 'media.link',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n\n this.extendObjectCached(`users.${user.id}.bot`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Bot'),\n role: 'indicator',\n type: 'boolean',\n read: true,\n write: false,\n def: false,\n },\n native: {},\n }),\n\n this.extendObjectCached(`users.${user.id}.status`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Status'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`users.${user.id}.activityType`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Activity type'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n this.extendObjectCached(`users.${user.id}.activityName`, {\n type: 'state',\n common: {\n name: i18n.getStringOrTranslated('Activity name'),\n role: 'text',\n type: 'string',\n read: true,\n write: false,\n def: '',\n },\n native: {},\n }),\n ]);\n\n this.messageReceiveStates.add(`${this.namespace}.users.${user.id}.message`);\n\n this.knownUsers.add(user.id);\n\n const ps = await this.updateUserPresence(user.id, presence, true);\n\n const proms: Promise[] = [];\n const json: JsonUsersObj = {\n id: user.id,\n tag: user.tag,\n name: user.username,\n activityName: ps.activityName,\n activityType: ps.activityType,\n avatarUrl: user.displayAvatarURL(),\n bot: user.bot,\n status: ps.status,\n };\n if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.users.${user.id}.json`))) {\n proms.push(this.setState(`users.${user.id}.json`, JSON.stringify(json), true));\n this.jsonStateCache.set(`${this.namespace}.users.${user.id}.json`, json);\n }\n await Promise.all([\n this.setState(`users.${user.id}.tag`, user.tag, true),\n this.setState(`users.${user.id}.name`, user.username, true),\n this.setState(`users.${user.id}.avatarUrl`, json.avatarUrl, true),\n this.setState(`users.${user.id}.bot`, user.bot, true),\n ...proms,\n this.updateUserPresence(user.id, presence),\n ]);\n\n }\n\n /*\n * Delete objects for unknown Channels/Servers\n */\n const objListServers = await this.getObjectListAsync({\n startkey: `${this.namespace}.servers.`,\n endkey: `${this.namespace}.servers.\\u9999`,\n });\n const reServersChannels = new RegExp(`^${this.name}\\\\.${this.instance}\\\\.servers\\\\.((\\\\d+)(\\\\.channels\\\\.(\\\\d+)){0,2})$`);\n for (const item of objListServers.rows) {\n const m = item.id.match(reServersChannels);\n if (m) {\n const idPath = m[1];\n if (!knownServersAndChannelsIds.has(item.id)) {\n this.log.debug(`Server/Channel ${idPath} \"${getObjName(item.value.common)}\" is no longer available - deleting objects`);\n this.messageReceiveStates.delete(`${this.namespace}.servers.${idPath}.message`);\n this.jsonStateCache.delete(`${this.namespace}.servers.${idPath}.json`);\n await this.delObjectAsyncCached(`servers.${idPath}`, { recursive: true });\n }\n }\n }\n\n /*\n * Delete objects for unknown users\n */\n const objListUsers = await this.getObjectListAsync({\n startkey: `${this.namespace}.users.`,\n endkey: `${this.namespace}.users.\\u9999`,\n });\n const reUsers = new RegExp(`^${this.name}\\\\.${this.instance}\\\\.users\\\\.(\\\\d+)$`);\n for (const item of objListUsers.rows) {\n const m = item.id.match(reUsers);\n if (m) {\n const userId = m[1];\n if (!allServersUsers.has(userId)) {\n this.log.debug(`User ${userId} \"${getObjName(item.value.common)}\" is no longer available - deleting objects`);\n this.knownUsers.delete(userId);\n this.messageReceiveStates.delete(`${this.namespace}.users.${userId}.message`);\n this.jsonStateCache.delete(`${this.namespace}.users.${userId}.json`);\n await this.delObjectAsyncCached(`users.${userId}`, { recursive: true });\n }\n }\n }\n }\n\n /**\n * Update the states containing basic information about a channel.\n *\n * This includes the following channel states: `.json`, `.memberCount`, `.members`\n * @param channel The channel to update the states for.\n */\n private async updateChannelInfoStates (channel: NonThreadGuildBasedChannel): Promise {\n const channelIdPrefix = channel.parentId ? `servers.${channel.guildId}.channels.${channel.parentId}.channels.${channel.id}` : `servers.${channel.guild.id}.channels.${channel.id}`;\n\n const members = [ ...channel.members.values() ];\n const json: JsonServersChannelsObj = {\n id: channel.id,\n name: channel.name,\n type: ChannelType[channel.type] as ChannelTypeNames,\n memberCount: members.length,\n members: members.map((m) => ({\n id: m.user.id,\n tag: m.user.tag,\n name: m.user.username,\n displayName: m.displayName,\n })),\n };\n const proms: Promise[] = [];\n if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.${channelIdPrefix}.json`))) {\n proms.push(this.setState(`${channelIdPrefix}.json`, JSON.stringify(json), true));\n this.jsonStateCache.set(`${this.namespace}.${channelIdPrefix}.json`, json);\n }\n await Promise.all([\n this.setState(`${channelIdPrefix}.memberCount`, members.length, true),\n this.setState(`${channelIdPrefix}.members`, members.map((m) => m.displayName).join(', '), true),\n ...proms,\n ]);\n }\n\n /**\n * Update the presence states of a user.\n * @param userId ID of the user.\n * @param presence The user presence.\n * @param skipJsonStateUpdate If the json state of the user should not be updated.\n */\n private async updateUserPresence (userId: Snowflake, presence: Presence | null, skipJsonStateUpdate: boolean = false): Promise {\n if (!this.config.observeUserPresence) {\n return { activityName: '', activityType: '', status: '' };\n }\n\n if (!this.knownUsers.has(userId)) {\n this.log.debug(`Can't update user presence for unknown user ${userId}`);\n return { activityName: '', activityType: '', status: '' };\n }\n\n try {\n const p: UpdateUserPresenceResult = {\n status: presence?.status ?? '',\n activityName: (presence?.activities[0]?.type === ActivityType.Custom ? presence?.activities[0]?.state : presence?.activities[0]?.name) ?? '',\n activityType: (presence?.activities[0]?.type !== undefined ? ActivityType[presence.activities[0].type] as ActivityTypeNames : '') ?? '',\n };\n\n const proms: Promise[] = [];\n if (!skipJsonStateUpdate) {\n const json = this.jsonStateCache.get(`${this.namespace}.users.${userId}.json`) as JsonUsersObj | undefined;\n if (json) {\n json.status = p.status;\n json.activityName = p.activityName;\n json.activityType = p.activityType;\n this.jsonStateCache.set(`${this.namespace}.users.${userId}.json`, json);\n proms.push(this.setState(`users.${userId}.json`, JSON.stringify(json), true));\n }\n }\n await Promise.all([\n this.setState(`users.${userId}.status`, p.status, true),\n this.setState(`users.${userId}.activityName`, p.activityName, true),\n this.setState(`users.${userId}.activityType`, p.activityType, true),\n ...proms,\n ]);\n return p;\n } catch (err) {\n this.log.warn(`Error while updating user presence of user ${userId}: ${err}`);\n return { activityName: '', activityType: '', status: '' };\n }\n }\n\n /**\n * Set the presence status of the discord bot.\n */\n private async setBotPresence (opts?: SetBotPresenceOptions): Promise {\n if (!this.client?.user) return;\n\n if (!opts) {\n opts = {};\n }\n\n if (!opts.status) {\n opts.status = ((await this.getStateAsync('bot.status'))?.val as PresenceStatusData | undefined) ?? 'online';\n }\n if (!VALID_PRESENCE_STATUS_DATA.includes(opts.status)) {\n opts.status = 'online';\n }\n\n const presenceData: PresenceData = {\n status: opts.status,\n activities: [],\n };\n\n if (opts.activityType === undefined) {\n opts.activityType = ((await this.getStateAsync('bot.activityType'))?.val as ActivityTypeNames | undefined) ?? '';\n }\n if (!ACTIVITY_TYPES.includes(opts.activityType)) {\n this.log.warn(`Invalid activityType! ${opts.activityType}`);\n opts.activityType = '';\n }\n if (opts.activityName === undefined) {\n opts.activityName = ((await this.getStateAsync('bot.activityName'))?.val as string | undefined) ?? '';\n }\n if (opts.activityType && opts.activityName) {\n presenceData.activities = [ {\n type: ActivityType[opts.activityType],\n name: opts.activityName,\n } ];\n }\n\n this.log.debug(`Set bot presence: ${JSON.stringify(presenceData)}`);\n this.client.user.setPresence(presenceData);\n }\n\n /**\n * Handler for received discord messages.\n * @param message The discord message.\n */\n @boundMethod\n private async onClientMessageCreate (message: Message): Promise {\n this.log.debug(`Discord message: mId:${message.id} cId:${message.channelId} uId: ${message.author.id} - ${message.content}`);\n\n // raw states enabled?\n if (this.config.enableRawStates) {\n // set raw state... not async here since it should not block!\n void this.setState('raw.messageJson', JSON.stringify(message.toJSON(), (_key, value: unknown) => typeof value === 'bigint' ? value.toString() : value), true);\n }\n\n if (!this.client?.user?.id) return;\n\n // don't process interactions here\n if (message.interactionMetadata) {\n return;\n }\n\n const { author, channel, content } = message;\n\n // don't process own messages\n if (author.id === this.client.user.id) {\n return;\n }\n\n const authCheckTarget = message.member ?? author;\n\n const isAuthorAuthorized = this.checkUserAuthorization(authCheckTarget);\n\n if (!this.config.processMessagesFromUnauthorizedUsers && !isAuthorAuthorized) {\n this.log.debug(`Ignore message from unauthorized user ${userNameOrTag(author)} (id:${author.id})`);\n return;\n }\n\n const mentioned = message.mentions.users.has(this.client.user.id);\n\n if (mentioned && this.config.reactOnMentions && isAuthorAuthorized) {\n try {\n await message.react(this.config.reactOnMentionsEmoji);\n } catch (err) {\n this.log.warn(`Error while adding reaction to message ${message.id}! ${err}`);\n }\n }\n\n if (!mentioned && (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildVoice) && !this.config.processAllMessagesInServerChannel) {\n this.log.debug('Server channel message without mention ignored');\n return;\n }\n\n let msgStateIdPrefix: string;\n if (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildVoice) {\n msgStateIdPrefix = channel.parentId ? `${this.namespace}.servers.${message.guildId}.channels.${channel.parentId}.channels.${channel.id}` : `${this.namespace}.servers.${message.guildId}.channels.${channel.id}`;\n } else if (channel.type === ChannelType.DM) {\n msgStateIdPrefix = `${this.namespace}.users.${author.id}`;\n } else if (channel.isThread()) {\n this.log.debug('Thread message ignored');\n return;\n } else {\n this.log.warn(`Received message from unsupported channel type ${ChannelType[channel.type]}!`);\n return;\n }\n\n // check if a valid object/state for this received message is known by the adapter\n if (!this.messageReceiveStates.has(`${msgStateIdPrefix}.message`)) {\n this.log.debug(`State for received message ${msgStateIdPrefix} is not known for receiving messages`);\n return;\n }\n\n // prepare json state object\n const json: JsonMessageObj = {\n content,\n attachments: message.attachments.map((att) => ({ attachment: att.url, name: att.name, description: att.description ?? '', size: att.size, contentType: att.contentType ?? '', id: att.id })),\n id: message.id,\n mentions: message.mentions.members?.map((m) => ({ id: m.id, tag: m.user.tag, name: m.user.username, displayName: m.displayName })) ?? [],\n mentioned,\n timestamp: message.createdTimestamp,\n authorized: isAuthorAuthorized,\n };\n const proms: Promise[] = [];\n if (message.guildId) {\n json.author = {\n id: author.id,\n tag: author.tag,\n name: author.username,\n displayName: this.client.guilds.cache.get(message.guildId)?.members.cache.get(author.id)?.displayName ?? author.username,\n };\n proms.push(this.setState(`${msgStateIdPrefix}.messageAuthor`, userNameOrTag(author), true));\n }\n if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.${msgStateIdPrefix}.messageJson`))) {\n proms.push(this.setState(`${msgStateIdPrefix}.messageJson`, JSON.stringify(json), true));\n this.jsonStateCache.set(`${this.namespace}.${msgStateIdPrefix}.messageJson`, json);\n }\n await Promise.all([\n this.setState(`${msgStateIdPrefix}.message`, content, true),\n this.setState(`${msgStateIdPrefix}.messageId`, message.id, true),\n this.setState(`${msgStateIdPrefix}.messageTimestamp`, message.createdTimestamp, true),\n ...proms,\n ]);\n\n // handle text2command if enabled for this receiving state\n if (content && this.config.text2commandInstance && this.text2commandObjects.has(`${msgStateIdPrefix}.message`)) {\n // check user authorization to use text2command\n if (this.checkUserAuthorization(authCheckTarget, { useText2command: true })) {\n // authorization disabled or user is allowed to use text2command\n this.log.debug(`Sending \"${content}\" to ${this.config.text2commandInstance}`);\n // prepare message payload\n const payload: Text2commandMessagePayload = {\n text: content,\n };\n // use callback style sendTo here to not block message processing here if text2command instance is not running\n this.sendTo(this.config.text2commandInstance, 'send', payload, async (responseObj) => {\n // Response object from text2command is the message payload from the sendTo call with a `response` property set\n const response: string | undefined = (responseObj as unknown as Text2commandMessagePayload | undefined)?.response;\n try {\n if (!response) {\n this.log.debug(`Empty response from ${this.config.text2commandInstance}`);\n return;\n }\n this.log.debug(`Response from ${this.config.text2commandInstance}: ${response}`);\n switch (this.config.text2commandRespondWith) {\n case 'reply':\n await message.reply(response);\n break;\n case 'message':\n if (message.channel.isTextBased()) {\n await (message.channel as DMChannel | TextChannel).send(response);\n }\n break;\n default:\n // no response needed\n }\n } catch (err) {\n this.log.warn(`Error while processing response \"${response}\" from ${this.config.text2commandInstance}! ${err}`);\n }\n });\n } else {\n // user NOT allowed to text2command\n this.log.debug(`User ${userNameOrTag(author)} (id:${author.id}) NOT allowed to use text2command`);\n }\n }\n\n }\n\n /**\n * Handler for user voice state changes.\n */\n @boundMethod\n private async onClientVoiceStateUpdate (oldState: VoiceState, newState: VoiceState): Promise {\n if (!newState.member?.id) {\n return;\n }\n\n const proms: Promise[] = [];\n\n // update channel states\n if (oldState.channelId !== newState.channelId) {\n if (oldState.channel) {\n proms.push(this.updateChannelInfoStates(oldState.channel));\n }\n if (newState.channel) {\n proms.push(this.updateChannelInfoStates(newState.channel));\n }\n }\n\n // update user states\n if (this.knownUsers.has(newState.member.id)) {\n const json: JsonServersMembersObj = {\n ...this.jsonStateCache.get(`${this.namespace}.servers.${newState.guild.id}.members.${newState.member.id}.json`) as JsonServersMembersObj,\n };\n\n let update: boolean = false;\n\n if (oldState.channelId !== newState.channelId) {\n proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceChannel`, newState.channel?.name ?? '', true));\n json.voiceChannel = newState.channel?.name ?? '';\n json.voiceChannelId = newState.channel?.id ?? '';\n update = true;\n }\n if (oldState.serverDeaf !== newState.serverDeaf) {\n proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerDeaf`, !!newState.serverDeaf, true));\n json.voiceSelfDeaf = !!newState.selfDeaf;\n update = true;\n }\n if (oldState.selfDeaf !== newState.selfDeaf) {\n proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfDeaf`, !!newState.selfDeaf, true));\n json.voiceServerDeaf = !!newState.serverDeaf;\n update = true;\n }\n if (oldState.serverMute !== newState.serverMute) {\n proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerMute`, !!newState.serverMute, true));\n json.voiceSelfMute = !!newState.selfMute;\n update = true;\n }\n if (oldState.selfMute !== newState.selfMute) {\n proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfMute`, !!newState.selfMute, true));\n json.voiceServerMute = !!newState.serverMute;\n update = true;\n }\n\n // json state update\n if (update) {\n proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.json`, JSON.stringify(json), true));\n this.jsonStateCache.set(`${this.namespace}.servers.${newState.guild.id}.members.${newState.member.id}.json`, json);\n }\n\n } else {\n this.log.debug(`Can't update user voice state for unknown user ${newState.member.id}`);\n }\n\n await Promise.all(proms);\n }\n\n /**\n * Setup for objects custom config related to the adapter instance.\n * E.g. text2command enabled or state availability for commands.\n * @param objId The object ID.\n * @param customCfg The custom config part of the object for this adapter instance.\n */\n private async setupObjCustom (objId: string, customCfg: ioBroker.CustomConfig | null | undefined, objCommon?: ioBroker.StateCommon): Promise {\n // own .message objects - enableText2command\n if (objId.startsWith(`${this.namespace}.`) && objId.endsWith('.message')) {\n if (customCfg?.enabled && customCfg.enableText2command) {\n this.log.debug(`Custom option text2command enabled for ${objId}`);\n this.text2commandObjects.add(objId);\n } else if (this.text2commandObjects.has(objId)) {\n this.log.debug(`Custom option text2command disabled for ${objId}`);\n this.text2commandObjects.delete(objId);\n }\n }\n\n if (customCfg?.enableCommands) {\n // commands enabled\n\n // load objCommon if not provided\n if (!objCommon) {\n const obj = await this.getForeignObjectAsync(objId);\n if (obj?.type === 'state') {\n objCommon = obj.common;\n } else {\n this.log.warn(`Object ${objId} has commands enabled but this seems to be an error because it is not a state object!`);\n }\n }\n\n // try to get the name\n let name = customCfg.commandsName;\n if (!name && objCommon) {\n if (typeof objCommon.name === 'object') {\n name = objCommon.name[i18n.language] ?? objCommon.name.en;\n } else {\n name = objCommon.name;\n }\n }\n\n const cfg: CommandObjectConfig = {\n id: objId,\n alias: customCfg.commandsAlias ?? objId,\n name: name ?? objId,\n get: !!customCfg.commandsAllowGet,\n set: !!customCfg.commandsAllowSet,\n };\n\n // do some checks\n let cfgOk: boolean = true;\n if (cfg.name.length > 100) {\n this.log.warn(`Command name for ${objId} exceeds the limit of 100 chars! This object will be ignored.`);\n cfgOk = false;\n }\n if (!(/^[0-9a-zA-Z._-]{0,100}$/.exec(cfg.alias))) {\n this.log.warn(`Command alias for ${objId} includes invalid chars or exceeds the limit of 100 chars! This object will be ignored.`);\n cfgOk = false;\n }\n\n // setup command\n this.discordSlashCommands.setupCommandObject(objId, cfgOk ? cfg : null);\n\n } else {\n // commands not enabled\n this.discordSlashCommands.setupCommandObject(objId, null);\n }\n }\n\n /**\n * Is called if a subscribed object changes.\n */\n @boundMethod\n private onObjectChange (objId: string, obj: ioBroker.Object | null | undefined): void {\n if (obj) {\n // The object was changed\n if (obj.type === 'state') {\n this.log.silly(`Object ${objId} changed: ${JSON.stringify(obj)}`);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n void this.setupObjCustom(objId, obj.common?.custom?.[this.namespace], obj.common);\n }\n } else {\n // The object was deleted\n this.log.silly(`Object ${objId} deleted`);\n void this.setupObjCustom(objId, null);\n }\n }\n\n /**\n * Is called if a subscribed state changes\n */\n @boundMethod\n private async onStateChange (stateId: string, state: ioBroker.State | null | undefined): Promise {\n this.log.silly(`State changed: ${stateId} ${state?.val} (ack=${state?.ack})`);\n\n if (!state || state.ack) return;\n\n let setAck = false;\n\n /*\n * Own states\n */\n if (stateId.startsWith(`${this.namespace}.`)) {\n\n switch (stateId) {\n case `${this.namespace}.bot.status`:\n await this.setBotPresence({ status: state.val as PresenceStatusData });\n setAck = true;\n break;\n case `${this.namespace}.bot.activityType`:\n await this.setBotPresence({ activityType: state.val as ActivityTypeNames });\n setAck = true;\n break;\n case `${this.namespace}.bot.activityName`:\n await this.setBotPresence({ activityName: state.val as string });\n setAck = true;\n break;\n\n default: // other own states\n // custom slash command reply\n if (/^discord\\.\\d+\\.slashCommands\\..*\\.sendReply/.exec(stateId)) {\n setAck = await this.onCustomCommandSendReplyStateChange(stateId, state);\n\n // custom slash command option choices\n } else if (/^discord\\.\\d+\\.slashCommands\\..*\\.option-[^.]+\\.choices/.exec(stateId)) {\n // trigger delayed register slash commands to handle multiple changes of choices states together\n this.discordSlashCommands.triggerDelayedRegisterSlashCommands();\n setAck = true;\n\n // .send / .sendFile / .sendReply\n } else if (stateId.endsWith('.send') || stateId.endsWith('.sendFile') || stateId.endsWith('.sendReply') || stateId.endsWith('.sendReaction')) {\n setAck = await this.onSendStateChange(stateId, state);\n\n // voice disconnect, mute/unmute, deafen/undeafen\n } else if (stateId.endsWith('.voiceDisconnect') || stateId.endsWith('.voiceServerMute') || stateId.endsWith('.voiceServerDeaf')) {\n setAck = await this.onVoiceStateChange(stateId, state);\n\n }\n }\n\n }\n\n if (setAck) {\n await this.setState(stateId, {\n ...state,\n ack: true,\n });\n }\n\n }\n\n /**\n * Handler for changes on own .send or .sendFile states.\n * Sends the given text, json or file to the corresponding discord channel.\n * @returns `true` if the message is send.\n */\n private async onSendStateChange (stateId: string, state: ioBroker.State): Promise {\n\n if (!this.client?.isReady()) {\n this.log.warn(`State ${stateId} changed but client is not ready!`);\n return false;\n }\n\n if (typeof state.val !== 'string') {\n this.log.warn(`State ${stateId} changed but value if not a string!`);\n return false;\n }\n\n if (state.val.length === 0) {\n this.log.debug(`State ${stateId} changed but value is empty`);\n return false;\n }\n\n let action: string;\n let target: NonThreadGuildBasedChannel | User;\n let targetName: string = '';\n let targetStateIdBase: string;\n\n // channel or user?\n let m = /^(discord\\.\\d+\\.servers\\.(\\d+)\\.channels\\.(\\d+)(\\.channels\\.(\\d+))?)\\.(send|sendFile|sendReaction|sendReply)$/.exec(stateId);\n if (m) {\n const guildId = m[2];\n const channelId = m[5] || m[3];\n targetStateIdBase = m[1];\n action = m[6];\n\n const channel = this.client.guilds.cache.get(guildId)?.channels.cache.get(channelId);\n if (!channel || (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildVoice) || channel.isThread()) {\n this.log.warn(`State ${stateId} changed but target is not a valid text channel!`);\n return false;\n }\n\n target = channel;\n targetName = channel.parent ? `${channel.guild.name}/${channel.parent.name}/${channel.name}` : `${channel.guild.name}/${channel.name}`;\n\n } else {\n m = /^(discord\\.\\d+\\.users\\.(\\d+))\\.(send|sendFile|sendReaction|sendReply)$/.exec(stateId);\n if (!m) {\n this.log.warn(`State ${stateId} changed but could not determine target to send message to!`);\n return false;\n }\n const userId = m[2];\n targetStateIdBase = m[1];\n action = m[3];\n\n const user = this.client.users.cache.get(userId);\n if (!user) {\n this.log.warn(`State ${stateId} changed but target is not a valid user!`);\n return false;\n }\n\n target = user;\n targetName = userNameOrTag(user);\n }\n\n let mo: MessageCreateOptions;\n\n /*\n * Special case .sendFile state\n */\n if (action === 'sendFile') {\n const idx = state.val.indexOf('|');\n let file: string;\n let content: string | undefined;\n if (idx > 0) {\n file = state.val.slice(0, idx);\n content = state.val.slice(idx + 1);\n } else {\n file = state.val;\n }\n\n // check for base64 encoded data\n const b64data = getBufferAndNameFromBase64String(file);\n if (b64data) {\n // base64 encoded content\n mo = {\n content,\n files: [ {\n attachment: b64data.buffer,\n name: b64data.name,\n } ],\n };\n\n } else {\n // not base64 encoded content\n const name = getBasenameFromFilePathOrUrl(file);\n\n // remove file:// prefix\n if (file.startsWith('file://')) {\n file = file.slice(7);\n }\n\n mo = {\n content,\n files: [ {\n attachment: file,\n name,\n } ],\n };\n }\n\n /*\n * Special case .sendReply state\n */\n } else if (action === 'sendReply' || action === 'sendReaction') {\n const idx = state.val.indexOf('|');\n let messageReference: string;\n let content: string;\n if (idx > 0) {\n messageReference = state.val.slice(0, idx);\n content = state.val.slice(idx + 1);\n } else {\n // use id from last received message\n this.log.debug(`Get reply message reference from last received message for ${targetStateIdBase}`);\n messageReference = (await this.getForeignStateAsync(`${targetStateIdBase}.messageId`))?.val as string;\n content = state.val;\n }\n\n if (action === 'sendReply') {\n // reply\n if (!messageReference || !content) {\n this.log.warn(`No message reference or no content for reply for ${stateId}!`);\n return false;\n }\n\n try {\n mo = this.parseStringifiedMessageOptions(state.val);\n } catch (err) {\n this.log.debug(`State ${stateId} value is invalid: ${err}`);\n return false;\n }\n\n // add the message reference if it is not already set\n if (!mo.reply) {\n mo.reply = {\n messageReference,\n };\n } else if (!mo.reply.messageReference) {\n mo.reply.messageReference = messageReference;\n }\n\n } else {\n // reaction\n if (!messageReference || !content) {\n this.log.warn(`No message reference or no/invalid content for reaction for ${stateId}!`);\n return false;\n }\n\n const channel = target instanceof User ? target.dmChannel ?? await target.createDM() : target;\n if (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildVoice && channel.type !== ChannelType.DM) {\n this.log.warn(`Could not determine target channel for reaction ${stateId}!`);\n return false;\n }\n\n // get the message from cache or try to fetch the message\n const message: Message | undefined = channel.messages.cache.get(messageReference) ?? await channel.messages.fetch(messageReference);\n if (!message) {\n this.log.warn(`Could not determine target message for reaction ${stateId}!`);\n return false;\n }\n\n try {\n await message.react(content);\n return true;\n } catch (err) {\n this.log.warn(`Message reaction ${stateId} failed: ${err}`);\n return false;\n }\n }\n\n /*\n * `state.val` may be JSON for .send states\n * Try to parse the JSON as MessageOptions object to allow sending of files, embeds, ...\n */\n } else {\n try {\n mo = this.parseStringifiedMessageOptions(state.val);\n } catch (err) {\n this.log.debug(`State ${stateId} value is invalid: ${err}`);\n return false;\n }\n }\n\n this.log.debug(`Send to ${targetName}: ${JSON.stringify(mo)}`);\n try {\n const msg = await target.send(this.prepareMessageForSend(mo));\n this.log.debug(`Sent with message ID ${msg.id}`);\n return true;\n } catch (err) {\n this.log.warn(`Error sending value of ${stateId} to ${targetName}: ${err}`);\n return false;\n }\n }\n\n /**\n * Handler for changes on own custom commands .sendReply states.\n * Sends the given text, json or file to the corresponding discord channel.\n * @returns `true` if the reply is send.\n */\n private async onCustomCommandSendReplyStateChange (stateId: string, state: ioBroker.State): Promise {\n\n if (!this.client?.isReady()) {\n this.log.warn(`State ${stateId} changed but client is not ready!`);\n return false;\n }\n\n if (typeof state.val !== 'string') {\n this.log.warn(`State ${stateId} changed but value if not a string!`);\n return false;\n }\n\n if (state.val.length === 0) {\n this.log.debug(`State ${stateId} changed but value is empty`);\n return false;\n }\n\n const targetStateIdBase = stateId.replace(/\\.\\w+$/, '');\n\n const idx = state.val.indexOf('|');\n let interactionId: Snowflake;\n let content: string;\n if (idx > 0) {\n interactionId = state.val.slice(0, idx);\n content = state.val.slice(idx + 1);\n } else {\n // use id from last received command\n this.log.debug(`Get reply interaction reference from last received interaction for ${targetStateIdBase}`);\n interactionId = (await this.getForeignStateAsync(`${targetStateIdBase}.interactionId`))?.val as string;\n content = state.val;\n }\n\n if (!interactionId || !content) {\n this.log.warn(`No interaction reference or no content for reply for ${stateId}!`);\n return false;\n }\n\n try {\n await this.discordSlashCommands.sendCmdCustomReply(interactionId, content);\n return true;\n } catch (err) {\n this.log.warn(`Error while replying to interaction ${interactionId} of custom slash command! ${err}`);\n return false;\n }\n }\n\n /**\n * Handler for changes of own .voiceDisconnect, .voiceServerMute or .voiceServerDeaf states.\n * @returns `true` if successfull.\n */\n private async onVoiceStateChange (stateId: string, state: ioBroker.State): Promise {\n const m = /^discord\\.\\d+\\.servers\\.(\\d+)\\.members\\.(\\d+)\\.voice(Disconnect|ServerMute|ServerDeaf)$/.exec(stateId);\n if (!m) {\n this.log.debug(`Voice state ${stateId} changed but could not get serverID and memberID!`);\n return false;\n }\n const [ , guildId, memberId, action ] = m;\n\n const guild = this.client?.guilds.cache.get(guildId);\n const member = guild?.members.cache.get(memberId);\n if (!guild || !member) {\n this.log.warn(`Voice state ${stateId} changed but could not get the server member!`);\n return false;\n }\n\n try {\n switch (action) {\n case 'Disconnect':\n if (!state.val) {\n return false;\n }\n await member.voice.disconnect();\n this.log.debug(`Voice member ${userNameOrTag(member.user)} of server ${guild.name} disconnected.`);\n break;\n\n case 'ServerDeaf':\n await member.voice.setDeaf(!!state.val);\n this.log.debug(`Voice server deafen of member ${userNameOrTag(member.user)} of server ${guild.name} set to ${!!state.val}.`);\n break;\n\n case 'ServerMute':\n await member.voice.setMute(!!state.val);\n this.log.debug(`Voice server mute of member ${userNameOrTag(member.user)} of server ${guild.name} set to ${!!state.val}.`);\n break;\n\n default:\n // should never happen...\n return false;\n }\n return true;\n } catch (err) {\n this.log.warn(`Voice server action of member ${userNameOrTag(member.user)} of server ${guild.name} can't be done! ${err}`);\n return false;\n }\n }\n\n /**\n * Handle messages send to the adapter.\n */\n @boundMethod\n private async onMessage (obj: ioBroker.Message): Promise {\n if (typeof obj !== 'object') return;\n this.log.debug(`Got message: ${JSON.stringify(obj)}`);\n\n // channel and msg are needed in some switch cases...\n let channel: GuildBasedChannel | undefined;\n let msg: Message;\n let user: User | undefined;\n\n switch (obj.command) {\n case 'getText2commandInstances': {\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n const view = await this.getObjectViewAsync('system', 'instance', {\n startkey: 'system.adapter.text2command.',\n endkey: 'system.adapter.text2command.\\u9999',\n });\n const text2commandInstances = view.rows.map((r) => {\n const id = r.id.slice(15);\n return {\n label: id,\n value: id,\n };\n });\n this.log.debug(`Found text2command instances: ${text2commandInstances.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, [ { value: '', label: '---' }, ...text2commandInstances ], obj.callback);\n break;\n } // getText2commandInstances\n\n case 'getNotificationTargets': {\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n const targets: { label: string, value: string }[] = [ { value: '', label: '---' } ];\n\n // users\n this.client?.users.cache.forEach((u) => {\n targets.push({ label: userNameOrTag(u), value: u.id });\n });\n\n // server channels\n this.client?.guilds.cache.forEach((g) => {\n g.channels.cache.forEach((c) => {\n if (c.type === ChannelType.GuildText) {\n if (c.parent) {\n // channel has a parent\n targets.push({ label: `${g.name} \u00BB ${c.parent.name} \u00BB ${c.name}`, value: `${g.id}/${c.id}` });\n } else {\n // channel has no parent\n targets.push({ label: `${g.name} \u00BB ${c.name}`, value: `${g.id}/${c.id}` });\n }\n }\n });\n });\n\n this.log.debug(`Notification targets: ${targets.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, targets, obj.callback);\n break;\n } // getNotificationTargets\n\n case 'getUsers': {\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n const users = this.client?.users.cache.map((u) => ({ label: userNameOrTag(u), value: u.id })) ?? [];\n this.log.debug(`Users: ${users.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, users, obj.callback);\n break;\n } // getUsers\n\n case 'getServers': {\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n const servers = this.client?.guilds.cache.map((g) => ({ label: g.name, value: g.id })) ?? [];\n this.log.debug(`Servers: ${servers.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, servers, obj.callback);\n break;\n } // getServers\n\n case 'getServerRoles': {\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (!this.client) {\n this.sendTo(obj.from, obj.command, [], obj.callback);\n return;\n }\n\n const guildRolesWithLabel = [];\n for (const [ , guild ] of this.client.guilds.cache) {\n for (const [ , role ] of guild.roles.cache) {\n guildRolesWithLabel.push({\n label: `${guild.name} - ${role.name}`,\n value: `${guild.id}|${role.id}`,\n });\n }\n }\n\n this.log.debug(`Server roles: ${guildRolesWithLabel.map((i) => i.value)}`);\n this.sendTo(obj.from, obj.command, guildRolesWithLabel, obj.callback);\n\n break;\n } // getServerRoles\n\n case 'getAddToServerLink': {\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n if (this.client?.user?.id) {\n const perms = new PermissionsBitField([\n PermissionsBitField.Flags.ChangeNickname,\n PermissionsBitField.Flags.ViewChannel,\n PermissionsBitField.Flags.ModerateMembers,\n PermissionsBitField.Flags.SendMessages,\n PermissionsBitField.Flags.EmbedLinks,\n PermissionsBitField.Flags.AttachFiles,\n PermissionsBitField.Flags.ReadMessageHistory,\n PermissionsBitField.Flags.MentionEveryone,\n PermissionsBitField.Flags.AddReactions,\n PermissionsBitField.Flags.MuteMembers,\n PermissionsBitField.Flags.DeafenMembers,\n PermissionsBitField.Flags.MoveMembers,\n ]);\n this.sendTo(obj.from, obj.command, `https://discord.com/api/oauth2/authorize?client_id=${this.client.user.id}&permissions=${perms.bitfield}&scope=bot%20applications.commands`, obj.callback);\n } else {\n this.sendTo(obj.from, obj.command, `- ${i18n.getString('Error: The Bot is not connected to Discord!')} -`, obj.callback);\n }\n break;\n } // getAddToServerLink\n\n case 'logConfiguredCommandObjects': {\n this.discordSlashCommands.logConfiguredCommandObjects();\n this.sendToIfCb(obj.from, obj.command, { result: 'ok' }, obj.callback);\n break;\n } // logConfiguredCommandObjects\n\n case 'send':\n case 'sendMessage': {\n /*\n * send a message\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const sendPayload = obj.message as SendToActionSendPayload;\n\n // check payload\n if (!sendPayload.content || (typeof sendPayload.content !== 'string' && typeof sendPayload.content !== 'object')) {\n this.sendToIfCb(obj.from, obj.command, { error: 'content needs to be a string or a MessageOptions object', ...sendPayload }, obj.callback);\n return;\n }\n\n if (sendPayload.userId || sendPayload.userTag || sendPayload.userName) {\n // send to a user\n if (sendPayload.userId) {\n // by userId\n user = this.client?.users.cache.get(sendPayload.userId);\n if (!user) {\n this.sendToIfCb(obj.from, obj.command, { error: `No user with userId ${sendPayload.userId} found`, ...sendPayload }, obj.callback);\n return;\n }\n } else if (sendPayload.userTag) {\n // by userTag\n user = this.client?.users.cache.find((u) => u.tag === sendPayload.userTag);\n if (!user) {\n this.sendToIfCb(obj.from, obj.command, { error: `No user with userTag ${sendPayload.userTag} found`, ...sendPayload }, obj.callback);\n return;\n }\n } else {\n // by unique userName\n user = this.client?.users.cache.find((u) => u.discriminator === '0' && u.username === sendPayload.userName);\n if (!user) {\n this.sendToIfCb(obj.from, obj.command, { error: `No user with unique userName ${sendPayload.userName} found`, ...sendPayload }, obj.callback);\n return;\n }\n }\n try {\n msg = await user.send(this.prepareMessageForSend(sendPayload.content));\n this.sendToIfCb(obj.from, obj.command, { result: `Message sent to user ${userNameOrTag(user)}`, ...sendPayload, messageId: msg.id }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error sending message to user ${userNameOrTag(user)}: ${err}`, ...sendPayload }, obj.callback);\n }\n\n } else if (sendPayload.serverId && sendPayload.channelId) {\n // send to a channel\n channel = this.client?.guilds.cache.get(sendPayload.serverId)?.channels.cache.get(sendPayload.channelId);\n if (channel?.type !== ChannelType.GuildText && channel?.type !== ChannelType.GuildVoice) {\n this.sendToIfCb(obj.from, obj.command, { error: `No text channel with channelId ${sendPayload.channelId} on server ${sendPayload.serverId} found`, ...sendPayload }, obj.callback);\n return;\n }\n try {\n msg = await channel.send(this.prepareMessageForSend(sendPayload.content));\n this.sendToIfCb(obj.from, obj.command, { result: `Message sent to channel ${channel.name}`, ...sendPayload, messageId: msg.id }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error sending message to channel ${channel.name}: ${err}`, ...sendPayload }, obj.callback);\n }\n\n } else {\n // missing arguments\n this.sendToIfCb(obj.from, obj.command, { error: 'userId, userTag, userName or serverId and channelId needs to be set', ...sendPayload }, obj.callback);\n }\n\n break;\n } // send / sendMessage\n\n case 'editMessage': {\n /*\n * edit a message\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const editMessagePayload = obj.message as SendToActionEditMessagePayload;\n\n // check payload\n if (!editMessagePayload.content || (typeof editMessagePayload.content !== 'string' && typeof editMessagePayload.content !== 'object')) {\n this.sendToIfCb(obj.from, obj.command, { error: 'content needs to be a string or a MessageOptions object', ...editMessagePayload }, obj.callback);\n return;\n }\n\n // try to get the message\n try {\n msg = await this.getPreviousMessage(editMessagePayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendToIfCb(obj.from, obj.command, { error: err.message, ...editMessagePayload }, obj.callback);\n } else {\n this.sendToIfCb(obj.from, obj.command, { error: err, ...editMessagePayload }, obj.callback);\n }\n return;\n }\n\n // try to edit the message\n try {\n if (!msg.editable) {\n this.sendToIfCb(obj.from, obj.command, { error: `Message with messageId ${editMessagePayload.messageId} is not editable`, ...editMessagePayload }, obj.callback);\n return;\n }\n await msg.edit(editMessagePayload.content);\n this.sendToIfCb(obj.from, obj.command, { result: `Message edited`, ...editMessagePayload }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error editing message: ${err}`, ...editMessagePayload }, obj.callback);\n }\n\n break;\n } // editMessage\n\n case 'deleteMessage': {\n /*\n * delete a message\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const deleteMessagePayload = obj.message as MessageIdentifier;\n\n // try to get the message\n try {\n msg = await this.getPreviousMessage(deleteMessagePayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendToIfCb(obj.from, obj.command, { error: err.message, ...deleteMessagePayload }, obj.callback);\n } else {\n this.sendToIfCb(obj.from, obj.command, { error: err, ...deleteMessagePayload }, obj.callback);\n }\n return;\n }\n\n // try to delete the message\n try {\n if (!msg.deletable) {\n this.sendToIfCb(obj.from, obj.command, { error: `Message with messageId ${deleteMessagePayload.messageId} is not deletable`, ...deleteMessagePayload }, obj.callback);\n return;\n }\n await msg.delete();\n this.sendToIfCb(obj.from, obj.command, { result: `Message deleted`, ...deleteMessagePayload }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error deleting message: ${err}`, ...deleteMessagePayload }, obj.callback);\n }\n\n break;\n } // deleteMessage\n\n case 'addReaction': {\n /*\n * add a reaction emoji to a message\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const addReactionPayload = obj.message as SendToActionAddReactionPayload;\n\n // check payload\n if (typeof addReactionPayload.emoji !== 'string') {\n this.sendToIfCb(obj.from, obj.command, { error: 'emoji needs to be a string', ...addReactionPayload }, obj.callback);\n return;\n }\n\n // try to get the message\n try {\n msg = await this.getPreviousMessage(addReactionPayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendToIfCb(obj.from, obj.command, { error: err.message, ...addReactionPayload }, obj.callback);\n } else {\n this.sendToIfCb(obj.from, obj.command, { error: err, ...addReactionPayload }, obj.callback);\n }\n return;\n }\n\n // try to add the reaction to the message\n try {\n await msg.react(addReactionPayload.emoji);\n this.sendToIfCb(obj.from, obj.command, { result: `Reaction added to message`, ...addReactionPayload }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error adding reaction to message: ${err}`, ...addReactionPayload }, obj.callback);\n }\n\n break;\n } // addReaction\n\n case 'awaitMessageReaction': {\n /*\n * wait for a message reaction\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const awaitMessageReactionPayload = obj.message as SendToActionAwaitMessageReactionPayload;\n\n // check payload\n if (typeof awaitMessageReactionPayload.timeout !== 'number' || awaitMessageReactionPayload.timeout < 100 || awaitMessageReactionPayload.timeout > 60000) {\n this.sendTo(obj.from, obj.command, { error: 'timeout needs to be a number between 100 and 60000', ...awaitMessageReactionPayload }, obj.callback);\n return;\n }\n if (typeof awaitMessageReactionPayload.max !== 'number' || awaitMessageReactionPayload.max < 1) {\n awaitMessageReactionPayload.max = 1;\n }\n\n // try to get the message\n try {\n msg = await this.getPreviousMessage(awaitMessageReactionPayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendTo(obj.from, obj.command, { error: err.message, ...awaitMessageReactionPayload }, obj.callback);\n } else {\n this.sendTo(obj.from, obj.command, { error: err, ...awaitMessageReactionPayload }, obj.callback);\n }\n return;\n }\n\n // collect reactions\n const reactionCollector = msg.createReactionCollector({\n filter: (_r, u) => u.id !== this.client?.user?.id,\n max: awaitMessageReactionPayload.max,\n time: awaitMessageReactionPayload.timeout,\n });\n reactionCollector.on('end', (collected) => {\n const reactions = collected.map((r) => ({ emoji: r.emoji.name, emojiId: r.emoji.id, users: r.users.cache.map((u) => ({ id: u.id, name: u.username, tag: u.tag })) }));\n this.sendTo(obj.from, obj.command, { reactions, ...awaitMessageReactionPayload }, obj.callback);\n });\n\n break;\n } // awaitMessageReaction\n\n case 'sendCustomCommandReply': {\n /*\n * send a reply to a custom slash command\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const sendCustomCommandReplyPayload = obj.message as SendToActionSendCustomCommandReplyPayload;\n\n // check payload\n if (typeof sendCustomCommandReplyPayload.interactionId !== 'string') {\n this.sendToIfCb(obj.from, obj.command, { error: 'interactionId needs to be a string', ...sendCustomCommandReplyPayload }, obj.callback);\n return;\n }\n if (!sendCustomCommandReplyPayload.content || (typeof sendCustomCommandReplyPayload.content !== 'string' && typeof sendCustomCommandReplyPayload.content !== 'object')) {\n this.sendToIfCb(obj.from, obj.command, { error: 'content needs to be a string or a MessageOptions object', ...sendCustomCommandReplyPayload }, obj.callback);\n return;\n }\n\n // send the reply\n try {\n const messageId = await this.discordSlashCommands.sendCmdCustomReply(sendCustomCommandReplyPayload.interactionId, this.prepareMessageForSend(sendCustomCommandReplyPayload.content));\n this.sendToIfCb(obj.from, obj.command, { result: `Reply sent`, ...sendCustomCommandReplyPayload, messageId }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error sending reply: ${err}`, ...sendCustomCommandReplyPayload }, obj.callback);\n }\n\n break;\n } // sendCustomCommandReply\n\n case 'leaveServer': {\n /*\n * let the bot leave a server\n */\n if (typeof obj.message !== 'object') {\n this.sendToIfCb(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const leaveServerPayload = obj.message as SendToActionServerIdentifier;\n\n // check payload\n if (!leaveServerPayload.serverId) {\n this.sendToIfCb(obj.from, obj.command, { error: 'serverId needs to be set', ...leaveServerPayload }, obj.callback);\n return;\n }\n\n const guildToLeave = this.client?.guilds.cache.get(leaveServerPayload.serverId);\n if (!guildToLeave) {\n this.sendToIfCb(obj.from, obj.command, { error: `No server with ID ${leaveServerPayload.serverId} found` }, obj.callback);\n return;\n }\n\n try {\n await guildToLeave.leave();\n this.log.info(`Left server ${guildToLeave.name} (${guildToLeave.id})`);\n\n this.sendToIfCb(obj.from, obj.command, { result: 'ok' }, obj.callback);\n } catch (err) {\n this.sendToIfCb(obj.from, obj.command, { error: `Error leaving server ${leaveServerPayload.serverId}: ${err}`, ...leaveServerPayload }, obj.callback);\n }\n\n break;\n } // leaveServer\n\n case 'getServerInfo': {\n /*\n * get information about a server\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getServerInfoPayload = obj.message as SendToActionServerIdentifier;\n\n // check payload\n if (!getServerInfoPayload.serverId) {\n this.sendTo(obj.from, obj.command, { error: 'serverId needs to be set', ...getServerInfoPayload }, obj.callback);\n return;\n }\n\n const server = this.client?.guilds.cache.get(getServerInfoPayload.serverId);\n if (!server) {\n this.sendTo(obj.from, obj.command, { error: `No server with ID ${getServerInfoPayload.serverId} found`, ...getServerInfoPayload }, obj.callback);\n return;\n }\n\n this.sendTo(obj.from, obj.command, {\n id: server.id,\n name: server.name,\n description: server.description,\n members: server.members.cache.map((m) => ({\n id: m.id,\n tag: m.user.tag,\n name: m.user.username,\n displayName: m.displayName,\n })),\n roles: server.roles.cache.map((r) => ({\n id: r.id,\n name: r.name,\n color: r.hexColor,\n })),\n channels: server.channels.cache.map((c) => ({\n id: c.id,\n parentId: c.parentId,\n name: c.name,\n type: c.type,\n })),\n }, obj.callback);\n\n break;\n } // getServerInfo\n\n case 'getChannelInfo': {\n /*\n * get information about a channel\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getChannelInfoPayload = obj.message as SendToActionChannelIdentifier;\n\n // check payload\n if (!getChannelInfoPayload.serverId || !getChannelInfoPayload.channelId) {\n this.sendTo(obj.from, obj.command, { error: 'serverId and channelId need to be set', ...getChannelInfoPayload }, obj.callback);\n return;\n }\n\n channel = this.client?.guilds.cache.get(getChannelInfoPayload.serverId)?.channels.cache.get(getChannelInfoPayload.channelId);\n if (!channel) {\n this.sendTo(obj.from, obj.command, { error: `No channel with ID ${getChannelInfoPayload.channelId} for server with ID ${getChannelInfoPayload.serverId} found`, ...getChannelInfoPayload }, obj.callback);\n return;\n }\n\n this.sendTo(obj.from, obj.command, {\n id: channel.id,\n parentId: channel.parentId,\n name: channel.name,\n type: channel.type,\n members: !channel.isThread() && channel.members.map((m) => ({\n id: m.id,\n tag: m.user.tag,\n name: m.user.username,\n displayName: m.displayName,\n })),\n }, obj.callback);\n\n break;\n } // getChannelInfo\n\n case 'getServerMemberInfo': {\n /*\n * get information about a server member\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getServerMemberInfoPayload = obj.message as SendToActionServerMemberIdentifier;\n\n // check payload\n if (!getServerMemberInfoPayload.serverId || (!getServerMemberInfoPayload.userId && !getServerMemberInfoPayload.userTag && !getServerMemberInfoPayload.userName)) {\n this.sendTo(obj.from, obj.command, { error: 'serverId and userlId, userTag or userName need to be set', ...getServerMemberInfoPayload }, obj.callback);\n return;\n }\n\n let member: GuildMember | undefined;\n if (getServerMemberInfoPayload.userId) {\n member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.get(getServerMemberInfoPayload.userId);\n if (!member) {\n this.sendTo(obj.from, obj.command, { error: `No member with ID ${getServerMemberInfoPayload.userId} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback);\n return;\n }\n } else if (getServerMemberInfoPayload.userTag) {\n member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.find((m) => m.user.tag === getServerMemberInfoPayload.userTag);\n if (!member) {\n this.sendTo(obj.from, obj.command, { error: `No member with tag ${getServerMemberInfoPayload.userTag} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback);\n return;\n }\n } else {\n member = this.client?.guilds.cache.get(getServerMemberInfoPayload.serverId)?.members.cache.find((m) => m.user.discriminator === '0' && m.user.username === getServerMemberInfoPayload.userName);\n if (!member) {\n this.sendTo(obj.from, obj.command, { error: `No member with unique name ${getServerMemberInfoPayload.userName} for server with ID ${getServerMemberInfoPayload.serverId} found`, ...getServerMemberInfoPayload }, obj.callback);\n return;\n }\n }\n\n this.sendTo(obj.from, obj.command, {\n id: member.id,\n tag: member.user.tag,\n name: member.user.username,\n displayName: member.displayName,\n displayColor: member.displayHexColor,\n displayAvatarUrl: member.displayAvatarURL(),\n roles: member.roles.cache.map((r) => ({\n id: r.id,\n name: r.name,\n color: r.hexColor,\n })),\n joinedAt: member.joinedTimestamp,\n voiceChannelId: member.voice.channelId,\n voiceMuted: member.voice.mute,\n voiceDeaf: member.voice.deaf,\n }, obj.callback);\n\n break;\n } // getServerMemberInfo\n\n case 'getUserInfo': {\n /*\n * get information about a user\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getUserInfoPayload = obj.message as SendToActionUserIdentifier;\n\n // check payload\n if (!getUserInfoPayload.userId && !getUserInfoPayload.userTag && !getUserInfoPayload.userName) {\n this.sendTo(obj.from, obj.command, { error: 'userId, userTag or userName need to be set', ...getUserInfoPayload }, obj.callback);\n return;\n }\n\n if (getUserInfoPayload.userId) {\n user = this.client?.users.cache.get(getUserInfoPayload.userId);\n if (!user) {\n this.sendTo(obj.from, obj.command, { error: `No user with ID ${getUserInfoPayload.userId} found`, ...getUserInfoPayload }, obj.callback);\n return;\n }\n } else if (getUserInfoPayload.userTag) {\n user = this.client?.users.cache.find((u) => u.tag === getUserInfoPayload.userTag);\n if (!user) {\n this.sendTo(obj.from, obj.command, { error: `No user with tag ${getUserInfoPayload.userTag} found`, ...getUserInfoPayload }, obj.callback);\n return;\n }\n } else {\n user = this.client?.users.cache.find((u) => u.discriminator === '0' && u.username === getUserInfoPayload.userName);\n if (!user) {\n this.sendTo(obj.from, obj.command, { error: `No user with unique name ${getUserInfoPayload.userName} found`, ...getUserInfoPayload }, obj.callback);\n return;\n }\n }\n\n this.sendTo(obj.from, obj.command, {\n id: user.id,\n tag: user.tag,\n name: user.username,\n avatarUrl: user.avatarURL(),\n bot: user.bot,\n accentColor: user.hexAccentColor,\n }, obj.callback);\n\n break;\n } // getUserInfo\n\n case 'getMessageInfo': {\n /*\n * get information about a message\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (typeof obj.message !== 'object') {\n this.sendTo(obj.from, obj.command, { error: 'sendTo message needs to be an object' }, obj.callback);\n return;\n }\n\n const getMessageInfoPayload = obj.message as MessageIdentifier;\n\n try {\n msg = await this.getPreviousMessage(getMessageInfoPayload);\n } catch (err) {\n if (err instanceof Error && err.message) {\n this.sendTo(obj.from, obj.command, { error: err.message, ...getMessageInfoPayload }, obj.callback);\n } else {\n this.sendTo(obj.from, obj.command, { error: err, ...getMessageInfoPayload }, obj.callback);\n }\n return;\n }\n\n this.sendTo(obj.from, obj.command, {\n id: msg.id,\n author: {\n id: msg.author.id,\n tag: msg.author.tag,\n name: msg.author.username,\n },\n content: msg.content,\n embeds: msg.embeds.map((e) => e.toJSON()),\n attachments: msg.attachments.map((a) => a.toJSON()),\n reactions: msg.reactions.cache.map((r) => r.toJSON()),\n createdTimestamp: msg.createdTimestamp,\n editedTimestamp: msg.editedTimestamp,\n reference: msg.reference,\n }, obj.callback);\n\n break;\n } // getMessageInfo\n\n case 'sendNotification': {\n /*\n * notification from ioBrokers notification system\n * see https://github.com/foxriver76/ioBroker.notification-manager\n */\n if (!obj.callback) {\n this.log.warn(`Message '${obj.command}' called without callback!`);\n return;\n }\n\n if (!this.config.sendNotificationsTo) {\n this.log.debug(`New notification received from ${obj.from}, but sending notifications is not enabled in adapter config`);\n this.sendTo(obj.from, obj.command, { sent: false }, obj.callback);\n return;\n }\n\n this.log.info(`New notification received from ${obj.from.replace(/^system\\.adapter\\./, '')}`);\n\n let target: User | TextChannel | undefined;\n\n if (this.config.sendNotificationsTo.indexOf('/') > 0) {\n // server channel\n const [ serverId, channelId ] = this.config.sendNotificationsTo.split('/');\n const channel2 = this.client?.guilds.cache.get(serverId)?.channels.cache.get(channelId);\n if (channel2?.type === ChannelType.GuildText) {\n target = channel2;\n }\n } else {\n // user\n target = this.client?.users.cache.get(this.config.sendNotificationsTo);\n }\n\n if (!target) {\n this.log.error(`Cannot send notification because the configured target is invalid!`);\n this.sendTo(obj.from, obj.command, { sent: false }, obj.callback);\n return;\n }\n\n const message = obj.message as LocalizedNotification;\n\n // check the message object\n if (!message?.category?.instances || !message.category.name) {\n this.log.warn(`Cannot send notification because the received message object is invalid`);\n this.sendTo(obj.from, obj.command, { sent: false }, obj.callback);\n return;\n }\n\n const { instances, severity } = message.category;\n\n let icon: string = '';\n switch (severity) {\n case 'alert':\n icon = ':warning: ';\n break;\n case 'info':\n icon = ':information_source: ';\n break;\n case 'notify':\n icon = ':bell: ';\n break;\n }\n\n const readableInstances = Object.entries(instances).map(([ instance, entry ]) => `${instance.substring('system.adapter.'.length)}: ${getNewestDate(entry.messages, i18n.language)}`);\n\n const text = `${icon}**${message.category.name}**\n\n${message.category.description ?? ''}\n\n${message.host}:\n${readableInstances.join('\\n')}`;\n\n try {\n const msg2 = await target.send(text);\n this.log.debug(`Sent message from notification-manager adapter with message ID ${msg2.id}`);\n this.sendTo(obj.from, obj.command, { sent: true }, obj.callback);\n } catch (err) {\n this.log.warn(`Error sending message from notification-manager adapter: ${err}`);\n this.sendTo(obj.from, obj.command, { sent: false }, obj.callback);\n }\n\n break;\n } // sendNotification\n\n default:\n /*\n * unknown command\n */\n this.log.warn(`Got message with unknown command: ${obj.command}`);\n if (obj.callback) {\n this.sendTo(obj.from, obj.command, { error: `Unknown command: ${obj.command}` }, obj.callback);\n }\n\n }\n }\n\n /**\n * Like `sendTo(...)` but only sends if a callback is given.\n *\n * If no callback given, but `message.error` is defined, the error will be\n * logged as a warning.\n * @see sendTo\n */\n private sendToIfCb (instanceName: string, command: string, message: ioBroker.MessagePayload, callback: ioBroker.MessageCallback | ioBroker.MessageCallbackInfo | undefined): void {\n if (callback) {\n this.sendTo(instanceName, command, message, callback);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n } else if (typeof message === 'object' && message.error) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access\n this.log.warn(message.error);\n }\n }\n\n /**\n * Prepare a message for sending.\n *\n * This some message parts to be valid discord message data.\n * @param msg The message as `string` or `MessageCreateOptions`.\n * @returns The prepared message.\n */\n private prepareMessageForSend (msg: string | MessageCreateOptions): string | MessageCreateOptions {\n if (typeof msg === 'string') {\n return msg;\n }\n\n // replace hexo color codes in embeds\n if (msg.embeds) {\n for (const embed of msg.embeds) {\n // color codes may be given as string in user defined embeds\n if (typeof (embed as APIEmbed).color === 'string') {\n const colorStr: string = (embed as APIEmbed).color as unknown as string;\n if (/^\\d+$/.exec(colorStr)) {\n // it's a number color given as string\n (embed as APIEmbed).color = parseInt(colorStr, 10);\n } else {\n // it's something else (maybe a color name or hexo color)\n // try to resolve the color\n try {\n (embed as APIEmbed).color = resolveColor(colorStr as HexColorString);\n } catch (err) {\n // color could not be resolved, use a default color\n (embed as APIEmbed).color = resolveColor('Greyple');\n this.log.warn(`Error embed color '${colorStr}': ${err}`);\n }\n }\n }\n }\n }\n\n return msg;\n }\n\n /**\n * Find a previous message from/to a user or in a server text channel.\n * @param identifier Parameters to find the message.\n * @throws An error if some parameters are missing or the message could not be found.\n */\n private async getPreviousMessage (identifier: MessageIdentifier): Promise> {\n if (!identifier.messageId) {\n throw new Error('messageId needs to be set');\n }\n\n if (identifier.userId || identifier.userTag || identifier.userName) {\n // a user\n let user: User | undefined;\n if (identifier.userId) {\n // by userId\n user = this.client?.users.cache.get(identifier.userId);\n if (!user) {\n throw new Error(`No user with userId ${identifier.userId} found`);\n }\n } else if (identifier.userTag) {\n // by userTag\n user = this.client?.users.cache.find((u) => u.tag === identifier.userTag);\n if (!user) {\n throw new Error(`No user with userTag ${identifier.userTag} found`);\n }\n } else {\n // by unique userName\n user = this.client?.users.cache.find((u) => u.discriminator === '0' && u.username === identifier.userName);\n if (!user) {\n throw new Error(`No user with unique userName ${identifier.userName} found`);\n }\n }\n try {\n if (!user.dmChannel) {\n await user.createDM();\n }\n const msg = user.dmChannel?.messages.cache.get(identifier.messageId) ?? await user.dmChannel?.messages.fetch(identifier.messageId);\n if (!msg) {\n throw new Error(`No message with messageId ${identifier.messageId} for user ${userNameOrTag(user)} found`);\n }\n return msg;\n } catch (err) {\n throw new Error(`Error finding message for user ${userNameOrTag(user)}: ${err}`);\n }\n\n } else if (identifier.serverId && identifier.channelId) {\n // a channel\n const channel = this.client?.guilds.cache.get(identifier.serverId)?.channels.cache.get(identifier.channelId);\n if (channel?.type !== ChannelType.GuildText && channel?.type !== ChannelType.GuildVoice) {\n throw new Error(`No text channel with channelId ${identifier.channelId} on server ${identifier.serverId} found`);\n }\n try {\n const msg = channel.messages.cache.get(identifier.messageId) ?? await channel.messages.fetch(identifier.messageId);\n if (!msg) {\n throw new Error(`No message with messageId ${identifier.messageId} for channel ${channel.name} found`);\n }\n return msg;\n } catch (err) {\n throw new Error(`Error finding message in channel ${channel.name}: ${err}`);\n }\n\n } else {\n // missing arguments\n throw new Error('userId, userTag, userName or serverId and channelId needs to be set');\n }\n }\n\n /**\n * Set the `info.connection` state if changed.\n * @param connected If connected.\n * @param force `true` to skip local cache check and always set the state.\n */\n private async setInfoConnectionState (connected: boolean, force: boolean = false): Promise {\n if (force || connected !== this.infoConnected) {\n await this.setState('info.connection', connected, true);\n this.infoConnected = connected;\n }\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n @boundMethod\n private async onUnload (callback: () => void): Promise {\n try {\n this.unloaded = true;\n\n await this.setInfoConnectionState(false, true);\n\n if (this.client) {\n await this.client.destroy();\n }\n\n callback();\n } catch (_e) {\n callback();\n }\n }\n\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial | undefined) => new DiscordAdapter(options);\n} else {\n // otherwise start the instance directly\n (() => new DiscordAdapter())();\n}\n\n// export the type of the adapter class to use it in other files\nexport type { DiscordAdapter };\n"], + "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,sBAAO;AAEP,uBAAkC;AAElC,gCAA4B;AAE5B,0BAIO;AAEP,qBA2BO;AAEP,sBAGO;AACP,yBAuBO;AACP,kBAAqB;AACrB,mBAKO;AACP,kCAAqD;AAErD,MAAM,mBAAmB;AAAA,EACvB;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;AAKA,MAAM,uBAAuB,4BAAQ;AAAA;AAAA;AAAA;AAAA,EAK5B,SAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMxB,WAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpB,+BAAwC;AAAA;AAAA;AAAA;AAAA,EAKvC,gBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzB,uBAAoC,oBAAI,IAAY;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpD,aAA6B,oBAAI,IAAe;AAAA;AAAA;AAAA;AAAA,EAKhD,sBAAmC,oBAAI,IAAY;AAAA;AAAA;AAAA;AAAA,EAKnD,oBAAgE,IAAI,0BAA2C;AAAA;AAAA;AAAA;AAAA,EAK/G,iBAAqH,IAAI,0BAAmG;AAAA;AAAA;AAAA;AAAA,EAK5N;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAA+B;AAAA,EAEhC,YAAa,UAAmC,CAAC,GAAG;AACzD,UAAM;AAAA,MACJ,GAAG;AAAA,MACH,MAAM;AAAA,IACR,CAAC;AAED,SAAK,uBAAuB,IAAI,4CAA4B,IAAI;AAEhE,SAAK,GAAG,SAAS,KAAK,OAAO;AAC7B,SAAK,GAAG,eAAe,KAAK,aAAa;AACzC,SAAK,GAAG,gBAAgB,KAAK,cAAc;AAC3C,SAAK,GAAG,WAAW,KAAK,SAAS;AACjC,SAAK,GAAG,UAAU,KAAK,QAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeO,+BAAgC,SAAuC;AAC5E,QAAI;AAEJ,QAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GAAG;AAEpD,WAAK,IAAI,MAAM,0BAA0B;AAEzC,UAAI;AACF,aAAK,KAAK,MAAM,OAAO;AAAA,MACzB,SAAS,MAAM;AACb,cAAM,IAAI,MAAM,gDAAgD;AAAA,MAClE;AAGA,UAAK,CAAC,IAAI,SAAS,CAAC,GAAG,WAAa,GAAG,SAAS,CAAC,MAAM,QAAQ,GAAG,KAAK,KAAO,GAAG,UAAU,CAAC,MAAM,QAAQ,GAAG,MAAM,GAAI;AACrH,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC5D;AAAA,IAEF,OAAO;AAEL,WAAK;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,uBAAwB,MAA0B,UAA4C;AACnG,QAAI,CAAC,KAAK,OAAO,qBAAqB;AACpC,aAAO;AAAA,IACT;AAGA,QAAI,QAA2D,KAAK,OAAO,gBAAgB,KAAK,CAAC,OAAO,GAAG,WAAW,KAAK,EAAE;AAG7H,QAAI,KAAK,OAAO,sBAAsB,SAAS,KAAK,gBAAgB,4BAAa;AAC/E,iBAAW,CAAE,EAAE,IAAK,KAAK,KAAK,MAAM,OAAO;AACzC,cAAM,YAAY,KAAK,OAAO,sBAAsB,KAAK,CAAC,OAAO,GAAG,oBAAoB,GAAG,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,EAAE;AACrH,YAAI,WAAW;AACb,cAAI,CAAC,OAAO;AACV,oBAAQ;AAAA,UACV,OAAO;AACL,oBAAQ;AAAA,cACN,WAAW,MAAM,aAAa,UAAU;AAAA,cACxC,WAAW,MAAM,aAAa,UAAU;AAAA,cACxC,mBAAmB,MAAM,qBAAqB,UAAU;AAAA,cACxD,iBAAiB,MAAM,mBAAmB,UAAU;AAAA,YACtD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAGA,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AAEA,QAAK,SAAS,aAAa,CAAC,MAAM,aAC5B,SAAS,aAAa,CAAC,MAAM,aAC7B,SAAS,qBAAqB,CAAC,MAAM,qBACrC,SAAS,mBAAmB,CAAC,MAAM,iBAAkB;AACzD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,KAAM,MAA6B;AAC9C,WAAO,MAAM,IAAI,QAAQ,CAAC,YAAwB,KAAK,WAAW,SAAS,IAAI,CAAC;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,mBAAoB,IAAY,SAAiC,SAAmE;AAC/I,UAAM,YAAgD,KAAK,kBAAkB,IAAI,EAAE;AAEnF,YAAI,oCAAkB,WAAW,OAAO,GAAG;AACzC,aAAO,EAAE,GAAG;AAAA,IACd;AACA,QAAI;AACJ,QAAI,SAAS;AACX,YAAM,MAAM,KAAK,aAAa,IAAI,SAAS,OAAO;AAAA,IACpD,OAAO;AACL,YAAM,MAAM,KAAK,aAAa,IAAI,OAAO;AAAA,IAC3C;AACA,SAAK,kBAAkB,IAAI,IAAI,OAAO;AACtC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,qBAAsB,IAAY,SAAoD;AACjG,QAAI,SAAS,WAAW;AACtB,WAAK,kBAAkB,OAAO,CAAC,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,QAAQ,KAAK,kBAAkB,OAAO,GAAG,CAAC;AAAA,IACzH,OAAO;AACL,WAAK,kBAAkB,OAAO,EAAE;AAAA,IAClC;AAEA,WAAO,MAAM,KAAK,eAAe,IAAI,OAAO;AAAA,EAC9C;AAAA,EAMA,MAAc,UAA0B;AAGtC,UAAM,KAAK,uBAAuB,OAAO,IAAI;AAG7C,SAAK,IAAI,MAAM,0BAA0B,eAAAA,OAAU,EAAE;AAGrD,UAAM,eAAe,MAAM,KAAK,sBAAsB,eAAe;AACrE,qBAAK,WAAW,cAAc,OAAO,YAAY;AACjD,qBAAK,eAAe,cAAc,OAAO,gBAAgB;AAGzD,QAAI,OAAO,KAAK,OAAO,UAAU,YAAY,CAAE,6DAA6D,KAAK,KAAK,OAAO,KAAK,GAAI;AACpI,WAAK,IAAI,MAAM,sBAAsB;AACrC;AAAA,IACF;AACA,QAAI,CAAC,MAAM,QAAQ,KAAK,OAAO,eAAe,GAAG;AAC/C,WAAK,OAAO,kBAAkB,CAAC;AAAA,IACjC;AACA,QAAI,CAAC,MAAM,QAAQ,KAAK,OAAO,qBAAqB,GAAG;AACrD,WAAK,OAAO,wBAAwB,CAAC;AAAA,IACvC;AACA,QAAI,CAAC,KAAK,OAAO,qBAAqB;AACpC,WAAK,IAAI,KAAK,0KAA0K;AAAA,IAC1L;AACA,QAAI,KAAK,OAAO,uBAAuB,KAAK,OAAO,gBAAgB,WAAW,KAAK,KAAK,OAAO,sBAAsB,WAAW,GAAG;AACjI,WAAK,IAAI,KAAK,+DAA+D;AAAA,IAC/E;AACA,QAAI,KAAK,OAAO,wBAAwB,CAAC,MAAM,QAAQ,KAAK,OAAO,cAAc,GAAG;AAClF,WAAK,OAAO,iBAAiB,CAAC;AAAA,IAChC;AACA,SAAK,OAAO,uBAAuB,KAAK,OAAO,sBAAsB,KAAK,KAAK;AAG/E,UAAM,qBAAqB,MAAM,KAAK,eAAe,kBAAkB;AAEvE,QAAI,oBAAoB,QAAQ,QAAQ,SAAS;AAE/C,aAAO,mBAAmB,OAAO,OAAO;AACxC,aAAO,mBAAmB,OAAO,OAAO;AACxC,aAAO,mBAAmB,OAAO,OAAO;AACxC,aAAO,mBAAmB,OAAO,OAAO;AACxC,aAAO,mBAAmB,OAAO,OAAO;AACxC,YAAM,KAAK,eAAe,oBAAoB,kBAAkB;AAAA,IAClE;AAIA,QAAI,KAAK,OAAO,iBAAiB;AAC/B,YAAM,KAAK,aAAa,OAAO;AAAA,QAC7B,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,MAAM,iBAAK,sBAAsB,UAAU;AAAA,QAC7C;AAAA,QACA,QAAQ,CAAC;AAAA,MACX,CAAC;AACD,YAAM,QAAQ,IAAI;AAAA,QAChB,KAAK,aAAa,uBAAuB;AAAA,UACvC,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,4BAA4B;AAAA,YAC7D,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,aAAa,mBAAmB;AAAA,UACnC,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,wBAAwB;AAAA,YACzD,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,MACH,CAAC;AAAA,IACH,OAAO;AACL,YAAM,KAAK,eAAe,OAAO,EAAE,WAAW,KAAK,CAAC;AAAA,IACtD;AAEA,QAAI,KAAK,OAAO,sBAAsB;AACpC,YAAM,KAAK,aAAa,iBAAiB;AAAA,QACvC,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,MAAM,iBAAK,sBAAsB,+BAA+B;AAAA,QAClE;AAAA,QACA,QAAQ,CAAC;AAAA,MACX,CAAC;AAAA,IACH,OAAO;AACL,YAAM,KAAK,eAAe,iBAAiB,EAAE,WAAW,KAAK,CAAC;AAAA,IAChE;AAGA,SAAK,SAAS,IAAI,sBAAO;AAAA,MACvB,SAAS;AAAA,QACP,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,QAClB,iCAAkB;AAAA,MACpB;AAAA,MACA,UAAU;AAAA,QACR,wBAAS;AAAA;AAAA,MACX;AAAA,IACF,CAAC;AAED,SAAK,OAAO,GAAG,SAAS,KAAK,aAAa;AAE1C,QAAI,KAAK,IAAI,UAAU,SAAS;AAC9B,WAAK,OAAO,GAAG,SAAS,CAAC,YAAY,KAAK,IAAI,MAAM,cAAc,OAAO,EAAE,CAAC;AAAA,IAC9E;AACA,SAAK,OAAO,GAAG,QAAQ,CAAC,YAAY,KAAK,IAAI,KAAK,2BAA2B,OAAO,EAAE,CAAC;AACvF,SAAK,OAAO,GAAG,SAAS,CAAC,QAAQ,KAAK,IAAI,MAAM,yBAAyB,IAAI,SAAS,CAAC,EAAE,CAAC;AAC1F,SAAK,OAAO,GAAG,aAAa,CAAC,kBAAkB,KAAK,IAAI,MAAM,kCAAkC,KAAK,UAAU,aAAa,CAAC,EAAE,CAAC;AAChI,SAAK,OAAO,GAAG,yBAAyB,CAAC,8BAA8B,KAAK,IAAI,KAAK,2CAA2C,KAAK,UAAU,yBAAyB,CAAC,EAAE,CAAC;AAE5K,SAAK,OAAO,GAAG,eAAe,MAAM;AAClC,WAAK,IAAI,KAAK,oCAAoC;AAClD,WAAK,KAAK,uBAAuB,KAAK;AAAA,IACxC,CAAC;AAED,SAAK,OAAO,GAAG,cAAc,CAAC,KAAY,YAAoB;AAK5D,UAAI;AACJ,UAAI,eAAe,gBAAgB;AAEjC,mBAAW,MAAM,KAAK,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,MAA6B,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAChG,OAAO;AACL,mBAAW,IAAI,SAAS;AAAA,MAC1B;AAEA,UAAI,KAAK,iBAAiB,UAAU;AAClC,aAAK,eAAe;AACpB,aAAK,IAAI,KAAK,2CAA2C,OAAO,MAAM,QAAQ,EAAE;AAChF,aAAK,KAAK,uBAAuB,KAAK;AAAA,MACxC,OAAO;AACL,aAAK,IAAI,MAAM,2CAA2C,OAAO,MAAM,QAAQ,EAAE;AAAA,MACnF;AAAA,IACF,CAAC;AAED,SAAK,OAAO,GAAG,cAAc,CAAC,YAAoB;AAEhD,WAAK,eAAe;AACpB,WAAK,IAAI,KAAK,+CAA+C,OAAO,GAAG;AACvE,WAAK,KAAK,uBAAuB,IAAI;AACrC,WAAK,KAAK,eAAe;AAAA,IAC3B,CAAC;AAED,SAAK,OAAO,GAAG,eAAe,CAAC,SAAiB,mBAA2B,KAAK,IAAI,MAAM,4CAA4C,OAAO,mBAAmB,cAAc,GAAG,CAAC;AAClL,SAAK,OAAO,GAAG,mBAAmB,CAAC,OAAsB,YAAoB,KAAK,IAAI,MAAM,gDAAgD,OAAO,SAAS,MAAM,IAAI,GAAG,CAAC;AAC1K,SAAK,OAAO,GAAG,qBAAqB,CAAC,YAAoB,KAAK,IAAI,MAAM,kDAAkD,OAAO,GAAG,CAAC;AAErI,SAAK,OAAO,GAAG,iBAAiB,KAAK,qBAAqB;AAE1D,QAAI,KAAK,OAAO,sBAAsB;AACpC,WAAK,OAAO,GAAG,iBAAiB,MAAM,KAAK,aAAa,CAAC;AACzD,WAAK,OAAO,GAAG,iBAAiB,MAAM,KAAK,aAAa,CAAC;AACzD,WAAK,OAAO,GAAG,iBAAiB,MAAM,KAAK,aAAa,CAAC;AACzD,WAAK,OAAO,GAAG,eAAe,MAAM,KAAK,aAAa,CAAC;AACvD,WAAK,OAAO,GAAG,eAAe,MAAM,KAAK,aAAa,CAAC;AACvD,WAAK,OAAO,GAAG,eAAe,MAAM,KAAK,aAAa,CAAC;AACvD,WAAK,OAAO,GAAG,kBAAkB,MAAM,KAAK,aAAa,CAAC;AAC1D,WAAK,OAAO,GAAG,qBAAqB,MAAM,KAAK,aAAa,CAAC;AAC7D,WAAK,OAAO,GAAG,cAAc,MAAM,KAAK,aAAa,CAAC;AACtD,WAAK,OAAO,GAAG,cAAc,MAAM,KAAK,aAAa,CAAC;AACtD,WAAK,OAAO,GAAG,cAAc,MAAM,KAAK,aAAa,CAAC;AACtD,WAAK,OAAO,GAAG,cAAc,MAAM,KAAK,aAAa,CAAC;AAAA,IACxD;AAEA,QAAI,KAAK,OAAO,qBAAqB;AACnC,WAAK,OAAO,GAAG,kBAAkB,CAAC,cAAc,gBAAgB,KAAK,mBAAmB,YAAY,QAAQ,WAAW,CAAC;AAAA,IAC1H;AAEA,QAAI,KAAK,OAAO,uBAAuB;AACrC,WAAK,OAAO,GAAG,oBAAoB,KAAK,wBAAwB;AAAA,IAClE;AAGA,UAAM,KAAK,qBAAqB,QAAQ;AAGxC,SAAK,gBAAgB,2BAA2B;AAChD,SAAK,gBAAgB,+BAA+B;AACpD,SAAK,gBAAgB,gCAAgC;AACrD,SAAK,gBAAgB,mCAAmC;AACxD,SAAK,gBAAgB,cAAc;AACnC,SAAK,gBAAgB,kBAAkB;AACvC,SAAK,gBAAgB,mBAAmB;AACxC,SAAK,gBAAgB,sBAAsB;AAC3C,SAAK,gBAAgB,qCAAqC;AAC1D,SAAK,gBAAgB,qCAAqC;AAC1D,SAAK,gBAAgB,qCAAqC;AAC1D,SAAK,gBAAgB,2BAA2B;AAChD,SAAK,gBAAgB,kCAAkC;AACvD,SAAK,gBAAgB,OAAO;AAC5B,SAAK,wBAAwB,GAAG;AAGhC,SAAK,IAAI,MAAM,wCAAwC;AACvD,UAAM,OAAO,MAAM,KAAK,mBAAmB,UAAU,UAAU,CAAC,CAAC;AACjE,QAAI,MAAM,MAAM;AACd,iBAAW,QAAQ,KAAK,MAAM;AAE5B,cAAM,KAAK,eAAe,KAAK,IAAI,KAAK,QAAQ,KAAK,SAAS,CAAC;AAAA,MACjE;AAAA,IACF;AACA,SAAK,IAAI,MAAM,6CAA6C;AAG5D,SAAK,+BAA+B;AAGpC,UAAM,cAAc,MAAM,KAAK,YAAY;AAC3C,QAAI,gBAAgB,MAAM;AACxB,UAAI,YAAY,SAAS,eAAe,GAAG;AACzC,aAAK,UAAU,mDAAmD,+BAAW,6BAA6B;AAAA,MAC5G,OAAO;AACL,aAAK,UAAU,4BAA4B,+BAAW,4BAA4B;AAAA,MACpF;AACA;AAAA,IACF;AAGA,UAAM,KAAK,qBAAqB,sBAAsB;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAc,YAAa,QAAgB,GAA2B;AACpE,QAAI,CAAC,KAAK,UAAU,KAAK,UAAU;AACjC,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,KAAK,OAAO,MAAM,KAAK,OAAO,KAAK;AACzC,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,eAAe,OAAO;AACxB,YAAI;AACJ,YAAI,eAAe,gBAAgB;AAEjC,qBAAW,MAAM,KAAK,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,MAA6B,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,QAChG,OAAO;AACL,qBAAW,IAAI,SAAS;AAAA,QAC1B;AAEA,YAAI,QAAQ,GAAG;AACb,eAAK,IAAI,KAAK,wBAAwB,QAAQ,EAAE;AAAA,QAClD,OAAO;AACL,eAAK,IAAI,KAAK,wBAAwB,QAAQ,EAAE;AAAA,QAClD;AACA,YAAI,IAAI,SAAS,gBAAgB,IAAI,SAAS,yBAA0B,IAA8B,SAAS,eACzG,eAAe,kBAAkB,IAAI,OAAO,IAAI,CAAC,MAA6B,EAAE,IAAI,EAAE,SAAS,aAAa,GAAI;AAKpH;AACA,cAAI,SAAS,iBAAiB,QAAQ;AACpC,oBAAQ,iBAAiB,SAAS;AAAA,UACpC;AAEA,eAAK,IAAI,KAAK,QAAQ,iBAAiB,KAAK,IAAI,GAAI,oCAAoC,QAAQ,CAAC,OAAO;AACxG,gBAAM,KAAK,KAAK,iBAAiB,KAAK,CAAC;AAEvC,iBAAO,MAAM,KAAK,YAAY,KAAK;AAAA,QACrC;AACA,eAAO,IAAI;AAAA,MACb,OAAO;AACL,aAAK,IAAI,MAAM,6BAA6B;AAC5C,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA,EAMA,MAAc,gBAAgC;AAC5C,QAAI,CAAC,KAAK,QAAQ,MAAM;AACtB,WAAK,IAAI,MAAM,6BAA6B;AAC5C;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,gBAAgB,KAAK,OAAO,KAAK,GAAG,GAAG;AACrD,SAAK,IAAI,MAAM,YAAY,KAAK,OAAO,KAAK,EAAE,EAAE;AAGhD,QAAI,KAAK,OAAO,SAAS;AACvB,UAAI,KAAK,OAAO,KAAK,aAAa,KAAK,OAAO,SAAS;AAErD,aAAK,IAAI,MAAM,6CAA6C,KAAK,OAAO,KAAK,QAAQ,uBAAuB,KAAK,OAAO,OAAO,EAAE;AACjI,YAAI;AACF,gBAAM,QAA4B,CAAC;AACnC,gBAAM,KAAK,KAAK,OAAO,KAAK,YAAY,KAAK,OAAO,OAAO,CAAC;AAE5D,qBAAW,CAAE,EAAE,KAAM,KAAK,KAAK,OAAO,OAAO,OAAO;AAClD,kBAAM,KAAK,MAAM,QAAQ,MAAM,IAAI,KAAK,OAAO,KAAK,EAAE;AACtD,gBAAI,IAAI;AACN,oBAAM,KAAK,GAAG,YAAY,KAAK,OAAO,OAAO,CAAC;AAAA,YAChD;AAAA,UACF;AAEA,gBAAM,QAAQ,IAAI,KAAK;AACvB,eAAK,IAAI,MAAM,kBAAkB;AAAA,QACnC,SAAS,KAAK;AACZ,eAAK,IAAI,KAAK,kCAAkC,KAAK,OAAO,OAAO,MAAM,GAAG,EAAE;AAAA,QAChF;AAAA,MACF,OAAO;AAEL,aAAK,IAAI,MAAM,wBAAwB;AAAA,MACzC;AAAA,IACF;AAEA,QAAI;AACF,YAAM,KAAK,aAAa;AAAA,IAC1B,SAAS,KAAK;AACZ,WAAK,IAAI,MAAM,4CAA4C,GAAG,EAAE;AAAA,IAClE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eAA+B;AAC3C,QAAI,CAAC,KAAK,QAAQ,MAAM;AACtB,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAMA,UAAM,kBAAoF,IAAI,0BAAiE;AAM/J,UAAM,6BAA0C,oBAAI,IAAY;AAEhE,QAAI,KAAK;AAAU;AACnB,UAAM,SAAS,MAAM,KAAK,OAAO,OAAO,MAAM;AAC9C,QAAI,KAAK;AAAU;AAEnB,eAAW,CAAE,EAAE,SAAU,KAAK,QAAQ;AAEpC,UAAI,KAAK;AAAU;AACnB,UAAI;AACJ,UAAI;AACF,gBAAQ,MAAM,UAAU,MAAM;AAAA,MAChC,SAAS,KAAK;AACZ,aAAK,IAAI,KAAK,gDAAgD,UAAU,IAAI,QAAQ,UAAU,EAAE,EAAE;AAClG,aAAK,IAAI,MAAM,UAAU,GAAG,EAAE;AAC9B;AAAA,MACF;AACA,UAAI,KAAK;AAAU;AAEnB,iCAA2B,IAAI,GAAG,KAAK,SAAS,YAAY,MAAM,EAAE,EAAE;AAGtE,YAAM,KAAK,mBAAmB,WAAW,MAAM,EAAE,IAAI;AAAA,QACnD,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,MAAM,MAAM;AAAA,QACd;AAAA,QACA,QAAQ,CAAC;AAAA,MACX,CAAC;AAED,YAAM,QAAQ,IAAI;AAAA,QAChB,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY;AAAA,UACrD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,SAAS;AAAA,UAC5C;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,aAAa;AAAA,UACtD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,UAAU;AAAA,UAC7C;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,MACH,CAAC;AAGD,YAAM,eAAe,MAAM,MAAM,QAAQ,MAAM;AAC/C,UAAI,KAAK;AAAU;AAEnB,iBAAW,CAAE,EAAE,MAAO,KAAK,cAAc;AAEvC,YAAI,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,IAAI;AAC1C,0BAAgB,IAAI,OAAO,KAAK,IAAI,EAAE,MAAM,OAAO,MAAM,UAAU,OAAO,SAAS,CAAC;AAAA,QACtF;AAEA,cAAM,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,IAAI;AAAA,UACxE,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,GAAG,OAAO,WAAW,SAAK,4BAAc,OAAO,IAAI,CAAC;AAAA,UAC5D;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAED,cAAM,QAAQ,IAAI;AAAA,UAChB,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,QAAQ;AAAA,YACtE,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,UAAU;AAAA,cAC3C,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,SAAS;AAAA,YACvE,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,WAAW;AAAA,cAC5C,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,gBAAgB;AAAA,YAC9E,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,cAAc;AAAA,cAC/C,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,UAAU;AAAA,YACxE,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,OAAO;AAAA,cACxC,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UAED,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,aAAa;AAAA,YAC3E,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,WAAW;AAAA,cAC5C,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UAED,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,iBAAiB;AAAA,YAC/E,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,eAAe;AAAA,cAChD,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,oBAAoB;AAAA,YAClF,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,kBAAkB;AAAA,cACnD,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,kBAAkB;AAAA,YAChF,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,mBAAmB;AAAA,cACpD,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,oBAAoB;AAAA,YAClF,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,qBAAqB;AAAA,cACtD,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,kBAAkB;AAAA,YAChF,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,iBAAiB;AAAA,cAClD,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UACD,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,oBAAoB;AAAA,YAClF,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,mBAAmB;AAAA,cACpD,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,UAED,KAAK,mBAAmB,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,SAAS;AAAA,YACvE,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,iBAAK,sBAAsB,WAAW;AAAA,cAC5C,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,cACP,KAAK;AAAA,YACP;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,QACH,CAAC;AAED,cAAM,cAAc,OAAO,MAAM,MAAM,IAAI,CAAC,SAAS,KAAK,IAAI;AAC9D,cAAM,QAAQ,IAAI;AAAA,UAChB,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,QAAQ,OAAO,KAAK,KAAK,IAAI;AAAA,UACnF,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,SAAS,OAAO,KAAK,UAAU,IAAI;AAAA,UACzF,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,gBAAgB,OAAO,aAAa,IAAI;AAAA,UAC9F,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,UAAU,YAAY,KAAK,IAAI,GAAG,IAAI;AAAA,UAC5F,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,aAAa,OAAO,iBAAiB,IAAI;AAAA,UAC/F,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,iBAAiB,OAAO,MAAM,SAAS,QAAQ,IAAI,IAAI;AAAA,UAC7G,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,kBAAkB,CAAC,CAAC,OAAO,MAAM,UAAU,IAAI;AAAA,UACrG,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,oBAAoB,CAAC,CAAC,OAAO,MAAM,YAAY,IAAI;AAAA,UACzG,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,kBAAkB,CAAC,CAAC,OAAO,MAAM,UAAU,IAAI;AAAA,UACrG,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,oBAAoB,CAAC,CAAC,OAAO,MAAM,YAAY,IAAI;AAAA,QAC3G,CAAC;AAED,cAAM,OAA8B;AAAA,UAClC,KAAK,OAAO,KAAK;AAAA,UACjB,MAAM,OAAO,KAAK;AAAA,UAClB,IAAI,OAAO;AAAA,UACX,aAAa,OAAO;AAAA,UACpB,OAAO;AAAA,UACP,QAAQ,OAAO;AAAA,UACf,cAAc,OAAO,MAAM,SAAS,QAAQ;AAAA,UAC5C,gBAAgB,OAAO,MAAM,SAAS,MAAM;AAAA,UAC5C,eAAe,CAAC,CAAC,OAAO,MAAM;AAAA,UAC9B,iBAAiB,CAAC,CAAC,OAAO,MAAM;AAAA,UAChC,eAAe,CAAC,CAAC,OAAO,MAAM;AAAA,UAC9B,iBAAiB,CAAC,CAAC,OAAO,MAAM;AAAA,QAClC;AACA,YAAI,KAAC,oCAAkB,MAAM,KAAK,eAAe,IAAI,GAAG,KAAK,SAAS,YAAY,MAAM,EAAE,YAAY,OAAO,EAAE,OAAO,CAAC,GAAG;AACxH,gBAAM,KAAK,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,EAAE,SAAS,KAAK,UAAU,IAAI,GAAG,IAAI;AAC/F,eAAK,eAAe,IAAI,GAAG,KAAK,SAAS,YAAY,MAAM,EAAE,YAAY,OAAO,EAAE,SAAS,IAAI;AAAA,QACjG;AAAA,MAEF;AAGA,UAAI,KAAK;AAAU;AACnB,YAAM,WAAW,MAAM,MAAM,SAAS,MAAM;AAC5C,UAAI,KAAK;AAAU;AAGnB,iBAAW,WAAW,CAAE,MAAM,KAAM,GAAG;AACrC,mBAAW,CAAE,EAAE,OAAQ,KAAK,UAAU;AACpC,cAAI,CAAC,WAAY,WAAW,QAAQ,YAAc,CAAC,WAAW,CAAC,QAAQ,UAAW;AAChF;AAAA,UACF;AACA,gBAAM,kBAAkB,UAAU,WAAW,MAAM,EAAE,aAAa,QAAQ,EAAE,KAAK,WAAW,MAAM,EAAE,aAAa,QAAQ,QAAQ,aAAa,QAAQ,EAAE;AAExJ,qCAA2B,IAAI,GAAG,KAAK,SAAS,IAAI,eAAe,EAAE;AAErE,cAAI;AACJ,cAAI,QAAQ,SAAS,2BAAY,WAAW;AAC1C,mBAAO;AAAA,UACT;AACA,cAAI,QAAQ,SAAS,2BAAY,YAAY;AAC3C,mBAAO;AAAA,UACT;AACA,gBAAM,KAAK,mBAAmB,iBAAiB;AAAA,YAC7C,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,QAAQ,SAAS,GAAG,QAAQ,OAAO,IAAI,MAAM,QAAQ,IAAI,KAAK,QAAQ;AAAA,cAC5E;AAAA,YACF;AAAA,YACA,QAAQ;AAAA,cACN,WAAW,QAAQ;AAAA,YACrB;AAAA,UACF,CAAC;AACD,cAAI,QAAQ,SAAS,2BAAY,eAAe;AAC9C,kBAAM,KAAK,mBAAmB,GAAG,eAAe,aAAa;AAAA,cAC3D,MAAM;AAAA,cACN,QAAQ;AAAA,gBACN,MAAM,iBAAK,sBAAsB,UAAU;AAAA,cAC7C;AAAA,cACA,QAAQ,CAAC;AAAA,YACX,CAAC;AAAA,UACH;AAEA,gBAAM,QAAQ,IAAI;AAAA,YAChB,KAAK,mBAAmB,GAAG,eAAe,SAAS;AAAA,cACjD,MAAM;AAAA,cACN,QAAQ;AAAA,gBACN,MAAM,iBAAK,sBAAsB,WAAW;AAAA,gBAC5C,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,KAAK;AAAA,cACP;AAAA,cACA,QAAQ,CAAC;AAAA,YACX,CAAC;AAAA,YACD,KAAK,mBAAmB,GAAG,eAAe,gBAAgB;AAAA,cACxD,MAAM;AAAA,cACN,QAAQ;AAAA,gBACN,MAAM,iBAAK,sBAAsB,cAAc;AAAA,gBAC/C,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,KAAK;AAAA,cACP;AAAA,cACA,QAAQ,CAAC;AAAA,YACX,CAAC;AAAA,YACD,KAAK,mBAAmB,GAAG,eAAe,YAAY;AAAA,cACpD,MAAM;AAAA,cACN,QAAQ;AAAA,gBACN,MAAM,iBAAK,sBAAsB,SAAS;AAAA,gBAC1C,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,KAAK;AAAA,cACP;AAAA,cACA,QAAQ,CAAC;AAAA,YACX,CAAC;AAAA,UACH,CAAC;AAED,cAAI,QAAQ,SAAS,2BAAY,aAAa,QAAQ,SAAS,2BAAY,YAAY;AACrF,kBAAM,QAAQ,IAAI;AAAA,cAChB,KAAK,mBAAmB,GAAG,eAAe,YAAY;AAAA,gBACpD,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,cAAc;AAAA,kBAC/C,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,cACD,KAAK,mBAAmB,GAAG,eAAe,cAAc;AAAA,gBACtD,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,iBAAiB;AAAA,kBAClD,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,cACD,KAAK,mBAAmB,GAAG,eAAe,kBAAkB;AAAA,gBAC1D,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,qBAAqB;AAAA,kBACtD,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,cACD,KAAK,mBAAmB,GAAG,eAAe,qBAAqB;AAAA,gBAC7D,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,wBAAwB;AAAA,kBACzD,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,cACD,KAAK,mBAAmB,GAAG,eAAe,gBAAgB;AAAA,gBACxD,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,wBAAwB;AAAA,kBACzD,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,cAED,KAAK,mBAAmB,GAAG,eAAe,SAAS;AAAA,gBACjD,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,cAAc;AAAA,kBAC/C,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,cACD,KAAK,mBAAmB,GAAG,eAAe,aAAa;AAAA,gBACrD,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,WAAW;AAAA,kBAC5C,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,cACD,KAAK,mBAAmB,GAAG,eAAe,cAAc;AAAA,gBACtD,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,YAAY;AAAA,kBAC7C,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,cACD,KAAK,mBAAmB,GAAG,eAAe,iBAAiB;AAAA,gBACzD,MAAM;AAAA,gBACN,QAAQ;AAAA,kBACN,MAAM,iBAAK,sBAAsB,eAAe;AAAA,kBAChD,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,KAAK;AAAA,gBACP;AAAA,gBACA,QAAQ,CAAC;AAAA,cACX,CAAC;AAAA,YACH,CAAC;AAED,iBAAK,qBAAqB,IAAI,GAAG,KAAK,SAAS,IAAI,eAAe,UAAU;AAAA,UAC9E;AAEA,gBAAM,KAAK,wBAAwB,OAAO;AAAA,QAC5C;AAAA,MACF;AAKA,YAAM,iBAAiB,MAAM,KAAK,mBAAmB;AAAA,QACnD,UAAU,GAAG,KAAK,SAAS,YAAY,MAAM,EAAE;AAAA,QAC/C,QAAQ,GAAG,KAAK,SAAS,YAAY,MAAM,EAAE;AAAA,MAC/C,CAAC;AACD,YAAM,mBAAmB,IAAI,OAAO,IAAI,KAAK,IAAI,MAAM,KAAK,QAAQ,gBAAgB,MAAM,EAAE,oBAAoB;AAChH,iBAAW,QAAQ,eAAe,MAAM;AACtC,cAAM,IAAI,KAAK,GAAG,MAAM,gBAAgB;AACxC,YAAI,GAAG;AACL,gBAAM,WAAW,EAAE,CAAC;AACpB,cAAI,CAAC,MAAM,QAAQ,MAAM,IAAI,QAAQ,GAAG;AACtC,iBAAK,IAAI,MAAM,iBAAiB,QAAQ,cAAc,MAAM,EAAE,4CAA4C;AAC1G,iBAAK,eAAe,OAAO,GAAG,KAAK,SAAS,YAAY,MAAM,EAAE,YAAY,QAAQ,OAAO;AAC3F,kBAAM,KAAK,qBAAqB,WAAW,MAAM,EAAE,YAAY,QAAQ,IAAI,EAAE,WAAW,KAAK,CAAC;AAAA,UAChG;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAKA,eAAW,CAAE,EAAE,EAAE,MAAM,SAAS,CAAE,KAAK,iBAAiB;AACtD,WAAK,IAAI,MAAM,eAAe,KAAK,GAAG,OAAO,KAAK,EAAE,EAAE;AAEtD,YAAM,KAAK,mBAAmB,SAAS,KAAK,EAAE,IAAI;AAAA,QAChD,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,UAAM,4BAAc,IAAI;AAAA,QAC1B;AAAA,QACA,QAAQ;AAAA,UACN,QAAQ,KAAK;AAAA,QACf;AAAA,MACF,CAAC;AAED,YAAM,QAAQ,IAAI;AAAA,QAChB,KAAK,mBAAmB,SAAS,KAAK,EAAE,SAAS;AAAA,UAC/C,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,WAAW;AAAA,YAC5C,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QAED,KAAK,mBAAmB,SAAS,KAAK,EAAE,QAAQ;AAAA,UAC9C,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,UAAU;AAAA,YAC3C,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QAED,KAAK,mBAAmB,SAAS,KAAK,EAAE,SAAS;AAAA,UAC/C,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,WAAW;AAAA,YAC5C,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QAED,KAAK,mBAAmB,SAAS,KAAK,EAAE,YAAY;AAAA,UAClD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,cAAc;AAAA,YAC/C,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,SAAS,KAAK,EAAE,cAAc;AAAA,UACpD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,iBAAiB;AAAA,YAClD,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,SAAS,KAAK,EAAE,qBAAqB;AAAA,UAC3D,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,wBAAwB;AAAA,YACzD,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,SAAS,KAAK,EAAE,gBAAgB;AAAA,UACtD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,wBAAwB;AAAA,YACzD,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QAED,KAAK,mBAAmB,SAAS,KAAK,EAAE,SAAS;AAAA,UAC/C,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,cAAc;AAAA,YAC/C,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,SAAS,KAAK,EAAE,aAAa;AAAA,UACnD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,WAAW;AAAA,YAC5C,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,SAAS,KAAK,EAAE,cAAc;AAAA,UACpD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,YAAY;AAAA,YAC7C,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,SAAS,KAAK,EAAE,iBAAiB;AAAA,UACvD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,eAAe;AAAA,YAChD,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QAED,KAAK,mBAAmB,SAAS,KAAK,EAAE,cAAc;AAAA,UACpD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,QAAQ;AAAA,YACzC,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QAED,KAAK,mBAAmB,SAAS,KAAK,EAAE,QAAQ;AAAA,UAC9C,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,KAAK;AAAA,YACtC,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QAED,KAAK,mBAAmB,SAAS,KAAK,EAAE,WAAW;AAAA,UACjD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,QAAQ;AAAA,YACzC,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,SAAS,KAAK,EAAE,iBAAiB;AAAA,UACvD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,eAAe;AAAA,YAChD,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,QACD,KAAK,mBAAmB,SAAS,KAAK,EAAE,iBAAiB;AAAA,UACvD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM,iBAAK,sBAAsB,eAAe;AAAA,YAChD,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,KAAK;AAAA,UACP;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAAA,MACH,CAAC;AAED,WAAK,qBAAqB,IAAI,GAAG,KAAK,SAAS,UAAU,KAAK,EAAE,UAAU;AAE1E,WAAK,WAAW,IAAI,KAAK,EAAE;AAE3B,YAAM,KAAK,MAAM,KAAK,mBAAmB,KAAK,IAAI,UAAU,IAAI;AAEhE,YAAM,QAA4B,CAAC;AACnC,YAAM,OAAqB;AAAA,QACzB,IAAI,KAAK;AAAA,QACT,KAAK,KAAK;AAAA,QACV,MAAM,KAAK;AAAA,QACX,cAAc,GAAG;AAAA,QACjB,cAAc,GAAG;AAAA,QACjB,WAAW,KAAK,iBAAiB;AAAA,QACjC,KAAK,KAAK;AAAA,QACV,QAAQ,GAAG;AAAA,MACb;AACA,UAAI,KAAC,oCAAkB,MAAM,KAAK,eAAe,IAAI,GAAG,KAAK,SAAS,UAAU,KAAK,EAAE,OAAO,CAAC,GAAG;AAChG,cAAM,KAAK,KAAK,SAAS,SAAS,KAAK,EAAE,SAAS,KAAK,UAAU,IAAI,GAAG,IAAI,CAAC;AAC7E,aAAK,eAAe,IAAI,GAAG,KAAK,SAAS,UAAU,KAAK,EAAE,SAAS,IAAI;AAAA,MACzE;AACA,YAAM,QAAQ,IAAI;AAAA,QAChB,KAAK,SAAS,SAAS,KAAK,EAAE,QAAQ,KAAK,KAAK,IAAI;AAAA,QACpD,KAAK,SAAS,SAAS,KAAK,EAAE,SAAS,KAAK,UAAU,IAAI;AAAA,QAC1D,KAAK,SAAS,SAAS,KAAK,EAAE,cAAc,KAAK,WAAW,IAAI;AAAA,QAChE,KAAK,SAAS,SAAS,KAAK,EAAE,QAAQ,KAAK,KAAK,IAAI;AAAA,QACpD,GAAG;AAAA,QACH,KAAK,mBAAmB,KAAK,IAAI,QAAQ;AAAA,MAC3C,CAAC;AAAA,IAEH;AAKA,UAAM,iBAAiB,MAAM,KAAK,mBAAmB;AAAA,MACnD,UAAU,GAAG,KAAK,SAAS;AAAA,MAC3B,QAAQ,GAAG,KAAK,SAAS;AAAA,IAC3B,CAAC;AACD,UAAM,oBAAoB,IAAI,OAAO,IAAI,KAAK,IAAI,MAAM,KAAK,QAAQ,mDAAmD;AACxH,eAAW,QAAQ,eAAe,MAAM;AACtC,YAAM,IAAI,KAAK,GAAG,MAAM,iBAAiB;AACzC,UAAI,GAAG;AACL,cAAM,SAAS,EAAE,CAAC;AAClB,YAAI,CAAC,2BAA2B,IAAI,KAAK,EAAE,GAAG;AAC5C,eAAK,IAAI,MAAM,kBAAkB,MAAM,SAAK,yBAAW,KAAK,MAAM,MAAM,CAAC,6CAA6C;AACtH,eAAK,qBAAqB,OAAO,GAAG,KAAK,SAAS,YAAY,MAAM,UAAU;AAC9E,eAAK,eAAe,OAAO,GAAG,KAAK,SAAS,YAAY,MAAM,OAAO;AACrE,gBAAM,KAAK,qBAAqB,WAAW,MAAM,IAAI,EAAE,WAAW,KAAK,CAAC;AAAA,QAC1E;AAAA,MACF;AAAA,IACF;AAKA,UAAM,eAAe,MAAM,KAAK,mBAAmB;AAAA,MACjD,UAAU,GAAG,KAAK,SAAS;AAAA,MAC3B,QAAQ,GAAG,KAAK,SAAS;AAAA,IAC3B,CAAC;AACD,UAAM,UAAU,IAAI,OAAO,IAAI,KAAK,IAAI,MAAM,KAAK,QAAQ,oBAAoB;AAC/E,eAAW,QAAQ,aAAa,MAAM;AACpC,YAAM,IAAI,KAAK,GAAG,MAAM,OAAO;AAC/B,UAAI,GAAG;AACL,cAAM,SAAS,EAAE,CAAC;AAClB,YAAI,CAAC,gBAAgB,IAAI,MAAM,GAAG;AAChC,eAAK,IAAI,MAAM,QAAQ,MAAM,SAAK,yBAAW,KAAK,MAAM,MAAM,CAAC,6CAA6C;AAC5G,eAAK,WAAW,OAAO,MAAM;AAC7B,eAAK,qBAAqB,OAAO,GAAG,KAAK,SAAS,UAAU,MAAM,UAAU;AAC5E,eAAK,eAAe,OAAO,GAAG,KAAK,SAAS,UAAU,MAAM,OAAO;AACnE,gBAAM,KAAK,qBAAqB,SAAS,MAAM,IAAI,EAAE,WAAW,KAAK,CAAC;AAAA,QACxE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,wBAAyB,SAAoD;AACzF,UAAM,kBAAkB,QAAQ,WAAW,WAAW,QAAQ,OAAO,aAAa,QAAQ,QAAQ,aAAa,QAAQ,EAAE,KAAK,WAAW,QAAQ,MAAM,EAAE,aAAa,QAAQ,EAAE;AAEhL,UAAM,UAAU,CAAE,GAAG,QAAQ,QAAQ,OAAO,CAAE;AAC9C,UAAM,OAA+B;AAAA,MACnC,IAAI,QAAQ;AAAA,MACZ,MAAM,QAAQ;AAAA,MACd,MAAM,2BAAY,QAAQ,IAAI;AAAA,MAC9B,aAAa,QAAQ;AAAA,MACrB,SAAS,QAAQ,IAAI,CAAC,OAAO;AAAA,QAC3B,IAAI,EAAE,KAAK;AAAA,QACX,KAAK,EAAE,KAAK;AAAA,QACZ,MAAM,EAAE,KAAK;AAAA,QACb,aAAa,EAAE;AAAA,MACjB,EAAE;AAAA,IACJ;AACA,UAAM,QAA4B,CAAC;AACnC,QAAI,KAAC,oCAAkB,MAAM,KAAK,eAAe,IAAI,GAAG,KAAK,SAAS,IAAI,eAAe,OAAO,CAAC,GAAG;AAClG,YAAM,KAAK,KAAK,SAAS,GAAG,eAAe,SAAS,KAAK,UAAU,IAAI,GAAG,IAAI,CAAC;AAC/E,WAAK,eAAe,IAAI,GAAG,KAAK,SAAS,IAAI,eAAe,SAAS,IAAI;AAAA,IAC3E;AACA,UAAM,QAAQ,IAAI;AAAA,MAChB,KAAK,SAAS,GAAG,eAAe,gBAAgB,QAAQ,QAAQ,IAAI;AAAA,MACpE,KAAK,SAAS,GAAG,eAAe,YAAY,QAAQ,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,IAAI,GAAG,IAAI;AAAA,MAC9F,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,mBAAoB,QAAmB,UAA2B,sBAA+B,OAA0C;AACvJ,QAAI,CAAC,KAAK,OAAO,qBAAqB;AACpC,aAAO,EAAE,cAAc,IAAI,cAAc,IAAI,QAAQ,GAAG;AAAA,IAC1D;AAEA,QAAI,CAAC,KAAK,WAAW,IAAI,MAAM,GAAG;AAChC,WAAK,IAAI,MAAM,+CAA+C,MAAM,EAAE;AACtE,aAAO,EAAE,cAAc,IAAI,cAAc,IAAI,QAAQ,GAAG;AAAA,IAC1D;AAEA,QAAI;AACF,YAAM,IAA8B;AAAA,QAClC,QAAQ,UAAU,UAAU;AAAA,QAC5B,eAAe,UAAU,WAAW,CAAC,GAAG,SAAS,4BAAa,SAAS,UAAU,WAAW,CAAC,GAAG,QAAQ,UAAU,WAAW,CAAC,GAAG,SAAS;AAAA,QAC1I,eAAe,UAAU,WAAW,CAAC,GAAG,SAAS,SAAY,4BAAa,SAAS,WAAW,CAAC,EAAE,IAAI,IAAyB,OAAO;AAAA,MACvI;AAEA,YAAM,QAA4B,CAAC;AACnC,UAAI,CAAC,qBAAqB;AACxB,cAAM,OAAO,KAAK,eAAe,IAAI,GAAG,KAAK,SAAS,UAAU,MAAM,OAAO;AAC7E,YAAI,MAAM;AACR,eAAK,SAAS,EAAE;AAChB,eAAK,eAAe,EAAE;AACtB,eAAK,eAAe,EAAE;AACtB,eAAK,eAAe,IAAI,GAAG,KAAK,SAAS,UAAU,MAAM,SAAS,IAAI;AACtE,gBAAM,KAAK,KAAK,SAAS,SAAS,MAAM,SAAS,KAAK,UAAU,IAAI,GAAG,IAAI,CAAC;AAAA,QAC9E;AAAA,MACF;AACA,YAAM,QAAQ,IAAI;AAAA,QAChB,KAAK,SAAS,SAAS,MAAM,WAAW,EAAE,QAAQ,IAAI;AAAA,QACtD,KAAK,SAAS,SAAS,MAAM,iBAAiB,EAAE,cAAc,IAAI;AAAA,QAClE,KAAK,SAAS,SAAS,MAAM,iBAAiB,EAAE,cAAc,IAAI;AAAA,QAClE,GAAG;AAAA,MACL,CAAC;AACD,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,IAAI,KAAK,8CAA8C,MAAM,KAAK,GAAG,EAAE;AAC5E,aAAO,EAAE,cAAc,IAAI,cAAc,IAAI,QAAQ,GAAG;AAAA,IAC1D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAAgB,MAA6C;AACzE,QAAI,CAAC,KAAK,QAAQ;AAAM;AAExB,QAAI,CAAC,MAAM;AACT,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,UAAW,MAAM,KAAK,cAAc,YAAY,IAAI,OAA0C;AAAA,IACrG;AACA,QAAI,CAAC,8CAA2B,SAAS,KAAK,MAAM,GAAG;AACrD,WAAK,SAAS;AAAA,IAChB;AAEA,UAAM,eAA6B;AAAA,MACjC,QAAQ,KAAK;AAAA,MACb,YAAY,CAAC;AAAA,IACf;AAEA,QAAI,KAAK,iBAAiB,QAAW;AACnC,WAAK,gBAAiB,MAAM,KAAK,cAAc,kBAAkB,IAAI,OAAyC;AAAA,IAChH;AACA,QAAI,CAAC,kCAAe,SAAS,KAAK,YAAY,GAAG;AAC/C,WAAK,IAAI,KAAK,yBAAyB,KAAK,YAAY,EAAE;AAC1D,WAAK,eAAe;AAAA,IACtB;AACA,QAAI,KAAK,iBAAiB,QAAW;AACnC,WAAK,gBAAiB,MAAM,KAAK,cAAc,kBAAkB,IAAI,OAA8B;AAAA,IACrG;AACA,QAAI,KAAK,gBAAgB,KAAK,cAAc;AAC1C,mBAAa,aAAa,CAAE;AAAA,QAC1B,MAAM,4BAAa,KAAK,YAAY;AAAA,QACpC,MAAM,KAAK;AAAA,MACb,CAAE;AAAA,IACJ;AAEA,SAAK,IAAI,MAAM,qBAAqB,KAAK,UAAU,YAAY,CAAC,EAAE;AAClE,SAAK,OAAO,KAAK,YAAY,YAAY;AAAA,EAC3C;AAAA,EAOA,MAAc,sBAAuB,SAA0C;AAC7E,SAAK,IAAI,MAAM,wBAAwB,QAAQ,EAAE,QAAQ,QAAQ,SAAS,SAAS,QAAQ,OAAO,EAAE,MAAM,QAAQ,OAAO,EAAE;AAG3H,QAAI,KAAK,OAAO,iBAAiB;AAE/B,WAAK,KAAK,SAAS,mBAAmB,KAAK,UAAU,QAAQ,OAAO,GAAG,CAAC,MAAM,UAAmB,OAAO,UAAU,WAAW,MAAM,SAAS,IAAI,KAAK,GAAG,IAAI;AAAA,IAC9J;AAEA,QAAI,CAAC,KAAK,QAAQ,MAAM;AAAI;AAG5B,QAAI,QAAQ,qBAAqB;AAC/B;AAAA,IACF;AAEA,UAAM,EAAE,QAAQ,SAAS,QAAQ,IAAI;AAGrC,QAAI,OAAO,OAAO,KAAK,OAAO,KAAK,IAAI;AACrC;AAAA,IACF;AAEA,UAAM,kBAAkB,QAAQ,UAAU;AAE1C,UAAM,qBAAqB,KAAK,uBAAuB,eAAe;AAEtE,QAAI,CAAC,KAAK,OAAO,wCAAwC,CAAC,oBAAoB;AAC5E,WAAK,IAAI,MAAM,6CAAyC,4BAAc,MAAM,CAAC,QAAQ,OAAO,EAAE,GAAG;AACjG;AAAA,IACF;AAEA,UAAM,YAAY,QAAQ,SAAS,MAAM,IAAI,KAAK,OAAO,KAAK,EAAE;AAEhE,QAAI,aAAa,KAAK,OAAO,mBAAmB,oBAAoB;AAClE,UAAI;AACF,cAAM,QAAQ,MAAM,KAAK,OAAO,oBAAoB;AAAA,MACtD,SAAS,KAAK;AACZ,aAAK,IAAI,KAAK,0CAA0C,QAAQ,EAAE,KAAK,GAAG,EAAE;AAAA,MAC9E;AAAA,IACF;AAEA,QAAI,CAAC,cAAc,QAAQ,SAAS,2BAAY,aAAa,QAAQ,SAAS,2BAAY,eAAe,CAAC,KAAK,OAAO,mCAAmC;AACvJ,WAAK,IAAI,MAAM,gDAAgD;AAC/D;AAAA,IACF;AAEA,QAAI;AACJ,QAAI,QAAQ,SAAS,2BAAY,aAAa,QAAQ,SAAS,2BAAY,YAAY;AACrF,yBAAmB,QAAQ,WAAW,GAAG,KAAK,SAAS,YAAY,QAAQ,OAAO,aAAa,QAAQ,QAAQ,aAAa,QAAQ,EAAE,KAAK,GAAG,KAAK,SAAS,YAAY,QAAQ,OAAO,aAAa,QAAQ,EAAE;AAAA,IAChN,WAAW,QAAQ,SAAS,2BAAY,IAAI;AAC1C,yBAAmB,GAAG,KAAK,SAAS,UAAU,OAAO,EAAE;AAAA,IACzD,WAAW,QAAQ,SAAS,GAAG;AAC7B,WAAK,IAAI,MAAM,wBAAwB;AACvC;AAAA,IACF,OAAO;AACL,WAAK,IAAI,KAAK,kDAAkD,2BAAY,QAAQ,IAAI,CAAC,GAAG;AAC5F;AAAA,IACF;AAGA,QAAI,CAAC,KAAK,qBAAqB,IAAI,GAAG,gBAAgB,UAAU,GAAG;AACjE,WAAK,IAAI,MAAM,8BAA8B,gBAAgB,sCAAsC;AACnG;AAAA,IACF;AAGA,UAAM,OAAuB;AAAA,MAC3B;AAAA,MACA,aAAa,QAAQ,YAAY,IAAI,CAAC,SAAS,EAAE,YAAY,IAAI,KAAK,MAAM,IAAI,MAAM,aAAa,IAAI,eAAe,IAAI,MAAM,IAAI,MAAM,aAAa,IAAI,eAAe,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MAC3L,IAAI,QAAQ;AAAA,MACZ,UAAU,QAAQ,SAAS,SAAS,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,KAAK,KAAK,MAAM,EAAE,KAAK,UAAU,aAAa,EAAE,YAAY,EAAE,KAAK,CAAC;AAAA,MACvI;AAAA,MACA,WAAW,QAAQ;AAAA,MACnB,YAAY;AAAA,IACd;AACA,UAAM,QAA4B,CAAC;AACnC,QAAI,QAAQ,SAAS;AACnB,WAAK,SAAS;AAAA,QACZ,IAAI,OAAO;AAAA,QACX,KAAK,OAAO;AAAA,QACZ,MAAM,OAAO;AAAA,QACb,aAAa,KAAK,OAAO,OAAO,MAAM,IAAI,QAAQ,OAAO,GAAG,QAAQ,MAAM,IAAI,OAAO,EAAE,GAAG,eAAe,OAAO;AAAA,MAClH;AACA,YAAM,KAAK,KAAK,SAAS,GAAG,gBAAgB,sBAAkB,4BAAc,MAAM,GAAG,IAAI,CAAC;AAAA,IAC5F;AACA,QAAI,KAAC,oCAAkB,MAAM,KAAK,eAAe,IAAI,GAAG,KAAK,SAAS,IAAI,gBAAgB,cAAc,CAAC,GAAG;AAC1G,YAAM,KAAK,KAAK,SAAS,GAAG,gBAAgB,gBAAgB,KAAK,UAAU,IAAI,GAAG,IAAI,CAAC;AACvF,WAAK,eAAe,IAAI,GAAG,KAAK,SAAS,IAAI,gBAAgB,gBAAgB,IAAI;AAAA,IACnF;AACA,UAAM,QAAQ,IAAI;AAAA,MAChB,KAAK,SAAS,GAAG,gBAAgB,YAAY,SAAS,IAAI;AAAA,MAC1D,KAAK,SAAS,GAAG,gBAAgB,cAAc,QAAQ,IAAI,IAAI;AAAA,MAC/D,KAAK,SAAS,GAAG,gBAAgB,qBAAqB,QAAQ,kBAAkB,IAAI;AAAA,MACpF,GAAG;AAAA,IACL,CAAC;AAGD,QAAI,WAAW,KAAK,OAAO,wBAAwB,KAAK,oBAAoB,IAAI,GAAG,gBAAgB,UAAU,GAAG;AAE9G,UAAI,KAAK,uBAAuB,iBAAiB,EAAE,iBAAiB,KAAK,CAAC,GAAG;AAE3E,aAAK,IAAI,MAAM,YAAY,OAAO,QAAQ,KAAK,OAAO,oBAAoB,EAAE;AAE5E,cAAM,UAAsC;AAAA,UAC1C,MAAM;AAAA,QACR;AAEA,aAAK,OAAO,KAAK,OAAO,sBAAsB,QAAQ,SAAS,OAAO,gBAAgB;AAEpF,gBAAM,WAAgC,aAAmE;AACzG,cAAI;AACF,gBAAI,CAAC,UAAU;AACb,mBAAK,IAAI,MAAM,uBAAuB,KAAK,OAAO,oBAAoB,EAAE;AACxE;AAAA,YACF;AACA,iBAAK,IAAI,MAAM,iBAAiB,KAAK,OAAO,oBAAoB,KAAK,QAAQ,EAAE;AAC/E,oBAAQ,KAAK,OAAO,yBAAyB;AAAA,cAC3C,KAAK;AACH,sBAAM,QAAQ,MAAM,QAAQ;AAC5B;AAAA,cACF,KAAK;AACH,oBAAI,QAAQ,QAAQ,YAAY,GAAG;AACjC,wBAAO,QAAQ,QAAoC,KAAK,QAAQ;AAAA,gBAClE;AACA;AAAA,cACF;AAAA,YAEF;AAAA,UACF,SAAS,KAAK;AACZ,iBAAK,IAAI,KAAK,oCAAoC,QAAQ,UAAU,KAAK,OAAO,oBAAoB,KAAK,GAAG,EAAE;AAAA,UAChH;AAAA,QACF,CAAC;AAAA,MACH,OAAO;AAEL,aAAK,IAAI,MAAM,YAAQ,4BAAc,MAAM,CAAC,QAAQ,OAAO,EAAE,mCAAmC;AAAA,MAClG;AAAA,IACF;AAAA,EAEF;AAAA,EAMA,MAAc,yBAA0B,UAAsB,UAAqC;AACjG,QAAI,CAAC,SAAS,QAAQ,IAAI;AACxB;AAAA,IACF;AAEA,UAAM,QAA4B,CAAC;AAGnC,QAAI,SAAS,cAAc,SAAS,WAAW;AAC7C,UAAI,SAAS,SAAS;AACpB,cAAM,KAAK,KAAK,wBAAwB,SAAS,OAAO,CAAC;AAAA,MAC3D;AACA,UAAI,SAAS,SAAS;AACpB,cAAM,KAAK,KAAK,wBAAwB,SAAS,OAAO,CAAC;AAAA,MAC3D;AAAA,IACF;AAGA,QAAI,KAAK,WAAW,IAAI,SAAS,OAAO,EAAE,GAAG;AAC3C,YAAM,OAA8B;AAAA,QAClC,GAAG,KAAK,eAAe,IAAI,GAAG,KAAK,SAAS,YAAY,SAAS,MAAM,EAAE,YAAY,SAAS,OAAO,EAAE,OAAO;AAAA,MAChH;AAEA,UAAI,SAAkB;AAEtB,UAAI,SAAS,cAAc,SAAS,WAAW;AAC7C,cAAM,KAAK,KAAK,SAAS,WAAW,SAAS,MAAM,EAAE,YAAY,SAAS,OAAO,EAAE,iBAAiB,SAAS,SAAS,QAAQ,IAAI,IAAI,CAAC;AACvI,aAAK,eAAe,SAAS,SAAS,QAAQ;AAC9C,aAAK,iBAAiB,SAAS,SAAS,MAAM;AAC9C,iBAAS;AAAA,MACX;AACA,UAAI,SAAS,eAAe,SAAS,YAAY;AAC/C,cAAM,KAAK,KAAK,SAAS,WAAW,SAAS,MAAM,EAAE,YAAY,SAAS,OAAO,EAAE,oBAAoB,CAAC,CAAC,SAAS,YAAY,IAAI,CAAC;AACnI,aAAK,gBAAgB,CAAC,CAAC,SAAS;AAChC,iBAAS;AAAA,MACX;AACA,UAAI,SAAS,aAAa,SAAS,UAAU;AAC3C,cAAM,KAAK,KAAK,SAAS,WAAW,SAAS,MAAM,EAAE,YAAY,SAAS,OAAO,EAAE,kBAAkB,CAAC,CAAC,SAAS,UAAU,IAAI,CAAC;AAC/H,aAAK,kBAAkB,CAAC,CAAC,SAAS;AAClC,iBAAS;AAAA,MACX;AACA,UAAI,SAAS,eAAe,SAAS,YAAY;AAC/C,cAAM,KAAK,KAAK,SAAS,WAAW,SAAS,MAAM,EAAE,YAAY,SAAS,OAAO,EAAE,oBAAoB,CAAC,CAAC,SAAS,YAAY,IAAI,CAAC;AACnI,aAAK,gBAAgB,CAAC,CAAC,SAAS;AAChC,iBAAS;AAAA,MACX;AACA,UAAI,SAAS,aAAa,SAAS,UAAU;AAC3C,cAAM,KAAK,KAAK,SAAS,WAAW,SAAS,MAAM,EAAE,YAAY,SAAS,OAAO,EAAE,kBAAkB,CAAC,CAAC,SAAS,UAAU,IAAI,CAAC;AAC/H,aAAK,kBAAkB,CAAC,CAAC,SAAS;AAClC,iBAAS;AAAA,MACX;AAGA,UAAI,QAAQ;AACV,cAAM,KAAK,KAAK,SAAS,WAAW,SAAS,MAAM,EAAE,YAAY,SAAS,OAAO,EAAE,SAAS,KAAK,UAAU,IAAI,GAAG,IAAI,CAAC;AACvH,aAAK,eAAe,IAAI,GAAG,KAAK,SAAS,YAAY,SAAS,MAAM,EAAE,YAAY,SAAS,OAAO,EAAE,SAAS,IAAI;AAAA,MACnH;AAAA,IAEF,OAAO;AACL,WAAK,IAAI,MAAM,kDAAkD,SAAS,OAAO,EAAE,EAAE;AAAA,IACvF;AAEA,UAAM,QAAQ,IAAI,KAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,eAAgB,OAAe,WAAqD,WAAiD;AAEjJ,QAAI,MAAM,WAAW,GAAG,KAAK,SAAS,GAAG,KAAK,MAAM,SAAS,UAAU,GAAG;AACxE,UAAI,WAAW,WAAW,UAAU,oBAAoB;AACtD,aAAK,IAAI,MAAM,0CAA0C,KAAK,EAAE;AAChE,aAAK,oBAAoB,IAAI,KAAK;AAAA,MACpC,WAAW,KAAK,oBAAoB,IAAI,KAAK,GAAG;AAC9C,aAAK,IAAI,MAAM,2CAA2C,KAAK,EAAE;AACjE,aAAK,oBAAoB,OAAO,KAAK;AAAA,MACvC;AAAA,IACF;AAEA,QAAI,WAAW,gBAAgB;AAI7B,UAAI,CAAC,WAAW;AACd,cAAM,MAAM,MAAM,KAAK,sBAAsB,KAAK;AAClD,YAAI,KAAK,SAAS,SAAS;AACzB,sBAAY,IAAI;AAAA,QAClB,OAAO;AACL,eAAK,IAAI,KAAK,UAAU,KAAK,uFAAuF;AAAA,QACtH;AAAA,MACF;AAGA,UAAI,OAAO,UAAU;AACrB,UAAI,CAAC,QAAQ,WAAW;AACtB,YAAI,OAAO,UAAU,SAAS,UAAU;AACtC,iBAAO,UAAU,KAAK,iBAAK,QAAQ,KAAK,UAAU,KAAK;AAAA,QACzD,OAAO;AACL,iBAAO,UAAU;AAAA,QACnB;AAAA,MACF;AAEA,YAAM,MAA2B;AAAA,QAC/B,IAAI;AAAA,QACJ,OAAO,UAAU,iBAAiB;AAAA,QAClC,MAAM,QAAQ;AAAA,QACd,KAAK,CAAC,CAAC,UAAU;AAAA,QACjB,KAAK,CAAC,CAAC,UAAU;AAAA,MACnB;AAGA,UAAI,QAAiB;AACrB,UAAI,IAAI,KAAK,SAAS,KAAK;AACzB,aAAK,IAAI,KAAK,oBAAoB,KAAK,+DAA+D;AACtG,gBAAQ;AAAA,MACV;AACA,UAAI,CAAE,0BAA0B,KAAK,IAAI,KAAK,GAAI;AAChD,aAAK,IAAI,KAAK,qBAAqB,KAAK,yFAAyF;AACjI,gBAAQ;AAAA,MACV;AAGA,WAAK,qBAAqB,mBAAmB,OAAO,QAAQ,MAAM,IAAI;AAAA,IAExE,OAAO;AAEL,WAAK,qBAAqB,mBAAmB,OAAO,IAAI;AAAA,IAC1D;AAAA,EACF;AAAA,EAMQ,eAAgB,OAAe,KAA+C;AACpF,QAAI,KAAK;AAEP,UAAI,IAAI,SAAS,SAAS;AACxB,aAAK,IAAI,MAAM,UAAU,KAAK,aAAa,KAAK,UAAU,GAAG,CAAC,EAAE;AAEhE,aAAK,KAAK,eAAe,OAAO,IAAI,QAAQ,SAAS,KAAK,SAAS,GAAG,IAAI,MAAM;AAAA,MAClF;AAAA,IACF,OAAO;AAEL,WAAK,IAAI,MAAM,UAAU,KAAK,UAAU;AACxC,WAAK,KAAK,eAAe,OAAO,IAAI;AAAA,IACtC;AAAA,EACF;AAAA,EAMA,MAAc,cAAe,SAAiB,OAAyD;AACrG,SAAK,IAAI,MAAM,kBAAkB,OAAO,IAAI,OAAO,GAAG,SAAS,OAAO,GAAG,GAAG;AAE5E,QAAI,CAAC,SAAS,MAAM;AAAK;AAEzB,QAAI,SAAS;AAKb,QAAI,QAAQ,WAAW,GAAG,KAAK,SAAS,GAAG,GAAG;AAE5C,cAAQ,SAAS;AAAA,QACf,KAAK,GAAG,KAAK,SAAS;AACpB,gBAAM,KAAK,eAAe,EAAE,QAAQ,MAAM,IAA0B,CAAC;AACrE,mBAAS;AACT;AAAA,QACF,KAAK,GAAG,KAAK,SAAS;AACpB,gBAAM,KAAK,eAAe,EAAE,cAAc,MAAM,IAAyB,CAAC;AAC1E,mBAAS;AACT;AAAA,QACF,KAAK,GAAG,KAAK,SAAS;AACpB,gBAAM,KAAK,eAAe,EAAE,cAAc,MAAM,IAAc,CAAC;AAC/D,mBAAS;AACT;AAAA,QAEF;AAEE,cAAI,8CAA8C,KAAK,OAAO,GAAG;AAC/D,qBAAS,MAAM,KAAK,oCAAoC,SAAS,KAAK;AAAA,UAGxE,WAAW,0DAA0D,KAAK,OAAO,GAAG;AAElF,iBAAK,qBAAqB,oCAAoC;AAC9D,qBAAS;AAAA,UAGX,WAAW,QAAQ,SAAS,OAAO,KAAK,QAAQ,SAAS,WAAW,KAAK,QAAQ,SAAS,YAAY,KAAK,QAAQ,SAAS,eAAe,GAAG;AAC5I,qBAAS,MAAM,KAAK,kBAAkB,SAAS,KAAK;AAAA,UAGtD,WAAW,QAAQ,SAAS,kBAAkB,KAAK,QAAQ,SAAS,kBAAkB,KAAK,QAAQ,SAAS,kBAAkB,GAAG;AAC/H,qBAAS,MAAM,KAAK,mBAAmB,SAAS,KAAK;AAAA,UAEvD;AAAA,MACJ;AAAA,IAEF;AAEA,QAAI,QAAQ;AACV,YAAM,KAAK,SAAS,SAAS;AAAA,QAC3B,GAAG;AAAA,QACH,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AAAA,EAEF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,kBAAmB,SAAiB,OAAyC;AAEzF,QAAI,CAAC,KAAK,QAAQ,QAAQ,GAAG;AAC3B,WAAK,IAAI,KAAK,SAAS,OAAO,mCAAmC;AACjE,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,MAAM,QAAQ,UAAU;AACjC,WAAK,IAAI,KAAK,SAAS,OAAO,qCAAqC;AACnE,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,IAAI,WAAW,GAAG;AAC1B,WAAK,IAAI,MAAM,SAAS,OAAO,6BAA6B;AAC5D,aAAO;AAAA,IACT;AAEA,QAAI;AACJ,QAAI;AACJ,QAAI,aAAqB;AACzB,QAAI;AAGJ,QAAI,IAAI,gHAAgH,KAAK,OAAO;AACpI,QAAI,GAAG;AACL,YAAM,UAAU,EAAE,CAAC;AACnB,YAAM,YAAY,EAAE,CAAC,KAAK,EAAE,CAAC;AAC7B,0BAAoB,EAAE,CAAC;AACvB,eAAS,EAAE,CAAC;AAEZ,YAAM,UAAU,KAAK,OAAO,OAAO,MAAM,IAAI,OAAO,GAAG,SAAS,MAAM,IAAI,SAAS;AACnF,UAAI,CAAC,WAAY,QAAQ,SAAS,2BAAY,aAAa,QAAQ,SAAS,2BAAY,cAAe,QAAQ,SAAS,GAAG;AACzH,aAAK,IAAI,KAAK,SAAS,OAAO,kDAAkD;AAChF,eAAO;AAAA,MACT;AAEA,eAAS;AACT,mBAAa,QAAQ,SAAS,GAAG,QAAQ,MAAM,IAAI,IAAI,QAAQ,OAAO,IAAI,IAAI,QAAQ,IAAI,KAAK,GAAG,QAAQ,MAAM,IAAI,IAAI,QAAQ,IAAI;AAAA,IAEtI,OAAO;AACL,UAAI,yEAAyE,KAAK,OAAO;AACzF,UAAI,CAAC,GAAG;AACN,aAAK,IAAI,KAAK,SAAS,OAAO,6DAA6D;AAC3F,eAAO;AAAA,MACT;AACA,YAAM,SAAS,EAAE,CAAC;AAClB,0BAAoB,EAAE,CAAC;AACvB,eAAS,EAAE,CAAC;AAEZ,YAAM,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,MAAM;AAC/C,UAAI,CAAC,MAAM;AACT,aAAK,IAAI,KAAK,SAAS,OAAO,0CAA0C;AACxE,eAAO;AAAA,MACT;AAEA,eAAS;AACT,uBAAa,4BAAc,IAAI;AAAA,IACjC;AAEA,QAAI;AAKJ,QAAI,WAAW,YAAY;AACzB,YAAM,MAAM,MAAM,IAAI,QAAQ,GAAG;AACjC,UAAI;AACJ,UAAI;AACJ,UAAI,MAAM,GAAG;AACX,eAAO,MAAM,IAAI,MAAM,GAAG,GAAG;AAC7B,kBAAU,MAAM,IAAI,MAAM,MAAM,CAAC;AAAA,MACnC,OAAO;AACL,eAAO,MAAM;AAAA,MACf;AAGA,YAAM,cAAU,+CAAiC,IAAI;AACrD,UAAI,SAAS;AAEX,aAAK;AAAA,UACH;AAAA,UACA,OAAO,CAAE;AAAA,YACP,YAAY,QAAQ;AAAA,YACpB,MAAM,QAAQ;AAAA,UAChB,CAAE;AAAA,QACJ;AAAA,MAEF,OAAO;AAEL,cAAM,WAAO,2CAA6B,IAAI;AAG9C,YAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,iBAAO,KAAK,MAAM,CAAC;AAAA,QACrB;AAEA,aAAK;AAAA,UACH;AAAA,UACA,OAAO,CAAE;AAAA,YACP,YAAY;AAAA,YACZ;AAAA,UACF,CAAE;AAAA,QACJ;AAAA,MACF;AAAA,IAKF,WAAW,WAAW,eAAe,WAAW,gBAAgB;AAC9D,YAAM,MAAM,MAAM,IAAI,QAAQ,GAAG;AACjC,UAAI;AACJ,UAAI;AACJ,UAAI,MAAM,GAAG;AACX,2BAAmB,MAAM,IAAI,MAAM,GAAG,GAAG;AACzC,kBAAU,MAAM,IAAI,MAAM,MAAM,CAAC;AAAA,MACnC,OAAO;AAEL,aAAK,IAAI,MAAM,8DAA8D,iBAAiB,EAAE;AAChG,4BAAoB,MAAM,KAAK,qBAAqB,GAAG,iBAAiB,YAAY,IAAI;AACxF,kBAAU,MAAM;AAAA,MAClB;AAEA,UAAI,WAAW,aAAa;AAE1B,YAAI,CAAC,oBAAoB,CAAC,SAAS;AACjC,eAAK,IAAI,KAAK,oDAAoD,OAAO,GAAG;AAC5E,iBAAO;AAAA,QACT;AAEA,YAAI;AACF,eAAK,KAAK,+BAA+B,MAAM,GAAG;AAAA,QACpD,SAAS,KAAK;AACZ,eAAK,IAAI,MAAM,SAAS,OAAO,sBAAsB,GAAG,EAAE;AAC1D,iBAAO;AAAA,QACT;AAGA,YAAI,CAAC,GAAG,OAAO;AACb,aAAG,QAAQ;AAAA,YACT;AAAA,UACF;AAAA,QACF,WAAW,CAAC,GAAG,MAAM,kBAAkB;AACrC,aAAG,MAAM,mBAAmB;AAAA,QAC9B;AAAA,MAEF,OAAO;AAEL,YAAI,CAAC,oBAAoB,CAAC,SAAS;AACjC,eAAK,IAAI,KAAK,+DAA+D,OAAO,GAAG;AACvF,iBAAO;AAAA,QACT;AAEA,cAAM,UAAU,kBAAkB,sBAAO,OAAO,aAAa,MAAM,OAAO,SAAS,IAAI;AACvF,YAAI,QAAQ,SAAS,2BAAY,aAAa,QAAQ,SAAS,2BAAY,cAAc,QAAQ,SAAS,2BAAY,IAAI;AACxH,eAAK,IAAI,KAAK,mDAAmD,OAAO,GAAG;AAC3E,iBAAO;AAAA,QACT;AAGA,cAAM,UAAwC,QAAQ,SAAS,MAAM,IAAI,gBAAgB,KAAK,MAAM,QAAQ,SAAS,MAAM,gBAAgB;AAC3I,YAAI,CAAC,SAAS;AACZ,eAAK,IAAI,KAAK,mDAAmD,OAAO,GAAG;AAC3E,iBAAO;AAAA,QACT;AAEA,YAAI;AACF,gBAAM,QAAQ,MAAM,OAAO;AAC3B,iBAAO;AAAA,QACT,SAAS,KAAK;AACZ,eAAK,IAAI,KAAK,oBAAoB,OAAO,YAAY,GAAG,EAAE;AAC1D,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IAMF,OAAO;AACL,UAAI;AACF,aAAK,KAAK,+BAA+B,MAAM,GAAG;AAAA,MACpD,SAAS,KAAK;AACZ,aAAK,IAAI,MAAM,SAAS,OAAO,sBAAsB,GAAG,EAAE;AAC1D,eAAO;AAAA,MACT;AAAA,IACF;AAEA,SAAK,IAAI,MAAM,WAAW,UAAU,KAAK,KAAK,UAAU,EAAE,CAAC,EAAE;AAC7D,QAAI;AACF,YAAM,MAAM,MAAM,OAAO,KAAK,KAAK,sBAAsB,EAAE,CAAC;AAC5D,WAAK,IAAI,MAAM,wBAAwB,IAAI,EAAE,EAAE;AAC/C,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,IAAI,KAAK,0BAA0B,OAAO,OAAO,UAAU,KAAK,GAAG,EAAE;AAC1E,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,oCAAqC,SAAiB,OAAyC;AAE3G,QAAI,CAAC,KAAK,QAAQ,QAAQ,GAAG;AAC3B,WAAK,IAAI,KAAK,SAAS,OAAO,mCAAmC;AACjE,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,MAAM,QAAQ,UAAU;AACjC,WAAK,IAAI,KAAK,SAAS,OAAO,qCAAqC;AACnE,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,IAAI,WAAW,GAAG;AAC1B,WAAK,IAAI,MAAM,SAAS,OAAO,6BAA6B;AAC5D,aAAO;AAAA,IACT;AAEA,UAAM,oBAAoB,QAAQ,QAAQ,UAAU,EAAE;AAEtD,UAAM,MAAM,MAAM,IAAI,QAAQ,GAAG;AACjC,QAAI;AACJ,QAAI;AACJ,QAAI,MAAM,GAAG;AACX,sBAAgB,MAAM,IAAI,MAAM,GAAG,GAAG;AACtC,gBAAU,MAAM,IAAI,MAAM,MAAM,CAAC;AAAA,IACnC,OAAO;AAEL,WAAK,IAAI,MAAM,sEAAsE,iBAAiB,EAAE;AACxG,uBAAiB,MAAM,KAAK,qBAAqB,GAAG,iBAAiB,gBAAgB,IAAI;AACzF,gBAAU,MAAM;AAAA,IAClB;AAEA,QAAI,CAAC,iBAAiB,CAAC,SAAS;AAC9B,WAAK,IAAI,KAAK,wDAAwD,OAAO,GAAG;AAChF,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,KAAK,qBAAqB,mBAAmB,eAAe,OAAO;AACzE,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,IAAI,KAAK,uCAAuC,aAAa,6BAA6B,GAAG,EAAE;AACpG,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBAAoB,SAAiB,OAAyC;AAC1F,UAAM,IAAI,0FAA0F,KAAK,OAAO;AAChH,QAAI,CAAC,GAAG;AACN,WAAK,IAAI,MAAM,eAAe,OAAO,mDAAmD;AACxF,aAAO;AAAA,IACT;AACA,UAAM,CAAE,EAAE,SAAS,UAAU,MAAO,IAAI;AAExC,UAAM,QAAQ,KAAK,QAAQ,OAAO,MAAM,IAAI,OAAO;AACnD,UAAM,SAAS,OAAO,QAAQ,MAAM,IAAI,QAAQ;AAChD,QAAI,CAAC,SAAS,CAAC,QAAQ;AACrB,WAAK,IAAI,KAAK,eAAe,OAAO,+CAA+C;AACnF,aAAO;AAAA,IACT;AAEA,QAAI;AACF,cAAQ,QAAQ;AAAA,QACd,KAAK;AACH,cAAI,CAAC,MAAM,KAAK;AACd,mBAAO;AAAA,UACT;AACA,gBAAM,OAAO,MAAM,WAAW;AAC9B,eAAK,IAAI,MAAM,oBAAgB,4BAAc,OAAO,IAAI,CAAC,cAAc,MAAM,IAAI,gBAAgB;AACjG;AAAA,QAEF,KAAK;AACH,gBAAM,OAAO,MAAM,QAAQ,CAAC,CAAC,MAAM,GAAG;AACtC,eAAK,IAAI,MAAM,qCAAiC,4BAAc,OAAO,IAAI,CAAC,cAAc,MAAM,IAAI,WAAW,CAAC,CAAC,MAAM,GAAG,GAAG;AAC3H;AAAA,QAEF,KAAK;AACH,gBAAM,OAAO,MAAM,QAAQ,CAAC,CAAC,MAAM,GAAG;AACtC,eAAK,IAAI,MAAM,mCAA+B,4BAAc,OAAO,IAAI,CAAC,cAAc,MAAM,IAAI,WAAW,CAAC,CAAC,MAAM,GAAG,GAAG;AACzH;AAAA,QAEF;AAEE,iBAAO;AAAA,MACX;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,WAAK,IAAI,KAAK,qCAAiC,4BAAc,OAAO,IAAI,CAAC,cAAc,MAAM,IAAI,mBAAmB,GAAG,EAAE;AACzH,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAMA,MAAc,UAAW,KAAsC;AAC7D,QAAI,OAAO,QAAQ;AAAU;AAC7B,SAAK,IAAI,MAAM,gBAAgB,KAAK,UAAU,GAAG,CAAC,EAAE;AAGpD,QAAI;AACJ,QAAI;AACJ,QAAI;AAEJ,YAAQ,IAAI,SAAS;AAAA,MACnB,KAAK,4BAA4B;AAC/B,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AACA,cAAM,OAAO,MAAM,KAAK,mBAAmB,UAAU,YAAY;AAAA,UAC/D,UAAU;AAAA,UACV,QAAQ;AAAA,QACV,CAAC;AACD,cAAM,wBAAwB,KAAK,KAAK,IAAI,CAAC,MAAM;AACjD,gBAAM,KAAK,EAAE,GAAG,MAAM,EAAE;AACxB,iBAAO;AAAA,YACL,OAAO;AAAA,YACP,OAAO;AAAA,UACT;AAAA,QACF,CAAC;AACD,aAAK,IAAI,MAAM,iCAAiC,sBAAsB,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;AAC3F,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS,CAAE,EAAE,OAAO,IAAI,OAAO,MAAM,GAAG,GAAG,qBAAsB,GAAG,IAAI,QAAQ;AAC1G;AAAA,MACF;AAAA,MAEA,KAAK,0BAA0B;AAC7B,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,cAAM,UAA8C,CAAE,EAAE,OAAO,IAAI,OAAO,MAAM,CAAE;AAGlF,aAAK,QAAQ,MAAM,MAAM,QAAQ,CAAC,MAAM;AACtC,kBAAQ,KAAK,EAAE,WAAO,4BAAc,CAAC,GAAG,OAAO,EAAE,GAAG,CAAC;AAAA,QACvD,CAAC;AAGD,aAAK,QAAQ,OAAO,MAAM,QAAQ,CAAC,MAAM;AACvC,YAAE,SAAS,MAAM,QAAQ,CAAC,MAAM;AAC9B,gBAAI,EAAE,SAAS,2BAAY,WAAW;AACpC,kBAAI,EAAE,QAAQ;AAEZ,wBAAQ,KAAK,EAAE,OAAO,GAAG,EAAE,IAAI,SAAM,EAAE,OAAO,IAAI,SAAM,EAAE,IAAI,IAAI,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC;AAAA,cAC9F,OAAO;AAEL,wBAAQ,KAAK,EAAE,OAAO,GAAG,EAAE,IAAI,SAAM,EAAE,IAAI,IAAI,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC;AAAA,cAC3E;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH,CAAC;AAED,aAAK,IAAI,MAAM,yBAAyB,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;AACrE,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS,SAAS,IAAI,QAAQ;AACxD;AAAA,MACF;AAAA,MAEA,KAAK,YAAY;AACf,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,cAAM,QAAQ,KAAK,QAAQ,MAAM,MAAM,IAAI,CAAC,OAAO,EAAE,WAAO,4BAAc,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;AAClG,aAAK,IAAI,MAAM,UAAU,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;AACpD,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS,OAAO,IAAI,QAAQ;AACtD;AAAA,MACF;AAAA,MAEA,KAAK,cAAc;AACjB,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,cAAM,UAAU,KAAK,QAAQ,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC;AAC3F,aAAK,IAAI,MAAM,YAAY,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;AACxD,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS,SAAS,IAAI,QAAQ;AACxD;AAAA,MACF;AAAA,MAEA,KAAK,kBAAkB;AACrB,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,YAAI,CAAC,KAAK,QAAQ;AAChB,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,QAAQ;AACnD;AAAA,QACF;AAEA,cAAM,sBAAsB,CAAC;AAC7B,mBAAW,CAAE,EAAE,KAAM,KAAK,KAAK,OAAO,OAAO,OAAO;AAClD,qBAAW,CAAE,EAAE,IAAK,KAAK,MAAM,MAAM,OAAO;AAC1C,gCAAoB,KAAK;AAAA,cACvB,OAAO,GAAG,MAAM,IAAI,MAAM,KAAK,IAAI;AAAA,cACnC,OAAO,GAAG,MAAM,EAAE,IAAI,KAAK,EAAE;AAAA,YAC/B,CAAC;AAAA,UACH;AAAA,QACF;AAEA,aAAK,IAAI,MAAM,iBAAiB,oBAAoB,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;AACzE,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS,qBAAqB,IAAI,QAAQ;AAEpE;AAAA,MACF;AAAA,MAEA,KAAK,sBAAsB;AACzB,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AACA,YAAI,KAAK,QAAQ,MAAM,IAAI;AACzB,gBAAM,QAAQ,IAAI,mCAAoB;AAAA,YACpC,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,YAC1B,mCAAoB,MAAM;AAAA,UAC5B,CAAC;AACD,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,sDAAsD,KAAK,OAAO,KAAK,EAAE,gBAAgB,MAAM,QAAQ,sCAAsC,IAAI,QAAQ;AAAA,QAC9L,OAAO;AACL,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,KAAK,iBAAK,UAAU,6CAA6C,CAAC,MAAM,IAAI,QAAQ;AAAA,QACzH;AACA;AAAA,MACF;AAAA,MAEA,KAAK,+BAA+B;AAClC,aAAK,qBAAqB,4BAA4B;AACtD,aAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,QAAQ,KAAK,GAAG,IAAI,QAAQ;AACrE;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK,eAAe;AAIlB,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AACtG;AAAA,QACF;AAEA,cAAM,cAAc,IAAI;AAGxB,YAAI,CAAC,YAAY,WAAY,OAAO,YAAY,YAAY,YAAY,OAAO,YAAY,YAAY,UAAW;AAChH,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,2DAA2D,GAAG,YAAY,GAAG,IAAI,QAAQ;AACzI;AAAA,QACF;AAEA,YAAI,YAAY,UAAU,YAAY,WAAW,YAAY,UAAU;AAErE,cAAI,YAAY,QAAQ;AAEtB,mBAAO,KAAK,QAAQ,MAAM,MAAM,IAAI,YAAY,MAAM;AACtD,gBAAI,CAAC,MAAM;AACT,mBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uBAAuB,YAAY,MAAM,UAAU,GAAG,YAAY,GAAG,IAAI,QAAQ;AACjI;AAAA,YACF;AAAA,UACF,WAAW,YAAY,SAAS;AAE9B,mBAAO,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,QAAQ,YAAY,OAAO;AACzE,gBAAI,CAAC,MAAM;AACT,mBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,wBAAwB,YAAY,OAAO,UAAU,GAAG,YAAY,GAAG,IAAI,QAAQ;AACnI;AAAA,YACF;AAAA,UACF,OAAO;AAEL,mBAAO,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,kBAAkB,OAAO,EAAE,aAAa,YAAY,QAAQ;AAC1G,gBAAI,CAAC,MAAM;AACT,mBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,gCAAgC,YAAY,QAAQ,UAAU,GAAG,YAAY,GAAG,IAAI,QAAQ;AAC5I;AAAA,YACF;AAAA,UACF;AACA,cAAI;AACF,kBAAM,MAAM,KAAK,KAAK,KAAK,sBAAsB,YAAY,OAAO,CAAC;AACrE,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,QAAQ,4BAAwB,4BAAc,IAAI,CAAC,IAAI,GAAG,aAAa,WAAW,IAAI,GAAG,GAAG,IAAI,QAAQ;AAAA,UACnJ,SAAS,KAAK;AACZ,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,qCAAiC,4BAAc,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,QAAQ;AAAA,UAChJ;AAAA,QAEF,WAAW,YAAY,YAAY,YAAY,WAAW;AAExD,oBAAU,KAAK,QAAQ,OAAO,MAAM,IAAI,YAAY,QAAQ,GAAG,SAAS,MAAM,IAAI,YAAY,SAAS;AACvG,cAAI,SAAS,SAAS,2BAAY,aAAa,SAAS,SAAS,2BAAY,YAAY;AACvF,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,kCAAkC,YAAY,SAAS,cAAc,YAAY,QAAQ,UAAU,GAAG,YAAY,GAAG,IAAI,QAAQ;AACjL;AAAA,UACF;AACA,cAAI;AACF,kBAAM,MAAM,QAAQ,KAAK,KAAK,sBAAsB,YAAY,OAAO,CAAC;AACxE,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,QAAQ,2BAA2B,QAAQ,IAAI,IAAI,GAAG,aAAa,WAAW,IAAI,GAAG,GAAG,IAAI,QAAQ;AAAA,UAC/I,SAAS,KAAK;AACZ,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,oCAAoC,QAAQ,IAAI,KAAK,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,QAAQ;AAAA,UAC5I;AAAA,QAEF,OAAO;AAEL,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uEAAuE,GAAG,YAAY,GAAG,IAAI,QAAQ;AAAA,QACvJ;AAEA;AAAA,MACF;AAAA,MAEA,KAAK,eAAe;AAIlB,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AACtG;AAAA,QACF;AAEA,cAAM,qBAAqB,IAAI;AAG/B,YAAI,CAAC,mBAAmB,WAAY,OAAO,mBAAmB,YAAY,YAAY,OAAO,mBAAmB,YAAY,UAAW;AACrI,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,2DAA2D,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAChJ;AAAA,QACF;AAGA,YAAI;AACF,gBAAM,MAAM,KAAK,mBAAmB,kBAAkB;AAAA,QACxD,SAAS,KAAK;AACZ,cAAI,eAAe,SAAS,IAAI,SAAS;AACvC,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,IAAI,SAAS,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,UACpG,OAAO;AACL,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,KAAK,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,UAC5F;AACA;AAAA,QACF;AAGA,YAAI;AACF,cAAI,CAAC,IAAI,UAAU;AACjB,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,0BAA0B,mBAAmB,SAAS,oBAAoB,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAC/J;AAAA,UACF;AACA,gBAAM,IAAI,KAAK,mBAAmB,OAAO;AACzC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,QAAQ,kBAAkB,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,QAC1G,SAAS,KAAK;AACZ,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,0BAA0B,GAAG,IAAI,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,QACxH;AAEA;AAAA,MACF;AAAA,MAEA,KAAK,iBAAiB;AAIpB,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AACtG;AAAA,QACF;AAEA,cAAM,uBAAuB,IAAI;AAGjC,YAAI;AACF,gBAAM,MAAM,KAAK,mBAAmB,oBAAoB;AAAA,QAC1D,SAAS,KAAK;AACZ,cAAI,eAAe,SAAS,IAAI,SAAS;AACvC,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,IAAI,SAAS,GAAG,qBAAqB,GAAG,IAAI,QAAQ;AAAA,UACtG,OAAO;AACL,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,KAAK,GAAG,qBAAqB,GAAG,IAAI,QAAQ;AAAA,UAC9F;AACA;AAAA,QACF;AAGA,YAAI;AACF,cAAI,CAAC,IAAI,WAAW;AAClB,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,0BAA0B,qBAAqB,SAAS,qBAAqB,GAAG,qBAAqB,GAAG,IAAI,QAAQ;AACpK;AAAA,UACF;AACA,gBAAM,IAAI,OAAO;AACjB,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,QAAQ,mBAAmB,GAAG,qBAAqB,GAAG,IAAI,QAAQ;AAAA,QAC7G,SAAS,KAAK;AACZ,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,2BAA2B,GAAG,IAAI,GAAG,qBAAqB,GAAG,IAAI,QAAQ;AAAA,QAC3H;AAEA;AAAA,MACF;AAAA,MAEA,KAAK,eAAe;AAIlB,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AACtG;AAAA,QACF;AAEA,cAAM,qBAAqB,IAAI;AAG/B,YAAI,OAAO,mBAAmB,UAAU,UAAU;AAChD,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,8BAA8B,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AACnH;AAAA,QACF;AAGA,YAAI;AACF,gBAAM,MAAM,KAAK,mBAAmB,kBAAkB;AAAA,QACxD,SAAS,KAAK;AACZ,cAAI,eAAe,SAAS,IAAI,SAAS;AACvC,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,IAAI,SAAS,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,UACpG,OAAO;AACL,iBAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,KAAK,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,UAC5F;AACA;AAAA,QACF;AAGA,YAAI;AACF,gBAAM,IAAI,MAAM,mBAAmB,KAAK;AACxC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,QAAQ,6BAA6B,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,QACrH,SAAS,KAAK;AACZ,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,qCAAqC,GAAG,IAAI,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,QACnI;AAEA;AAAA,MACF;AAAA,MAEA,KAAK,wBAAwB;AAI3B,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AAClG;AAAA,QACF;AAEA,cAAM,8BAA8B,IAAI;AAGxC,YAAI,OAAO,4BAA4B,YAAY,YAAY,4BAA4B,UAAU,OAAO,4BAA4B,UAAU,KAAO;AACvJ,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,sDAAsD,GAAG,4BAA4B,GAAG,IAAI,QAAQ;AAChJ;AAAA,QACF;AACA,YAAI,OAAO,4BAA4B,QAAQ,YAAY,4BAA4B,MAAM,GAAG;AAC9F,sCAA4B,MAAM;AAAA,QACpC;AAGA,YAAI;AACF,gBAAM,MAAM,KAAK,mBAAmB,2BAA2B;AAAA,QACjE,SAAS,KAAK;AACZ,cAAI,eAAe,SAAS,IAAI,SAAS;AACvC,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,IAAI,SAAS,GAAG,4BAA4B,GAAG,IAAI,QAAQ;AAAA,UACzG,OAAO;AACL,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,KAAK,GAAG,4BAA4B,GAAG,IAAI,QAAQ;AAAA,UACjG;AACA;AAAA,QACF;AAGA,cAAM,oBAAoB,IAAI,wBAAwB;AAAA,UACpD,QAAQ,CAAC,IAAI,MAAM,EAAE,OAAO,KAAK,QAAQ,MAAM;AAAA,UAC/C,KAAK,4BAA4B;AAAA,UACjC,MAAM,4BAA4B;AAAA,QACpC,CAAC;AACD,0BAAkB,GAAG,OAAO,CAAC,cAAc;AACzC,gBAAM,YAAY,UAAU,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,SAAS,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,MAAM,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,MAAM,EAAE,UAAU,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;AACpK,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,WAAW,GAAG,4BAA4B,GAAG,IAAI,QAAQ;AAAA,QAChG,CAAC;AAED;AAAA,MACF;AAAA,MAEA,KAAK,0BAA0B;AAI7B,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AACtG;AAAA,QACF;AAEA,cAAM,gCAAgC,IAAI;AAG1C,YAAI,OAAO,8BAA8B,kBAAkB,UAAU;AACnE,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,sCAAsC,GAAG,8BAA8B,GAAG,IAAI,QAAQ;AACtI;AAAA,QACF;AACA,YAAI,CAAC,8BAA8B,WAAY,OAAO,8BAA8B,YAAY,YAAY,OAAO,8BAA8B,YAAY,UAAW;AACtK,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,2DAA2D,GAAG,8BAA8B,GAAG,IAAI,QAAQ;AAC3J;AAAA,QACF;AAGA,YAAI;AACF,gBAAM,YAAY,MAAM,KAAK,qBAAqB,mBAAmB,8BAA8B,eAAe,KAAK,sBAAsB,8BAA8B,OAAO,CAAC;AACnL,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,QAAQ,cAAc,GAAG,+BAA+B,UAAU,GAAG,IAAI,QAAQ;AAAA,QAC5H,SAAS,KAAK;AACZ,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,wBAAwB,GAAG,IAAI,GAAG,8BAA8B,GAAG,IAAI,QAAQ;AAAA,QACjI;AAEA;AAAA,MACF;AAAA,MAEA,KAAK,eAAe;AAIlB,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AACtG;AAAA,QACF;AAEA,cAAM,qBAAqB,IAAI;AAG/B,YAAI,CAAC,mBAAmB,UAAU;AAChC,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,4BAA4B,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AACjH;AAAA,QACF;AAEA,cAAM,eAAe,KAAK,QAAQ,OAAO,MAAM,IAAI,mBAAmB,QAAQ;AAC9E,YAAI,CAAC,cAAc;AACjB,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,qBAAqB,mBAAmB,QAAQ,SAAS,GAAG,IAAI,QAAQ;AACxH;AAAA,QACF;AAEA,YAAI;AACF,gBAAM,aAAa,MAAM;AACzB,eAAK,IAAI,KAAK,eAAe,aAAa,IAAI,KAAK,aAAa,EAAE,GAAG;AAErE,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,QAAQ,KAAK,GAAG,IAAI,QAAQ;AAAA,QACvE,SAAS,KAAK;AACZ,eAAK,WAAW,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,wBAAwB,mBAAmB,QAAQ,KAAK,GAAG,IAAI,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAAA,QACtJ;AAEA;AAAA,MACF;AAAA,MAEA,KAAK,iBAAiB;AAIpB,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AAClG;AAAA,QACF;AAEA,cAAM,uBAAuB,IAAI;AAGjC,YAAI,CAAC,qBAAqB,UAAU;AAClC,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,4BAA4B,GAAG,qBAAqB,GAAG,IAAI,QAAQ;AAC/G;AAAA,QACF;AAEA,cAAM,SAAS,KAAK,QAAQ,OAAO,MAAM,IAAI,qBAAqB,QAAQ;AAC1E,YAAI,CAAC,QAAQ;AACX,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,qBAAqB,qBAAqB,QAAQ,UAAU,GAAG,qBAAqB,GAAG,IAAI,QAAQ;AAC/I;AAAA,QACF;AAEA,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS;AAAA,UACjC,IAAI,OAAO;AAAA,UACX,MAAM,OAAO;AAAA,UACb,aAAa,OAAO;AAAA,UACpB,SAAS,OAAO,QAAQ,MAAM,IAAI,CAAC,OAAO;AAAA,YACxC,IAAI,EAAE;AAAA,YACN,KAAK,EAAE,KAAK;AAAA,YACZ,MAAM,EAAE,KAAK;AAAA,YACb,aAAa,EAAE;AAAA,UACjB,EAAE;AAAA,UACF,OAAO,OAAO,MAAM,MAAM,IAAI,CAAC,OAAO;AAAA,YACpC,IAAI,EAAE;AAAA,YACN,MAAM,EAAE;AAAA,YACR,OAAO,EAAE;AAAA,UACX,EAAE;AAAA,UACF,UAAU,OAAO,SAAS,MAAM,IAAI,CAAC,OAAO;AAAA,YAC1C,IAAI,EAAE;AAAA,YACN,UAAU,EAAE;AAAA,YACZ,MAAM,EAAE;AAAA,YACR,MAAM,EAAE;AAAA,UACV,EAAE;AAAA,QACJ,GAAG,IAAI,QAAQ;AAEf;AAAA,MACF;AAAA,MAEA,KAAK,kBAAkB;AAIrB,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AAClG;AAAA,QACF;AAEA,cAAM,wBAAwB,IAAI;AAGlC,YAAI,CAAC,sBAAsB,YAAY,CAAC,sBAAsB,WAAW;AACvE,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,yCAAyC,GAAG,sBAAsB,GAAG,IAAI,QAAQ;AAC7H;AAAA,QACF;AAEA,kBAAU,KAAK,QAAQ,OAAO,MAAM,IAAI,sBAAsB,QAAQ,GAAG,SAAS,MAAM,IAAI,sBAAsB,SAAS;AAC3H,YAAI,CAAC,SAAS;AACZ,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,sBAAsB,sBAAsB,SAAS,uBAAuB,sBAAsB,QAAQ,UAAU,GAAG,sBAAsB,GAAG,IAAI,QAAQ;AACxM;AAAA,QACF;AAEA,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS;AAAA,UACjC,IAAI,QAAQ;AAAA,UACZ,UAAU,QAAQ;AAAA,UAClB,MAAM,QAAQ;AAAA,UACd,MAAM,QAAQ;AAAA,UACd,SAAS,CAAC,QAAQ,SAAS,KAAK,QAAQ,QAAQ,IAAI,CAAC,OAAO;AAAA,YAC1D,IAAI,EAAE;AAAA,YACN,KAAK,EAAE,KAAK;AAAA,YACZ,MAAM,EAAE,KAAK;AAAA,YACb,aAAa,EAAE;AAAA,UACjB,EAAE;AAAA,QACJ,GAAG,IAAI,QAAQ;AAEf;AAAA,MACF;AAAA,MAEA,KAAK,uBAAuB;AAI1B,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AAClG;AAAA,QACF;AAEA,cAAM,6BAA6B,IAAI;AAGvC,YAAI,CAAC,2BAA2B,YAAa,CAAC,2BAA2B,UAAU,CAAC,2BAA2B,WAAW,CAAC,2BAA2B,UAAW;AAC/J,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,4DAA4D,GAAG,2BAA2B,GAAG,IAAI,QAAQ;AACrJ;AAAA,QACF;AAEA,YAAI;AACJ,YAAI,2BAA2B,QAAQ;AACrC,mBAAS,KAAK,QAAQ,OAAO,MAAM,IAAI,2BAA2B,QAAQ,GAAG,QAAQ,MAAM,IAAI,2BAA2B,MAAM;AAChI,cAAI,CAAC,QAAQ;AACX,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,qBAAqB,2BAA2B,MAAM,uBAAuB,2BAA2B,QAAQ,UAAU,GAAG,2BAA2B,GAAG,IAAI,QAAQ;AACnN;AAAA,UACF;AAAA,QACF,WAAW,2BAA2B,SAAS;AAC7C,mBAAS,KAAK,QAAQ,OAAO,MAAM,IAAI,2BAA2B,QAAQ,GAAG,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,QAAQ,2BAA2B,OAAO;AACxJ,cAAI,CAAC,QAAQ;AACX,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,sBAAsB,2BAA2B,OAAO,uBAAuB,2BAA2B,QAAQ,UAAU,GAAG,2BAA2B,GAAG,IAAI,QAAQ;AACrN;AAAA,UACF;AAAA,QACF,OAAO;AACL,mBAAS,KAAK,QAAQ,OAAO,MAAM,IAAI,2BAA2B,QAAQ,GAAG,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,kBAAkB,OAAO,EAAE,KAAK,aAAa,2BAA2B,QAAQ;AAC9L,cAAI,CAAC,QAAQ;AACX,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,8BAA8B,2BAA2B,QAAQ,uBAAuB,2BAA2B,QAAQ,UAAU,GAAG,2BAA2B,GAAG,IAAI,QAAQ;AAC9N;AAAA,UACF;AAAA,QACF;AAEA,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS;AAAA,UACjC,IAAI,OAAO;AAAA,UACX,KAAK,OAAO,KAAK;AAAA,UACjB,MAAM,OAAO,KAAK;AAAA,UAClB,aAAa,OAAO;AAAA,UACpB,cAAc,OAAO;AAAA,UACrB,kBAAkB,OAAO,iBAAiB;AAAA,UAC1C,OAAO,OAAO,MAAM,MAAM,IAAI,CAAC,OAAO;AAAA,YACpC,IAAI,EAAE;AAAA,YACN,MAAM,EAAE;AAAA,YACR,OAAO,EAAE;AAAA,UACX,EAAE;AAAA,UACF,UAAU,OAAO;AAAA,UACjB,gBAAgB,OAAO,MAAM;AAAA,UAC7B,YAAY,OAAO,MAAM;AAAA,UACzB,WAAW,OAAO,MAAM;AAAA,QAC1B,GAAG,IAAI,QAAQ;AAEf;AAAA,MACF;AAAA,MAEA,KAAK,eAAe;AAIlB,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AAClG;AAAA,QACF;AAEA,cAAM,qBAAqB,IAAI;AAG/B,YAAI,CAAC,mBAAmB,UAAU,CAAC,mBAAmB,WAAW,CAAC,mBAAmB,UAAU;AAC7F,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,8CAA8C,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAC/H;AAAA,QACF;AAEA,YAAI,mBAAmB,QAAQ;AAC7B,iBAAO,KAAK,QAAQ,MAAM,MAAM,IAAI,mBAAmB,MAAM;AAC7D,cAAI,CAAC,MAAM;AACT,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,mBAAmB,mBAAmB,MAAM,UAAU,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AACvI;AAAA,UACF;AAAA,QACF,WAAW,mBAAmB,SAAS;AACrC,iBAAO,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,QAAQ,mBAAmB,OAAO;AAChF,cAAI,CAAC,MAAM;AACT,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,oBAAoB,mBAAmB,OAAO,UAAU,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AACzI;AAAA,UACF;AAAA,QACF,OAAO;AACL,iBAAO,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,kBAAkB,OAAO,EAAE,aAAa,mBAAmB,QAAQ;AACjH,cAAI,CAAC,MAAM;AACT,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,4BAA4B,mBAAmB,QAAQ,UAAU,GAAG,mBAAmB,GAAG,IAAI,QAAQ;AAClJ;AAAA,UACF;AAAA,QACF;AAEA,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS;AAAA,UACjC,IAAI,KAAK;AAAA,UACT,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,WAAW,KAAK,UAAU;AAAA,UAC1B,KAAK,KAAK;AAAA,UACV,aAAa,KAAK;AAAA,QACpB,GAAG,IAAI,QAAQ;AAEf;AAAA,MACF;AAAA,MAEA,KAAK,kBAAkB;AAIrB,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,YAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,uCAAuC,GAAG,IAAI,QAAQ;AAClG;AAAA,QACF;AAEA,cAAM,wBAAwB,IAAI;AAElC,YAAI;AACF,gBAAM,MAAM,KAAK,mBAAmB,qBAAqB;AAAA,QAC3D,SAAS,KAAK;AACZ,cAAI,eAAe,SAAS,IAAI,SAAS;AACvC,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,IAAI,SAAS,GAAG,sBAAsB,GAAG,IAAI,QAAQ;AAAA,UACnG,OAAO;AACL,iBAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,KAAK,GAAG,sBAAsB,GAAG,IAAI,QAAQ;AAAA,UAC3F;AACA;AAAA,QACF;AAEA,aAAK,OAAO,IAAI,MAAM,IAAI,SAAS;AAAA,UACjC,IAAI,IAAI;AAAA,UACR,QAAQ;AAAA,YACN,IAAI,IAAI,OAAO;AAAA,YACf,KAAK,IAAI,OAAO;AAAA,YAChB,MAAM,IAAI,OAAO;AAAA,UACnB;AAAA,UACA,SAAS,IAAI;AAAA,UACb,QAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,UACxC,aAAa,IAAI,YAAY,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,UAClD,WAAW,IAAI,UAAU,MAAM,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,UACpD,kBAAkB,IAAI;AAAA,UACtB,iBAAiB,IAAI;AAAA,UACrB,WAAW,IAAI;AAAA,QACjB,GAAG,IAAI,QAAQ;AAEf;AAAA,MACF;AAAA,MAEA,KAAK,oBAAoB;AAKvB,YAAI,CAAC,IAAI,UAAU;AACjB,eAAK,IAAI,KAAK,YAAY,IAAI,OAAO,4BAA4B;AACjE;AAAA,QACF;AAEA,YAAI,CAAC,KAAK,OAAO,qBAAqB;AACpC,eAAK,IAAI,MAAM,kCAAkC,IAAI,IAAI,8DAA8D;AACvH,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,GAAG,IAAI,QAAQ;AAChE;AAAA,QACF;AAEA,aAAK,IAAI,KAAK,kCAAkC,IAAI,KAAK,QAAQ,sBAAsB,EAAE,CAAC,EAAE;AAE5F,YAAI;AAEJ,YAAI,KAAK,OAAO,oBAAoB,QAAQ,GAAG,IAAI,GAAG;AAEpD,gBAAM,CAAE,UAAU,SAAU,IAAI,KAAK,OAAO,oBAAoB,MAAM,GAAG;AACzE,gBAAM,WAAW,KAAK,QAAQ,OAAO,MAAM,IAAI,QAAQ,GAAG,SAAS,MAAM,IAAI,SAAS;AACtF,cAAI,UAAU,SAAS,2BAAY,WAAW;AAC5C,qBAAS;AAAA,UACX;AAAA,QACF,OAAO;AAEL,mBAAS,KAAK,QAAQ,MAAM,MAAM,IAAI,KAAK,OAAO,mBAAmB;AAAA,QACvE;AAEA,YAAI,CAAC,QAAQ;AACX,eAAK,IAAI,MAAM,oEAAoE;AACnF,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,GAAG,IAAI,QAAQ;AAChE;AAAA,QACF;AAEA,cAAM,UAAU,IAAI;AAGpB,YAAI,CAAC,SAAS,UAAU,aAAa,CAAC,QAAQ,SAAS,MAAM;AAC3D,eAAK,IAAI,KAAK,yEAAyE;AACvF,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,GAAG,IAAI,QAAQ;AAChE;AAAA,QACF;AAEA,cAAM,EAAE,WAAW,SAAS,IAAI,QAAQ;AAExC,YAAI,OAAe;AACnB,gBAAQ,UAAU;AAAA,UAChB,KAAK;AACH,mBAAO;AACP;AAAA,UACF,KAAK;AACH,mBAAO;AACP;AAAA,UACF,KAAK;AACH,mBAAO;AACP;AAAA,QACJ;AAEA,cAAM,oBAAoB,OAAO,QAAQ,SAAS,EAAE,IAAI,CAAC,CAAE,UAAU,KAAM,MAAM,GAAG,SAAS,UAAU,kBAAkB,MAAM,CAAC,SAAK,2CAAc,MAAM,UAAU,iBAAK,QAAQ,CAAC,EAAE;AAEnL,cAAM,OAAO,GAAG,IAAI,KAAK,QAAQ,SAAS,IAAI;AAAA;AAAA,EAEpD,QAAQ,SAAS,eAAe,EAAE;AAAA;AAAA,EAElC,QAAQ,IAAI;AAAA,EACZ,kBAAkB,KAAK,IAAI,CAAC;AAEtB,YAAI;AACF,gBAAM,OAAO,MAAM,OAAO,KAAK,IAAI;AACnC,eAAK,IAAI,MAAM,kEAAkE,KAAK,EAAE,EAAE;AAC1F,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,MAAM,KAAK,GAAG,IAAI,QAAQ;AAAA,QACjE,SAAS,KAAK;AACZ,eAAK,IAAI,KAAK,4DAA4D,GAAG,EAAE;AAC/E,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,GAAG,IAAI,QAAQ;AAAA,QAClE;AAEA;AAAA,MACF;AAAA,MAEA;AAIE,aAAK,IAAI,KAAK,qCAAqC,IAAI,OAAO,EAAE;AAChE,YAAI,IAAI,UAAU;AAChB,eAAK,OAAO,IAAI,MAAM,IAAI,SAAS,EAAE,OAAO,oBAAoB,IAAI,OAAO,GAAG,GAAG,IAAI,QAAQ;AAAA,QAC/F;AAAA,IAEJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,WAAY,cAAsB,SAAiB,SAAkC,UAAqF;AAChL,QAAI,UAAU;AACZ,WAAK,OAAO,cAAc,SAAS,SAAS,QAAQ;AAAA,IAEtD,WAAW,OAAO,YAAY,YAAY,QAAQ,OAAO;AAEvD,WAAK,IAAI,KAAK,QAAQ,KAAK;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,sBAAuB,KAAmE;AAChG,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO;AAAA,IACT;AAGA,QAAI,IAAI,QAAQ;AACd,iBAAW,SAAS,IAAI,QAAQ;AAE9B,YAAI,OAAQ,MAAmB,UAAU,UAAU;AACjD,gBAAM,WAAoB,MAAmB;AAC7C,cAAI,QAAQ,KAAK,QAAQ,GAAG;AAE1B,YAAC,MAAmB,QAAQ,SAAS,UAAU,EAAE;AAAA,UACnD,OAAO;AAGL,gBAAI;AACF,cAAC,MAAmB,YAAQ,6BAAa,QAA0B;AAAA,YACrE,SAAS,KAAK;AAEZ,cAAC,MAAmB,YAAQ,6BAAa,SAAS;AAClD,mBAAK,IAAI,KAAK,sBAAsB,QAAQ,MAAM,GAAG,EAAE;AAAA,YACzD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,mBAAoB,YAA0D;AAC1F,QAAI,CAAC,WAAW,WAAW;AACzB,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAEA,QAAI,WAAW,UAAU,WAAW,WAAW,WAAW,UAAU;AAElE,UAAI;AACJ,UAAI,WAAW,QAAQ;AAErB,eAAO,KAAK,QAAQ,MAAM,MAAM,IAAI,WAAW,MAAM;AACrD,YAAI,CAAC,MAAM;AACT,gBAAM,IAAI,MAAM,uBAAuB,WAAW,MAAM,QAAQ;AAAA,QAClE;AAAA,MACF,WAAW,WAAW,SAAS;AAE7B,eAAO,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,QAAQ,WAAW,OAAO;AACxE,YAAI,CAAC,MAAM;AACT,gBAAM,IAAI,MAAM,wBAAwB,WAAW,OAAO,QAAQ;AAAA,QACpE;AAAA,MACF,OAAO;AAEL,eAAO,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,kBAAkB,OAAO,EAAE,aAAa,WAAW,QAAQ;AACzG,YAAI,CAAC,MAAM;AACT,gBAAM,IAAI,MAAM,gCAAgC,WAAW,QAAQ,QAAQ;AAAA,QAC7E;AAAA,MACF;AACA,UAAI;AACF,YAAI,CAAC,KAAK,WAAW;AACnB,gBAAM,KAAK,SAAS;AAAA,QACtB;AACA,cAAM,MAAM,KAAK,WAAW,SAAS,MAAM,IAAI,WAAW,SAAS,KAAK,MAAM,KAAK,WAAW,SAAS,MAAM,WAAW,SAAS;AACjI,YAAI,CAAC,KAAK;AACR,gBAAM,IAAI,MAAM,6BAA6B,WAAW,SAAS,iBAAa,4BAAc,IAAI,CAAC,QAAQ;AAAA,QAC3G;AACA,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,cAAM,IAAI,MAAM,sCAAkC,4BAAc,IAAI,CAAC,KAAK,GAAG,EAAE;AAAA,MACjF;AAAA,IAEF,WAAW,WAAW,YAAY,WAAW,WAAW;AAEtD,YAAM,UAAU,KAAK,QAAQ,OAAO,MAAM,IAAI,WAAW,QAAQ,GAAG,SAAS,MAAM,IAAI,WAAW,SAAS;AAC3G,UAAI,SAAS,SAAS,2BAAY,aAAa,SAAS,SAAS,2BAAY,YAAY;AACvF,cAAM,IAAI,MAAM,kCAAkC,WAAW,SAAS,cAAc,WAAW,QAAQ,QAAQ;AAAA,MACjH;AACA,UAAI;AACF,cAAM,MAAM,QAAQ,SAAS,MAAM,IAAI,WAAW,SAAS,KAAK,MAAM,QAAQ,SAAS,MAAM,WAAW,SAAS;AACjH,YAAI,CAAC,KAAK;AACR,gBAAM,IAAI,MAAM,6BAA6B,WAAW,SAAS,gBAAgB,QAAQ,IAAI,QAAQ;AAAA,QACvG;AACA,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,cAAM,IAAI,MAAM,oCAAoC,QAAQ,IAAI,KAAK,GAAG,EAAE;AAAA,MAC5E;AAAA,IAEF,OAAO;AAEL,YAAM,IAAI,MAAM,qEAAqE;AAAA,IACvF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,uBAAwB,WAAoB,QAAiB,OAAsB;AAC/F,QAAI,SAAS,cAAc,KAAK,eAAe;AAC7C,YAAM,KAAK,SAAS,mBAAmB,WAAW,IAAI;AACtD,WAAK,gBAAgB;AAAA,IACvB;AAAA,EACF;AAAA,EAMA,MAAc,SAAU,UAAqC;AAC3D,QAAI;AACF,WAAK,WAAW;AAEhB,YAAM,KAAK,uBAAuB,OAAO,IAAI;AAE7C,UAAI,KAAK,QAAQ;AACf,cAAM,KAAK,OAAO,QAAQ;AAAA,MAC5B;AAEA,eAAS;AAAA,IACX,SAAS,IAAI;AACX,eAAS;AAAA,IACX;AAAA,EACF;AAEF;AAp1FgB;AAAA,EADb;AAAA,GAjOG,eAkOU;AA+SA;AAAA,EADb;AAAA,GAhhBG,eAihBU;AA67BA;AAAA,EADb;AAAA,GA78CG,eA88CU;AAiJA;AAAA,EADb;AAAA,GA9lDG,eA+lDU;AA0IN;AAAA,EADP;AAAA,GAxuDG,eAyuDI;AAmBM;AAAA,EADb;AAAA,GA3vDG,eA4vDU;AA+WA;AAAA,EADb;AAAA,GA1mEG,eA2mEU;AA27BA;AAAA,EADb;AAAA,GAriGG,eAsiGU;AAkBhB,IAAI,QAAQ,SAAS,QAAQ;AAE3B,SAAO,UAAU,CAAC,YAAiD,IAAI,eAAe,OAAO;AAC/F,OAAO;AAEL,GAAC,MAAM,IAAI,eAAe,GAAG;AAC/B;", + "names": ["djsVersion"] } diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..42ab904 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,62 @@ +import tseslint from 'typescript-eslint'; + +import crycode from '@crycode/eslint-config'; + +export default tseslint.config( + ...crycode.configs.ts, + ...crycode.configs.stylistic, + + { + ignores: [ + '.dev-server/', + 'build/', + 'test/', + ], + }, + + { + files: [ + 'src/**/*', + ], + + languageOptions: { + parserOptions: { + ecmaVersion: 2022, + sourceType: 'module', + project: [ + './tsconfig.json', + ], + }, + }, + + }, + + { + files: [ + 'admin/blockly.js', + ], + + languageOptions: { + globals: { + Blockly: 'readonly', + document: 'readonly', + goog: 'readonly', + main: 'readonly', + setTimeout: 'readonly', + console: 'readonly', + }, + }, + + rules: { + '@stylistic/operator-linebreak': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/dot-notation': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + 'no-console': 'off', + }, + }, +); diff --git a/io-package.json b/io-package.json index 330d3b1..40d4e20 100644 --- a/io-package.json +++ b/io-package.json @@ -136,7 +136,6 @@ }, "tier": 2, "platform": "Javascript/Node.js", - "main": "build/main.js", "icon": "discord.png", "enabled": true, "extIcon": "https://raw.githubusercontent.com/crycode-de/ioBroker.discord/main/admin/discord.png", @@ -169,12 +168,12 @@ }, "dependencies": [ { - "js-controller": ">=4.0.0" + "js-controller": ">=5.0.19" } ], "globalDependencies": [ { - "admin": ">=5.3.0" + "admin": ">=6.17.0" } ], "messages": [ diff --git a/package-lock.json b/package-lock.json index 26c5a2e..01b0a16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,49 +11,41 @@ "dependencies": { "@iobroker/adapter-core": "^3.1.6", "autobind-decorator": "^2.4.0", - "discord.js": "^14.15.3", + "discord.js": "^14.16.2", "source-map-support": "^0.5.21" }, "devDependencies": { - "@alcalzone/release-script": "^3.7.3", + "@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", + "@crycode/eslint-config": "^2.1.1", "@iobroker/adapter-dev": "^1.3.0", - "@iobroker/testing": "^4.1.3", - "@types/chai": "^4.3.16", - "@types/chai-as-promised": "^7.1.8", - "@types/mocha": "^10.0.7", - "@types/node": "^20.14.10", + "@iobroker/testing": "^5.0.0", + "@types/chai": "^4.3.19", + "@types/chai-as-promised": "^8.0.0", + "@types/mocha": "^10.0.8", + "@types/node": "^22.5.5", "@types/proxyquire": "^1.3.31", "@types/sinon": "^17.0.3", "@types/sinon-chai": "^3.2.12", - "@typescript-eslint/eslint-plugin": "^7.15.0", - "@typescript-eslint/parser": "^7.15.0", - "chai": "^4.4.1", - "chai-as-promised": "^7.1.2", - "eslint": "^8.57.0", - "mocha": "^10.6.0", + "@typescript-eslint/eslint-plugin": "^8.6.0", + "@typescript-eslint/parser": "^8.6.0", + "chai": "^5.1.1", + "chai-as-promised": "^8.0.0", + "eslint": "^9.11.0", + "mocha": "^10.7.3", "proxyquire": "^2.1.3", - "rimraf": "^5.0.8", - "sinon": "^18.0.0", - "sinon-chai": "^3.7.0", + "rimraf": "^6.0.1", + "sinon": "^19.0.2", + "sinon-chai": "^4.0.0", "ts-node": "^10.9.2", - "typescript": "^5.5.3" + "typescript": "^5.5.4" }, "engines": { "node": ">=18" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@alcalzone/pak": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.10.2.tgz", @@ -91,15 +83,16 @@ } }, "node_modules/@alcalzone/release-script": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script/-/release-script-3.7.3.tgz", - "integrity": "sha512-5g32LqzLb2tubKhQxPIJifuXZpsJV8qkkDUKWT+6sbAZoSAPBpr1hIr5StkvPEZUgJcyfRApKeA19/SDgSo2kA==", + "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.7.0", "@alcalzone/release-script-plugin-changelog": "3.7.0", "@alcalzone/release-script-plugin-exec": "3.7.0", - "@alcalzone/release-script-plugin-git": "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", @@ -158,10 +151,11 @@ } }, "node_modules/@alcalzone/release-script-plugin-git": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-git/-/release-script-plugin-git-3.7.0.tgz", - "integrity": "sha512-4wA1XNnU7uyNnzXaLe4eBd1pfyk6VhVBuTzQ5EKraLNEXZ+JWWxeYMdcJGI6QdA1qAtld91gLRfLI1Ewye9ecQ==", + "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.7.0", "fs-extra": "^10.1.0" @@ -256,6 +250,23 @@ "node": ">=6.0.0" } }, + "node_modules/@crycode/eslint-config": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@crycode/eslint-config/-/eslint-config-2.1.1.tgz", + "integrity": "sha512-+WPKcEY16370kBcVE0xe9GWCMu5cD4WP7ayeQNZBhsHr2StDU+E7eXY4wVNR/P2IT9VLr6fGhwES6xMl18qpBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/js": "^9.10.0", + "@stylistic/eslint-plugin": "^2.8.0", + "@stylistic/eslint-plugin-js": "^2.8.0", + "@types/eslint__js": "^8.42.3" + }, + "peerDependencies": { + "eslint": "^9.10.0", + "typescript-eslint": "^8.5.0" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -269,25 +280,32 @@ } }, "node_modules/@discordjs/builders": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.8.2.tgz", - "integrity": "sha512-6wvG3QaCjtMu0xnle4SoOIeFB4y6fKMN6WZfy3BMKJdQQtPLik8KGzDwBVL/+wTtcE/ZlFjgEk74GublyEVZ7g==", - "dependencies": { - "@discordjs/formatters": "^0.4.0", - "@discordjs/util": "^1.1.0", - "@sapphire/shapeshift": "^3.9.7", - "discord-api-types": "0.37.83", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.9.0.tgz", + "integrity": "sha512-0zx8DePNVvQibh5ly5kCEei5wtPBIUbSoE9n+91Rlladz4tgtFbJ36PZMxxZrTEOQ7AHMZ/b0crT/0fCy6FTKg==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/formatters": "^0.5.0", + "@discordjs/util": "^1.1.1", + "@sapphire/shapeshift": "^4.0.0", + "discord-api-types": "0.37.97", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", - "tslib": "^2.6.2" + "tslib": "^2.6.3" }, "engines": { - "node": ">=16.11.0" + "node": ">=18" }, "funding": { "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@discordjs/builders/node_modules/discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==", + "license": "MIT" + }, "node_modules/@discordjs/collection": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", @@ -297,45 +315,54 @@ } }, "node_modules/@discordjs/formatters": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.4.0.tgz", - "integrity": "sha512-fJ06TLC1NiruF35470q3Nr1bi95BdvKFAF+T5bNfZJ4bNdqZ3VZ+Ttg6SThqTxm6qumSG3choxLBHMC69WXNXQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.5.0.tgz", + "integrity": "sha512-98b3i+Y19RFq1Xke4NkVY46x8KjJQjldHUuEbCqMvp1F5Iq9HgnGpu91jOi/Ufazhty32eRsKnnzS8n4c+L93g==", + "license": "Apache-2.0", "dependencies": { - "discord-api-types": "0.37.83" + "discord-api-types": "0.37.97" }, "engines": { - "node": ">=16.11.0" + "node": ">=18" }, "funding": { "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@discordjs/formatters/node_modules/discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==", + "license": "MIT" + }, "node_modules/@discordjs/rest": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.3.0.tgz", - "integrity": "sha512-C1kAJK8aSYRv3ZwMG8cvrrW4GN0g5eMdP8AuN8ODH5DyOCbHgJspze1my3xHOAgwLJdKUbWNVyAeJ9cEdduqIg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.0.tgz", + "integrity": "sha512-Xb2irDqNcq+O8F0/k/NaDp7+t091p+acb51iA4bCKfIn+WFWd6HrNvcsSbMMxIR9NjcMZS6NReTKygqiQN+ntw==", + "license": "Apache-2.0", "dependencies": { - "@discordjs/collection": "^2.1.0", - "@discordjs/util": "^1.1.0", - "@sapphire/async-queue": "^1.5.2", + "@discordjs/collection": "^2.1.1", + "@discordjs/util": "^1.1.1", + "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", - "@vladfrangu/async_event_emitter": "^2.2.4", - "discord-api-types": "0.37.83", + "@vladfrangu/async_event_emitter": "^2.4.6", + "discord-api-types": "0.37.97", "magic-bytes.js": "^1.10.0", - "tslib": "^2.6.2", - "undici": "6.13.0" + "tslib": "^2.6.3", + "undici": "6.19.8" }, "engines": { - "node": ">=16.11.0" + "node": ">=18" }, "funding": { "url": "https://github.com/discordjs/discord.js?sponsor" } }, "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.0.tgz", - "integrity": "sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz", + "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==", + "license": "Apache-2.0", "engines": { "node": ">=18" }, @@ -343,12 +370,19 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@discordjs/rest/node_modules/discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==", + "license": "MIT" + }, "node_modules/@discordjs/util": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.0.tgz", - "integrity": "sha512-IndcI5hzlNZ7GS96RV3Xw1R2kaDuXEp7tRIy/KlhidpN/BQ1qh1NZt3377dMLTa44xDUNKT7hnXkA/oUAzD/lg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz", + "integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==", + "license": "Apache-2.0", "engines": { - "node": ">=16.11.0" + "node": ">=18" }, "funding": { "url": "https://github.com/discordjs/discord.js?sponsor" @@ -760,6 +794,7 @@ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -771,24 +806,65 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -796,19 +872,98 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.0.tgz", + "integrity": "sha512-LPkkenkDqyzTFauZLLAPhIb48fj6drrfMvRGSL9tS3AcZBSVTllemLSNyCvHNNL2t797S/6DJNSIwRwXgMO/eQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", + "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@esm2cjs/execa": { @@ -1010,25 +1165,12 @@ "node": ">=6" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -1037,11 +1179,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@iobroker/adapter-core": { "version": "3.1.6", @@ -1092,47 +1242,144 @@ } }, "node_modules/@iobroker/testing": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@iobroker/testing/-/testing-4.1.3.tgz", - "integrity": "sha512-PTfvlXQBXDJVX35bkJxzgjuMX6bEjUmB4Dy8+bWLqbOgyq1JQVrRn+ah5IB7hEf+4lP8wD0MpAjXFJTv3zfTvA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@iobroker/testing/-/testing-5.0.0.tgz", + "integrity": "sha512-JrtWaGrgTU5MGRZowwyrDHVz8nzh/1QUqiOo1g9SXrRwT3PH0f6wRQKfe/RKiULFD2O4N3isc7pqyZg/uv4wdA==", "dev": true, + "license": "MIT", "dependencies": { - "alcalzone-shared": "~4.0.3", - "chai": "^4.3.7", - "chai-as-promised": "^7.1.1", - "debug": "^4.3.4", - "fs-extra": "^10.1.0", - "mocha": "^10.2.0", - "sinon": "^15.0.1", + "alcalzone-shared": "~4.0.8", + "chai": "^4.5.0", + "chai-as-promised": "^7.1.2", + "debug": "^4.3.7", + "fs-extra": "^11.2.0", + "mocha": "^10.7.3", + "sinon": "^19.0.2", "sinon-chai": "^3.7.0" } }, - "node_modules/@iobroker/testing/node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "node_modules/@iobroker/testing/node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@iobroker/testing/node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", "dependencies": { - "type-detect": "4.0.8" + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@iobroker/testing/node_modules/sinon": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", - "integrity": "sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==", - "deprecated": "16.1.1", + "node_modules/@iobroker/testing/node_modules/chai-as-promised": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", + "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", "dev": true, + "license": "WTFPL", "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^10.3.0", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.4", - "supports-color": "^7.2.0" + "check-error": "^1.0.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" + "peerDependencies": { + "chai": ">= 2.1.2 < 6" + } + }, + "node_modules/@iobroker/testing/node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@iobroker/testing/node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@iobroker/testing/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@iobroker/testing/node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/@iobroker/testing/node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@iobroker/testing/node_modules/sinon-chai": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", + "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "dev": true, + "license": "(BSD-2-Clause OR WTFPL)", + "peerDependencies": { + "chai": "^4.0.0", + "sinon": ">=4.0.0" + } + }, + "node_modules/@iobroker/testing/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/@iobroker/types": { @@ -1149,6 +1396,7 @@ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1162,10 +1410,11 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -1178,6 +1427,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -1189,13 +1439,15 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -1213,6 +1465,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1228,6 +1481,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -1282,6 +1536,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1295,6 +1550,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1304,6 +1560,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1317,6 +1574,7 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -1387,18 +1645,20 @@ "dev": true }, "node_modules/@sapphire/async-queue": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz", - "integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.3.tgz", + "integrity": "sha512-x7zadcfJGxFka1Q3f8gCts1F0xMwCKbZweM85xECGI0hBTeIZJGGCrHgLggihBoprlQ/hBmDR5LKfIPqnmHM3w==", + "license": "MIT", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, "node_modules/@sapphire/shapeshift": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz", - "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz", + "integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" @@ -1417,48 +1677,165 @@ } }, "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.2.tgz", + "integrity": "sha512-4Bb+oqXZTSTZ1q27Izly9lv8B9dlV61CROxPiVtywwzv5SnytJqhvYe6FclHYuXml4cd1VHPo1zd5PmTeJozvA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@sinonjs/commons": "^3.0.1" } }, - "node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "node_modules/@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "type-detect": "4.0.8" + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" } }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "dev": true, + "license": "(Unlicense OR Apache-2.0)" + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.8.0.tgz", + "integrity": "sha512-Ufvk7hP+bf+pD35R/QfunF793XlSRIC7USr3/EdgduK9j13i2JjmsM0LUz3/foS+jDYp2fzyWZA9N44CPur0Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.4.0", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.8.0.tgz", + "integrity": "sha512-/e7pSzVMrwBd6yzSDsKHwax3TS96+pd/xSKzELaTkOuYqUhYfj/becWdfDbFSBGQD7BBBCiiE4L8L2cUfu5h+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/@tootallnate/once": { "version": "2.0.0", @@ -1494,20 +1871,50 @@ "dev": true }, "node_modules/@types/chai": { - "version": "4.3.16", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", - "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", - "dev": true + "version": "4.3.19", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.19.tgz", + "integrity": "sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai-as-promised": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.0.tgz", + "integrity": "sha512-YbYaXFqJwSABp9OXQTVrPPmstZgNjkRieWVd/xAl5Yc/e5+F44bXLeQggpvm0sjsS1bg+2Y5cwU+rquwwD2dXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } }, - "node_modules/@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "node_modules/@types/eslint__js": { + "version": "8.42.3", + "resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz", + "integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/chai": "*" + "@types/eslint": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", @@ -1518,6 +1925,13 @@ "@types/node": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/linkify-it": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", @@ -1553,17 +1967,19 @@ "dev": true }, "node_modules/@types/mocha": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.7.tgz", - "integrity": "sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==", - "dev": true + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.8.tgz", + "integrity": "sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "22.5.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", + "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/proxyquire": { @@ -1616,31 +2032,32 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz", - "integrity": "sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz", + "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/type-utils": "7.15.0", - "@typescript-eslint/utils": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/type-utils": "8.6.0", + "@typescript-eslint/utils": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -1649,26 +2066,27 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz", + "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -1677,16 +2095,17 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.15.0.tgz", - "integrity": "sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz", + "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0" + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1694,26 +2113,24 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.15.0.tgz", - "integrity": "sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz", + "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/utils": "7.15.0", + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/utils": "8.6.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.56.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -1721,12 +2138,13 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.6.0.tgz", + "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1734,22 +2152,23 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.15.0.tgz", - "integrity": "sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz", + "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1761,79 +2180,52 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.15.0.tgz", - "integrity": "sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.6.0.tgz", + "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0" + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.15.0.tgz", - "integrity": "sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz", + "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", + "@typescript-eslint/types": "8.6.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/@vladfrangu/async_event_emitter": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.0.tgz", - "integrity": "sha512-eNb/9DMwNvhhgn1UuQ8Rl90jhj9PBkYH4oQ522TkiWUVWRfbh3PjdOTFkVGNKs5+xUXalkgFrUSwtY8u0g0S4g==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz", + "integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==", + "license": "MIT", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" @@ -1852,10 +2244,11 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1898,6 +2291,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1955,10 +2349,11 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1979,15 +2374,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -1998,12 +2384,13 @@ } }, "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">=12" } }, "node_modules/asynckit": { @@ -2068,12 +2455,16 @@ } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bluebird": { @@ -2083,13 +2474,13 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -2097,6 +2488,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -2108,7 +2500,8 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", @@ -2126,6 +2519,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2135,6 +2529,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2155,30 +2550,30 @@ } }, "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", + "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", "dev": true, + "license": "MIT", "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=12" } }, "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.0.tgz", + "integrity": "sha512-sMsGXTrS3FunP/wbqh/KxM8Kj/aLPXQGkNtvE5wPfSToq8wkkvBpTZo1LIiEVmC4BwkKpag+l5h/20lBMk6nUg==", "dev": true, + "license": "WTFPL", "dependencies": { - "check-error": "^1.0.2" + "check-error": "^2.0.0" }, "peerDependencies": { "chai": ">= 2.1.2 < 6" @@ -2201,28 +2596,21 @@ } }, "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">= 16" } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2235,6 +2623,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -2244,6 +2635,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -2256,6 +2648,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -2296,7 +2689,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/create-require": { "version": "1.1.1", @@ -2319,12 +2713,13 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2340,6 +2735,7 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2348,13 +2744,11 @@ } }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, + "license": "MIT", "engines": { "node": ">=6" } @@ -2383,59 +2777,42 @@ "node": ">=0.3.1" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/discord-api-types": { "version": "0.37.83", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.83.tgz", "integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==" }, "node_modules/discord.js": { - "version": "14.15.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.15.3.tgz", - "integrity": "sha512-/UJDQO10VuU6wQPglA4kz2bw2ngeeSbogiIPx/TsnctfzV/tNf+q+i1HlgtX1OGpeOBpJH9erZQNO5oRM2uAtQ==", + "version": "14.16.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.16.2.tgz", + "integrity": "sha512-VGNi9WE2dZIxYM8/r/iatQQ+3LT8STW4hhczJOwm+DBeHq66vsKDCk8trChNCB01sMO9crslYuEMeZl2d7r3xw==", + "license": "Apache-2.0", "dependencies": { - "@discordjs/builders": "^1.8.2", + "@discordjs/builders": "^1.9.0", "@discordjs/collection": "1.5.3", - "@discordjs/formatters": "^0.4.0", - "@discordjs/rest": "^2.3.0", - "@discordjs/util": "^1.1.0", - "@discordjs/ws": "^1.1.1", + "@discordjs/formatters": "^0.5.0", + "@discordjs/rest": "^2.4.0", + "@discordjs/util": "^1.1.1", + "@discordjs/ws": "1.1.1", "@sapphire/snowflake": "3.5.3", - "discord-api-types": "0.37.83", + "discord-api-types": "0.37.97", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", - "tslib": "2.6.2", - "undici": "6.13.0" + "tslib": "^2.6.3", + "undici": "6.19.8" }, "engines": { - "node": ">=16.11.0" + "node": ">=18" }, "funding": { "url": "https://github.com/discordjs/discord.js?sponsor" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } + "node_modules/discord.js/node_modules/discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==", + "license": "MIT" }, "node_modules/duplexify": { "version": "4.1.3", @@ -2453,7 +2830,8 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", @@ -2558,6 +2936,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2648,43 +3027,40 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.0.tgz", + "integrity": "sha512-yVS6XODx+tMFMDFcG4+Hlh+qG7RM6cCJXtQhCKLSsr3XkLvWggHjCqjfh0XsPPnt1c56oaT6PMgW9XWQQjdHXA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.11.0", + "@eslint/plugin-kit": "^0.2.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", @@ -2696,23 +3072,32 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2730,6 +3115,61 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -2761,10 +3201,11 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -2777,6 +3218,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -2850,6 +3292,7 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -2866,6 +3309,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -2877,7 +3321,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -2892,24 +3337,26 @@ "dev": true }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-keys": { @@ -2930,6 +3377,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2942,6 +3390,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -2958,43 +3407,31 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.6", @@ -3017,10 +3454,11 @@ } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -3037,6 +3475,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -3079,11 +3518,12 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3140,6 +3580,7 @@ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -3157,20 +3598,21 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3181,23 +3623,35 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", "dependencies": { - "is-glob": "^4.0.3" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10.13.0" + "node": ">=10" } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3209,26 +3663,6 @@ "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", "dev": true }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globrex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", @@ -3310,7 +3744,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/gtoken": { "version": "6.1.2", @@ -3352,6 +3787,7 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } @@ -3405,10 +3841,11 @@ } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -3418,6 +3855,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -3434,6 +3872,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -3459,6 +3898,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -3483,6 +3923,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3501,6 +3942,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -3525,6 +3967,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3543,6 +3986,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3552,6 +3996,7 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3579,6 +4024,7 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3586,12 +4032,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3599,15 +4039,16 @@ "dev": true }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">=14" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3621,6 +4062,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -3684,17 +4126,26 @@ "bignumber.js": "^9.0.0" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jsonfile": { "version": "6.1.0", @@ -3709,10 +4160,11 @@ } }, "node_modules/just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", - "dev": true + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", + "dev": true, + "license": "MIT" }, "node_modules/jwa": { "version": "2.0.0", @@ -3735,6 +4187,16 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", @@ -3749,6 +4211,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -3771,6 +4234,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -3796,13 +4260,15 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.snakecase": { "version": "4.1.1", @@ -3814,6 +4280,7 @@ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -3832,10 +4299,11 @@ "dev": true }, "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", + "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", "dev": true, + "license": "MIT", "dependencies": { "get-func-name": "^2.0.1" } @@ -3924,15 +4392,17 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -3972,15 +4442,19 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -3993,10 +4467,11 @@ } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -4014,10 +4489,11 @@ } }, "node_modules/mocha": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", - "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", @@ -4048,39 +4524,12 @@ "node": ">= 14.0.0" } }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/mocha/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4088,17 +4537,12 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -4114,6 +4558,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -4134,28 +4579,31 @@ "dev": true }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nise": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", - "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/nise/-/nise-6.1.1.tgz", + "integrity": "sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "^10.0.2", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.1", + "@sinonjs/text-encoding": "^0.7.3", + "just-extend": "^6.2.0", + "path-to-regexp": "^8.1.0" } }, "node_modules/node-fetch": { @@ -4192,6 +4640,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4242,17 +4691,18 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -4263,6 +4713,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -4278,6 +4729,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -4288,11 +4740,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -4305,19 +4765,11 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -4334,55 +4786,50 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz", + "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==", "dev": true, + "license": "ISC", "engines": { - "node": "14 || >=16.14" + "node": "20 || >=22" } }, "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.1.0.tgz", + "integrity": "sha512-Bqn3vc8CMHty6zuD+tG23s6v2kwxslHEhTj4eYaVKGIEB+YX/2wd0/rgXLFD9G9id9KCtbVy/3ZgmvZjpa0UdQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=16" } }, "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">= 14.16" } }, "node_modules/picocolors": { @@ -4396,6 +4843,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -4408,6 +4856,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -4476,46 +4925,6 @@ "protobufjs": "^7.0.0" } }, - "node_modules/protobufjs-cli/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/protobufjs-cli/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/protobufjs-cli/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -4538,6 +4947,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4560,13 +4970,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -4590,6 +5002,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -4637,6 +5050,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -4659,70 +5073,67 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, + "license": "ISC", "dependencies": { - "glob": "^10.3.7" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "bin": { "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/rimraf/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rimraf/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4747,6 +5158,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -4791,6 +5203,7 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -4823,17 +5236,18 @@ "dev": true }, "node_modules/sinon": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-18.0.0.tgz", - "integrity": "sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==", + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-19.0.2.tgz", + "integrity": "sha512-euuToqM+PjO4UgXeLETsfQiuoyPXlqFezr6YZDFwHR3t4qaX0fZUe1MfPMznTL5f8BWrVS89KduLdMUsxFCO6g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.2.0", - "nise": "^6.0.0", - "supports-color": "^7" + "@sinonjs/fake-timers": "^13.0.2", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "nise": "^6.1.1", + "supports-color": "^7.2.0" }, "funding": { "type": "opencollective", @@ -4841,65 +5255,24 @@ } }, "node_modules/sinon-chai": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", - "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-4.0.0.tgz", + "integrity": "sha512-cWqO7O2I4XfJDWyWElAQ9D/dtdh5Mo0RHndsfiiYyjWnlPzBJdIvjCVURO4EjyYaC3BjV+ISNXCfTXPXTEIEWA==", "dev": true, + "license": "(BSD-2-Clause OR WTFPL)", "peerDependencies": { - "chai": "^4.0.0", - "sinon": ">=4.0.0" - } - }, - "node_modules/sinon/node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/sinon/node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/sinon/node_modules/just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true - }, - "node_modules/sinon/node_modules/nise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-6.0.0.tgz", - "integrity": "sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/text-encoding": "^0.7.2", - "just-extend": "^6.2.0", - "path-to-regexp": "^6.2.1" + "chai": "^5.0.0", + "sinon": ">=4.0.0" } }, - "node_modules/sinon/node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/sinon/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">=0.3.1" } }, "node_modules/source-map": { @@ -4963,6 +5336,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -4990,6 +5364,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5068,7 +5443,8 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tiny-glob": { "version": "0.2.9", @@ -5094,6 +5470,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -5112,6 +5489,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -5122,7 +5500,8 @@ "node_modules/ts-mixer": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", - "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==", + "license": "MIT" }, "node_modules/ts-node": { "version": "10.9.2", @@ -5177,15 +5556,17 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -5198,27 +5579,17 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5227,6 +5598,31 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.6.0.tgz", + "integrity": "sha512-eEhhlxCEpCd4helh3AO1hk0UP2MvbRi9CtIAJTVPQjuSXOOO2jsEacNi4UdcJzZJbeuVg1gMhtZ8UYb+NFYPrA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.6.0", + "@typescript-eslint/parser": "8.6.0", + "@typescript-eslint/utils": "8.6.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -5252,17 +5648,19 @@ "dev": true }, "node_modules/undici": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.13.0.tgz", - "integrity": "sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz", + "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==", + "license": "MIT", "engines": { - "node": ">=18.0" + "node": ">=18.17" } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" }, "node_modules/universalify": { "version": "2.0.0", @@ -5278,6 +5676,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -5351,7 +5750,8 @@ "version": "6.5.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/wrap-ansi": { "version": "7.0.0", @@ -5376,6 +5776,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5458,6 +5859,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -5467,6 +5869,7 @@ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", @@ -5514,6 +5917,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5523,12 +5927,6 @@ } }, "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true - }, "@alcalzone/pak": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.10.2.tgz", @@ -5562,15 +5960,15 @@ } }, "@alcalzone/release-script": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script/-/release-script-3.7.3.tgz", - "integrity": "sha512-5g32LqzLb2tubKhQxPIJifuXZpsJV8qkkDUKWT+6sbAZoSAPBpr1hIr5StkvPEZUgJcyfRApKeA19/SDgSo2kA==", + "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.7.0", "@alcalzone/release-script-plugin-changelog": "3.7.0", "@alcalzone/release-script-plugin-exec": "3.7.0", - "@alcalzone/release-script-plugin-git": "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", @@ -5614,9 +6012,9 @@ } }, "@alcalzone/release-script-plugin-git": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-git/-/release-script-plugin-git-3.7.0.tgz", - "integrity": "sha512-4wA1XNnU7uyNnzXaLe4eBd1pfyk6VhVBuTzQ5EKraLNEXZ+JWWxeYMdcJGI6QdA1qAtld91gLRfLI1Ewye9ecQ==", + "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.7.0", @@ -5688,6 +6086,18 @@ "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "dev": true }, + "@crycode/eslint-config": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@crycode/eslint-config/-/eslint-config-2.1.1.tgz", + "integrity": "sha512-+WPKcEY16370kBcVE0xe9GWCMu5cD4WP7ayeQNZBhsHr2StDU+E7eXY4wVNR/P2IT9VLr6fGhwES6xMl18qpBg==", + "dev": true, + "requires": { + "@eslint/js": "^9.10.0", + "@stylistic/eslint-plugin": "^2.8.0", + "@stylistic/eslint-plugin-js": "^2.8.0", + "@types/eslint__js": "^8.42.3" + } + }, "@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -5698,17 +6108,24 @@ } }, "@discordjs/builders": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.8.2.tgz", - "integrity": "sha512-6wvG3QaCjtMu0xnle4SoOIeFB4y6fKMN6WZfy3BMKJdQQtPLik8KGzDwBVL/+wTtcE/ZlFjgEk74GublyEVZ7g==", - "requires": { - "@discordjs/formatters": "^0.4.0", - "@discordjs/util": "^1.1.0", - "@sapphire/shapeshift": "^3.9.7", - "discord-api-types": "0.37.83", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.9.0.tgz", + "integrity": "sha512-0zx8DePNVvQibh5ly5kCEei5wtPBIUbSoE9n+91Rlladz4tgtFbJ36PZMxxZrTEOQ7AHMZ/b0crT/0fCy6FTKg==", + "requires": { + "@discordjs/formatters": "^0.5.0", + "@discordjs/util": "^1.1.1", + "@sapphire/shapeshift": "^4.0.0", + "discord-api-types": "0.37.97", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", - "tslib": "^2.6.2" + "tslib": "^2.6.3" + }, + "dependencies": { + "discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==" + } } }, "@discordjs/collection": { @@ -5717,40 +6134,52 @@ "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==" }, "@discordjs/formatters": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.4.0.tgz", - "integrity": "sha512-fJ06TLC1NiruF35470q3Nr1bi95BdvKFAF+T5bNfZJ4bNdqZ3VZ+Ttg6SThqTxm6qumSG3choxLBHMC69WXNXQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.5.0.tgz", + "integrity": "sha512-98b3i+Y19RFq1Xke4NkVY46x8KjJQjldHUuEbCqMvp1F5Iq9HgnGpu91jOi/Ufazhty32eRsKnnzS8n4c+L93g==", "requires": { - "discord-api-types": "0.37.83" + "discord-api-types": "0.37.97" + }, + "dependencies": { + "discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==" + } } }, "@discordjs/rest": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.3.0.tgz", - "integrity": "sha512-C1kAJK8aSYRv3ZwMG8cvrrW4GN0g5eMdP8AuN8ODH5DyOCbHgJspze1my3xHOAgwLJdKUbWNVyAeJ9cEdduqIg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.0.tgz", + "integrity": "sha512-Xb2irDqNcq+O8F0/k/NaDp7+t091p+acb51iA4bCKfIn+WFWd6HrNvcsSbMMxIR9NjcMZS6NReTKygqiQN+ntw==", "requires": { - "@discordjs/collection": "^2.1.0", - "@discordjs/util": "^1.1.0", - "@sapphire/async-queue": "^1.5.2", + "@discordjs/collection": "^2.1.1", + "@discordjs/util": "^1.1.1", + "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", - "@vladfrangu/async_event_emitter": "^2.2.4", - "discord-api-types": "0.37.83", + "@vladfrangu/async_event_emitter": "^2.4.6", + "discord-api-types": "0.37.97", "magic-bytes.js": "^1.10.0", - "tslib": "^2.6.2", - "undici": "6.13.0" + "tslib": "^2.6.3", + "undici": "6.19.8" }, "dependencies": { "@discordjs/collection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.0.tgz", - "integrity": "sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz", + "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==" + }, + "discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==" } } }, "@discordjs/util": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.0.tgz", - "integrity": "sha512-IndcI5hzlNZ7GS96RV3Xw1R2kaDuXEp7tRIy/KlhidpN/BQ1qh1NZt3377dMLTa44xDUNKT7hnXkA/oUAzD/lg==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz", + "integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==" }, "@discordjs/ws": { "version": "1.1.1", @@ -5946,34 +6375,119 @@ } }, "@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true }, + "@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "requires": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, "@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true + }, + "espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "requires": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.0.tgz", + "integrity": "sha512-LPkkenkDqyzTFauZLLAPhIb48fj6drrfMvRGSL9tS3AcZBSVTllemLSNyCvHNNL2t797S/6DJNSIwRwXgMO/eQ==", + "dev": true + }, + "@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true }, + "@eslint/plugin-kit": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", + "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "dev": true, + "requires": { + "levn": "^0.4.1" + } + }, "@esm2cjs/execa": { "version": "6.1.1-cjs.1", "resolved": "https://registry.npmjs.org/@esm2cjs/execa/-/execa-6.1.1-cjs.1.tgz", @@ -6104,27 +6618,16 @@ "yargs": "^17.7.2" } }, - "@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - } - }, "@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true }, - "@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", "dev": true }, "@iobroker/adapter-core": { @@ -6163,43 +6666,107 @@ } }, "@iobroker/testing": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@iobroker/testing/-/testing-4.1.3.tgz", - "integrity": "sha512-PTfvlXQBXDJVX35bkJxzgjuMX6bEjUmB4Dy8+bWLqbOgyq1JQVrRn+ah5IB7hEf+4lP8wD0MpAjXFJTv3zfTvA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@iobroker/testing/-/testing-5.0.0.tgz", + "integrity": "sha512-JrtWaGrgTU5MGRZowwyrDHVz8nzh/1QUqiOo1g9SXrRwT3PH0f6wRQKfe/RKiULFD2O4N3isc7pqyZg/uv4wdA==", "dev": true, "requires": { - "alcalzone-shared": "~4.0.3", - "chai": "^4.3.7", - "chai-as-promised": "^7.1.1", - "debug": "^4.3.4", - "fs-extra": "^10.1.0", - "mocha": "^10.2.0", - "sinon": "^15.0.1", + "alcalzone-shared": "~4.0.8", + "chai": "^4.5.0", + "chai-as-promised": "^7.1.2", + "debug": "^4.3.7", + "fs-extra": "^11.2.0", + "mocha": "^10.7.3", + "sinon": "^19.0.2", "sinon-chai": "^3.7.0" }, "dependencies": { - "@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + } + }, + "chai-as-promised": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", + "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "dev": true, + "requires": { + "check-error": "^1.0.2" + } + }, + "check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "requires": { + "get-func-name": "^2.0.2" + } + }, + "deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, "requires": { - "type-detect": "4.0.8" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" } }, - "sinon": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", - "integrity": "sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==", + "loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "requires": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^10.3.0", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.4", - "supports-color": "^7.2.0" + "get-func-name": "^2.0.1" } + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "sinon-chai": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", + "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "dev": true, + "requires": {} + }, + "type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true } } }, @@ -6224,9 +6791,9 @@ }, "dependencies": { "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true }, "ansi-styles": { @@ -6403,14 +6970,14 @@ "dev": true }, "@sapphire/async-queue": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz", - "integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==" + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.3.tgz", + "integrity": "sha512-x7zadcfJGxFka1Q3f8gCts1F0xMwCKbZweM85xECGI0hBTeIZJGGCrHgLggihBoprlQ/hBmDR5LKfIPqnmHM3w==" }, "@sapphire/shapeshift": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz", - "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz", + "integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==", "requires": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" @@ -6422,51 +6989,115 @@ "integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==" }, "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.2.tgz", + "integrity": "sha512-4Bb+oqXZTSTZ1q27Izly9lv8B9dlV61CROxPiVtywwzv5SnytJqhvYe6FclHYuXml4cd1VHPo1zd5PmTeJozvA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1" + } + }, + "@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + }, + "dependencies": { + "type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true + } + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "dev": true + }, + "@stylistic/eslint-plugin": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.8.0.tgz", + "integrity": "sha512-Ufvk7hP+bf+pD35R/QfunF793XlSRIC7USr3/EdgduK9j13i2JjmsM0LUz3/foS+jDYp2fzyWZA9N44CPur0Ow==", "dev": true, "requires": { - "@sinonjs/commons": "^3.0.0" + "@typescript-eslint/utils": "^8.4.0", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" }, "dependencies": { - "@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true + }, + "espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "requires": { - "type-detect": "4.0.8" + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" } + }, + "picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true } } }, - "@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "@stylistic/eslint-plugin-js": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.8.0.tgz", + "integrity": "sha512-/e7pSzVMrwBd6yzSDsKHwax3TS96+pd/xSKzELaTkOuYqUhYfj/becWdfDbFSBGQD7BBBCiiE4L8L2cUfu5h+A==", "dev": true, "requires": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true + }, + "espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "requires": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + } + } } }, - "@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -6498,20 +7129,45 @@ "dev": true }, "@types/chai": { - "version": "4.3.16", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", - "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", + "version": "4.3.19", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.19.tgz", + "integrity": "sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw==", "dev": true }, "@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.0.tgz", + "integrity": "sha512-YbYaXFqJwSABp9OXQTVrPPmstZgNjkRieWVd/xAl5Yc/e5+F44bXLeQggpvm0sjsS1bg+2Y5cwU+rquwwD2dXA==", "dev": true, "requires": { "@types/chai": "*" } }, + "@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint__js": { + "version": "8.42.3", + "resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz", + "integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==", + "dev": true, + "requires": { + "@types/eslint": "*" + } + }, + "@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, "@types/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", @@ -6522,6 +7178,12 @@ "@types/node": "*" } }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "@types/linkify-it": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", @@ -6557,17 +7219,17 @@ "dev": true }, "@types/mocha": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.7.tgz", - "integrity": "sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==", + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.8.tgz", + "integrity": "sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw==", "dev": true }, "@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "22.5.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", + "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", "requires": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "@types/proxyquire": { @@ -6620,16 +7282,16 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz", - "integrity": "sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz", + "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/type-utils": "7.15.0", - "@typescript-eslint/utils": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/type-utils": "8.6.0", + "@typescript-eslint/utils": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -6637,114 +7299,88 @@ } }, "@typescript-eslint/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz", + "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.15.0.tgz", - "integrity": "sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz", + "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==", "dev": true, "requires": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0" + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0" } }, "@typescript-eslint/type-utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.15.0.tgz", - "integrity": "sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz", + "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/utils": "7.15.0", + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/utils": "8.6.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.6.0.tgz", + "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.15.0.tgz", - "integrity": "sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz", + "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==", "dev": true, "requires": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^1.3.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } } }, "@typescript-eslint/utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.15.0.tgz", - "integrity": "sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.6.0.tgz", + "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0" + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0" } }, "@typescript-eslint/visitor-keys": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.15.0.tgz", - "integrity": "sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz", + "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==", "dev": true, "requires": { - "@typescript-eslint/types": "7.15.0", + "@typescript-eslint/types": "8.6.0", "eslint-visitor-keys": "^3.4.3" } }, - "@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "@vladfrangu/async_event_emitter": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.0.tgz", - "integrity": "sha512-eNb/9DMwNvhhgn1UuQ8Rl90jhj9PBkYH4oQ522TkiWUVWRfbh3PjdOTFkVGNKs5+xUXalkgFrUSwtY8u0g0S4g==" + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz", + "integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==" }, "abort-controller": { "version": "3.0.0", @@ -6756,9 +7392,9 @@ } }, "acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true }, "acorn-jsx": { @@ -6826,9 +7462,9 @@ } }, "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -6843,14 +7479,8 @@ }, "argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, "arrify": { @@ -6860,9 +7490,9 @@ "dev": true }, "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true }, "asynckit": { @@ -6906,9 +7536,9 @@ "dev": true }, "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true }, "bluebird": { @@ -6918,13 +7548,12 @@ "dev": true }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "braces": { @@ -6975,27 +7604,25 @@ } }, "chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", + "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", "dev": true, "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" } }, "chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.0.tgz", + "integrity": "sha512-sMsGXTrS3FunP/wbqh/KxM8Kj/aLPXQGkNtvE5wPfSToq8wkkvBpTZo1LIiEVmC4BwkKpag+l5h/20lBMk6nUg==", "dev": true, "requires": { - "check-error": "^1.0.2" + "check-error": "^2.0.0" } }, "chalk": { @@ -7009,18 +7636,15 @@ } }, "check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "requires": { - "get-func-name": "^2.0.2" - } + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true }, "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "requires": { "anymatch": "~3.1.2", @@ -7103,12 +7727,12 @@ } }, "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, "decamelize": { @@ -7118,13 +7742,10 @@ "dev": true }, "deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true }, "deep-is": { "version": "0.1.4", @@ -7144,46 +7765,35 @@ "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, "discord-api-types": { "version": "0.37.83", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.83.tgz", "integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==" }, "discord.js": { - "version": "14.15.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.15.3.tgz", - "integrity": "sha512-/UJDQO10VuU6wQPglA4kz2bw2ngeeSbogiIPx/TsnctfzV/tNf+q+i1HlgtX1OGpeOBpJH9erZQNO5oRM2uAtQ==", + "version": "14.16.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.16.2.tgz", + "integrity": "sha512-VGNi9WE2dZIxYM8/r/iatQQ+3LT8STW4hhczJOwm+DBeHq66vsKDCk8trChNCB01sMO9crslYuEMeZl2d7r3xw==", "requires": { - "@discordjs/builders": "^1.8.2", + "@discordjs/builders": "^1.9.0", "@discordjs/collection": "1.5.3", - "@discordjs/formatters": "^0.4.0", - "@discordjs/rest": "^2.3.0", - "@discordjs/util": "^1.1.0", - "@discordjs/ws": "^1.1.1", + "@discordjs/formatters": "^0.5.0", + "@discordjs/rest": "^2.4.0", + "@discordjs/util": "^1.1.1", + "@discordjs/ws": "1.1.1", "@sapphire/snowflake": "3.5.3", - "discord-api-types": "0.37.83", + "discord-api-types": "0.37.97", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", - "tslib": "2.6.2", - "undici": "6.13.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" + "tslib": "^2.6.3", + "undici": "6.19.8" + }, + "dependencies": { + "discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==" + } } }, "duplexify": { @@ -7353,55 +7963,89 @@ } }, "eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.0.tgz", + "integrity": "sha512-yVS6XODx+tMFMDFcG4+Hlh+qG7RM6cCJXtQhCKLSsr3XkLvWggHjCqjfh0XsPPnt1c56oaT6PMgW9XWQQjdHXA==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.11.0", + "@eslint/plugin-kit": "^0.2.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true + }, + "espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "requires": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, "requires": { "esrecurse": "^4.3.0", @@ -7432,9 +8076,9 @@ "dev": true }, "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -7538,21 +8182,21 @@ "dev": true }, "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "requires": { "reusify": "^1.0.4" } }, "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "requires": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" } }, "fill-keys": { @@ -7591,30 +8235,19 @@ "dev": true }, "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } + "flatted": "^3.2.9", + "keyv": "^4.5.4" } }, "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "follow-redirects": { @@ -7624,9 +8257,9 @@ "dev": true }, "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "requires": { "cross-spawn": "^7.0.0", @@ -7670,9 +8303,9 @@ "dev": true }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, @@ -7723,17 +8356,27 @@ "dev": true }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "glob-parent": { @@ -7746,13 +8389,10 @@ } }, "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true }, "globalyzer": { "version": "0.1.0", @@ -7760,20 +8400,6 @@ "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", "dev": true }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, "globrex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", @@ -7907,9 +8533,9 @@ "dev": true }, "ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true }, "import-fresh": { @@ -8034,12 +8660,6 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -8047,9 +8667,9 @@ "dev": true }, "jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", "dev": true, "requires": { "@isaacs/cliui": "^8.0.2", @@ -8114,6 +8734,12 @@ "bignumber.js": "^9.0.0" } }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -8137,9 +8763,9 @@ } }, "just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", "dev": true }, "jwa": { @@ -8163,6 +8789,15 @@ "safe-buffer": "^5.0.1" } }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, "klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", @@ -8245,9 +8880,9 @@ "dev": true }, "loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", + "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", "dev": true, "requires": { "get-func-name": "^2.0.1" @@ -8324,9 +8959,9 @@ "dev": true }, "micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "requires": { "braces": "^3.0.3", @@ -8355,12 +8990,12 @@ "dev": true }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" } }, "minimist": { @@ -8370,9 +9005,9 @@ "dev": true }, "minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true }, "mkdirp": { @@ -8382,9 +9017,9 @@ "dev": true }, "mocha": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", - "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", "dev": true, "requires": { "ansi-colors": "^4.1.3", @@ -8409,28 +9044,6 @@ "yargs-unparser": "^2.0.0" }, "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, "minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -8440,12 +9053,6 @@ "brace-expansion": "^2.0.1" } }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -8479,9 +9086,9 @@ "dev": true }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "natural-compare": { @@ -8491,16 +9098,16 @@ "dev": true }, "nise": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", - "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/nise/-/nise-6.1.1.tgz", + "integrity": "sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==", "dev": true, "requires": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "^10.0.2", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.1", + "@sinonjs/text-encoding": "^0.7.3", + "just-extend": "^6.2.0", + "path-to-regexp": "^8.1.0" } }, "node-fetch": { @@ -8558,17 +9165,17 @@ } }, "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" } }, "p-limit": { @@ -8589,6 +9196,12 @@ "p-limit": "^3.0.2" } }, + "package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -8604,12 +9217,6 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -8623,42 +9230,33 @@ "dev": true }, "path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, "requires": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "dependencies": { "lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz", + "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==", "dev": true } } }, "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.1.0.tgz", + "integrity": "sha512-Bqn3vc8CMHty6zuD+tG23s6v2kwxslHEhTj4eYaVKGIEB+YX/2wd0/rgXLFD9G9id9KCtbVy/3ZgmvZjpa0UdQ==", "dev": true }, "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true }, "picocolors": { @@ -8724,39 +9322,6 @@ "semver": "^7.1.2", "tmp": "^0.2.1", "uglify-js": "^3.7.7" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } } }, "proxy-from-env": { @@ -8866,40 +9431,33 @@ "dev": true }, "rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, "requires": { - "glob": "^10.3.7" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dev": true, "requires": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" } }, "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -8962,77 +9520,34 @@ "dev": true }, "sinon": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-18.0.0.tgz", - "integrity": "sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==", + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-19.0.2.tgz", + "integrity": "sha512-euuToqM+PjO4UgXeLETsfQiuoyPXlqFezr6YZDFwHR3t4qaX0fZUe1MfPMznTL5f8BWrVS89KduLdMUsxFCO6g==", "dev": true, "requires": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.2.0", - "nise": "^6.0.0", - "supports-color": "^7" + "@sinonjs/fake-timers": "^13.0.2", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "nise": "^6.1.1", + "supports-color": "^7.2.0" }, "dependencies": { - "@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0" - } - }, - "just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true - }, - "nise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-6.0.0.tgz", - "integrity": "sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/text-encoding": "^0.7.2", - "just-extend": "^6.2.0", - "path-to-regexp": "^6.2.1" - } - }, - "path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", + "diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true } } }, "sinon-chai": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", - "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-4.0.0.tgz", + "integrity": "sha512-cWqO7O2I4XfJDWyWElAQ9D/dtdh5Mo0RHndsfiiYyjWnlPzBJdIvjCVURO4EjyYaC3BjV+ISNXCfTXPXTEIEWA==", "dev": true, "requires": {} }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9236,9 +9751,9 @@ } }, "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "type-check": { "version": "0.4.0", @@ -9255,18 +9770,24 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, "typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true }, + "typescript-eslint": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.6.0.tgz", + "integrity": "sha512-eEhhlxCEpCd4helh3AO1hk0UP2MvbRi9CtIAJTVPQjuSXOOO2jsEacNi4UdcJzZJbeuVg1gMhtZ8UYb+NFYPrA==", + "dev": true, + "peer": true, + "requires": { + "@typescript-eslint/eslint-plugin": "8.6.0", + "@typescript-eslint/parser": "8.6.0", + "@typescript-eslint/utils": "8.6.0" + } + }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -9286,14 +9807,14 @@ "dev": true }, "undici": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.13.0.tgz", - "integrity": "sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==" + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz", + "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==" }, "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "universalify": { "version": "2.0.0", diff --git a/package.json b/package.json index 9290be0..cabf01b 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "notification", "message", "bot", - "iobroker" + "ioBroker" ], "repository": { "type": "git", @@ -26,35 +26,36 @@ "dependencies": { "@iobroker/adapter-core": "^3.1.6", "autobind-decorator": "^2.4.0", - "discord.js": "^14.15.3", + "discord.js": "^14.16.2", "source-map-support": "^0.5.21" }, "devDependencies": { - "@alcalzone/release-script": "^3.7.3", + "@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", + "@crycode/eslint-config": "^2.1.1", "@iobroker/adapter-dev": "^1.3.0", - "@iobroker/testing": "^4.1.3", - "@types/chai": "^4.3.16", - "@types/chai-as-promised": "^7.1.8", - "@types/mocha": "^10.0.7", - "@types/node": "^20.14.10", + "@iobroker/testing": "^5.0.0", + "@types/chai": "^4.3.19", + "@types/chai-as-promised": "^8.0.0", + "@types/mocha": "^10.0.8", + "@types/node": "^22.5.5", "@types/proxyquire": "^1.3.31", "@types/sinon": "^17.0.3", "@types/sinon-chai": "^3.2.12", - "@typescript-eslint/eslint-plugin": "^7.15.0", - "@typescript-eslint/parser": "^7.15.0", - "chai": "^4.4.1", - "chai-as-promised": "^7.1.2", - "eslint": "^8.57.0", - "mocha": "^10.6.0", + "@typescript-eslint/eslint-plugin": "^8.6.0", + "@typescript-eslint/parser": "^8.6.0", + "chai": "^5.1.1", + "chai-as-promised": "^8.0.0", + "eslint": "^9.11.0", + "mocha": "^10.7.3", "proxyquire": "^2.1.3", - "rimraf": "^5.0.8", - "sinon": "^18.0.0", - "sinon-chai": "^3.7.0", + "rimraf": "^6.0.1", + "sinon": "^19.0.2", + "sinon-chai": "^4.0.0", "ts-node": "^10.9.2", - "typescript": "^5.5.3" + "typescript": "^5.5.4" }, "main": "build/main.js", "files": [ @@ -77,7 +78,7 @@ "test:integration": "mocha test/integration --exit", "test": "npm run test:ts && npm run test:package", "check": "tsc --noEmit", - "lint": "eslint --ext .ts src/", + "lint": "eslint .", "translate": "translate-adapter -b admin/i18n/en.json", "release": "release-script" }, diff --git a/src/commands.ts b/src/commands.ts index 6c1b0bc..4ceec17 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -83,7 +83,7 @@ export class DiscordAdapterSlashCommands { /** * Collection of the known (registered) custom commands and their option choices. */ - private customCommands: Collection> = new Collection(); + private customCommands: Collection> = new Collection>(); /** * If commands are fully registered including their permissions. @@ -94,12 +94,12 @@ export class DiscordAdapterSlashCommands { * The last registered commands. * Used to check if something changed an we need to register the commands again. */ - private lastCommandsJson: any[] | null = null; + private lastCommandsJson: unknown[] | null = null; /** * Collection of configurations for objects with commands enabled. */ - private commandObjectConfig: Collection = new Collection(); + private commandObjectConfig: Collection = new Collection(); /** * Collection of the last seen interactions of custom commands (not iob-get/-set) @@ -108,7 +108,7 @@ export class DiscordAdapterSlashCommands { * Need to cache this here since there seems to be no way to get an interaction * by ID from discord.js. */ - private lastInteractions: Collection | Interaction> = new Collection(); + private lastInteractions: Collection | Interaction> = new Collection | Interaction>(); /** * Timeout to trigger the delayed registration of the slash commands. @@ -120,7 +120,7 @@ export class DiscordAdapterSlashCommands { * This is extended by some localized strings at runtime. * Used to determine true values from iob-set slash commands. */ - private wellKnownbooleanTrueValues: Set = new Set(['true', 'on', 'yes', '1']); + private wellKnownbooleanTrueValues: Set = new Set([ 'true', 'on', 'yes', '1' ]); constructor (adapter: DiscordAdapter) { this.adapter = adapter; @@ -130,10 +130,11 @@ export class DiscordAdapterSlashCommands { * When the adapter is Ready. * Called by `adapter.onReady()` after some basic checks and setup. */ + // eslint-disable-next-line @typescript-eslint/require-await public async onReady (): Promise { // apply custom command names if configured if (this.adapter.config.cmdGetStateName) { - if (this.adapter.config.cmdGetStateName.match(/^[a-z][0-9a-z-_]{1,32}$/)) { + if (/^[a-z][0-9a-z-_]{1,32}$/.exec(this.adapter.config.cmdGetStateName)) { this.cmdGetStateName = this.adapter.config.cmdGetStateName; } else { this.adapter.log.warn(`Invalid custom get state command name '${this.adapter.config.cmdGetStateName}' provied! Using default 'iob-get'.`); @@ -141,7 +142,7 @@ export class DiscordAdapterSlashCommands { } if (this.adapter.config.cmdSetStateName) { this.cmdSetStateName = this.adapter.config.cmdSetStateName; - if (this.adapter.config.cmdSetStateName.match(/^[a-z][0-9a-z-_]{1,32}$/)) { + if (/^[a-z][0-9a-z-_]{1,32}$/.exec(this.adapter.config.cmdSetStateName)) { this.cmdSetStateName = this.adapter.config.cmdSetStateName; } else { this.adapter.log.warn(`Invalid custom set state command name '${this.adapter.config.cmdSetStateName}' provied! Using default 'iob-set'.`); @@ -185,7 +186,7 @@ export class DiscordAdapterSlashCommands { this.adapter.log.debug('Commands not enabled'); // check for commands and remove them all - for (const [, guild] of this.adapter.client.guilds.cache) { + for (const [ , guild ] of this.adapter.client.guilds.cache) { await this.removeGuildCommands(guild); } @@ -241,7 +242,7 @@ export class DiscordAdapterSlashCommands { // setup choices for get and set commands this.cmdGetStateChoices = []; this.cmdSetStateChoices = []; - for (const [, objCfg] of this.commandObjectConfig) { + for (const [ , objCfg ] of this.commandObjectConfig) { if (objCfg.get) { this.cmdGetStateChoices.push({ name: objCfg.name, @@ -270,7 +271,7 @@ export class DiscordAdapterSlashCommands { if (this.adapter.config.enableCustomCommands) { loopCustomCommands: for (const customCommandCfg of this.adapter.config.customCommands) { - if (!customCommandCfg.name.match(/^[a-z][0-9a-z-_]{1,32}$/) || customCommandCfg.description.length === 0 || customCommandCfg.description.length > 100) { + if (!(/^[a-z][0-9a-z-_]{1,32}$/.exec(customCommandCfg.name)) || customCommandCfg.description.length === 0 || customCommandCfg.description.length > 100) { this.adapter.log.warn(`Custom command "${customCommandCfg.name}" has an invalid name or description configured!`); continue; } @@ -297,7 +298,7 @@ export class DiscordAdapterSlashCommands { const optionsChoices = new Collection(); // add configured options - const cmdOpts: Set = new Set(); + const cmdOpts: Set = new Set(); if (Array.isArray(customCommandCfg.options)) { // max 25 options are allowed if (customCommandCfg.options.length > 25) { @@ -312,7 +313,7 @@ export class DiscordAdapterSlashCommands { await this.setupCustomCommandIobObjects(customCommandCfg); for (const customCommandCfgOpt of customCommandCfg.options) { - if (!customCommandCfgOpt.name.match(/^[a-z][0-9a-z-_]{1,32}$/) || customCommandCfgOpt.description.length === 0 || customCommandCfgOpt.description.length > 100) { + if (!(/^[a-z][0-9a-z-_]{1,32}$/.exec(customCommandCfgOpt.name)) || customCommandCfgOpt.description.length === 0 || customCommandCfgOpt.description.length > 100) { this.adapter.log.warn(`Custom command "${customCommandCfg.name}" option "${customCommandCfgOpt.name}" has an invalid name or description configured!`); continue loopCustomCommands; } @@ -324,7 +325,7 @@ export class DiscordAdapterSlashCommands { cmdOpts.add(customCommandCfgOpt.name); switch (customCommandCfgOpt.type) { - case 'string': + case 'string': { // string options may have choices from the ioBroker object let choices: (string | CommandOptionChoiceData)[] = []; try { @@ -332,7 +333,7 @@ export class DiscordAdapterSlashCommands { if (typeof val !== 'string') { this.adapter.log.warn(`Value of ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices is not a string!`); } else { - choices = JSON.parse(val); + choices = JSON.parse(val) as (string | CommandOptionChoiceData)[]; } } catch (err) { this.adapter.log.warn(`Could not parse JSON from ${this.adapter.namespace}.slashCommands.${customCommandCfg.name}.option-${customCommandCfgOpt.name}.choices! ${err}`); @@ -361,6 +362,7 @@ export class DiscordAdapterSlashCommands { return opt; }); break; + } case 'number': cmdCustom.addNumberOption((opt) => opt.setName(customCommandCfgOpt.name).setDescription(customCommandCfgOpt.description).setRequired(!!customCommandCfgOpt.required)); @@ -433,7 +435,7 @@ export class DiscordAdapterSlashCommands { this.adapter.log.debug('Commands needs to be updated'); // register commands for all servers of the bot (guild commands are applied instant and may have permissions per user set) - for (const [, guild] of this.adapter.client.guilds.cache) { + for (const [ , guild ] of this.adapter.client.guilds.cache) { try { if (this.adapter.config.commandsGlobal) { // global commands enabled, remove per guild commands @@ -446,7 +448,8 @@ export class DiscordAdapterSlashCommands { } } catch (err) { - if (err instanceof DiscordAPIError && err.message === 'Missing Access'){ + if (err instanceof DiscordAPIError && err.message === 'Missing Access') { + // eslint-disable-next-line @typescript-eslint/no-base-to-string this.adapter.log.warn(`Error registering commands for server ${guild.name} (id:${guild.id}). Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`); } else { this.adapter.log.warn(`Error registering commands for server ${guild.name} (id:${guild.id}): ${err}`); @@ -468,6 +471,7 @@ export class DiscordAdapterSlashCommands { } catch (err) { if (err instanceof DiscordAPIError && err.message === 'Missing Access') { + // eslint-disable-next-line @typescript-eslint/no-base-to-string this.adapter.log.warn(`Error registering global commands. Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`); } else { this.adapter.log.warn(`Error registering global commands: ${err}`); @@ -484,6 +488,122 @@ export class DiscordAdapterSlashCommands { this.registerCommandsDone = true; } + /** + * Setup an ioBroker object for discord slash commands. + * @param objId ID of the ioBroker object to set up. + * @param cfg Command configuration for the ioBroker object or null to remove a possibly existing configuration. + */ + public setupCommandObject (objId: string, cfg: CommandObjectConfig | null): void { + // check if alias is already in use + if (cfg) { + const conflictingAlias = this.commandObjectConfig.find((coc) => coc.alias === cfg?.alias && coc.id !== cfg.id); + if (conflictingAlias) { + this.adapter.log.warn(`Command alias ${cfg.alias} of object ${cfg.id} already in use by object ${conflictingAlias.id}! ${cfg.id} will be ignored.`); + cfg = null; + } + } + + // remove if commands are not enabled or alias conflict + if (!cfg) { + if (this.commandObjectConfig.has(objId)) { + this.commandObjectConfig.delete(objId); + this.triggerDelayedRegisterSlashCommands(); + } + return; + } + + // update only if changed + const currentCfg = this.commandObjectConfig.get(objId); + if (!isDeepStrictEqual(cfg, currentCfg)) { + this.adapter.log.debug(`Update command configuration for ${objId}: ${JSON.stringify(cfg)}`); + this.commandObjectConfig.set(objId, cfg); + this.triggerDelayedRegisterSlashCommands(); + } + } + + /** + * Initialize a delayed registration of the slash commands. + * Calls `registerSlashCommands()` five seconds after the last call of this method. + * If called again within the five seconds the timeout starts again. + * + * This is used to handle object changes better and concat multiple changed + * object configurations into a single API call. + * + * If the initial custom objects setup of the adapter isn't done, this method + * does nothing since the command registration is called during this explicit. + */ + public triggerDelayedRegisterSlashCommands (): void { + // do nothing on init + if (!this.adapter.initialCustomObjectSetupDone) return; + + if (this.triggerDelayedRegisterSlashCommandsTimeout) { + this.adapter.clearTimeout(this.triggerDelayedRegisterSlashCommandsTimeout); + } + + this.adapter.setTimeout(() => { + this.triggerDelayedRegisterSlashCommandsTimeout = null; + this.adapter.log.debug('Starting delayed slash commands registration...'); + void this.registerSlashCommands(); + }, 5000); + } + + /** + * Send a reply to a custom slash command. + * @param interactionId The ID of the interaction to reply to. The interactions needs to be cached in this instance. + * @param msg The message to reply with. May be a simple string, a MessageOptions object or a stringified JSON MessageOptions object. + * @returns Promise which resolves withe the ID of the reply message if the reply is sent. + * @throws Error if the reply could not be sent for some reason (i.e. some check failed). + */ + public async sendCmdCustomReply (interactionId: Snowflake, msg: string | MessageCreateOptions): Promise { + // get the interaction + const interaction = this.lastInteractions.get(interactionId); + + if (!interaction) { + throw new Error(`No current interaction with ID ${interactionId} found for reply!`); + } + + let cscTxt: string = ''; + + if (interaction.isCommand()) { + // command interaction + const { commandName } = interaction; + + const cmdCfg = this.adapter.config.customCommands.find((c) => c.name === commandName); + if (!cmdCfg) { + throw new Error(`No configuration for custom slash command ${commandName} of interaction ${interactionId} found for reply!`); + } + + cscTxt = ` of custom slash command ${commandName}`; + } + + if (!interaction.isRepliable()) { + throw new Error(`Interaction ${interactionId}${cscTxt} is not repliable!`); + } + + // if a string is given try to parse it and prepare it as MessageOptions object + if (typeof msg === 'string') { + try { + msg = this.adapter.parseStringifiedMessageOptions(msg); + } catch (err) { + throw new Error(`Reply to interaction ${interactionId}${cscTxt} is invalid: ${err}`); + } + } + + // send the reply + const replyMsg = await interaction.editReply(msg); + return replyMsg.id; + } + + /** + * Write a summay of all currently for commands configured objects to the log. + */ + public logConfiguredCommandObjects (): void { + this.adapter.log.info('Configured state objects for discord slash commands:'); + for (const [ , cmdObjCfg ] of this.commandObjectConfig) { + this.adapter.log.info(` |- ${cmdObjCfg.id} - alias:${cmdObjCfg.alias}, name:${cmdObjCfg.name}, get:${cmdObjCfg.get}, set:${cmdObjCfg.set}`); + } + this.adapter.log.info('---'); + } /** * Remove registered global commands if any. @@ -504,6 +624,7 @@ export class DiscordAdapterSlashCommands { } } catch (err) { if (err instanceof DiscordAPIError && err.message === 'Missing Access') { + // eslint-disable-next-line @typescript-eslint/no-base-to-string this.adapter.log.warn(`Error while removing registered global commands. Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`); } else { this.adapter.log.warn(`Error while removing registered global commands: ${err}`); @@ -531,6 +652,7 @@ export class DiscordAdapterSlashCommands { } } catch (err) { if (err instanceof DiscordAPIError && err.message === 'Missing Access') { + // eslint-disable-next-line @typescript-eslint/no-base-to-string this.adapter.log.warn(`Error while removing registered commands for server ${guild.name} (id:${guild.id}). Seams like the bot is missing the 'applications.commands' scope on the server. ${err}`); } else { this.adapter.log.warn(`Error while removing registered commands for server ${guild.name} (id:${guild.id}): ${err}`); @@ -544,7 +666,7 @@ export class DiscordAdapterSlashCommands { private async setupCustomCommandIobObjects (cmdCfg: ioBroker.AdapterConfigCustomCommand): Promise { const cmdName = cmdCfg.name; - await this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}`, { + await this.adapter.extendObjectCached(`slashCommands.${cmdName}`, { type: 'channel', common: { name: cmdCfg.description, @@ -554,7 +676,7 @@ export class DiscordAdapterSlashCommands { // generic custom command objects await Promise.all([ - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.json`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.json`, { type: 'state', common: { name: i18n.getStringOrTranslated('JSON data'), @@ -566,7 +688,7 @@ export class DiscordAdapterSlashCommands { }, native: {}, }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.timestamp`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.timestamp`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last use timestamp'), @@ -578,7 +700,7 @@ export class DiscordAdapterSlashCommands { }, native: {}, }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.sendReply`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.sendReply`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send reply'), @@ -590,7 +712,7 @@ export class DiscordAdapterSlashCommands { }, native: {}, }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.interactionId`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.interactionId`, { type: 'state', common: { name: i18n.getStringOrTranslated('Interaction ID'), @@ -602,7 +724,7 @@ export class DiscordAdapterSlashCommands { }, native: {}, }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userId`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.userId`, { type: 'state', common: { name: i18n.getStringOrTranslated('User ID'), @@ -614,7 +736,7 @@ export class DiscordAdapterSlashCommands { }, native: {}, }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userTag`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.userTag`, { type: 'state', common: { name: i18n.getStringOrTranslated('User tag'), @@ -626,7 +748,7 @@ export class DiscordAdapterSlashCommands { }, native: {}, }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.userName`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.userName`, { type: 'state', common: { name: i18n.getStringOrTranslated('User name'), @@ -638,7 +760,7 @@ export class DiscordAdapterSlashCommands { }, native: {}, }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.serverId`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.serverId`, { type: 'state', common: { name: i18n.getStringOrTranslated('Server ID'), @@ -650,7 +772,7 @@ export class DiscordAdapterSlashCommands { }, native: {}, }), - this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.channelId`, { + this.adapter.extendObjectCached(`slashCommands.${cmdName}.channelId`, { type: 'state', common: { name: i18n.getStringOrTranslated('Channel ID'), @@ -665,9 +787,9 @@ export class DiscordAdapterSlashCommands { ]); // custom command option objects - const proms: Promise[] = []; + const proms: Promise[] = []; for (const cmdCfgOpt of cmdCfg.options) { - await this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}`, { + await this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}`, { type: 'channel', common: { name: i18n.getStringOrTranslated('Option %s', cmdCfgOpt.description), @@ -677,7 +799,7 @@ export class DiscordAdapterSlashCommands { let role: string; let type: ioBroker.CommonType; - let def: any; + let def: unknown; switch (cmdCfgOpt.type) { case 'number': role = 'value'; @@ -697,7 +819,7 @@ export class DiscordAdapterSlashCommands { def = ''; } - proms.push(this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.value`, { + proms.push(this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.value`, { type: 'state', common: { name: i18n.getStringOrTranslated('Option %s value', cmdCfgOpt.description), @@ -712,7 +834,7 @@ export class DiscordAdapterSlashCommands { // for string options add a choices state if (cmdCfgOpt.type === 'string') { - proms.push(this.adapter.extendObjectAsyncCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.choices`, { + proms.push(this.adapter.extendObjectCached(`slashCommands.${cmdName}.option-${cmdCfgOpt.name}.choices`, { type: 'state', common: { name: i18n.getStringOrTranslated('Option %s choices', cmdCfgOpt.description), @@ -752,65 +874,6 @@ export class DiscordAdapterSlashCommands { await Promise.all(proms); } - /** - * Setup an ioBroker object for discord slash commands. - * @param objId ID of the ioBroker object to set up. - * @param cfg Command configuration for the ioBroker object or null to remove a possibly existing configuration. - */ - public setupCommandObject (objId: string, cfg: CommandObjectConfig | null): void { - // check if alias is already in use - if (cfg) { - const conflictingAlias = this.commandObjectConfig.find((coc) => coc.alias === cfg?.alias && coc.id !== cfg.id); - if (conflictingAlias) { - this.adapter.log.warn(`Command alias ${cfg.alias} of object ${cfg.id} already in use by object ${conflictingAlias.id}! ${cfg.id} will be ignored.`); - cfg = null; - } - } - - // remove if commands are not enabled or alias conflict - if (!cfg) { - if (this.commandObjectConfig.has(objId)) { - this.commandObjectConfig.delete(objId); - this.triggerDelayedRegisterSlashCommands(); - } - return; - } - - // update only if changed - const currentCfg = this.commandObjectConfig.get(objId); - if (!isDeepStrictEqual(cfg, currentCfg)) { - this.adapter.log.debug(`Update command configuration for ${objId}: ${JSON.stringify(cfg)}`); - this.commandObjectConfig.set(objId, cfg); - this.triggerDelayedRegisterSlashCommands(); - } - } - - /** - * Initialize a delayed registration of the slash commands. - * Calls `registerSlashCommands()` five seconds after the last call of this method. - * If called again within the five seconds the timeout starts again. - * - * This is used to handle object changes better and concat multiple changed - * object configurations into a single API call. - * - * If the initial custom objects setup of the adapter isn't done, this method - * does nothing since the command registration is called during this explicit. - */ - public triggerDelayedRegisterSlashCommands (): void { - // do nothing on init - if (!this.adapter.initialCustomObjectSetupDone) return; - - if (this.triggerDelayedRegisterSlashCommandsTimeout) { - this.adapter.clearTimeout(this.triggerDelayedRegisterSlashCommandsTimeout); - } - - this.adapter.setTimeout(() => { - this.triggerDelayedRegisterSlashCommandsTimeout = null; - this.adapter.log.debug('Starting delayed slash commands registration...'); - this.registerSlashCommands(); - }, 5000); - } - /** * Handle interactions. */ @@ -818,11 +881,11 @@ export class DiscordAdapterSlashCommands { private async onInteractionCreate (interaction: Interaction): Promise { if (interaction.isCommand()) { // handle command interaction for build in commands and custom commands - this.handleCommandInteraction(interaction); + void this.handleCommandInteraction(interaction); } else if (interaction.isAutocomplete()) { // handle auto complete interaction - this.handleAutocompleteInteraction(interaction); + void this.handleAutocompleteInteraction(interaction); } else { // handle other interaction types to allow the usage of them in scripts @@ -843,7 +906,7 @@ export class DiscordAdapterSlashCommands { if (interaction.isCommand()) { interactionJson.options = interaction.options.data; } - this.adapter.setState('raw.interactionJson', JSON.stringify(interactionJson, (_key, value) => typeof value === 'bigint' ? value.toString() : value), true); + void this.adapter.setState('raw.interactionJson', JSON.stringify(interactionJson, (_key, value: unknown) => typeof value === 'bigint' ? value.toString() : value), true); } // remove outdated interactions @@ -926,7 +989,7 @@ export class DiscordAdapterSlashCommands { const focused = interaction.options.getFocused(true); let focusedValue: string; if (typeof focused.value !== 'string') { - return interaction.respond([]); + return await interaction.respond([]); } else { focusedValue = focused.value.toLowerCase(); } @@ -939,7 +1002,7 @@ export class DiscordAdapterSlashCommands { if (commandName === this.cmdGetStateName) { // get state command if (!this.adapter.checkUserAuthorization(authCheckTarget, { getStates: true })) { - return interaction.respond([]); + return await interaction.respond([]); } choices = this.cmdGetStateChoices; @@ -947,7 +1010,7 @@ export class DiscordAdapterSlashCommands { } else if (commandName === this.cmdSetStateName) { // set state command if (!this.adapter.checkUserAuthorization(authCheckTarget, { setStates: true })) { - return interaction.respond([]); + return await interaction.respond([]); } choices = this.cmdSetStateChoices; @@ -955,14 +1018,14 @@ export class DiscordAdapterSlashCommands { } else if (this.customCommands.has(commandName)) { // custom command if (!this.adapter.checkUserAuthorization(authCheckTarget, { useCustomCommands: true })) { - return interaction.respond([]); + return await interaction.respond([]); } choices = this.customCommands.get(commandName)?.get(focused.name) ?? []; } else { // unknown command - return interaction.respond([]); + return await interaction.respond([]); } // filter for given input @@ -974,7 +1037,7 @@ export class DiscordAdapterSlashCommands { // max. 25 choices are allowed matchedChoices.splice(25); - return interaction.respond(matchedChoices); + return await interaction.respond(matchedChoices); } /** @@ -1000,7 +1063,7 @@ export class DiscordAdapterSlashCommands { ephemeral: true, }); } - return [null, null]; + return [ null, null ]; } // get the object @@ -1016,7 +1079,7 @@ export class DiscordAdapterSlashCommands { ephemeral: true, }); } - return [null, null]; + return [ null, null ]; } if (obj.type !== 'state') { if (interaction.replied) { @@ -1029,10 +1092,10 @@ export class DiscordAdapterSlashCommands { ephemeral: true, }); } - return [null, null]; + return [ null, null ]; } - return [obj, cfg]; + return [ obj, cfg ]; } /** @@ -1042,12 +1105,12 @@ export class DiscordAdapterSlashCommands { private async handleCmdGetState (interaction: CommandInteraction): Promise { const objAlias = interaction.options.get('state', true).value as string; - const [obj, cfg] = await this.getObjectAndCfgFromAlias(objAlias, interaction); + const [ obj, cfg ] = await this.getObjectAndCfgFromAlias(objAlias, interaction); if (!obj || !cfg) { return; } - const objCustom: ioBroker.CustomConfig | undefined = obj.common.custom?.[this.adapter.namespace]; + const objCustom: ioBroker.CustomConfig | undefined = obj.common.custom?.[this.adapter.namespace] as ioBroker.CustomConfig | undefined; // check if get allowed if (!objCustom?.commandsAllowGet) { @@ -1077,7 +1140,7 @@ export class DiscordAdapterSlashCommands { let val: string = ''; // an optional MessageOptions object for special cases (like sending files) - let msgOpts: MessageCreateOptions | undefined = undefined; + let msgOpts: MessageCreateOptions | undefined; // add unit if defined in the object const unit = obj.common.unit ? ` ${obj.common.unit}` : ''; @@ -1098,10 +1161,10 @@ export class DiscordAdapterSlashCommands { msgOpts = { content: `${cfg.name}${ack}:`, - files: [{ + files: [ { attachment: b64data.buffer, name: b64data.name, - }], + } ], }; val = 'file:base64'; @@ -1115,10 +1178,10 @@ export class DiscordAdapterSlashCommands { msgOpts = { content: `${cfg.name}${ack}:`, - files: [{ + files: [ { attachment: state.val, name: getBasenameFromFilePathOrUrl(state.val), - }], + } ], }; val = `file:${state.val}`; } @@ -1134,7 +1197,7 @@ export class DiscordAdapterSlashCommands { } break; - case 'number': + case 'number': { // number values const decimals = objCustom.commandsNumberDecimals ?? 0; if (typeof state.val === 'number') { @@ -1148,6 +1211,7 @@ export class DiscordAdapterSlashCommands { val = val.replace('.', ','); } break; + } default: if (typeof state.val === 'string') { @@ -1183,12 +1247,12 @@ export class DiscordAdapterSlashCommands { private async handleCmdSetState (interaction: CommandInteraction): Promise { const objAlias = interaction.options.get('state', true).value as string; - const [obj, cfg] = await this.getObjectAndCfgFromAlias(objAlias, interaction); + const [ obj, cfg ] = await this.getObjectAndCfgFromAlias(objAlias, interaction); if (!obj || !cfg) { return; } - const objCustom: ioBroker.CustomConfig | undefined = obj.common.custom?.[this.adapter.namespace]; + const objCustom: ioBroker.CustomConfig | undefined = obj.common.custom?.[this.adapter.namespace] as ioBroker.CustomConfig | undefined; // check if set allowed if (!objCustom?.commandsAllowSet) { @@ -1320,7 +1384,7 @@ export class DiscordAdapterSlashCommands { this.lastInteractions.set(interaction.id, interaction); // promises for all set state actions - const proms: Promise[] = []; + const proms: Promise[] = []; // prepare json data const json: JsonSlashCommandObj = { @@ -1375,7 +1439,7 @@ export class DiscordAdapterSlashCommands { id: opt.channel.id, name: opt.channel.name, type: ChannelType[opt.channel.type] as ChannelTypeNames, - lastMessageId: (opt.channel.type === ChannelType.GuildText || opt.channel.type == ChannelType.GuildVoice) ? opt.channel.lastMessageId : null, + lastMessageId: (opt.channel.type === ChannelType.GuildText || opt.channel.type === ChannelType.GuildVoice) ? opt.channel.lastMessageId : null, }; } } else { @@ -1384,19 +1448,19 @@ export class DiscordAdapterSlashCommands { type: null, }; } - proms.push(this.adapter.setStateAsync(`slashCommands.${commandName}.option-${optCfg.name}.value`, json.options[optCfg.name].value, true)); + proms.push(this.adapter.setState(`slashCommands.${commandName}.option-${optCfg.name}.value`, json.options[optCfg.name].value, true)); } // set the states await Promise.all([ - this.adapter.setStateAsync(`slashCommands.${commandName}.interactionId`, interaction.id, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.channelId`, channelId, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.serverId`, guildId ?? null, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.userId`, user.id, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.userTag`, user.tag, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.userName`, user.username, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.timestamp`, interaction.createdTimestamp, true), - this.adapter.setStateAsync(`slashCommands.${commandName}.json`, JSON.stringify(json), true), + this.adapter.setState(`slashCommands.${commandName}.interactionId`, interaction.id, true), + this.adapter.setState(`slashCommands.${commandName}.channelId`, channelId, true), + this.adapter.setState(`slashCommands.${commandName}.serverId`, guildId ?? null, true), + this.adapter.setState(`slashCommands.${commandName}.userId`, user.id, true), + this.adapter.setState(`slashCommands.${commandName}.userTag`, user.tag, true), + this.adapter.setState(`slashCommands.${commandName}.userName`, user.username, true), + this.adapter.setState(`slashCommands.${commandName}.timestamp`, interaction.createdTimestamp, true), + this.adapter.setState(`slashCommands.${commandName}.json`, JSON.stringify(json), true), ...proms, ]); @@ -1405,62 +1469,4 @@ export class DiscordAdapterSlashCommands { * The reply must be triggered by the user using the .sendReply state or a `sendTo(...)` action. *****/ } - - /** - * Send a reply to a custom slash command. - * @param interactionId The ID of the interaction to reply to. The interactions needs to be cached in this instance. - * @param msg The message to reply with. May be a simple string, a MessageOptions object or a stringified JSON MessageOptions object. - * @returns Promise which resolves withe the ID of the reply message if the reply is sent. - * @throws Error if the reply could not be sent for some reason (i.e. some check failed). - */ - public async sendCmdCustomReply (interactionId: Snowflake, msg: string | MessageCreateOptions): Promise { - // get the interaction - const interaction = this.lastInteractions.get(interactionId); - - if (!interaction) { - throw new Error(`No current interaction with ID ${interactionId} found for reply!`); - } - - let cscTxt: string = ''; - - if (interaction.isCommand()) { - // command interaction - const { commandName } = interaction; - - const cmdCfg = this.adapter.config.customCommands.find((c) => c.name === commandName); - if (!cmdCfg) { - throw new Error(`No configuration for custom slash command ${commandName} of interaction ${interactionId} found for reply!`); - } - - cscTxt = ` of custom slash command ${commandName}`; - } - - if (!interaction.isRepliable()) { - throw new Error(`Interaction ${interactionId}${cscTxt} is not repliable!`); - } - - // if a string is given try to parse it and prepare it as MessageOptions object - if (typeof msg === 'string') { - try { - msg = this.adapter.parseStringifiedMessageOptions(msg); - } catch (err) { - throw new Error(`Reply to interaction ${interactionId}${cscTxt} is invalid: ${err}`); - } - } - - // send the reply - const replyMsg = await interaction.editReply(msg); - return replyMsg.id; - } - - /** - * Write a summay of all currently for commands configured objects to the log. - */ - public logConfiguredCommandObjects (): void { - this.adapter.log.info('Configured state objects for discord slash commands:'); - for (const [, cmdObjCfg] of this.commandObjectConfig) { - this.adapter.log.info(` |- ${cmdObjCfg.id} - alias:${cmdObjCfg.alias}, name:${cmdObjCfg.name}, get:${cmdObjCfg.get}, set:${cmdObjCfg.set}`); - } - this.adapter.log.info('---'); - } } diff --git a/src/lib/adapter-config.d.ts b/src/lib/adapter-config.d.ts index 5a238e0..daa5974 100644 --- a/src/lib/adapter-config.d.ts +++ b/src/lib/adapter-config.d.ts @@ -10,6 +10,7 @@ declare global { botName: string; processAllMessagesInServerChannel: boolean; reactOnMentions: boolean; + // eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents reactOnMentionsEmoji: string | Snowflake; text2commandInstance: string; text2commandRespondWith: 'message' | 'reply' | 'none'; @@ -84,4 +85,4 @@ declare global { } // this is required so the above AdapterConfig is found by TypeScript / type checking -export {}; \ No newline at end of file +export {}; diff --git a/src/lib/definitions.ts b/src/lib/definitions.ts index 7c77bf5..aa13ffa 100644 --- a/src/lib/definitions.ts +++ b/src/lib/definitions.ts @@ -1,10 +1,10 @@ -export const VALID_PRESENCE_STATUS_DATA = ['online', 'idle', 'dnd', 'invisible']; +export const VALID_PRESENCE_STATUS_DATA = [ 'online', 'idle', 'dnd', 'invisible' ] as const; -export const ACTIVITY_TYPES = ['', 'Playing', 'Streaming', 'Listening', 'Watching', 'Custom', 'Competing']; +export const ACTIVITY_TYPES = [ '', 'Playing', 'Streaming', 'Listening', 'Watching', 'Custom', 'Competing' ] as const; export type ActivityTypeNames = typeof ACTIVITY_TYPES[number]; -//export const VALID_ACTIVITY_TYPES = ['', 'Playing', 'Streaming', 'Listening', 'Watching', 'Competing']; -//export type ValidActivityTypeNames = typeof VALID_ACTIVITY_TYPES[number]; +// export const VALID_ACTIVITY_TYPES = ['', 'Playing', 'Streaming', 'Listening', 'Watching', 'Competing']; +// export type ValidActivityTypeNames = typeof VALID_ACTIVITY_TYPES[number]; /** * Valid channel types. @@ -13,8 +13,8 @@ export type ActivityTypeNames = typeof ACTIVITY_TYPES[number]; export type ChannelTypeNames = 'GuildText' | 'DM' | 'GuildVoice' | 'GroupDM' | 'GuildCategory' | 'GuildAnnouncement' | 'AnnouncementThread' | 'PublicThread' | 'PrivateThread' | 'GuildStageVoice' | 'GuildDirectory' | 'GuildForum' | 'GuildNews' | 'GuildNewsThread' | 'GuildPublicThread' | 'GuildPrivateThread'; import { - MessageEditOptions, MessageCreateOptions, + MessageEditOptions, PresenceStatus, PresenceStatusData, Snowflake, diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts index 99498b3..7964b50 100644 --- a/src/lib/i18n.ts +++ b/src/lib/i18n.ts @@ -61,6 +61,7 @@ class I18n { public getString (key: I18nKey, ...args: string[]): string { let str: string; switch (this.language) { + /* eslint-disable @stylistic/max-statements-per-line */ case 'de': str = (de as I18nObj)[key] ?? key; break; case 'en': str = (en as I18nObj)[key] ?? key; break; case 'es': str = (es as I18nObj)[key] ?? key; break; @@ -71,6 +72,7 @@ class I18n { case 'pt': str = (pt as I18nObj)[key] ?? key; break; case 'ru': str = (ru as I18nObj)[key] ?? key; break; case 'zh-cn': str = (zhCn as I18nObj)[key] ?? key; break; + /* eslint-enable @stylistic/max-statements-per-line */ default: str = key; } @@ -82,7 +84,7 @@ class I18n { * @param text The text. * @param args Array of strings to be inserted at `%s` in the text. */ - private replacePlaceholders (text: string, ...args: string[]) : string { + private replacePlaceholders (text: string, ...args: string[]): string { for (const s of args) { text = text.replace('%s', s); } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index f230978..583d7ff 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -15,7 +15,7 @@ interface BufferAndName { */ export function getBufferAndNameFromBase64String (base64String: string, name?: string): BufferAndName | null { // check for base64 encoded data - const b64match = base64String.match(/^data:([^/]+)\/([^;]+);base64,([a-zA-Z0-9+/]+=*)$/); + const b64match = /^data:([^/]+)\/([^;]+);base64,([a-zA-Z0-9+/]+=*)$/.exec(base64String); if (!b64match) { return null; } @@ -40,11 +40,11 @@ export function getBufferAndNameFromBase64String (base64String: string, name?: s * @returns The basename of the file. */ export function getBasenameFromFilePathOrUrl (file: string): string { - if (file.match(/^\w+:\/\//)) { + if (/^\w+:\/\//.exec(file)) { try { const url = new URL(file); return basename(url.pathname); - } catch (err) { + } catch (_err) { return basename(file); } } else { @@ -64,7 +64,7 @@ export function getObjName (common: ioBroker.ObjectCommon): string { return common.name; } - return common.name['en']; + return common.name.en; } /** diff --git a/src/main.ts b/src/main.ts index 1544225..13d3aab 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,14 +11,19 @@ import { } from '@iobroker/adapter-core'; import { + ActivityType, + APIEmbed, ChannelType, Client, - CloseEvent as DjsCloseEvent, Collection, + CloseEvent as DjsCloseEvent, + version as djsVersion, + DMChannel, GatewayIntentBits, Guild, GuildBasedChannel, GuildMember, + HexColorString, Message, MessageCreateOptions, NonThreadGuildBasedChannel, @@ -27,15 +32,11 @@ import { Presence, PresenceData, PresenceStatusData, + resolveColor, Snowflake, + TextChannel, User, - version as djsVersion, VoiceState, - ActivityType, - TextChannel, - APIEmbed, - resolveColor, - HexColorString, } from 'discord.js'; import { @@ -43,28 +44,28 @@ import { DiscordAdapterSlashCommands, } from './commands'; import { - SetBotPresenceOptions, - Text2commandMessagePayload, - VALID_PRESENCE_STATUS_DATA, - JsonServersMembersObj, + ACTIVITY_TYPES, + ActivityTypeNames, + ChannelTypeNames, + CheckAuthorizationOpts, + JsonMessageObj, JsonServersChannelsObj, + JsonServersMembersObj, JsonUsersObj, - UpdateUserPresenceResult, - JsonMessageObj, - CheckAuthorizationOpts, - SendToActionSendPayload, - SendToActionEditMessagePayload, MessageIdentifier, - SendToActionAwaitMessageReactionPayload, SendToActionAddReactionPayload, - SendToActionServerIdentifier, - SendToActionSendCustomCommandReplyPayload, + SendToActionAwaitMessageReactionPayload, SendToActionChannelIdentifier, + SendToActionEditMessagePayload, + SendToActionSendCustomCommandReplyPayload, + SendToActionSendPayload, + SendToActionServerIdentifier, SendToActionServerMemberIdentifier, SendToActionUserIdentifier, - ACTIVITY_TYPES, - ActivityTypeNames, - ChannelTypeNames, + SetBotPresenceOptions, + Text2commandMessagePayload, + UpdateUserPresenceResult, + VALID_PRESENCE_STATUS_DATA, } from './lib/definitions'; import { i18n } from './lib/i18n'; import { @@ -73,9 +74,9 @@ import { getObjName, userNameOrTag, } from './lib/utils'; -import { LocalizedNotification, getNewestDate } from './lib/notification-manager'; +import { getNewestDate, LocalizedNotification } from './lib/notification-manager'; -const LOGIN_WAIT_TIMES = [ +const LOGIN_WAIT_TIMES = [ 0, // none - first try! 5000, // 5 sek 10000, // 10 sek @@ -87,7 +88,7 @@ const LOGIN_WAIT_TIMES = [ 300000, // 5 min 300000, // 5 min 600000, // 10 min -]; +] as const; /** * ioBroker.discord adapter @@ -95,54 +96,60 @@ const LOGIN_WAIT_TIMES = [ class DiscordAdapter extends Adapter { /** - * Local cache for `info.connection` state. + * Instance of the discord client. */ - private infoConnected: boolean = false; + public client: Client | null = null; /** - * Instance of the discord client. + * Flag if the adapter is unloaded or is unloading. + * Used to check this in some async operations. */ - public client: Client | null = null; + public unloaded: boolean = false; + + /** + * Flag if the initial setup of the custom object configurations is done or not. + * While not done, custom object configuration changes will not trigger a + * slash commands registration automatically. + */ + public initialCustomObjectSetupDone: boolean = false; + + /** + * Local cache for `info.connection` state. + */ + private infoConnected: boolean = false; /** * Set of state IDs where received discord messages will be stored to. * Used to identify target states for received discord messages. */ - private messageReceiveStates: Set = new Set(); + private messageReceiveStates: Set = new Set(); /** * Set user IDs known to set up. * Used to check if the user objects are created on some events. */ - private knownUsers: Set = new Set(); + private knownUsers: Set = new Set(); /** * Set of objects from this instance with text2command enabled. */ - private text2commandObjects: Set = new Set(); + private text2commandObjects: Set = new Set(); /** * Cache for `extendObjectCache(...)` calls to extend objects only when changed. */ - private extendObjectCache: Collection = new Collection(); + private extendObjectCache: Collection = new Collection(); /** * Cache for `.json` states. */ - private jsonStateCache: Collection = new Collection(); + private jsonStateCache: Collection = new Collection(); /** * Instance of the slash commands handler class. */ private discordSlashCommands: DiscordAdapterSlashCommands; - /** - * Flag if the initial setup of the custom object configurations is done or not. - * While not done, custom object configuration changes will not trigger a - * slash commands registration automatically. - */ - public initialCustomObjectSetupDone: boolean = false; - /** * Flag if we are currently in shard error state from discord.js. * `false` currently not on error state, A `string` containing the error name in @@ -150,13 +157,7 @@ class DiscordAdapter extends Adapter { */ private isShardError: false | string = false; - /** - * Flag if the adapter is unloaded or is unloading. - * Used to check this in some async operations. - */ - public unloaded: boolean = false; - - public constructor(options: Partial = {}) { + public constructor (options: Partial = {}) { super({ ...options, name: 'discord', @@ -171,11 +172,154 @@ class DiscordAdapter extends Adapter { this.on('unload', this.onUnload); } + /** + * Try to detect and parse stringified JSON MessageOptions. + * + * If the `content` starts/ends with curly braces if will be treated as + * stringified JSON. Then the JSON will be parsed and some basic checks will + * be run against the parsed object. + * + * Otherwise the content will be treated as a simple string and wrapped into + * a `MessageOptions` object. + * @param content The stringified content to be parsed. + * @returns A `MessageOptions` object. + * @throws An error if parsing JSON or a check failed. + */ + public parseStringifiedMessageOptions (content: string): MessageCreateOptions { + let mo: MessageCreateOptions; + + if (content.startsWith('{') && content.endsWith('}')) { + // seems to be json + this.log.debug(`Content seems to be json`); + + try { + mo = JSON.parse(content) as MessageCreateOptions; + } catch (_err) { + throw new Error(`Content seems to be json but cannot be parsed!`); + } + + // do some basic checks against the parsed object + if ((!mo?.files && !mo.content) || (mo.files && !Array.isArray(mo.files)) || (mo.embeds && !Array.isArray(mo.embeds))) { + throw new Error(`Content is json but seems to be invalid!`); + } + + } else { + // just a string... create MessageOptions object + mo = { + content, + }; + } + + return mo; + } + + /** + * Check if a user or guild member is authorized to do something. + * For guild members their roles will also be checked. + * @param user The User or GuildMember to check. + * @param required Object containing the required flags. If not provided the check returns if the user in the list of authorized users. + * @returns `true` if the user is authorized or authorization is not enabled, `false` otherwise + */ + public checkUserAuthorization (user: User | GuildMember, required?: CheckAuthorizationOpts): boolean { + if (!this.config.enableAuthorization) { + return true; + } + + // get direct user flags + let given: ioBroker.AdapterConfigAuthorizedFlags | undefined = this.config.authorizedUsers.find((au) => au.userId === user.id); + + // for guild members find role flags and merge them all together + if (this.config.authorizedServerRoles.length > 0 && user instanceof GuildMember) { + for (const [ , role ] of user.roles.cache) { + const roleGiven = this.config.authorizedServerRoles.find((ar) => ar.serverAndRoleId === `${user.guild.id}|${role.id}`); + if (roleGiven) { + if (!given) { + given = roleGiven; + } else { + given = { + getStates: given.getStates || roleGiven.getStates, + setStates: given.setStates || roleGiven.setStates, + useCustomCommands: given.useCustomCommands || roleGiven.useCustomCommands, + useText2command: given.useText2command || roleGiven.useText2command, + }; + } + } + } + } + + // nothing found? + if (!given) { + return false; + } + + // if no required flags given just return true if something found + if (!required) { + return true; + } + + if ((required.getStates && !given.getStates) + || (required.setStates && !given.setStates) + || (required.useCustomCommands && !given.useCustomCommands) + || (required.useText2command && !given.useText2command)) { + return false; + } + + return true; + } + + /** + * Awaitable function to just wait some time. + * + * Uses `Adapter.setTimeout(...)` internally to make sure the timeout is cleared on adapter unload. + * @param time Time to wait in ms. + */ + public async wait (time: number): Promise { + return await new Promise((resolve: () => void) => this.setTimeout(resolve, time)); + } + + /** + * Internal replacemend for `extendObject(...)` which compares the given + * object for each `id` against a cached version and only calls na original + * `extendObject(...)` if the object changed. + * Using this, the object gets only updated if + * a) it's the first call for this `id` or + * b) the object needs to be changed. + */ + public async extendObjectCached (id: string, objPart: ioBroker.PartialObject, options?: ioBroker.ExtendObjectOptions): ioBroker.SetObjectPromise { + const cachedObj: ioBroker.PartialObject | undefined = this.extendObjectCache.get(id); + + if (isDeepStrictEqual(cachedObj, objPart)) { + return { id }; + } + let ret: ioBroker.NonNullCallbackReturnTypeOf; + if (options) { + ret = await this.extendObject(id, objPart, options); + } else { + ret = await this.extendObject(id, objPart); + } + this.extendObjectCache.set(id, objPart); + return ret; + } + + /** + * Internal replacement for `delObjectAsync(...)` which also removes the local + * cache entry for the given `id`. + */ + public async delObjectAsyncCached (id: string, options?: ioBroker.DelObjectOptions): Promise { + if (options?.recursive) { + this.extendObjectCache.filter((_obj, id2) => id2.startsWith(id)).each((_obj, id2) => this.extendObjectCache.delete(id2)); + } else { + this.extendObjectCache.delete(id); + } + + return await this.delObjectAsync(id, options); + } + /** * Is called when databases are connected and adapter received configuration. */ @boundMethod - private async onReady(): Promise { + private async onReady (): Promise { // Reset the connection indicator during startup await this.setInfoConnectionState(false, true); @@ -185,11 +329,11 @@ class DiscordAdapter extends Adapter { // try to get the system language const systemConfig = await this.getForeignObjectAsync('system.config'); - i18n.language = systemConfig?.common.language || 'en'; - i18n.isFloatComma = systemConfig?.common.isFloatComma || false; + i18n.language = systemConfig?.common.language ?? 'en'; + i18n.isFloatComma = systemConfig?.common.isFloatComma ?? false; // validate config - if (typeof this.config.token !== 'string' || !this.config.token.match(/^[0-9a-zA-Z-_]{24,}\.[0-9a-zA-Z-_]{6}\.[0-9a-zA-Z-_]{27,}$/)) { + if (typeof this.config.token !== 'string' || !(/^[0-9a-zA-Z-_]{24,}\.[0-9a-zA-Z-_]{6}\.[0-9a-zA-Z-_]{27,}$/.exec(this.config.token))) { this.log.error(`No or invalid token!`); return; } @@ -212,8 +356,9 @@ class DiscordAdapter extends Adapter { // setup/fix native objects from older adapter versions const botActivityTypeObj = await this.getObjectAsync('bot.activityType'); - if (botActivityTypeObj?.common?.states?.hasOwnProperty('PLAYING')) { - // TODO: use extendObjectAsync with null values when issue https://github.com/ioBroker/ioBroker.js-controller/issues/1735 is resolved + /* eslint-disable @typescript-eslint/no-unsafe-member-access */ + if (botActivityTypeObj?.common?.states?.PLAYING) { + // TODO: use extendObject with null values when issue https://github.com/ioBroker/ioBroker.js-controller/issues/1735 is resolved delete botActivityTypeObj.common.states.PLAYING; delete botActivityTypeObj.common.states.STREAMING; delete botActivityTypeObj.common.states.LISTENING; @@ -221,10 +366,11 @@ class DiscordAdapter extends Adapter { delete botActivityTypeObj.common.states.COMPETING; await this.setObjectAsync('bot.activityType', botActivityTypeObj); } + /* eslint-enable @typescript-eslint/no-unsafe-member-access */ // setup generic dynamic objects (most objects will be set up in `updateGuilds` method) if (this.config.enableRawStates) { - await this.extendObjectAsync('raw', { + await this.extendObject('raw', { type: 'channel', common: { name: i18n.getStringOrTranslated('Raw data'), @@ -232,7 +378,7 @@ class DiscordAdapter extends Adapter { native: {}, }); await Promise.all([ - this.extendObjectAsync('raw.interactionJson', { + this.extendObject('raw.interactionJson', { type: 'state', common: { name: i18n.getStringOrTranslated('Last interaction JSON data'), @@ -244,7 +390,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsync('raw.messageJson', { + this.extendObject('raw.messageJson', { type: 'state', common: { name: i18n.getStringOrTranslated('Last message JSON data'), @@ -262,7 +408,7 @@ class DiscordAdapter extends Adapter { } if (this.config.enableCustomCommands) { - await this.extendObjectAsync('slashCommands', { + await this.extendObject('slashCommands', { type: 'channel', common: { name: i18n.getStringOrTranslated('Custom Discord slash commands'), @@ -304,7 +450,7 @@ class DiscordAdapter extends Adapter { this.client.on('invalidated', () => { this.log.warn('Discord client session invalidated'); - this.setInfoConnectionState(false); + void this.setInfoConnectionState(false); }); this.client.on('shardError', (err: Error, shardId: number) => { @@ -320,10 +466,10 @@ class DiscordAdapter extends Adapter { errorMsg = err.toString(); } - if (this.isShardError != errorMsg) { + if (this.isShardError !== errorMsg) { this.isShardError = errorMsg; this.log.warn(`Discord client websocket error (shardId:${shardId}): ${errorMsg}`); - this.setInfoConnectionState(false); + void this.setInfoConnectionState(false); } else { this.log.debug(`Discord client websocket error (shardId:${shardId}): ${errorMsg}`); } @@ -333,8 +479,8 @@ class DiscordAdapter extends Adapter { // discord.js websocket is ready (connected) this.isShardError = false; this.log.info(`Discord client websocket connected (shardId:${shardId})`); - this.setInfoConnectionState(true); - this.setBotPresence(); + void this.setInfoConnectionState(true); + void this.setBotPresence(); }); this.client.on('shardResume', (shardId: number, replayedEvents: number) => this.log.debug(`Discord client websocket resume (shardId:${shardId} replayedEvents:${replayedEvents})`)); @@ -359,7 +505,7 @@ class DiscordAdapter extends Adapter { } if (this.config.observeUserPresence) { - this.client.on('presenceUpdate', (_oldPresence, newPresence) => { this.updateUserPresence(newPresence.userId, newPresence); }); + this.client.on('presenceUpdate', (_oldPresence, newPresence) => this.updateUserPresence(newPresence.userId, newPresence)); } if (this.config.observeUserVoiceState) { @@ -367,7 +513,7 @@ class DiscordAdapter extends Adapter { } // init commands instance - need to be done after discord client setup - this.discordSlashCommands.onReady(); + await this.discordSlashCommands.onReady(); // subscribe needed states and objects this.subscribeStates('servers.*.channels.*.send'); @@ -391,6 +537,7 @@ class DiscordAdapter extends Adapter { const view = await this.getObjectViewAsync('system', 'custom', {}); if (view?.rows) { for (const item of view.rows) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument await this.setupObjCustom(item.id, item.value?.[this.namespace]); } } @@ -448,7 +595,7 @@ class DiscordAdapter extends Adapter { this.log.warn(`Discord login error: ${errorMsg}`); } if (err.name === 'AbortError' || err.name === 'ConnectTimeoutError' || (err as NodeJS.ErrnoException).code === 'EAI_AGAIN' - || (err instanceof AggregateError && err.errors.map((e: NodeJS.ErrnoException) => e.code).includes('ENETUNREACH')) ) { + || (err instanceof AggregateError && err.errors.map((e: NodeJS.ErrnoException) => e.code).includes('ENETUNREACH'))) { // AbortError and ConnectTimeoutError are results of network errors // EAI_AGAIN is a result of DNS errors // AggregateError containing ENETUNREACH occurs in case routing problems @@ -458,10 +605,10 @@ class DiscordAdapter extends Adapter { tryNr = LOGIN_WAIT_TIMES.length - 1; } - this.log.info(`Wait ${LOGIN_WAIT_TIMES[tryNr] / 1000} seconds before next login try (#${tryNr+1}) ...`); + this.log.info(`Wait ${LOGIN_WAIT_TIMES[tryNr] / 1000} seconds before next login try (#${tryNr + 1}) ...`); await this.wait(LOGIN_WAIT_TIMES[tryNr]); - return this.loginClient(tryNr); + return await this.loginClient(tryNr); } return err.name; } else { @@ -490,10 +637,10 @@ class DiscordAdapter extends Adapter { // update needed this.log.debug(`Update of bot name needed - current name: ${this.client.user.username} - configured name: ${this.config.botName}`); try { - const proms: Promise[] = []; + const proms: Promise[] = []; proms.push(this.client.user.setUsername(this.config.botName)); - for (const [, guild] of this.client.guilds.cache) { + for (const [ , guild ] of this.client.guilds.cache) { const me = guild.members.cache.get(this.client.user.id); if (me) { proms.push(me.setNickname(this.config.botName)); @@ -531,19 +678,19 @@ class DiscordAdapter extends Adapter { * Collection of known users on all known servers. * Used to create/delete user objects. */ - const allServersUsers: Collection = new Collection(); + const allServersUsers: Collection = new Collection(); /** * Set of object IDs for all known servers and channels. * Used to detect server/channel objects which have be deleted. */ - const knownServersAndChannelsIds: Set = new Set(); + const knownServersAndChannelsIds: Set = new Set(); if (this.unloaded) return; const guilds = await this.client.guilds.fetch(); if (this.unloaded) return; - for (const [, guildBase] of guilds) { + for (const [ , guildBase ] of guilds) { if (this.unloaded) return; let guild: Guild; @@ -559,7 +706,7 @@ class DiscordAdapter extends Adapter { knownServersAndChannelsIds.add(`${this.namespace}.servers.${guild.id}`); // create channel for this guild - await this.extendObjectAsyncCached(`servers.${guild.id}`, { + await this.extendObjectCached(`servers.${guild.id}`, { type: 'channel', common: { name: guild.name, @@ -568,14 +715,14 @@ class DiscordAdapter extends Adapter { }); await Promise.all([ - this.extendObjectAsyncCached(`servers.${guild.id}.members`, { + this.extendObjectCached(`servers.${guild.id}.members`, { type: 'channel', common: { name: i18n.getStringOrTranslated('Members'), }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.channels`, { + this.extendObjectCached(`servers.${guild.id}.channels`, { type: 'channel', common: { name: i18n.getStringOrTranslated('Channels'), @@ -588,13 +735,13 @@ class DiscordAdapter extends Adapter { const guildMembers = await guild.members.fetch(); if (this.unloaded) return; - for (const [, member] of guildMembers) { + for (const [ , member ] of guildMembers) { // remember user if not the bot itself if (member.user.id !== this.client.user.id) { allServersUsers.set(member.user.id, { user: member.user, presence: member.presence }); } - await this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}`, { + await this.extendObjectCached(`servers.${guild.id}.members.${member.id}`, { type: 'channel', common: { name: `${member.displayName} (${userNameOrTag(member.user)})`, @@ -603,7 +750,7 @@ class DiscordAdapter extends Adapter { }); await Promise.all([ - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.tag`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.tag`, { type: 'state', common: { name: i18n.getStringOrTranslated('User tag'), @@ -615,7 +762,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.name`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.name`, { type: 'state', common: { name: i18n.getStringOrTranslated('User name'), @@ -627,7 +774,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.displayName`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.displayName`, { type: 'state', common: { name: i18n.getStringOrTranslated('Display name'), @@ -639,7 +786,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.roles`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.roles`, { type: 'state', common: { name: i18n.getStringOrTranslated('Roles'), @@ -652,7 +799,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.joinedAt`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.joinedAt`, { type: 'state', common: { name: i18n.getStringOrTranslated('Joined at'), @@ -665,7 +812,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceChannel`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceChannel`, { type: 'state', common: { name: i18n.getStringOrTranslated('Voice channel'), @@ -677,7 +824,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceDisconnect`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceDisconnect`, { type: 'state', common: { name: i18n.getStringOrTranslated('Voice disconnect'), @@ -689,7 +836,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, { type: 'state', common: { name: i18n.getStringOrTranslated('Voice self deafen'), @@ -701,7 +848,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, { type: 'state', common: { name: i18n.getStringOrTranslated('Voice server deafen'), @@ -713,7 +860,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, { type: 'state', common: { name: i18n.getStringOrTranslated('Voice self mute'), @@ -725,7 +872,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.voiceServerMute`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.voiceServerMute`, { type: 'state', common: { name: i18n.getStringOrTranslated('Voice server mute'), @@ -738,7 +885,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`servers.${guild.id}.members.${member.id}.json`, { + this.extendObjectCached(`servers.${guild.id}.members.${member.id}.json`, { type: 'state', common: { name: i18n.getStringOrTranslated('JSON data'), @@ -752,19 +899,18 @@ class DiscordAdapter extends Adapter { }), ]); - const memberRoles = member.roles.cache.map((role) => role.name); await Promise.all([ - this.setStateAsync(`servers.${guild.id}.members.${member.id}.tag`, member.user.tag, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.name`, member.user.username, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.displayName`, member.displayName, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.roles`, memberRoles.join(', '), true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.joinedAt`, member.joinedTimestamp, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceChannel`, member.voice.channel?.name ?? '', true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, !!member.voice.selfDeaf, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, !!member.voice.serverDeaf, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, !!member.voice.selfMute, true), - this.setStateAsync(`servers.${guild.id}.members.${member.id}.voiceServerMute`, !!member.voice.serverMute, true), + this.setState(`servers.${guild.id}.members.${member.id}.tag`, member.user.tag, true), + this.setState(`servers.${guild.id}.members.${member.id}.name`, member.user.username, true), + this.setState(`servers.${guild.id}.members.${member.id}.displayName`, member.displayName, true), + this.setState(`servers.${guild.id}.members.${member.id}.roles`, memberRoles.join(', '), true), + this.setState(`servers.${guild.id}.members.${member.id}.joinedAt`, member.joinedTimestamp, true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceChannel`, member.voice.channel?.name ?? '', true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceSelfDeaf`, !!member.voice.selfDeaf, true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceServerDeaf`, !!member.voice.serverDeaf, true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceSelfMute`, !!member.voice.selfMute, true), + this.setState(`servers.${guild.id}.members.${member.id}.voiceServerMute`, !!member.voice.serverMute, true), ]); const json: JsonServersMembersObj = { @@ -782,7 +928,7 @@ class DiscordAdapter extends Adapter { voiceServerMute: !!member.voice.serverMute, }; if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.servers.${guild.id}.members.${member.id}.json`))) { - await this.setStateAsync(`servers.${guild.id}.members.${member.id}.json`, JSON.stringify(json), true); + await this.setState(`servers.${guild.id}.members.${member.id}.json`, JSON.stringify(json), true); this.jsonStateCache.set(`${this.namespace}.servers.${guild.id}.members.${member.id}.json`, json); } @@ -794,8 +940,8 @@ class DiscordAdapter extends Adapter { if (this.unloaded) return; // loop over all channels twice to setup the parent channel objects first and afterwards the child channel objects - for (const parents of [true, false]) { - for (const [, channel] of channels) { + for (const parents of [ true, false ]) { + for (const [ , channel ] of channels) { if (!channel || (parents && channel.parentId) || (!parents && !channel.parentId)) { continue; } @@ -803,14 +949,14 @@ class DiscordAdapter extends Adapter { knownServersAndChannelsIds.add(`${this.namespace}.${channelIdPrefix}`); - let icon: string | undefined = undefined; + let icon: string | undefined; if (channel.type === ChannelType.GuildText) { icon = 'channel-text.svg'; } if (channel.type === ChannelType.GuildVoice) { icon = 'channel-voice.svg'; } - await this.extendObjectAsyncCached(channelIdPrefix, { + await this.extendObjectCached(channelIdPrefix, { type: 'channel', common: { name: channel.parent ? `${channel.parent.name} / ${channel.name}` : channel.name, @@ -821,7 +967,7 @@ class DiscordAdapter extends Adapter { }, }); if (channel.type === ChannelType.GuildCategory) { - await this.extendObjectAsyncCached(`${channelIdPrefix}.channels`, { + await this.extendObjectCached(`${channelIdPrefix}.channels`, { type: 'channel', common: { name: i18n.getStringOrTranslated('Channels'), @@ -831,7 +977,7 @@ class DiscordAdapter extends Adapter { } await Promise.all([ - this.extendObjectAsyncCached(`${channelIdPrefix}.json`, { + this.extendObjectCached(`${channelIdPrefix}.json`, { type: 'state', common: { name: i18n.getStringOrTranslated('JSON data'), @@ -843,7 +989,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.memberCount`, { + this.extendObjectCached(`${channelIdPrefix}.memberCount`, { type: 'state', common: { name: i18n.getStringOrTranslated('Member count'), @@ -855,7 +1001,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.members`, { + this.extendObjectCached(`${channelIdPrefix}.members`, { type: 'state', common: { name: i18n.getStringOrTranslated('Members'), @@ -871,7 +1017,7 @@ class DiscordAdapter extends Adapter { if (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildVoice) { await Promise.all([ - this.extendObjectAsyncCached(`${channelIdPrefix}.message`, { + this.extendObjectCached(`${channelIdPrefix}.message`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message'), @@ -883,7 +1029,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.messageId`, { + this.extendObjectCached(`${channelIdPrefix}.messageId`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message ID'), @@ -895,7 +1041,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.messageAuthor`, { + this.extendObjectCached(`${channelIdPrefix}.messageAuthor`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message author'), @@ -907,7 +1053,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.messageTimestamp`, { + this.extendObjectCached(`${channelIdPrefix}.messageTimestamp`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message timestamp'), @@ -919,7 +1065,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.messageJson`, { + this.extendObjectCached(`${channelIdPrefix}.messageJson`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message JSON data'), @@ -932,7 +1078,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.send`, { + this.extendObjectCached(`${channelIdPrefix}.send`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send message'), @@ -944,7 +1090,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.sendFile`, { + this.extendObjectCached(`${channelIdPrefix}.sendFile`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send file'), @@ -956,7 +1102,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.sendReply`, { + this.extendObjectCached(`${channelIdPrefix}.sendReply`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send reply'), @@ -968,7 +1114,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`${channelIdPrefix}.sendReaction`, { + this.extendObjectCached(`${channelIdPrefix}.sendReaction`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send reaction'), @@ -1013,10 +1159,10 @@ class DiscordAdapter extends Adapter { /* * Create objects/states for all known users. */ - for (const [, {user, presence}] of allServersUsers) { + for (const [ , { user, presence } ] of allServersUsers) { this.log.debug(`Known user: ${user.tag} id:${user.id}`); - await this.extendObjectAsyncCached(`users.${user.id}`, { + await this.extendObjectCached(`users.${user.id}`, { type: 'channel', common: { name: userNameOrTag(user), @@ -1027,7 +1173,7 @@ class DiscordAdapter extends Adapter { }); await Promise.all([ - this.extendObjectAsyncCached(`users.${user.id}.json`, { + this.extendObjectCached(`users.${user.id}.json`, { type: 'state', common: { name: i18n.getStringOrTranslated('JSON data'), @@ -1040,7 +1186,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.tag`, { + this.extendObjectCached(`users.${user.id}.tag`, { type: 'state', common: { name: i18n.getStringOrTranslated('User tag'), @@ -1053,7 +1199,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.name`, { + this.extendObjectCached(`users.${user.id}.name`, { type: 'state', common: { name: i18n.getStringOrTranslated('User name'), @@ -1066,7 +1212,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.message`, { + this.extendObjectCached(`users.${user.id}.message`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message'), @@ -1078,7 +1224,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.messageId`, { + this.extendObjectCached(`users.${user.id}.messageId`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message ID'), @@ -1090,7 +1236,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.messageTimestamp`, { + this.extendObjectCached(`users.${user.id}.messageTimestamp`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message timestamp'), @@ -1102,7 +1248,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.messageJson`, { + this.extendObjectCached(`users.${user.id}.messageJson`, { type: 'state', common: { name: i18n.getStringOrTranslated('Last message JSON data'), @@ -1115,7 +1261,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.send`, { + this.extendObjectCached(`users.${user.id}.send`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send message'), @@ -1127,7 +1273,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.sendFile`, { + this.extendObjectCached(`users.${user.id}.sendFile`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send file'), @@ -1139,7 +1285,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.sendReply`, { + this.extendObjectCached(`users.${user.id}.sendReply`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send reply'), @@ -1151,7 +1297,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.sendReaction`, { + this.extendObjectCached(`users.${user.id}.sendReaction`, { type: 'state', common: { name: i18n.getStringOrTranslated('Send reaction'), @@ -1164,7 +1310,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.avatarUrl`, { + this.extendObjectCached(`users.${user.id}.avatarUrl`, { type: 'state', common: { name: i18n.getStringOrTranslated('Avatar'), @@ -1177,7 +1323,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.bot`, { + this.extendObjectCached(`users.${user.id}.bot`, { type: 'state', common: { name: i18n.getStringOrTranslated('Bot'), @@ -1190,7 +1336,7 @@ class DiscordAdapter extends Adapter { native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.status`, { + this.extendObjectCached(`users.${user.id}.status`, { type: 'state', common: { name: i18n.getStringOrTranslated('Status'), @@ -1202,7 +1348,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.activityType`, { + this.extendObjectCached(`users.${user.id}.activityType`, { type: 'state', common: { name: i18n.getStringOrTranslated('Activity type'), @@ -1214,7 +1360,7 @@ class DiscordAdapter extends Adapter { }, native: {}, }), - this.extendObjectAsyncCached(`users.${user.id}.activityName`, { + this.extendObjectCached(`users.${user.id}.activityName`, { type: 'state', common: { name: i18n.getStringOrTranslated('Activity name'), @@ -1234,7 +1380,7 @@ class DiscordAdapter extends Adapter { const ps = await this.updateUserPresence(user.id, presence, true); - const proms: Promise[] = []; + const proms: Promise[] = []; const json: JsonUsersObj = { id: user.id, tag: user.tag, @@ -1246,14 +1392,14 @@ class DiscordAdapter extends Adapter { status: ps.status, }; if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.users.${user.id}.json`))) { - proms.push(this.setStateAsync(`users.${user.id}.json`, JSON.stringify(json), true)); + proms.push(this.setState(`users.${user.id}.json`, JSON.stringify(json), true)); this.jsonStateCache.set(`${this.namespace}.users.${user.id}.json`, json); } await Promise.all([ - this.setStateAsync(`users.${user.id}.tag`, user.tag, true), - this.setStateAsync(`users.${user.id}.name`, user.username, true), - this.setStateAsync(`users.${user.id}.avatarUrl`, json.avatarUrl, true), - this.setStateAsync(`users.${user.id}.bot`, user.bot, true), + this.setState(`users.${user.id}.tag`, user.tag, true), + this.setState(`users.${user.id}.name`, user.username, true), + this.setState(`users.${user.id}.avatarUrl`, json.avatarUrl, true), + this.setState(`users.${user.id}.bot`, user.bot, true), ...proms, this.updateUserPresence(user.id, presence), ]); @@ -1313,7 +1459,7 @@ class DiscordAdapter extends Adapter { private async updateChannelInfoStates (channel: NonThreadGuildBasedChannel): Promise { const channelIdPrefix = channel.parentId ? `servers.${channel.guildId}.channels.${channel.parentId}.channels.${channel.id}` : `servers.${channel.guild.id}.channels.${channel.id}`; - const members = [...channel.members.values()]; + const members = [ ...channel.members.values() ]; const json: JsonServersChannelsObj = { id: channel.id, name: channel.name, @@ -1326,14 +1472,14 @@ class DiscordAdapter extends Adapter { displayName: m.displayName, })), }; - const proms: Promise[] = []; + const proms: Promise[] = []; if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.${channelIdPrefix}.json`))) { - proms.push(this.setStateAsync(`${channelIdPrefix}.json`, JSON.stringify(json), true)); + proms.push(this.setState(`${channelIdPrefix}.json`, JSON.stringify(json), true)); this.jsonStateCache.set(`${this.namespace}.${channelIdPrefix}.json`, json); } await Promise.all([ - this.setStateAsync(`${channelIdPrefix}.memberCount`, members.length, true), - this.setStateAsync(`${channelIdPrefix}.members`, members.map((m) => m.displayName).join(', '), true), + this.setState(`${channelIdPrefix}.memberCount`, members.length, true), + this.setState(`${channelIdPrefix}.members`, members.map((m) => m.displayName).join(', '), true), ...proms, ]); } @@ -1361,7 +1507,7 @@ class DiscordAdapter extends Adapter { activityType: (presence?.activities[0]?.type !== undefined ? ActivityType[presence.activities[0].type] as ActivityTypeNames : '') ?? '', }; - const proms: Promise[] = []; + const proms: Promise[] = []; if (!skipJsonStateUpdate) { const json = this.jsonStateCache.get(`${this.namespace}.users.${userId}.json`) as JsonUsersObj | undefined; if (json) { @@ -1369,13 +1515,13 @@ class DiscordAdapter extends Adapter { json.activityName = p.activityName; json.activityType = p.activityType; this.jsonStateCache.set(`${this.namespace}.users.${userId}.json`, json); - proms.push(this.setStateAsync(`users.${userId}.json`, JSON.stringify(json), true)); + proms.push(this.setState(`users.${userId}.json`, JSON.stringify(json), true)); } } await Promise.all([ - this.setStateAsync(`users.${userId}.status`, p.status , true), - this.setStateAsync(`users.${userId}.activityName`, p.activityName, true), - this.setStateAsync(`users.${userId}.activityType`, p.activityType, true), + this.setState(`users.${userId}.status`, p.status, true), + this.setState(`users.${userId}.activityName`, p.activityName, true), + this.setState(`users.${userId}.activityType`, p.activityType, true), ...proms, ]); return p; @@ -1418,10 +1564,10 @@ class DiscordAdapter extends Adapter { opts.activityName = ((await this.getStateAsync('bot.activityName'))?.val as string | undefined) ?? ''; } if (opts.activityType && opts.activityName) { - presenceData.activities = [{ + presenceData.activities = [ { type: ActivityType[opts.activityType], name: opts.activityName, - }]; + } ]; } this.log.debug(`Set bot presence: ${JSON.stringify(presenceData)}`); @@ -1439,13 +1585,13 @@ class DiscordAdapter extends Adapter { // raw states enabled? if (this.config.enableRawStates) { // set raw state... not async here since it should not block! - this.setState('raw.messageJson', JSON.stringify(message.toJSON(), (_key, value) => typeof value === 'bigint' ? value.toString() : value), true); + void this.setState('raw.messageJson', JSON.stringify(message.toJSON(), (_key, value: unknown) => typeof value === 'bigint' ? value.toString() : value), true); } if (!this.client?.user?.id) return; // don't process interactions here - if (message.interaction) { + if (message.interactionMetadata) { return; } @@ -1509,7 +1655,7 @@ class DiscordAdapter extends Adapter { timestamp: message.createdTimestamp, authorized: isAuthorAuthorized, }; - const proms: Promise[] = []; + const proms: Promise[] = []; if (message.guildId) { json.author = { id: author.id, @@ -1517,16 +1663,16 @@ class DiscordAdapter extends Adapter { name: author.username, displayName: this.client.guilds.cache.get(message.guildId)?.members.cache.get(author.id)?.displayName ?? author.username, }; - proms.push(this.setStateAsync(`${msgStateIdPrefix}.messageAuthor`, userNameOrTag(author), true)); + proms.push(this.setState(`${msgStateIdPrefix}.messageAuthor`, userNameOrTag(author), true)); } if (!isDeepStrictEqual(json, this.jsonStateCache.get(`${this.namespace}.${msgStateIdPrefix}.messageJson`))) { - proms.push(this.setStateAsync(`${msgStateIdPrefix}.messageJson`, JSON.stringify(json), true)); + proms.push(this.setState(`${msgStateIdPrefix}.messageJson`, JSON.stringify(json), true)); this.jsonStateCache.set(`${this.namespace}.${msgStateIdPrefix}.messageJson`, json); } await Promise.all([ - this.setStateAsync(`${msgStateIdPrefix}.message`, content, true), - this.setStateAsync(`${msgStateIdPrefix}.messageId`, message.id, true), - this.setStateAsync(`${msgStateIdPrefix}.messageTimestamp`, message.createdTimestamp, true), + this.setState(`${msgStateIdPrefix}.message`, content, true), + this.setState(`${msgStateIdPrefix}.messageId`, message.id, true), + this.setState(`${msgStateIdPrefix}.messageTimestamp`, message.createdTimestamp, true), ...proms, ]); @@ -1555,7 +1701,9 @@ class DiscordAdapter extends Adapter { await message.reply(response); break; case 'message': - await message.channel.send(response); + if (message.channel.isTextBased()) { + await (message.channel as DMChannel | TextChannel).send(response); + } break; default: // no response needed @@ -1581,7 +1729,7 @@ class DiscordAdapter extends Adapter { return; } - const proms: Promise[] = []; + const proms: Promise[] = []; // update channel states if (oldState.channelId !== newState.channelId) { @@ -1602,35 +1750,35 @@ class DiscordAdapter extends Adapter { let update: boolean = false; if (oldState.channelId !== newState.channelId) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceChannel`, newState.channel?.name ?? '', true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceChannel`, newState.channel?.name ?? '', true)); json.voiceChannel = newState.channel?.name ?? ''; json.voiceChannelId = newState.channel?.id ?? ''; update = true; } if (oldState.serverDeaf !== newState.serverDeaf) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerDeaf`, !!newState.serverDeaf, true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerDeaf`, !!newState.serverDeaf, true)); json.voiceSelfDeaf = !!newState.selfDeaf; update = true; } if (oldState.selfDeaf !== newState.selfDeaf) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfDeaf`, !!newState.selfDeaf, true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfDeaf`, !!newState.selfDeaf, true)); json.voiceServerDeaf = !!newState.serverDeaf; update = true; } if (oldState.serverMute !== newState.serverMute) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerMute`, !!newState.serverMute, true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceServerMute`, !!newState.serverMute, true)); json.voiceSelfMute = !!newState.selfMute; update = true; } if (oldState.selfMute !== newState.selfMute) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfMute`, !!newState.selfMute, true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.voiceSelfMute`, !!newState.selfMute, true)); json.voiceServerMute = !!newState.serverMute; update = true; } // json state update if (update) { - proms.push(this.setStateAsync(`servers.${newState.guild.id}.members.${newState.member.id}.json`, JSON.stringify(json), true)); + proms.push(this.setState(`servers.${newState.guild.id}.members.${newState.member.id}.json`, JSON.stringify(json), true)); this.jsonStateCache.set(`${this.namespace}.servers.${newState.guild.id}.members.${newState.member.id}.json`, json); } @@ -1696,7 +1844,7 @@ class DiscordAdapter extends Adapter { this.log.warn(`Command name for ${objId} exceeds the limit of 100 chars! This object will be ignored.`); cfgOk = false; } - if (!cfg.alias.match(/^[0-9a-zA-Z._-]{0,100}$/)) { + if (!(/^[0-9a-zA-Z._-]{0,100}$/.exec(cfg.alias))) { this.log.warn(`Command alias for ${objId} includes invalid chars or exceeds the limit of 100 chars! This object will be ignored.`); cfgOk = false; } @@ -1719,12 +1867,13 @@ class DiscordAdapter extends Adapter { // The object was changed if (obj.type === 'state') { this.log.silly(`Object ${objId} changed: ${JSON.stringify(obj)}`); - this.setupObjCustom(objId, obj.common?.custom?.[this.namespace], obj.common); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + void this.setupObjCustom(objId, obj.common?.custom?.[this.namespace], obj.common); } } else { // The object was deleted this.log.silly(`Object ${objId} deleted`); - this.setupObjCustom(objId, null); + void this.setupObjCustom(objId, null); } } @@ -1732,7 +1881,7 @@ class DiscordAdapter extends Adapter { * Is called if a subscribed state changes */ @boundMethod - private async onStateChange(stateId: string, state: ioBroker.State | null | undefined): Promise { + private async onStateChange (stateId: string, state: ioBroker.State | null | undefined): Promise { this.log.silly(`State changed: ${stateId} ${state?.val} (ack=${state?.ack})`); if (!state || state.ack) return; @@ -1760,11 +1909,11 @@ class DiscordAdapter extends Adapter { default: // other own states // custom slash command reply - if (stateId.match(/^discord\.\d+\.slashCommands\..*\.sendReply/)) { + if (/^discord\.\d+\.slashCommands\..*\.sendReply/.exec(stateId)) { setAck = await this.onCustomCommandSendReplyStateChange(stateId, state); // custom slash command option choices - } else if (stateId.match(/^discord\.\d+\.slashCommands\..*\.option-[^.]+\.choices/)) { + } else if (/^discord\.\d+\.slashCommands\..*\.option-[^.]+\.choices/.exec(stateId)) { // trigger delayed register slash commands to handle multiple changes of choices states together this.discordSlashCommands.triggerDelayedRegisterSlashCommands(); setAck = true; @@ -1783,7 +1932,7 @@ class DiscordAdapter extends Adapter { } if (setAck) { - await this.setStateAsync(stateId, { + await this.setState(stateId, { ...state, ack: true, }); @@ -1819,7 +1968,7 @@ class DiscordAdapter extends Adapter { let targetStateIdBase: string; // channel or user? - let m = stateId.match(/^(discord\.\d+\.servers\.(\d+)\.channels\.(\d+)(\.channels\.(\d+))?)\.(send|sendFile|sendReaction|sendReply)$/); + let m = /^(discord\.\d+\.servers\.(\d+)\.channels\.(\d+)(\.channels\.(\d+))?)\.(send|sendFile|sendReaction|sendReply)$/.exec(stateId); if (m) { const guildId = m[2]; const channelId = m[5] || m[3]; @@ -1836,7 +1985,7 @@ class DiscordAdapter extends Adapter { targetName = channel.parent ? `${channel.guild.name}/${channel.parent.name}/${channel.name}` : `${channel.guild.name}/${channel.name}`; } else { - m = stateId.match(/^(discord\.\d+\.users\.(\d+))\.(send|sendFile|sendReaction|sendReply)$/); + m = /^(discord\.\d+\.users\.(\d+))\.(send|sendFile|sendReaction|sendReply)$/.exec(stateId); if (!m) { this.log.warn(`State ${stateId} changed but could not determine target to send message to!`); return false; @@ -1863,7 +2012,7 @@ class DiscordAdapter extends Adapter { if (action === 'sendFile') { const idx = state.val.indexOf('|'); let file: string; - let content: string | undefined = undefined; + let content: string | undefined; if (idx > 0) { file = state.val.slice(0, idx); content = state.val.slice(idx + 1); @@ -1877,10 +2026,10 @@ class DiscordAdapter extends Adapter { // base64 encoded content mo = { content, - files: [{ + files: [ { attachment: b64data.buffer, name: b64data.name, - }], + } ], }; } else { @@ -1894,14 +2043,13 @@ class DiscordAdapter extends Adapter { mo = { content, - files: [{ + files: [ { attachment: file, name, - }], + } ], }; } - /* * Special case .sendReply state */ @@ -1971,7 +2119,6 @@ class DiscordAdapter extends Adapter { } } - /* * `state.val` may be JSON for .send states * Try to parse the JSON as MessageOptions object to allow sending of files, embeds, ... @@ -2052,12 +2199,12 @@ class DiscordAdapter extends Adapter { * @returns `true` if successfull. */ private async onVoiceStateChange (stateId: string, state: ioBroker.State): Promise { - const m = stateId.match(/^discord\.\d+\.servers\.(\d+)\.members\.(\d+)\.voice(Disconnect|ServerMute|ServerDeaf)$/); + const m = /^discord\.\d+\.servers\.(\d+)\.members\.(\d+)\.voice(Disconnect|ServerMute|ServerDeaf)$/.exec(stateId); if (!m) { this.log.debug(`Voice state ${stateId} changed but could not get serverID and memberID!`); return false; } - const [, guildId, memberId, action] = m; + const [ , guildId, memberId, action ] = m; const guild = this.client?.guilds.cache.get(guildId); const member = guild?.members.cache.get(memberId); @@ -2111,7 +2258,7 @@ class DiscordAdapter extends Adapter { let user: User | undefined; switch (obj.command) { - case 'getText2commandInstances': + case 'getText2commandInstances': { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2128,16 +2275,17 @@ class DiscordAdapter extends Adapter { }; }); this.log.debug(`Found text2command instances: ${text2commandInstances.map((i) => i.value)}`); - this.sendTo(obj.from, obj.command, [{value: '', label: '---'}, ...text2commandInstances], obj.callback); + this.sendTo(obj.from, obj.command, [ { value: '', label: '---' }, ...text2commandInstances ], obj.callback); break; + } // getText2commandInstances - case 'getNotificationTargets': + case 'getNotificationTargets': { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; } - const targets: { label: string, value: string }[] = [{ value: '', label: '---' }]; + const targets: { label: string, value: string }[] = [ { value: '', label: '---' } ]; // users this.client?.users.cache.forEach((u) => { @@ -2162,8 +2310,9 @@ class DiscordAdapter extends Adapter { this.log.debug(`Notification targets: ${targets.map((i) => i.value)}`); this.sendTo(obj.from, obj.command, targets, obj.callback); break; + } // getNotificationTargets - case 'getUsers': + case 'getUsers': { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2173,8 +2322,9 @@ class DiscordAdapter extends Adapter { this.log.debug(`Users: ${users.map((i) => i.value)}`); this.sendTo(obj.from, obj.command, users, obj.callback); break; + } // getUsers - case 'getServers': + case 'getServers': { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2184,8 +2334,9 @@ class DiscordAdapter extends Adapter { this.log.debug(`Servers: ${servers.map((i) => i.value)}`); this.sendTo(obj.from, obj.command, servers, obj.callback); break; + } // getServers - case 'getServerRoles': + case 'getServerRoles': { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2197,8 +2348,8 @@ class DiscordAdapter extends Adapter { } const guildRolesWithLabel = []; - for (const [, guild] of this.client.guilds.cache) { - for (const [, role] of guild.roles.cache) { + for (const [ , guild ] of this.client.guilds.cache) { + for (const [ , role ] of guild.roles.cache) { guildRolesWithLabel.push({ label: `${guild.name} - ${role.name}`, value: `${guild.id}|${role.id}`, @@ -2210,8 +2361,9 @@ class DiscordAdapter extends Adapter { this.sendTo(obj.from, obj.command, guildRolesWithLabel, obj.callback); break; + } // getServerRoles - case 'getAddToServerLink': + case 'getAddToServerLink': { if (!obj.callback) { this.log.warn(`Message '${obj.command}' called without callback!`); return; @@ -2236,14 +2388,16 @@ class DiscordAdapter extends Adapter { this.sendTo(obj.from, obj.command, `- ${i18n.getString('Error: The Bot is not connected to Discord!')} -`, obj.callback); } break; + } // getAddToServerLink - case 'logConfiguredCommandObjects': + case 'logConfiguredCommandObjects': { this.discordSlashCommands.logConfiguredCommandObjects(); this.sendToIfCb(obj.from, obj.command, { result: 'ok' }, obj.callback); break; + } // logConfiguredCommandObjects case 'send': - case 'sendMessage': + case 'sendMessage': { /* * send a message */ @@ -2310,9 +2464,10 @@ class DiscordAdapter extends Adapter { this.sendToIfCb(obj.from, obj.command, { error: 'userId, userTag, userName or serverId and channelId needs to be set', ...sendPayload }, obj.callback); } - break; // send / sendMessage + break; + } // send / sendMessage - case 'editMessage': + case 'editMessage': { /* * edit a message */ @@ -2353,9 +2508,10 @@ class DiscordAdapter extends Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error editing message: ${err}`, ...editMessagePayload }, obj.callback); } - break; // editMessage + break; + } // editMessage - case 'deleteMessage': + case 'deleteMessage': { /* * delete a message */ @@ -2390,9 +2546,10 @@ class DiscordAdapter extends Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error deleting message: ${err}`, ...deleteMessagePayload }, obj.callback); } - break; // deleteMessage + break; + } // deleteMessage - case 'addReaction': + case 'addReaction': { /* * add a reaction emoji to a message */ @@ -2429,9 +2586,10 @@ class DiscordAdapter extends Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error adding reaction to message: ${err}`, ...addReactionPayload }, obj.callback); } - break; // addReaction + break; + } // addReaction - case 'awaitMessageReaction': + case 'awaitMessageReaction': { /* * wait for a message reaction */ @@ -2479,9 +2637,10 @@ class DiscordAdapter extends Adapter { this.sendTo(obj.from, obj.command, { reactions, ...awaitMessageReactionPayload }, obj.callback); }); - break; // awaitMessageReaction + break; + } // awaitMessageReaction - case 'sendCustomCommandReply': + case 'sendCustomCommandReply': { /* * send a reply to a custom slash command */ @@ -2510,9 +2669,10 @@ class DiscordAdapter extends Adapter { this.sendToIfCb(obj.from, obj.command, { error: `Error sending reply: ${err}`, ...sendCustomCommandReplyPayload }, obj.callback); } - break; // sendCustomCommandReply + break; + } // sendCustomCommandReply - case 'leaveServer': + case 'leaveServer': { /* * let the bot leave a server */ @@ -2545,8 +2705,9 @@ class DiscordAdapter extends Adapter { } break; + } // leaveServer - case 'getServerInfo': + case 'getServerInfo': { /* * get information about a server */ @@ -2597,9 +2758,10 @@ class DiscordAdapter extends Adapter { })), }, obj.callback); - break; // getServerInfo + break; + } // getServerInfo - case 'getChannelInfo': + case 'getChannelInfo': { /* * get information about a channel */ @@ -2640,9 +2802,10 @@ class DiscordAdapter extends Adapter { })), }, obj.callback); - break; // getChannelInfo + break; + } // getChannelInfo - case 'getServerMemberInfo': + case 'getServerMemberInfo': { /* * get information about a server member */ @@ -2703,9 +2866,10 @@ class DiscordAdapter extends Adapter { voiceDeaf: member.voice.deaf, }, obj.callback); - break; // getServerMemberInfo + break; + } // getServerMemberInfo - case 'getUserInfo': + case 'getUserInfo': { /* * get information about a user */ @@ -2756,9 +2920,10 @@ class DiscordAdapter extends Adapter { accentColor: user.hexAccentColor, }, obj.callback); - break; // getUserInfo + break; + } // getUserInfo - case 'getMessageInfo': + case 'getMessageInfo': { /* * get information about a message */ @@ -2801,9 +2966,10 @@ class DiscordAdapter extends Adapter { reference: msg.reference, }, obj.callback); - break; // getMessageInfo + break; + } // getMessageInfo - case 'sendNotification': + case 'sendNotification': { /* * notification from ioBrokers notification system * see https://github.com/foxriver76/ioBroker.notification-manager @@ -2821,14 +2987,14 @@ class DiscordAdapter extends Adapter { this.log.info(`New notification received from ${obj.from.replace(/^system\.adapter\./, '')}`); - let target: User | TextChannel | undefined = undefined; + let target: User | TextChannel | undefined; if (this.config.sendNotificationsTo.indexOf('/') > 0) { // server channel - const [serverId, channelId] = this.config.sendNotificationsTo.split('/'); - const channel = this.client?.guilds.cache.get(serverId)?.channels.cache.get(channelId); - if (channel?.type === ChannelType.GuildText) { - target = channel; + const [ serverId, channelId ] = this.config.sendNotificationsTo.split('/'); + const channel2 = this.client?.guilds.cache.get(serverId)?.channels.cache.get(channelId); + if (channel2?.type === ChannelType.GuildText) { + target = channel2; } } else { // user @@ -2865,7 +3031,7 @@ class DiscordAdapter extends Adapter { break; } - const readableInstances = Object.entries(instances).map(([instance, entry]) => `${instance.substring('system.adapter.'.length)}: ${getNewestDate(entry.messages, i18n.language)}`); + const readableInstances = Object.entries(instances).map(([ instance, entry ]) => `${instance.substring('system.adapter.'.length)}: ${getNewestDate(entry.messages, i18n.language)}`); const text = `${icon}**${message.category.name}** @@ -2875,8 +3041,8 @@ ${message.host}: ${readableInstances.join('\n')}`; try { - const msg = await target.send(text); - this.log.debug(`Sent message from notification-manager adapter with message ID ${msg.id}`); + const msg2 = await target.send(text); + this.log.debug(`Sent message from notification-manager adapter with message ID ${msg2.id}`); this.sendTo(obj.from, obj.command, { sent: true }, obj.callback); } catch (err) { this.log.warn(`Error sending message from notification-manager adapter: ${err}`); @@ -2884,6 +3050,7 @@ ${readableInstances.join('\n')}`; } break; + } // sendNotification default: /* @@ -2907,52 +3074,13 @@ ${readableInstances.join('\n')}`; private sendToIfCb (instanceName: string, command: string, message: ioBroker.MessagePayload, callback: ioBroker.MessageCallback | ioBroker.MessageCallbackInfo | undefined): void { if (callback) { this.sendTo(instanceName, command, message, callback); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access } else if (typeof message === 'object' && message.error) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access this.log.warn(message.error); } } - /** - * Try to detect and parse stringified JSON MessageOptions. - * - * If the `content` starts/ends with curly braces if will be treated as - * stringified JSON. Then the JSON will be parsed and some basic checks will - * be run against the parsed object. - * - * Otherwise the content will be treated as a simple string and wrapped into - * a `MessageOptions` object. - * @param content The stringified content to be parsed. - * @returns A `MessageOptions` object. - * @throws An error if parsing JSON or a check failed. - */ - public parseStringifiedMessageOptions (content: string): MessageCreateOptions { - let mo: MessageCreateOptions; - - if (content.startsWith('{') && content.endsWith('}')) { - // seems to be json - this.log.debug(`Content seems to be json`); - - try { - mo = JSON.parse(content) as MessageCreateOptions; - } catch (err) { - throw new Error(`Content seems to be json but cannot be parsed!`); - } - - // do some basic checks against the parsed object - if ((!mo?.files && !mo.content) || (mo.files && !Array.isArray(mo.files)) || (mo.embeds && !Array.isArray(mo.embeds))) { - throw new Error(`Content is json but seems to be invalid!`); - } - - } else { - // just a string... create MessageOptions object - mo = { - content, - }; - } - - return mo; - } - /** * Prepare a message for sending. * @@ -2971,7 +3099,7 @@ ${readableInstances.join('\n')}`; // color codes may be given as string in user defined embeds if (typeof (embed as APIEmbed).color === 'string') { const colorStr: string = (embed as APIEmbed).color as unknown as string; - if (colorStr.match(/^\d+$/)) { + if (/^\d+$/.exec(colorStr)) { // it's a number color given as string (embed as APIEmbed).color = parseInt(colorStr, 10); } else { @@ -3059,70 +3187,6 @@ ${readableInstances.join('\n')}`; } } - /** - * Check if a user or guild member is authorized to do something. - * For guild members their roles will also be checked. - * @param user The User or GuildMember to check. - * @param required Object containing the required flags. If not provided the check returns if the user in the list of authorized users. - * @returns `true` if the user is authorized or authorization is not enabled, `false` otherwise - */ - public checkUserAuthorization (user: User | GuildMember, required?: CheckAuthorizationOpts): boolean { - if (!this.config.enableAuthorization) { - return true; - } - - // get direct user flags - let given: ioBroker.AdapterConfigAuthorizedFlags | undefined = this.config.authorizedUsers.find((au) => au.userId === user.id); - - // for guild members find role flags and merge them all together - if (this.config.authorizedServerRoles.length > 0 && user instanceof GuildMember) { - for (const [, role] of user.roles.cache) { - const roleGiven = this.config.authorizedServerRoles.find((ar) => ar.serverAndRoleId === `${user.guild.id}|${role.id}`); - if (roleGiven) { - if (!given) { - given = roleGiven; - } else { - given = { - getStates: given.getStates || roleGiven.getStates, - setStates: given.setStates || roleGiven.setStates, - useCustomCommands: given.useCustomCommands || roleGiven.useCustomCommands, - useText2command: given.useText2command || roleGiven.useText2command, - }; - } - } - } - } - - // nothing found? - if (!given) { - return false; - } - - // if no required flags given just return true if something found - if (!required) { - return true; - } - - if ((required.getStates && !given.getStates) - || (required.setStates && !given.setStates) - || (required.useCustomCommands && !given.useCustomCommands) - || (required.useText2command && !given.useText2command)) { - return false; - } - - return true; - } - - /** - * Awaitable function to just wait some time. - * - * Uses `Adapter.setTimeout(...)` internally to make sure the timeout is cleared on adapter unload. - * @param time Time to wait in ms. - */ - public wait (time: number): Promise { - return new Promise((resolve: () => void) => this.setTimeout(resolve, time)); - } - /** * Set the `info.connection` state if changed. * @param connected If connected. @@ -3130,45 +3194,11 @@ ${readableInstances.join('\n')}`; */ private async setInfoConnectionState (connected: boolean, force: boolean = false): Promise { if (force || connected !== this.infoConnected) { - await this.setStateAsync('info.connection', connected, true); + await this.setState('info.connection', connected, true); this.infoConnected = connected; } } - /** - * Internal replacemend for `extendObjectAsync(...)` which compares the given - * object for each `id` against a cached version and only calls na original - * `extendObjectAsync(...)` if the object changed. - * Using this, the object gets only updated if - * a) it's the first call for this `id` or - * b) the object needs to be changed. - */ - public async extendObjectAsyncCached (id: string, objPart: ioBroker.PartialObject, options?: ioBroker.ExtendObjectOptions): ioBroker.SetObjectPromise { - const cachedObj: ioBroker.PartialObject | undefined = this.extendObjectCache.get(id); - - if (isDeepStrictEqual(cachedObj, objPart)) { - return { id }; - } - - const ret = await this.extendObjectAsync(id, objPart, options); - this.extendObjectCache.set(id, objPart); - return ret; - } - - /** - * Internal replacement for `delObjectAsync(...)` which also removes the local - * cache entry for the given `id`. - */ - public async delObjectAsyncCached (id: string, options?: ioBroker.DelObjectOptions): Promise { - if (options?.recursive) { - this.extendObjectCache.filter((_obj, id2) => id2.startsWith(id)).each((_obj, id2) => this.extendObjectCache.delete(id2)); - } else { - this.extendObjectCache.delete(id); - } - - return this.delObjectAsync(id, options); - } - /** * Is called when adapter shuts down - callback has to be called under any circumstances! */ @@ -3180,11 +3210,11 @@ ${readableInstances.join('\n')}`; await this.setInfoConnectionState(false, true); if (this.client) { - this.client.destroy(); + await this.client.destroy(); } callback(); - } catch (e) { + } catch (_e) { callback(); } } diff --git a/tsconfig.json b/tsconfig.json index 7a381ff..0b8ca9f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -36,9 +36,8 @@ // "useUnknownInCatchVariables": false, "forceConsistentCasingInFileNames": true, - // Node 16 - "target": "es2021", - "lib": ["es2021"], + "target": "es2022", + "lib": ["es2022"], "sourceMap": true, "inlineSourceMap": false @@ -46,7 +45,9 @@ "include": [ "src/**/*.ts", "admin/**/*.ts", - "admin/**/*.tsx" + "admin/**/*.tsx", + "admin/blockly.js", + "eslint.config.mjs" ], "exclude": [ "build/**",